1a4f3ed62SAlex Bennée /*
2a4f3ed62SAlex Bennée * Fused Multiply Add (Single)
3a4f3ed62SAlex Bennée *
4*542b10bdSAlex Bennée * Copyright (c) 2019, 2024 Linaro
5a4f3ed62SAlex Bennée *
6*542b10bdSAlex Bennée * SPDX-License-Identifier: GPL-2.0-or-later
7a4f3ed62SAlex Bennée */
8a4f3ed62SAlex Bennée
9a4f3ed62SAlex Bennée #include <stdio.h>
10a4f3ed62SAlex Bennée #include <stdlib.h>
11a4f3ed62SAlex Bennée #include <math.h>
12a4f3ed62SAlex Bennée #include <float.h>
13a4f3ed62SAlex Bennée #include <fenv.h>
14a4f3ed62SAlex Bennée
15a4f3ed62SAlex Bennée #include "float_helpers.h"
16a4f3ed62SAlex Bennée
17a4f3ed62SAlex Bennée #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
18a4f3ed62SAlex Bennée
19a4f3ed62SAlex Bennée typedef struct {
20a4f3ed62SAlex Bennée int flag;
21a4f3ed62SAlex Bennée char *desc;
22a4f3ed62SAlex Bennée } float_mapping;
23a4f3ed62SAlex Bennée
24a4f3ed62SAlex Bennée float_mapping round_flags[] = {
25a4f3ed62SAlex Bennée { FE_TONEAREST, "to nearest" },
26a4f3ed62SAlex Bennée #ifdef FE_UPWARD
27a4f3ed62SAlex Bennée { FE_UPWARD, "upwards" },
28a4f3ed62SAlex Bennée #endif
29a4f3ed62SAlex Bennée #ifdef FE_DOWNWARD
30a4f3ed62SAlex Bennée { FE_DOWNWARD, "downwards" },
31a4f3ed62SAlex Bennée #endif
324c71dc37SRichard Henderson #ifdef FE_TOWARDZERO
33a4f3ed62SAlex Bennée { FE_TOWARDZERO, "to zero" }
344c71dc37SRichard Henderson #endif
35a4f3ed62SAlex Bennée };
36a4f3ed62SAlex Bennée
37a4f3ed62SAlex Bennée
print_inputs(float a,float b,float c)38a4f3ed62SAlex Bennée static void print_inputs(float a, float b, float c)
39a4f3ed62SAlex Bennée {
40a4f3ed62SAlex Bennée char *a_fmt, *b_fmt, *c_fmt;
41a4f3ed62SAlex Bennée
42a4f3ed62SAlex Bennée a_fmt = fmt_f32(a);
43a4f3ed62SAlex Bennée b_fmt = fmt_f32(b);
44a4f3ed62SAlex Bennée c_fmt = fmt_f32(c);
45a4f3ed62SAlex Bennée
46a4f3ed62SAlex Bennée printf("op : %s * %s + %s\n", a_fmt, b_fmt, c_fmt);
47a4f3ed62SAlex Bennée
48a4f3ed62SAlex Bennée free(a_fmt);
49a4f3ed62SAlex Bennée free(b_fmt);
50a4f3ed62SAlex Bennée free(c_fmt);
51a4f3ed62SAlex Bennée }
52a4f3ed62SAlex Bennée
print_result(float r,int j,int k)53a4f3ed62SAlex Bennée static void print_result(float r, int j, int k)
54a4f3ed62SAlex Bennée {
55a4f3ed62SAlex Bennée char *r_fmt, *flag_fmt;
56a4f3ed62SAlex Bennée
57a4f3ed62SAlex Bennée flag_fmt = fmt_flags();
58603bd9c2SRichard Henderson r_fmt = fmt_f32(r);
59a4f3ed62SAlex Bennée
60a4f3ed62SAlex Bennée printf("res: %s flags=%s (%d/%d)\n", r_fmt, flag_fmt, j, k);
61a4f3ed62SAlex Bennée
62a4f3ed62SAlex Bennée free(r_fmt);
63a4f3ed62SAlex Bennée free(flag_fmt);
64a4f3ed62SAlex Bennée }
65a4f3ed62SAlex Bennée
do_madds(float a,float b,float c,int j,int k)66a4f3ed62SAlex Bennée static void do_madds(float a, float b, float c, int j, int k)
67a4f3ed62SAlex Bennée {
68a4f3ed62SAlex Bennée float r;
69a4f3ed62SAlex Bennée
70a4f3ed62SAlex Bennée print_inputs(a, b, c);
71a4f3ed62SAlex Bennée
72a4f3ed62SAlex Bennée feclearexcept(FE_ALL_EXCEPT);
73a4f3ed62SAlex Bennée r = __builtin_fmaf(a, b, c);
74a4f3ed62SAlex Bennée
75a4f3ed62SAlex Bennée print_result(r, j, k);
76a4f3ed62SAlex Bennée }
77a4f3ed62SAlex Bennée
main(int argc,char * argv[argc])78a4f3ed62SAlex Bennée int main(int argc, char *argv[argc])
79a4f3ed62SAlex Bennée {
80a4f3ed62SAlex Bennée int i, j, k, nums = get_num_f32();
81a4f3ed62SAlex Bennée float a, b, c;
82a4f3ed62SAlex Bennée
83a4f3ed62SAlex Bennée for (i = 0; i < ARRAY_SIZE(round_flags); ++i) {
84a4f3ed62SAlex Bennée if (fesetround(round_flags[i].flag) != 0) {
85a4f3ed62SAlex Bennée printf("### Rounding %s skipped\n", round_flags[i].desc);
86a4f3ed62SAlex Bennée continue;
87a4f3ed62SAlex Bennée }
88a4f3ed62SAlex Bennée printf("### Rounding %s\n", round_flags[i].desc);
89a4f3ed62SAlex Bennée for (j = 0; j < nums; j++) {
90a4f3ed62SAlex Bennée for (k = 0; k < 3; k++) {
91a4f3ed62SAlex Bennée a = get_f32(j + ((k)%3));
92a4f3ed62SAlex Bennée b = get_f32(j + ((k+1)%3));
93a4f3ed62SAlex Bennée c = get_f32(j + ((k+2)%3));
94a4f3ed62SAlex Bennée do_madds(a, b, c, j, k);
95a4f3ed62SAlex Bennée }
96a4f3ed62SAlex Bennée }
97a4f3ed62SAlex Bennée
98a4f3ed62SAlex Bennée /* From https://bugs.launchpad.net/qemu/+bug/1841491 */
99a4f3ed62SAlex Bennée printf("# LP184149\n");
100a4f3ed62SAlex Bennée do_madds(0x1.ffffffffffffcp-1022, 0x1.0000000000001p-1, 0x0.0000000000001p-1022, j, 0);
101a4f3ed62SAlex Bennée do_madds(0x8p-152, 0x8p-152, 0x8p-152, j+1, 0);
102a4f3ed62SAlex Bennée }
103a4f3ed62SAlex Bennée
104a4f3ed62SAlex Bennée return 0;
105a4f3ed62SAlex Bennée }
106