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