xref: /openbmc/qemu/tests/fp/fp-test-log2.c (revision 7d87775f)
1 /*
2  * fp-test-log2.c - test QEMU's softfloat log2
3  *
4  * Copyright (C) 2020, Linaro, Ltd.
5  *
6  * License: GNU GPL, version 2 or later.
7  *   See the COPYING file in the top-level directory.
8  */
9 #ifndef HW_POISON_H
10 #error Must define HW_POISON_H to work around TARGET_* poisoning
11 #endif
12 
13 #include "qemu/osdep.h"
14 #include "qemu/cutils.h"
15 #include <math.h>
16 #include "fpu/softfloat.h"
17 
18 typedef union {
19     double d;
20     float64 i;
21 } ufloat64;
22 
23 static int errors;
24 
25 static void compare(ufloat64 test, ufloat64 real, ufloat64 soft, bool exact)
26 {
27     int msb;
28     uint64_t ulp = UINT64_MAX;
29 
30     if (real.i == soft.i) {
31         return;
32     }
33     msb = 63 - __builtin_clzll(real.i ^ soft.i);
34 
35     if (msb < 52) {
36         if (real.i > soft.i) {
37             ulp = real.i - soft.i;
38         } else {
39             ulp = soft.i - real.i;
40         }
41     }
42 
43     /* glibc allows 3 ulp error in its libm-test-ulps; allow 4 here */
44     if (!exact && ulp <= 4) {
45         return;
46     }
47 
48     printf("test: %016" PRIx64 "  %+.13a\n"
49            "  sf: %016" PRIx64 "  %+.13a\n"
50            "libm: %016" PRIx64 "  %+.13a\n",
51            test.i, test.d, soft.i, soft.d, real.i, real.d);
52 
53     if (msb == 63) {
54         printf("Error in sign!\n\n");
55     } else if (msb >= 52) {
56         printf("Error in exponent: %d\n\n",
57                (int)(soft.i >> 52) - (int)(real.i >> 52));
58     } else {
59         printf("Error in fraction: %" PRIu64 " ulp\n\n", ulp);
60     }
61 
62     if (++errors == 20) {
63         exit(1);
64     }
65 }
66 
67 int main(int ac, char **av)
68 {
69     ufloat64 test, real, soft;
70     float_status qsf = {0};
71     int i;
72 
73     set_float_2nan_prop_rule(float_2nan_prop_s_ab, &qsf);
74     set_float_rounding_mode(float_round_nearest_even, &qsf);
75 
76     test.d = 0.0;
77     real.d = -__builtin_inf();
78     soft.i = float64_log2(test.i, &qsf);
79     compare(test, real, soft, true);
80 
81     test.d = 1.0;
82     real.d = 0.0;
83     soft.i = float64_log2(test.i, &qsf);
84     compare(test, real, soft, true);
85 
86     test.d = 2.0;
87     real.d = 1.0;
88     soft.i = float64_log2(test.i, &qsf);
89     compare(test, real, soft, true);
90 
91     test.d = 4.0;
92     real.d = 2.0;
93     soft.i = float64_log2(test.i, &qsf);
94     compare(test, real, soft, true);
95 
96     test.d = 0x1p64;
97     real.d = 64.0;
98     soft.i = float64_log2(test.i, &qsf);
99     compare(test, real, soft, true);
100 
101     test.d = __builtin_inf();
102     real.d = __builtin_inf();
103     soft.i = float64_log2(test.i, &qsf);
104     compare(test, real, soft, true);
105 
106     for (i = 0; i < 10000; ++i) {
107         test.d = drand48() + 1.0;    /* [1.0, 2.0) */
108         real.d = log2(test.d);
109         soft.i = float64_log2(test.i, &qsf);
110         compare(test, real, soft, false);
111 
112         test.d = drand48() * 100;    /* [0.0, 100) */
113         real.d = log2(test.d);
114         soft.i = float64_log2(test.i, &qsf);
115         compare(test, real, soft, false);
116     }
117 
118     return 0;
119 }
120