1 //===-- aeabi_cdcmpeq.c - Test __aeabi_cdcmpeq ----------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is dual licensed under the MIT and the University of Illinois Open
6 // Source Licenses. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file tests __aeabi_cdcmpeq for the compiler_rt library.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include <stdint.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <math.h>
18 #include <pico/double.h>
19 #include "pico/stdlib.h"
20 // Include sys/types.h before inttypes.h to work around issue with
21 // certain versions of GCC and newlib which causes omission of PRIx64
22 #include <sys/types.h>
23 #include "inttypes.h"
24 
25 #define test_assert(x) ({ if (!(x)) { printf("Assertion failed: ");puts(#x);printf("  at " __FILE__ ":%d\n", __LINE__); exit(-1); } })
26 
27 extern int __aeabi_dcmpun(double a, double b);
28 
29 #if __arm__
30 
31 #include "call_apsr.h"
32 
33 extern __attribute__((pcs("aapcs"))) void __aeabi_cdcmpeq(double a, double b);
34 
test__aeabi_cdcmpeq(double a,double b,int expected)35 int test__aeabi_cdcmpeq(double a, double b, int expected) {
36     uint32_t cpsr_value = call_apsr_d(a, b, __aeabi_cdcmpeq);
37     union cpsr cpsr = {.value = cpsr_value};
38     if (expected != cpsr.flags.z) {
39         printf("error in __aeabi_cdcmpeq(%f, %f) => Z = %08x, expected %08x\n",
40                a, b, cpsr.flags.z, expected);
41         return 1;
42     }
43     return 0;
44 }
45 
46 #endif
47 
test_cdcmpeq()48 int test_cdcmpeq() {
49 #if __arm__
50     if (test__aeabi_cdcmpeq(1.0, 1.0, 1))
51         return 1;
52     if (test__aeabi_cdcmpeq(1234.567, 765.4321, 0))
53         return 1;
54     if (test__aeabi_cdcmpeq(-123.0, -678.0, 0))
55         return 1;
56     if (test__aeabi_cdcmpeq(0.0, -0.0, 1))
57         return 1;
58     if (test__aeabi_cdcmpeq(0.0, 0.0, 1))
59         return 1;
60     if (test__aeabi_cdcmpeq(-0.0, -0.0, 1))
61         return 1;
62     if (test__aeabi_cdcmpeq(-0.0, 0.0, 1))
63         return 1;
64     if (test__aeabi_cdcmpeq(0.0, -1.0, 0))
65         return 1;
66     if (test__aeabi_cdcmpeq(-0.0, -1.0, 0))
67         return 1;
68     if (test__aeabi_cdcmpeq(-1.0, 0.0, 0))
69         return 1;
70     if (test__aeabi_cdcmpeq(-1.0, -0.0, 0))
71         return 1;
72     if (test__aeabi_cdcmpeq(1.0, NAN, 0))
73         return 1;
74     if (test__aeabi_cdcmpeq(NAN, 1.0, 0))
75         return 1;
76     if (test__aeabi_cdcmpeq(NAN, NAN, 0))
77         return 1;
78     if (test__aeabi_cdcmpeq(INFINITY, 1.0, 0))
79         return 1;
80     if (test__aeabi_cdcmpeq(0.0, INFINITY, 0))
81         return 1;
82     if (test__aeabi_cdcmpeq(-INFINITY, 0.0, 0))
83         return 1;
84     if (test__aeabi_cdcmpeq(0.0, -INFINITY, 0))
85         return 1;
86     if (test__aeabi_cdcmpeq(INFINITY, INFINITY, 1))
87         return 1;
88     if (test__aeabi_cdcmpeq(-INFINITY, -INFINITY, 1))
89         return 1;
90 #else
91     printf("skipped\n");
92 #endif
93     return 0;
94 }
95 
96 #if __arm__
97 
98 extern __attribute__((pcs("aapcs"))) void __aeabi_cdcmple(double a, double b);
99 
100 extern __attribute__((pcs("aapcs"))) void __aeabi_cdrcmple(double a, double b);
101 
test_dcmple_gt(double a,double b,int expected)102 int test_dcmple_gt(double a, double b, int expected) {
103     if ((a <= b) != expected) {
104         printf("error in dcmple(%f, %f) => %d, expected %d\n",
105                a, b, a <= b, expected);
106         return 1;
107     }
108     if ((a > b) == expected && !isnan(a) && !isnan(b)) {
109         printf("error in dcmpgt(%f, %f) => %d, expected %d\n",
110                a, b, a > b, !expected);
111         return 1;
112     }
113     return 0;
114 }
115 
test_dcmplt_ge(double a,double b,int expected)116 int test_dcmplt_ge(double a, double b, int expected) {
117     if ((a < b) != expected) {
118         printf("error in dcmplt(%f, %f) => %d, expected %d\n",
119                a, b, a < b, expected);
120         return 1;
121     }
122     if ((a >= b) == expected && !isnan(a) && !isnan(b)) {
123         printf("error in dcmpge(%f, %f) => %d, expected %d\n",
124                a, b, a >= b, !expected);
125         return 1;
126     }
127     return 0;
128 }
129 
test__aeabi_cdcmple(double a,double b,int expected)130 int test__aeabi_cdcmple(double a, double b, int expected) {
131     int32_t cpsr_value = call_apsr_d(a, b, __aeabi_cdcmple);
132     int32_t r_cpsr_value = call_apsr_d(b, a, __aeabi_cdrcmple);
133     int32_t cpsr_value2 = call_apsr_d(b, a, __aeabi_cdcmple);
134     int32_t r_cpsr_value2 = call_apsr_d(a, b, __aeabi_cdrcmple);
135 
136     if (cpsr_value != r_cpsr_value) {
137         printf("error: __aeabi_cdcmple(%f, %f) != __aeabi_cdrcmple(%f, %f)\n", a, b, b, a);
138         return 1;
139     }
140 
141     int expected_z, expected_c;
142     if (expected == -1) {
143         expected_z = 0;
144         expected_c = 0;
145     } else if (expected == 0) {
146         expected_z = 1;
147         expected_c = 1;
148     } else {
149         // a or b is NaN, or a > b
150         expected_z = 0;
151         expected_c = 1;
152     }
153 #if PICO_DOUBLE_COMPILER
154     // gcc has this backwards it seems - not a good thing, but I guess it doesn't ever call them
155     expected_c ^= 1;
156 #endif
157 
158     union cpsr cpsr = {.value = cpsr_value};
159     if (expected_z != cpsr.flags.z || expected_c != cpsr.flags.c) {
160         printf("error in __aeabi_cdcmple(%f, %f) => (Z = %d, C = %d), expected (Z = %d, C = %d)\n",
161                a, b, cpsr.flags.z, cpsr.flags.c, expected_z, expected_c);
162         return 1;
163     }
164 
165     cpsr.value = r_cpsr_value;
166     if (expected_z != cpsr.flags.z || expected_c != cpsr.flags.c) {
167         printf("error in __aeabi_cfrcmple(%f, %f) => (Z = %d, C = %d), expected (Z = %d, C = %d)\n",
168                a, b, cpsr.flags.z, cpsr.flags.c, expected_z, expected_c);
169         return 1;
170     }
171     return 0;
172 }
173 
174 #endif
175 
test_cdcmple()176 int test_cdcmple() {
177 #if __arm__
178     if (test__aeabi_cdcmple(1.0, 1.0, 0))
179         return 1;
180     if (test__aeabi_cdcmple(1234.567, 765.4321, 1))
181         return 1;
182     if (test__aeabi_cdcmple(765.4321, 1234.567, -1))
183         return 1;
184     if (test__aeabi_cdcmple(-123.0, -678.0, 1))
185         return 1;
186     if (test__aeabi_cdcmple(-678.0, -123.0, -1))
187         return 1;
188     if (test__aeabi_cdcmple(-123.0, 678.0, -1))
189         return 1;
190     if (test__aeabi_cdcmple(678.0, -123.0, 1))
191         return 1;
192     if (test__aeabi_cdcmple(0.0, -0.0, 0))
193         return 1;
194     if (test__aeabi_cdcmple(1.0, NAN, 1))
195         return 1;
196     if (test__aeabi_cdcmple(NAN, 1.0, 1))
197         return 1;
198     if (test__aeabi_cdcmple(NAN, NAN, 1))
199         return 1;
200 #else
201     printf("skipped\n");
202 #endif
203     return 0;
204 }
205 
test_cmple_gt()206 int test_cmple_gt() {
207     if (test_dcmple_gt(1.0, 1.0, 1))
208         return 1;
209     if (test_dcmple_gt(1234.567, 765.4321, 0))
210         return 1;
211     if (test_dcmple_gt(765.4321, 1234.567, 1))
212         return 1;
213     if (test_dcmple_gt(-123.0, -678.0, 0))
214         return 1;
215     if (test_dcmple_gt(-678.0, -123.0, 1))
216         return 1;
217     if (test_dcmple_gt(-123.0, 678.0, 1))
218         return 1;
219     if (test_dcmple_gt(678.0, -123.0, 0))
220         return 1;
221     if (test_dcmple_gt(0.0, -0.0, 1))
222         return 1;
223     if (test_dcmple_gt(-0.0, 0.0, 1))
224         return 1;
225     if (test_dcmple_gt(1.0, NAN, 0))
226         return 1;
227     if (test_dcmple_gt(NAN, 1.0, 0))
228         return 1;
229     if (test_dcmple_gt(NAN, NAN, 0))
230         return 1;
231     return 0;
232 }
233 
test_cmplt_ge()234 int test_cmplt_ge() {
235     if (test_dcmplt_ge(1.0, 1.0, 0))
236         return 1;
237     if (test_dcmplt_ge(1234.567, 765.4321, 0))
238         return 1;
239     if (test_dcmplt_ge(765.4321, 1234.567, 1))
240         return 1;
241     if (test_dcmplt_ge(-123.0, -678.0, 0))
242         return 1;
243     if (test_dcmplt_ge(-678.0, -123.0, 1))
244         return 1;
245     if (test_dcmplt_ge(-123.0, 678.0, 1))
246         return 1;
247     if (test_dcmplt_ge(678.0, -123.0, 0))
248         return 1;
249     if (test_dcmplt_ge(0.0, -0.0, 0))
250         return 1;
251     if (test_dcmplt_ge(-0.0, 0.0, 0))
252         return 1;
253     if (test_dcmplt_ge(1.0, NAN, 0))
254         return 1;
255     if (test_dcmplt_ge(NAN, 1.0, 0))
256         return 1;
257     if (test_dcmplt_ge(NAN, NAN, 0))
258         return 1;
259     return 0;
260 }
261 
check_dcmpun(double a,double b,bool expected,bool expect_equal)262 int check_dcmpun(double a, double b, bool expected, bool expect_equal) {
263     if (__aeabi_dcmpun(a, b) != expected) {
264         printf("Failed dcmpun(%f, %f)\n", a, b);
265         return 1;
266     }
267     if ((a == b) != expect_equal) {
268         printf("Failed equality check %f %f\n", a, b);
269         __breakpoint();
270         if (b == a) {
271             printf("SAS\n");
272         }
273         return 1;
274     }
275     return 0;
276 }
277 
test_dcmpun()278 int test_dcmpun() {
279     if (check_dcmpun(0, 0, false, true) ||
280         check_dcmpun(-INFINITY, INFINITY, false, false) ||
281         check_dcmpun(NAN, 0, true, false) ||
282         check_dcmpun(0, NAN, true, false) ||
283         check_dcmpun(NAN, NAN, true, false) ||
284         check_dcmpun(-NAN, NAN, true, false)) {
285         return 1;
286     }
287     return 0;
288 }
289 
290 #define assert_nan(a) test_assert(isnan(a))
291 #define check_nan(a) ({ assert_nan(a); a; })
292 
293 double __aeabi_i2d(int32_t);
294 double __aeabi_ui2d(int32_t);
295 double __aeabi_l2d(int64_t);
296 double __aeabi_ul2d(int64_t);
297 int32_t __aeabi_d2iz(double);
298 int64_t __aeabi_d2lz(double);
299 double __aeabi_dmul(double, double);
300 double __aeabi_ddiv(double, double);
301 #if LIB_PICO_DOUBLE_PICO
302 double __real___aeabi_i2d(int);
303 double __real___aeabi_ui2d(int);
304 double __real___aeabi_l2d(int64_t);
305 double __real___aeabi_ul2d(int64_t);
306 double __real___aeabi_dmul(double, double);
307 double __real___aeabi_ddiv(double, double);
308 int32_t __real___aeabi_d2iz(double);
309 int64_t __real___aeabi_d2lz(double);
310 double __real_sqrt(double);
311 double __real_cos(double);
312 double __real_sin(double);
313 double __real_tan(double);
314 double __real_exp(double);
315 double __real_log(double);
316 double __real_atan2(double, double);
317 double __real_pow(double, double);
318 double __real_trunc(double);
319 double __real_ldexp(double, int);
320 double __real_fmod(double, double);
321 
322 #define FRAC ((double)(1ull << 50))
323 #define allowed_range(a) (fabs(a) / FRAC)
324 #define assert_close(a, b) test_assert((fabs(a - b) <= allowed_range(a) || ({ printf("  error: %f != %f\n", a, b); 0; })) || (isinf(a) && isinf(b) && (a < 0) == (b < 0)))
325 #define check1(func,p0) ({ typeof(p0) r = func(p0), r2 = __CONCAT(__real_, func)(p0); test_assert(r == r2); r; })
326 #define check2(func,p0,p1) ({ typeof(p0) r = func(p0,p1), r2 = __CONCAT(__real_, func)(p0,p1); test_assert(r == r2); r; })
327 #define check_close1(func,p0) ({ typeof(p0) r = func(p0), r2 = __CONCAT(__real_, func)(p0); if (isnan(p0)) assert_nan(r); else assert_close(r, r2); r; })
328 #define check_close2(func,p0,p1) ({ typeof(p0) r = func(p0,p1), r2 = __CONCAT(__real_, func)(p0,p1); if (isnan(p0) || isnan(p1)) assert_nan(r); else assert_close(r, r2); r; })
329 #else
330 #define check1(func,p0) func(p0)
331 #define check2(func,p0,p1) func(p0,p1)
332 #define check_close1(func,p0) func(p0)
333 #define check_close2(func,p0,p1) func(p0,p1)
334 #endif
335 
336 double aa = 0.5;
337 double bb = 1;
338 
main()339 int main() {
340     setup_default_uart();
341 
342     bool fail = false;
343 
344     printf("%d\n", aa < bb);
345     for(double a = -1; a <= 1; a++) {
346         for(double b = -1; b <= 1; b++) {
347             printf("%f < %f ? %d\n", a, b, a < b);
348         }
349     }
350     for(double a = -1; a <=1; a++) {
351         for(double b = -1; b <= 1; b++) {
352             printf("%f > %f ? %d\n", a, b, a > b);
353         }
354     }
355 
356 #if 1
357     for (double x = 0; x < 3; x++) {
358         printf("\n ----- %g\n", x);
359         printf("SQRT %10.18g\n", check_close1(sqrt, x));
360         printf("COS %10.18g\n", check_close1(cos, x));
361         printf("SIN %10.18g\n", check_close1(sin, x));
362         printf("TAN %10.18g\n", check_close1(tan, x));
363         printf("ATAN2 %10.18g\n", check_close2(atan2, x, 10.0));
364         printf("ATAN2 %10.18g\n", check_close2(atan2, 10.0, x));
365         printf("EXP %10.18g\n", check_close1(exp, x));
366         printf("LN %10.18g\n", check_close1(log, x));
367         printf("POW %10.18f\n", check_close2(pow, x, x));
368         printf("TRUNC %10.18f\n", check_close1(trunc, x));
369         printf("LDEXP %10.18f\n", check_close2(ldexp, x, x));
370         // todo come pack
371     //    printf("FMOD %10.18f\n", check_close2(fmod, x, 3.0f));
372         double s, c;
373         sincos(x, &s, &c);
374         printf("SINCOS %10.18f %10.18f\n", s, c);
375         if (s != sin(x) || c != cos(x)) {
376             printf("SINCOS mismatch\n");
377             fail = true;
378         }
379     }
380 
381 #if PICO_DOUBLE_PROPAGATE_NANS
382     {
383         float x = NAN;
384         printf("SQRT %10.18g\n", check_close1(sqrt, x));
385         printf("COS %10.18g\n", check_close1(cos, x));
386         printf("SIN %10.18g\n", check_close1(sin, x));
387         printf("TAN %10.18g\n", check_close1(tan, x));
388         printf("ATAN2 %10.18g\n", check_close2(atan2, x, 10.0));
389         printf("ATAN2 %10.18g\n", check_close2(atan2, 10.0, x));
390         printf("EXP %10.18g\n", check_close1(exp, x));
391         printf("LN %10.18g\n", check_close1(log, x));
392         printf("POW %10.18f\n", check_nan(pow(x, x)));
393         printf("TRUNC %10.18f\n", check_nan(trunc(x)));
394         printf("LDEXP %10.18f\n", check_nan(ldexp(x, x)));
395         printf("FMOD %10.18f\n", check_nan(fmod(x, 3.0f)));
396         double s, c;
397         sincos(x, &s, &c);
398         printf("SINCOS %10.18f %10.18f\n", check_nan(s), check_nan(c));
399 
400         for(int j=0;j<2;j++) {
401             for (int i = 1; i < 4; i++) {
402                 char buf[4];
403                 sprintf(buf, "%d", i);
404                 float f0 = -nanf(buf);
405                 double d0 = -nan(buf);
406                 // hmm nanf/nan seem to ignore payload
407                 *(uint64_t *) &d0 |= i;
408                 *(uint32_t *) &f0 |= i;
409                 if (j) {
410                     // try without top bit set
411                     *(uint64_t *) &d0 &= ~0x0008000000000000ull;
412                     *(uint32_t *) &f0 &= ~0x00400000u;
413                 }
414                 float f = (float) d0;
415                 double d = (double) f0;
416                 printf("f2d %f %08"PRIx32" -> %g %016"PRIx64"\n", f0, *(uint32_t *) &f0, d, *(uint64_t *) &d);
417                 printf("d2f %f %016"PRIx64" -> %f %08"PRIx32"\n", d0, *(uint64_t *) &d0, f, *(uint32_t *) &f);
418             }
419         }
420     }
421 #endif
422 
423     {
424         int32_t y;
425 //        for (int32_t x = 0; x>-512; x--) {
426 //            printf("i %d->%f\n", (int)x, (float) x);
427 //        }
428         for (int32_t x = -1; x; x <<= 1) {
429             printf("i %d->%f\n", x, (double) x);
430             check1(__aeabi_i2d, x);
431         }
432         for (int32_t x = 1; x; x <<= 1) {
433             printf("i %d->%f\n", x, (double) x);
434             check1(__aeabi_i2d, x);
435             y = x << 1;
436         }
437         for (int64_t x = 1; x; x <<= 1) {
438             printf("i %lld->%f\n", x, (double) x);
439             check1(__aeabi_l2d, x);
440             y = x << 1;
441         }
442         for (int64_t x = -1; x; x <<= 1) {
443             printf("i %lld->%f\n", x, (double) x);
444             check1(__aeabi_l2d, x);
445             y = x << 1;
446         }
447         printf("d %d->%f\n", y, (float) y);
448     }
449 
450     {
451         uint32_t y;
452         for(uint32_t x = 1; x; x <<= 1) {
453             printf("u %u->%f\n", x, (double)x);
454             check1(__aeabi_ui2d, x);
455             y = x << 1;
456         }
457         printf("u %u->%f\n", y, (double)y);
458     }
459     for(int64_t x = 1; x !=0; x <<= 1u) {
460         printf("%lld->%f\n", x, (double)x);
461         check1(__aeabi_l2d, x);
462     }
463     for(double x = -4294967296.f * 4294967296.f * 2.f; x<=-0.5f; x/=2.f) {
464         printf("d2i64 %f->%lld\n", x, (int64_t)x);
465         if (x <= (double) INT64_MIN) {
466             // seems like there is a bug in the gcc version!
467             test_assert(__aeabi_d2lz(x) == INT64_MIN);
468         } else {
469             check1(__aeabi_d2lz, x);
470         }
471     }
472     for(double x = 4294967296.f * 4294967296.f * 2.f; x>=0.5f; x/=2.f) {
473         printf("d2i64 %f->%lld\n", x, (int64_t)x);
474         if (x >= (double)INT64_MAX) {
475             // seems like there is a bug in the clang and gcc versions!
476             test_assert(__aeabi_d2lz(x) == INT64_MAX);
477         } else {
478             check1(__aeabi_d2lz, x);
479         }
480     }
481     for(double x = -4294967296.f * 4294967296.f; x<=-0.5f; x/=2.f) {
482         printf("d2i32 %f->%d\n", x, (int32_t)x);
483         check1(__aeabi_d2iz, x);
484     }
485     for(double x = 4294967296.f * 4294967296.f; x>=0.5f; x/=2.f) {
486         printf("d2i32 %f->%d\n", x, (int32_t)x);
487         if (x >= (double) INT32_MAX - 1 && x <= (double) INT32_MAX + 1) {
488             // seems like there is a bug in the clang version!
489             test_assert(__aeabi_d2iz(x) == INT32_MAX);
490         } else {
491             check1(__aeabi_d2iz, x);
492         }
493     }
494     for (double x = 1; x < 11.0; x += 2.0) {
495         double f = x * x;
496         double g = 1.0 / x;
497         printf("%g %10.18g %10.18g, %10.18g, %10.18g %10.18g\n", x, f, x + 0.37777777777777777777777777777,
498                x - 0.377777777777777777777777777777, g, 123456789.0 / x);
499         check2(__aeabi_dmul, x, x);
500         check2(__aeabi_ddiv, 1.0, x);
501     }
502 
503     if (fail ||
504         test_cdcmpeq() ||
505         test_cdcmple() ||
506         test_dcmpun() ||
507         test_cmple_gt() ||
508         test_cmplt_ge()) {
509         printf("FAILED\n");
510         return 1;
511     } else {
512         printf("PASSED\n");
513         return 0;
514     }
515 #endif
516 }
517