History

Add arm64 (AArch64) as a target architecture.

Edmund Grimley Evans committed 11 years ago

Commit b14ef0e1 parent 738606d16 files · +3265 −40Browse files

Showing the changes to lib (3 of 16 files). Show all

Unified · Split

3 files
  1. lib/Makefile +12 −0
  2. lib/lib-arm64.c +652 −0
  3. lib/testfp.c +510 −0
lib/Makefile+12−0
@@ -28,6 +28,11 @@ ifndef TARGET # native library · 27 unmodified lines
2828 ifeq ($(ARCH),arm)
2929 TARGET = arm
3030 XCC = $(CC)
31+ else
32+ ifeq ($(ARCH),arm64)
33+ TARGET = arm64
34+ else
35+ endif
3136 endif
3237 endif
3338 endif
@@ -49,6 +54,7 @@ X86_64_O = libtcc1.o alloca86_64.o · 15 unmodified lines
4954 ARM_O = libtcc1.o armeabi.o alloca-arm.o
5055 WIN32_O = $(I386_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o
5156 WIN64_O = $(X86_64_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o
57+ARM64_O = lib-arm64.o
5258
5359 # build TCC runtime library to contain PIC code, so it can be linked
5460 # into shared libraries
@@ -86,6 +92,11 @@ ifeq "$(TARGET)" "arm" · 31 unmodified lines
8692 OBJ = $(addprefix $(DIR)/,$(ARM_O))
8793 TGT = -DTCC_TARGET_ARM
8894 XCC ?= $(TCC) -B$(TOP)
95+else
96+ifeq "$(TARGET)" "arm64"
97+ OBJ = $(addprefix $(DIR)/,$(ARM64_O))
98+ TGT = -DTCC_TARGET_ARM64
99+ XCC ?= $(TCC) -B$(TOP)
89100 else
90101 $(error libtcc1.a not supported on target '$(TARGET)')
91102 endif
@@ -93,6 +104,7 @@ endif · 1 unmodified line
93104 endif
94105 endif
95106 endif
107+endif
96108
97109 XFLAGS = $(CPPFLAGS) $(CFLAGS) $(PICFLAGS) $(TGT)
98110
lib/lib-arm64.c+652−0
@@ -0,0 +1,652 @@
1+/*
2+ * TCC runtime library for arm64.
3+ *
4+ * Copyright (c) 2015 Edmund Grimley Evans
5+ *
6+ * Copying and distribution of this file, with or without modification,
7+ * are permitted in any medium without royalty provided the copyright
8+ * notice and this notice are preserved. This file is offered as-is,
9+ * without any warranty.
10+ */
11+
12+#include <stdint.h>
13+#include <string.h>
14+
15+void __clear_cache(char *beg, char *end)
16+{
17+#warning __clear_cache not yet implemented
18+}
19+
20+typedef struct {
21+ uint64_t x0, x1;
22+} u128_t;
23+
24+static long double f3_zero(int sgn)
25+{
26+ long double f;
27+ u128_t x = { 0, (uint64_t)sgn << 63 };
28+ memcpy(&f, &x, 16);
29+ return f;
30+}
31+
32+static long double f3_infinity(int sgn)
33+{
34+ long double f;
35+ u128_t x = { 0, (uint64_t)sgn << 63 | 0x7fff000000000000 };
36+ memcpy(&f, &x, 16);
37+ return f;
38+}
39+
40+static long double f3_NaN(void)
41+{
42+ long double f;
43+#if 0
44+ // ARM's default NaN usually has just the top fraction bit set:
45+ u128_t x = { 0, 0x7fff800000000000 };
46+#else
47+ // GCC's library sets all fraction bits:
48+ u128_t x = { -1, 0x7fffffffffffffff };
49+#endif
50+ memcpy(&f, &x, 16);
51+ return f;
52+}
53+
54+static int fp3_convert_NaN(long double *f, int sgn, u128_t mnt)
55+{
56+ u128_t x = { mnt.x0,
57+ mnt.x1 | 0x7fff800000000000 | (uint64_t)sgn << 63 };
58+ memcpy(f, &x, 16);
59+ return 1;
60+}
61+
62+static int fp3_detect_NaNs(long double *f,
63+ int a_sgn, int a_exp, u128_t a,
64+ int b_sgn, int b_exp, u128_t b)
65+{
66+ // Detect signalling NaNs:
67+ if (a_exp == 32767 && (a.x0 | a.x1 << 16) && !(a.x1 >> 47 & 1))
68+ return fp3_convert_NaN(f, a_sgn, a);
69+ if (b_exp == 32767 && (b.x0 | b.x1 << 16) && !(b.x1 >> 47 & 1))
70+ return fp3_convert_NaN(f, b_sgn, b);
71+
72+ // Detect quiet NaNs:
73+ if (a_exp == 32767 && (a.x0 | a.x1 << 16))
74+ return fp3_convert_NaN(f, a_sgn, a);
75+ if (b_exp == 32767 && (b.x0 | b.x1 << 16))
76+ return fp3_convert_NaN(f, b_sgn, b);
77+
78+ return 0;
79+}
80+
81+static void f3_unpack(int *sgn, int32_t *exp, u128_t *mnt, long double f)
82+{
83+ u128_t x;
84+ memcpy(&x, &f, 16);
85+ *sgn = x.x1 >> 63;
86+ *exp = x.x1 >> 48 & 32767;
87+ x.x1 = x.x1 << 16 >> 16;
88+ if (*exp)
89+ x.x1 |= (uint64_t)1 << 48;
90+ else
91+ *exp = 1;
92+ *mnt = x;
93+}
94+
95+static u128_t f3_normalise(int32_t *exp, u128_t mnt)
96+{
97+ int sh;
98+ if (!(mnt.x0 | mnt.x1))
99+ return mnt;
100+ if (!mnt.x1) {
101+ mnt.x1 = mnt.x0;
102+ mnt.x0 = 0;
103+ *exp -= 64;
104+ }
105+ for (sh = 32; sh; sh >>= 1) {
106+ if (!(mnt.x1 >> (64 - sh))) {
107+ mnt.x1 = mnt.x1 << sh | mnt.x0 >> (64 - sh);
108+ mnt.x0 = mnt.x0 << sh;
109+ *exp -= sh;
110+ }
111+ }
112+ return mnt;
113+}
114+
115+static u128_t f3_sticky_shift(int32_t sh, u128_t x)
116+{
117+ if (sh >= 128) {
118+ x.x0 = !!(x.x0 | x.x1);
119+ x.x1 = 0;
120+ return x;
121+ }
122+ if (sh >= 64) {
123+ x.x0 = x.x1 | !!x.x0;
124+ x.x1 = 0;
125+ sh -= 64;
126+ }
127+ if (sh > 0) {
128+ x.x0 = x.x0 >> sh | x.x1 << (64 - sh) | !!(x.x0 << (64 - sh));
129+ x.x1 = x.x1 >> sh;
130+ }
131+ return x;
132+}
133+
134+static long double f3_round(int sgn, int32_t exp, u128_t x)
135+{
136+ long double f;
137+ int error;
138+
139+ if (exp > 0) {
140+ x = f3_sticky_shift(13, x);
141+ }
142+ else {
143+ x = f3_sticky_shift(14 - exp, x);
144+ exp = 0;
145+ }
146+
147+ error = x.x0 & 3;
148+ x.x0 = x.x0 >> 2 | x.x1 << 62;
149+ x.x1 = x.x1 >> 2;
150+
151+ if (error == 3 || ((error == 2) & (x.x0 & 1))) {
152+ if (!++x.x0) {
153+ ++x.x1;
154+ if (x.x1 == (uint64_t)1 << 48)
155+ exp = 1;
156+ else if (x.x1 == (uint64_t)1 << 49) {
157+ ++exp;
158+ x.x0 = x.x0 >> 1 | x.x1 << 63;
159+ x.x1 = x.x1 >> 1;
160+ }
161+ }
162+ }
163+
164+ if (exp >= 32767)
165+ return f3_infinity(sgn);
166+
167+ x.x1 = x.x1 << 16 >> 16 | (uint64_t)exp << 48 | (uint64_t)sgn << 63;
168+ memcpy(&f, &x, 16);
169+ return f;
170+}
171+
172+static long double f3_add(long double fa, long double fb, int neg)
173+{
174+ u128_t a, b, x;
175+ int32_t a_exp, b_exp, x_exp;
176+ int a_sgn, b_sgn, x_sgn;
177+ long double fx;
178+
179+ f3_unpack(&a_sgn, &a_exp, &a, fa);
180+ f3_unpack(&b_sgn, &b_exp, &b, fb);
181+
182+ if (fp3_detect_NaNs(&fx, a_sgn, a_exp, a, b_sgn, b_exp, b))
183+ return fx;
184+
185+ b_sgn ^= neg;
186+
187+ // Handle infinities and zeroes:
188+ if (a_exp == 32767 && b_exp == 32767 && a_sgn != b_sgn)
189+ return f3_NaN();
190+ if (a_exp == 32767)
191+ return f3_infinity(a_sgn);
192+ if (b_exp == 32767)
193+ return f3_infinity(b_sgn);
194+ if (!(a.x0 | a.x1 | b.x0 | b.x1))
195+ return f3_zero(a_sgn & b_sgn);
196+
197+ a.x1 = a.x1 << 3 | a.x0 >> 61;
198+ a.x0 = a.x0 << 3;
199+ b.x1 = b.x1 << 3 | b.x0 >> 61;
200+ b.x0 = b.x0 << 3;
201+
202+ if (a_exp <= b_exp) {
203+ a = f3_sticky_shift(b_exp - a_exp, a);
204+ a_exp = b_exp;
205+ }
206+ else {
207+ b = f3_sticky_shift(a_exp - b_exp, b);
208+ b_exp = a_exp;
209+ }
210+
211+ x_sgn = a_sgn;
212+ x_exp = a_exp;
213+ if (a_sgn == b_sgn) {
214+ x.x0 = a.x0 + b.x0;
215+ x.x1 = a.x1 + b.x1 + (x.x0 < a.x0);
216+ }
217+ else {
218+ x.x0 = a.x0 - b.x0;
219+ x.x1 = a.x1 - b.x1 - (x.x0 > a.x0);
220+ if (x.x1 >> 63) {
221+ x_sgn ^= 1;
222+ x.x0 = -x.x0;
223+ x.x1 = -x.x1 - !!x.x0;
224+ }
225+ }
226+
227+ if (!(x.x0 | x.x1))
228+ return f3_zero(0);
229+
230+ x = f3_normalise(&x_exp, x);
231+
232+ return f3_round(x_sgn, x_exp + 12, x);
233+}
234+
235+long double __addtf3(long double a, long double b)
236+{
237+ return f3_add(a, b, 0);
238+}
239+
240+long double __subtf3(long double a, long double b)
241+{
242+ return f3_add(a, b, 1);
243+}
244+
245+long double __multf3(long double fa, long double fb)
246+{
247+ u128_t a, b, x;
248+ int32_t a_exp, b_exp, x_exp;
249+ int a_sgn, b_sgn, x_sgn;
250+ long double fx;
251+
252+ f3_unpack(&a_sgn, &a_exp, &a, fa);
253+ f3_unpack(&b_sgn, &b_exp, &b, fb);
254+
255+ if (fp3_detect_NaNs(&fx, a_sgn, a_exp, a, b_sgn, b_exp, b))
256+ return fx;
257+
258+ // Handle infinities and zeroes:
259+ if ((a_exp == 32767 && !(b.x0 | b.x1)) ||
260+ (b_exp == 32767 && !(a.x0 | a.x1)))
261+ return f3_NaN();
262+ if (a_exp == 32767 || b_exp == 32767)
263+ return f3_infinity(a_sgn ^ b_sgn);
264+ if (!(a.x0 | a.x1) || !(b.x0 | b.x1))
265+ return f3_zero(a_sgn ^ b_sgn);
266+
267+ a = f3_normalise(&a_exp, a);
268+ b = f3_normalise(&b_exp, b);
269+
270+ x_sgn = a_sgn ^ b_sgn;
271+ x_exp = a_exp + b_exp - 16352;
272+
273+ {
274+ // Convert to base (1 << 30), discarding bottom 6 bits, which are zero,
275+ // so there are (32, 30, 30, 30) bits in (a3, a2, a1, a0):
276+ uint64_t a0 = a.x0 << 28 >> 34;
277+ uint64_t b0 = b.x0 << 28 >> 34;
278+ uint64_t a1 = a.x0 >> 36 | a.x1 << 62 >> 34;
279+ uint64_t b1 = b.x0 >> 36 | b.x1 << 62 >> 34;
280+ uint64_t a2 = a.x1 << 32 >> 34;
281+ uint64_t b2 = b.x1 << 32 >> 34;
282+ uint64_t a3 = a.x1 >> 32;
283+ uint64_t b3 = b.x1 >> 32;
284+ // Use 16 small multiplications and additions that do not overflow:
285+ uint64_t x0 = a0 * b0;
286+ uint64_t x1 = (x0 >> 30) + a0 * b1 + a1 * b0;
287+ uint64_t x2 = (x1 >> 30) + a0 * b2 + a1 * b1 + a2 * b0;
288+ uint64_t x3 = (x2 >> 30) + a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0;
289+ uint64_t x4 = (x3 >> 30) + a1 * b3 + a2 * b2 + a3 * b1;
290+ uint64_t x5 = (x4 >> 30) + a2 * b3 + a3 * b2;
291+ uint64_t x6 = (x5 >> 30) + a3 * b3;
292+ // We now have (64, 30, 30, ...) bits in (x6, x5, x4, ...).
293+ // Take the top 128 bits, setting bottom bit if any lower bits were set:
294+ uint64_t y0 = (x5 << 34 | x4 << 34 >> 30 | x3 << 34 >> 60 |
295+ !!(x3 << 38 | (x2 | x1 | x0) << 34));
296+ uint64_t y1 = x6;
297+ // Top bit may be zero. Renormalise:
298+ if (!(y1 >> 63)) {
299+ y1 = y1 << 1 | y0 >> 63;
300+ y0 = y0 << 1;
301+ --x_exp;
302+ }
303+ x.x0 = y0;
304+ x.x1 = y1;
305+ }
306+
307+ return f3_round(x_sgn, x_exp, x);
308+}
309+
310+long double __divtf3(long double fa, long double fb)
311+{
312+ u128_t a, b, x;
313+ int32_t a_exp, b_exp, x_exp;
314+ int a_sgn, b_sgn, x_sgn, i;
315+ long double fx;
316+
317+ f3_unpack(&a_sgn, &a_exp, &a, fa);
318+ f3_unpack(&b_sgn, &b_exp, &b, fb);
319+
320+ if (fp3_detect_NaNs(&fx, a_sgn, a_exp, a, b_sgn, b_exp, b))
321+ return fx;
322+
323+ // Handle infinities and zeroes:
324+ if ((a_exp == 32767 && b_exp == 32767) ||
325+ (!(a.x0 | a.x1) && !(b.x0 | b.x1)))
326+ return f3_NaN();
327+ if (a_exp == 32767 || !(b.x0 | b.x1))
328+ return f3_infinity(a_sgn ^ b_sgn);
329+ if (!(a.x0 | a.x1) || b_exp == 32767)
330+ return f3_zero(a_sgn ^ b_sgn);
331+
332+ a = f3_normalise(&a_exp, a);
333+ b = f3_normalise(&b_exp, b);
334+
335+ x_sgn = a_sgn ^ b_sgn;
336+ x_exp = a_exp - b_exp + 16395;
337+
338+ a.x0 = a.x0 >> 1 | a.x1 << 63;
339+ a.x1 = a.x1 >> 1;
340+ b.x0 = b.x0 >> 1 | b.x1 << 63;
341+ b.x1 = b.x1 >> 1;
342+ x.x0 = 0;
343+ x.x1 = 0;
344+ for (i = 0; i < 116; i++) {
345+ x.x1 = x.x1 << 1 | x.x0 >> 63;
346+ x.x0 = x.x0 << 1;
347+ if (a.x1 > b.x1 || (a.x1 == b.x1 && a.x0 >= b.x0)) {
348+ a.x1 = a.x1 - b.x1 - (a.x0 < b.x0);
349+ a.x0 = a.x0 - b.x0;
350+ x.x0 |= 1;
351+ }
352+ a.x1 = a.x1 << 1 | a.x0 >> 63;
353+ a.x0 = a.x0 << 1;
354+ }
355+ x.x0 |= !!(a.x0 | a.x1);
356+
357+ x = f3_normalise(&x_exp, x);
358+
359+ return f3_round(x_sgn, x_exp, x);
360+}
361+
362+long double __extendsftf2(float f)
363+{
364+ long double fx;
365+ u128_t x;
366+ uint32_t a;
367+ uint64_t aa;
368+ memcpy(&a, &f, 4);
369+ aa = a;
370+ x.x0 = 0;
371+ if (!(a << 1))
372+ x.x1 = aa << 32;
373+ else if (a << 1 >> 24 == 255)
374+ x.x1 = (0x7fff000000000000 | aa >> 31 << 63 | aa << 41 >> 16 |
375+ (uint64_t)!!(a << 9) << 47);
376+ else
377+ x.x1 = (aa >> 31 << 63 | ((aa >> 23 & 255) + 16256) << 48 |
378+ aa << 41 >> 16);
379+ memcpy(&fx, &x, 16);
380+ return fx;
381+}
382+
383+long double __extenddftf2(double f)
384+{
385+ long double fx;
386+ u128_t x;
387+ uint64_t a;
388+ memcpy(&a, &f, 8);
389+ x.x0 = a << 60;
390+ if (!(a << 1))
391+ x.x1 = a;
392+ else if (a << 1 >> 53 == 2047)
393+ x.x1 = (0x7fff000000000000 | a >> 63 << 63 | a << 12 >> 16 |
394+ (uint64_t)!!(a << 12) << 47);
395+ else
396+ x.x1 = a >> 63 << 63 | ((a >> 52 & 2047) + 15360) << 48 | a << 12 >> 16;
397+ memcpy(&fx, &x, 16);
398+ return fx;
399+}
400+
401+float __trunctfsf2(long double f)
402+{
403+ u128_t mnt;
404+ int32_t exp;
405+ int sgn;
406+ uint32_t x;
407+ float fx;
408+
409+ f3_unpack(&sgn, &exp, &mnt, f);
410+
411+ if (exp == 32767 && (mnt.x0 | mnt.x1 << 16))
412+ x = 0x7fc00000 | (uint32_t)sgn << 31 | (mnt.x1 >> 25 & 0x007fffff);
413+ else if (exp > 16510)
414+ x = 0x7f800000 | (uint32_t)sgn << 31;
415+ else if (exp < 16233)
416+ x = (uint32_t)sgn << 31;
417+ else {
418+ exp -= 16257;
419+ x = mnt.x1 >> 23 | !!(mnt.x0 | mnt.x1 << 41);
420+ if (exp < 0) {
421+ x = x >> -exp | !!(x << (32 + exp));
422+ exp = 0;
423+ }
424+ if ((x & 3) == 3 || (x & 7) == 6)
425+ x += 4;
426+ x = ((x >> 2) + (exp << 23)) | (uint32_t)sgn << 31;
427+ }
428+ memcpy(&fx, &x, 4);
429+ return fx;
430+}
431+
432+double __trunctfdf2(long double f)
433+{
434+ u128_t mnt;
435+ int32_t exp;
436+ int sgn;
437+ uint64_t x;
438+ double fx;
439+
440+ f3_unpack(&sgn, &exp, &mnt, f);
441+
442+ if (exp == 32767 && (mnt.x0 | mnt.x1 << 16))
443+ x = (0x7ff8000000000000 | (uint64_t)sgn << 63 |
444+ mnt.x1 << 16 >> 12 | mnt.x0 >> 60);
445+ else if (exp > 17406)
446+ x = 0x7ff0000000000000 | (uint64_t)sgn << 63;
447+ else if (exp < 15308)
448+ x = (uint64_t)sgn << 63;
449+ else {
450+ exp -= 15361;
451+ x = mnt.x1 << 6 | mnt.x0 >> 58 | !!(mnt.x0 << 6);
452+ if (exp < 0) {
453+ x = x >> -exp | !!(x << (64 + exp));
454+ exp = 0;
455+ }
456+ if ((x & 3) == 3 || (x & 7) == 6)
457+ x += 4;
458+ x = ((x >> 2) + ((uint64_t)exp << 52)) | (uint64_t)sgn << 63;
459+ }
460+ memcpy(&fx, &x, 8);
461+ return fx;
462+}
463+
464+int32_t __fixtfsi(long double fa)
465+{
466+ u128_t a;
467+ int32_t a_exp;
468+ int a_sgn;
469+ int32_t x;
470+ f3_unpack(&a_sgn, &a_exp, &a, fa);
471+ if (a_exp < 16369)
472+ return 0;
473+ if (a_exp > 16413)
474+ return a_sgn ? -0x80000000 : 0x7fffffff;
475+ x = a.x1 >> (16431 - a_exp);
476+ return a_sgn ? -x : x;
477+}
478+
479+int64_t __fixtfdi(long double fa)
480+{
481+ u128_t a;
482+ int32_t a_exp;
483+ int a_sgn;
484+ int64_t x;
485+ f3_unpack(&a_sgn, &a_exp, &a, fa);
486+ if (a_exp < 16383)
487+ return 0;
488+ if (a_exp > 16445)
489+ return a_sgn ? -0x8000000000000000 : 0x7fffffffffffffff;
490+ x = (a.x1 << 15 | a.x0 >> 49) >> (16446 - a_exp);
491+ return a_sgn ? -x : x;
492+}
493+
494+uint32_t __fixunstfsi(long double fa)
495+{
496+ u128_t a;
497+ int32_t a_exp;
498+ int a_sgn;
499+ f3_unpack(&a_sgn, &a_exp, &a, fa);
500+ if (a_sgn || a_exp < 16369)
501+ return 0;
502+ if (a_exp > 16414)
503+ return -1;
504+ return a.x1 >> (16431 - a_exp);
505+}
506+
507+uint64_t __fixunstfdi(long double fa)
508+{
509+ u128_t a;
510+ int32_t a_exp;
511+ int a_sgn;
512+ f3_unpack(&a_sgn, &a_exp, &a, fa);
513+ if (a_sgn || a_exp < 16383)
514+ return 0;
515+ if (a_exp > 16446)
516+ return -1;
517+ return (a.x1 << 15 | a.x0 >> 49) >> (16446 - a_exp);
518+}
519+
520+long double __floatsitf(int32_t a)
521+{
522+ int sgn = 0;
523+ int exp = 16414;
524+ uint32_t mnt = a;
525+ u128_t x = { 0, 0 };
526+ long double f;
527+ int i;
528+ if (a) {
529+ if (a < 0) {
530+ sgn = 1;
531+ mnt = -mnt;
532+ }
533+ for (i = 16; i; i >>= 1)
534+ if (!(mnt >> (32 - i))) {
535+ mnt <<= i;
536+ exp -= i;
537+ }
538+ x.x1 = ((uint64_t)sgn << 63 | (uint64_t)exp << 48 |
539+ (uint64_t)(mnt << 1) << 16);
540+ }
541+ memcpy(&f, &x, 16);
542+ return f;
543+}
544+
545+long double __floatditf(int64_t a)
546+{
547+ int sgn = 0;
548+ int exp = 16446;
549+ uint64_t mnt = a;
550+ u128_t x = { 0, 0 };
551+ long double f;
552+ int i;
553+ if (a) {
554+ if (a < 0) {
555+ sgn = 1;
556+ mnt = -mnt;
557+ }
558+ for (i = 32; i; i >>= 1)
559+ if (!(mnt >> (64 - i))) {
560+ mnt <<= i;
561+ exp -= i;
562+ }
563+ x.x0 = mnt << 49;
564+ x.x1 = (uint64_t)sgn << 63 | (uint64_t)exp << 48 | mnt << 1 >> 16;
565+ }
566+ memcpy(&f, &x, 16);
567+ return f;
568+}
569+
570+long double __floatunsitf(uint32_t a)
571+{
572+ int exp = 16414;
573+ uint32_t mnt = a;
574+ u128_t x = { 0, 0 };
575+ long double f;
576+ int i;
577+ if (a) {
578+ for (i = 16; i; i >>= 1)
579+ if (!(mnt >> (32 - i))) {
580+ mnt <<= i;
581+ exp -= i;
582+ }
583+ x.x1 = (uint64_t)exp << 48 | (uint64_t)(mnt << 1) << 16;
584+ }
585+ memcpy(&f, &x, 16);
586+ return f;
587+}
588+
589+long double __floatunditf(uint64_t a)
590+{
591+ int exp = 16446;
592+ uint64_t mnt = a;
593+ u128_t x = { 0, 0 };
594+ long double f;
595+ int i;
596+ if (a) {
597+ for (i = 32; i; i >>= 1)
598+ if (!(mnt >> (64 - i))) {
599+ mnt <<= i;
600+ exp -= i;
601+ }
602+ x.x0 = mnt << 49;
603+ x.x1 = (uint64_t)exp << 48 | mnt << 1 >> 16;
604+ }
605+ memcpy(&f, &x, 16);
606+ return f;
607+}
608+
609+static int f3_cmp(long double fa, long double fb)
610+{
611+ u128_t a, b;
612+ memcpy(&a, &fa, 16);
613+ memcpy(&b, &fb, 16);
614+ return (!(a.x0 | a.x1 << 1 | b.x0 | b.x1 << 1) ? 0 :
615+ ((a.x1 << 1 >> 49 == 0x7fff && (a.x0 | a.x1 << 16)) ||
616+ (b.x1 << 1 >> 49 == 0x7fff && (b.x0 | b.x1 << 16))) ? 2 :
617+ a.x1 >> 63 != b.x1 >> 63 ? (int)(b.x1 >> 63) - (int)(a.x1 >> 63) :
618+ a.x1 < b.x1 ? (int)(a.x1 >> 63 << 1) - 1 :
619+ a.x1 > b.x1 ? 1 - (int)(a.x1 >> 63 << 1) :
620+ a.x0 < b.x0 ? (int)(a.x1 >> 63 << 1) - 1 :
621+ b.x0 < a.x0 ? 1 - (int)(a.x1 >> 63 << 1) : 0);
622+}
623+
624+int __eqtf2(long double a, long double b)
625+{
626+ return !!f3_cmp(a, b);
627+}
628+
629+int __netf2(long double a, long double b)
630+{
631+ return !!f3_cmp(a, b);
632+}
633+
634+int __lttf2(long double a, long double b)
635+{
636+ return f3_cmp(a, b);
637+}
638+
639+int __letf2(long double a, long double b)
640+{
641+ return f3_cmp(a, b);
642+}
643+
644+int __gttf2(long double a, long double b)
645+{
646+ return -f3_cmp(b, a);
647+}
648+
649+int __getf2(long double a, long double b)
650+{
651+ return -f3_cmp(b, a);
652+}
lib/testfp.c+510−0
@@ -0,0 +1,510 @@
1+/*
2+ * Test 128-bit floating-point arithmetic on arm64:
3+ * build with two different compilers and compare the output.
4+ *
5+ * Copyright (c) 2015 Edmund Grimley Evans
6+ *
7+ * Copying and distribution of this file, with or without modification,
8+ * are permitted in any medium without royalty provided the copyright
9+ * notice and this notice are preserved. This file is offered as-is,
10+ * without any warranty.
11+ */
12+
13+#include <stdint.h>
14+#include <stdio.h>
15+#include <stdlib.h>
16+#include <string.h>
17+
18+#define check(x) ((x) ? (void)0 : check_fail(#x, __FILE__, __LINE__))
19+
20+void check_fail(const char *assertion, const char *file, unsigned int line)
21+{
22+ printf("%s:%d: Check (%s) failed.", file, line, assertion);
23+ exit(1);
24+}
25+
26+typedef struct {
27+ unsigned long long x0, x1;
28+} u128_t;
29+
30+float copy_fi(uint32_t x)
31+{
32+ float f;
33+ memcpy(&f, &x, 4);
34+ return f;
35+}
36+
37+double copy_di(uint64_t x)
38+{
39+ double f;
40+ memcpy(&f, &x, 8);
41+ return f;
42+}
43+
44+long double copy_ldi(u128_t x)
45+{
46+ long double f;
47+ memcpy(&f, &x, 16);
48+ return f;
49+}
50+
51+uint32_t copy_if(float f)
52+{
53+ uint32_t x;
54+ memcpy(&x, &f, 4);
55+ return x;
56+}
57+
58+uint64_t copy_id(double f)
59+{
60+ uint64_t x;
61+ memcpy(&x, &f, 8);
62+ return x;
63+}
64+
65+u128_t copy_ild(long double f)
66+{
67+ u128_t x;
68+ memcpy(&x, &f, 16);
69+ return x;
70+}
71+
72+long double make(int sgn, int exp, uint64_t high, uint64_t low)
73+{
74+ u128_t x = { low,
75+ (0x0000ffffffffffff & high) |
76+ (0x7fff000000000000 & (uint64_t)exp << 48) |
77+ (0x8000000000000000 & (uint64_t)sgn << 63) };
78+ return copy_ldi(x);
79+}
80+
81+void cmp(long double a, long double b)
82+{
83+ u128_t ax = copy_ild(a);
84+ u128_t bx = copy_ild(b);
85+ int eq = (a == b);
86+ int ne = (a != b);
87+ int lt = (a < b);
88+ int le = (a <= b);
89+ int gt = (a > b);
90+ int ge = (a >= b);
91+
92+ check(eq == 0 || eq == 1);
93+ check(lt == 0 || lt == 1);
94+ check(gt == 0 || gt == 1);
95+ check(ne == !eq && le == (lt | eq) && ge == (gt | eq));
96+ check(eq + lt + gt < 2);
97+
98+ printf("cmp %016llx%016llx %016llx%016llx %d %d %d\n",
99+ ax.x1, ax.x0, bx.x1, bx.x0, lt, eq, gt);
100+}
101+
102+void cmps(void)
103+{
104+ int i, j;
105+
106+ for (i = 0; i < 2; i++)
107+ for (j = 0; j < 2; j++)
108+ cmp(make(i, 0, 0, 0), make(j, 0, 0, 0));
109+
110+ for (i = 0; i < 2; i++) {
111+ for (j = 0; j < 64; j++) {
112+ long double f1 = make(i, 32767, (uint64_t)1 << j, 0);
113+ long double f2 = make(i, 32767, 0, (uint64_t)1 << j);
114+ cmp(f1, 0);
115+ cmp(f2, 0);
116+ cmp(0, f1);
117+ cmp(0, f2);
118+ }
119+ }
120+
121+ for (i = 0; i < 6; i++)
122+ for (j = 0; j < 6; j++)
123+ cmp(make(i & 1, i >> 1, 0, 0),
124+ make(j & 1, j >> 1, 0, 0));
125+
126+ for (i = 0; i < 2; i++) {
127+ for (j = 0; j < 2; j++) {
128+ int a, b;
129+ for (a = 0; a < 2; a++) {
130+ for (b = 0; b < 2; b++) {
131+ cmp(make(i, j, a, b), make(i, j, 0, 0));
132+ cmp(make(i, j, 0, 0), make(i, j, a, b));
133+ }
134+ }
135+ }
136+ }
137+}
138+
139+void xop(const char *name, long double a, long double b, long double c)
140+{
141+ u128_t ax = copy_ild(a);
142+ u128_t bx = copy_ild(b);
143+ u128_t cx = copy_ild(c);
144+ printf("%s %016llx%016llx %016llx%016llx %016llx%016llx\n",
145+ name, ax.x1, ax.x0, bx.x1, bx.x0, cx.x1, cx.x0);
146+}
147+
148+void fadd(long double a, long double b)
149+{
150+ xop("add", a, b, a + b);
151+}
152+
153+void fsub(long double a, long double b)
154+{
155+ xop("sub", a, b, a - b);
156+}
157+
158+void fmul(long double a, long double b)
159+{
160+ xop("mul", a, b, a * b);
161+}
162+
163+void fdiv(long double a, long double b)
164+{
165+ xop("div", a, b, a / b);
166+}
167+
168+void nanz(void)
169+{
170+ // Check NaNs:
171+ {
172+ long double x[7];
173+ int i, j, n = 0;
174+ x[n++] = make(0, 32000, 0x95132b76effc, 0xd79035214b4f8d53);
175+ x[n++] = make(1, 32001, 0xbe71d7a51587, 0x30601c6815d6c3ac);
176+ x[n++] = make(0, 32767, 0, 1);
177+ x[n++] = make(0, 32767, (uint64_t)1 << 46, 0);
178+ x[n++] = make(1, 32767, (uint64_t)1 << 47, 0);
179+ x[n++] = make(1, 32767, 0x7596c7099ad5, 0xe25fed2c58f73fc9);
180+ x[n++] = make(0, 32767, 0x835d143360f9, 0x5e315efb35630666);
181+ check(n == sizeof(x) / sizeof(*x));
182+ for (i = 0; i < n; i++) {
183+ for (j = 0; j < n; j++) {
184+ fadd(x[i], x[j]);
185+ fsub(x[i], x[j]);
186+ fmul(x[i], x[j]);
187+ fdiv(x[i], x[j]);
188+ }
189+ }
190+ }
191+
192+ // Check infinities and zeroes:
193+ {
194+ long double x[6];
195+ int i, j, n = 0;
196+ x[n++] = make(1, 32000, 0x62acda85f700, 0x47b6c9f35edc4044);
197+ x[n++] = make(0, 32001, 0x94b7abf55af7, 0x9f425fe354428e19);
198+ x[n++] = make(0, 32767, 0, 0);
199+ x[n++] = make(1, 32767, 0, 0);
200+ x[n++] = make(0, 0, 0, 0);
201+ x[n++] = make(1, 0, 0, 0);
202+ check(n == sizeof(x) / sizeof(*x));
203+ for (i = 0; i < n; i++) {
204+ for (j = 0; j < n; j++) {
205+ fadd(x[i], x[j]);
206+ fsub(x[i], x[j]);
207+ fmul(x[i], x[j]);
208+ fdiv(x[i], x[j]);
209+ }
210+ }
211+ }
212+}
213+
214+void adds(void)
215+{
216+ // Check shifting and add/sub:
217+ {
218+ int i;
219+ for (i = -130; i <= 130; i++) {
220+ int s1 = (uint32_t)i % 3 < 1;
221+ int s2 = (uint32_t)i % 5 < 2;
222+ fadd(make(s1, 16384 , 0x502c065e4f71a65d, 0xd2f9bdb031f4f031),
223+ make(s2, 16384 + i, 0xae267395a9bc1033, 0xb56b5800da1ba448));
224+ }
225+ }
226+
227+ // Check normalisation:
228+ {
229+ uint64_t a0 = 0xc6bab0a6afbef5ed;
230+ uint64_t a1 = 0x4f84136c4a2e9b52;
231+ int ee[] = { 0, 1, 10000 };
232+ int e, i;
233+ for (e = 0; e < sizeof(ee) / sizeof(*ee); e++) {
234+ int exp = ee[e];
235+ fsub(make(0, exp, a1, a0), make(0, 0, 0, 0));
236+ for (i = 63; i >= 0; i--)
237+ fsub(make(0, exp, a1 | (uint64_t)1 << i >> 1, a0),
238+ make(0, exp, a1 >> i << i, 0));
239+ for (i = 63; i >=0; i--)
240+ fsub(make(0, exp, a1, a0 | (uint64_t)1 << i >> 1),
241+ make(0, exp, a1, a0 >> i << i));
242+ }
243+ }
244+
245+ // Carry/overflow from rounding:
246+ {
247+ fadd(make(0, 114, -1, -1), make(0, 1, 0, 0));
248+ fadd(make(0, 32766, -1, -1), make(0, 32653, 0, 0));
249+ fsub(make(1, 32766, -1, -1), make(0, 32653, 0, 0));
250+ }
251+}
252+
253+void muls(void)
254+{
255+ int i, j;
256+
257+ {
258+ long double max = make(0, 32766, -1, -1);
259+ long double min = make(0, 0, 0, 1);
260+ fmul(max, max);
261+ fmul(max, min);
262+ fmul(min, min);
263+ }
264+
265+ for (i = 117; i > 0; i--)
266+ fmul(make(0, 16268, 0x643dcea76edc, 0xe0877a598403627a),
267+ make(i & 1, i, 0, 0));
268+
269+ fmul(make(0, 16383, -1, -3), make(0, 16383, 0, 1));
270+ // Round to next exponent:
271+ fmul(make(0, 16383, -1, -2), make(0, 16383, 0, 1));
272+ // Round from subnormal to normal:
273+ fmul(make(0, 1, -1, -1), make(0, 16382, 0, 0));
274+
275+ for (i = 0; i < 2; i++)
276+ for (j = 0; j < 112; j++)
277+ fmul(make(0, 16383, (uint64_t)1 << i, 0),
278+ make(0, 16383,
279+ j < 64 ? 0 : (uint64_t)1 << (j - 64),
280+ j < 64 ? (uint64_t)1 << j : 0));
281+}
282+
283+void divs(void)
284+{
285+ int i;
286+
287+ {
288+ long double max = make(0, 32766, -1, -1);
289+ long double min = make(0, 0, 0, 1);
290+ fdiv(max, max);
291+ fdiv(max, min);
292+ fdiv(min, max);
293+ fdiv(min, min);
294+ }
295+
296+ for (i = 0; i < 64; i++)
297+ fdiv(make(0, 16383, -1, -1), make(0, 16383, -1, -(uint64_t)1 << i));
298+ for (i = 0; i < 48; i++)
299+ fdiv(make(0, 16383, -1, -1), make(0, 16383, -(uint64_t)1 << i, 0));
300+}
301+
302+void cvtlsw(int32_t a)
303+{
304+ long double f = a;
305+ u128_t x = copy_ild(f);
306+ printf("cvtlsw %08lx %016llx%016llx\n", (long)(uint32_t)a, x.x1, x.x0);
307+}
308+
309+void cvtlsx(int64_t a)
310+{
311+ long double f = a;
312+ u128_t x = copy_ild(f);
313+ printf("cvtlsx %016llx %016llx%016llx\n",
314+ (long long)(uint64_t)a, x.x1, x.x0);
315+}
316+
317+void cvtluw(uint32_t a)
318+{
319+ long double f = a;
320+ u128_t x = copy_ild(f);
321+ printf("cvtluw %08lx %016llx%016llx\n", (long)a, x.x1, x.x0);
322+}
323+
324+void cvtlux(uint64_t a)
325+{
326+ long double f = a;
327+ u128_t x = copy_ild(f);
328+ printf("cvtlux %016llx %016llx%016llx\n", (long long)a, x.x1, x.x0);
329+}
330+
331+void cvtil(long double a)
332+{
333+ u128_t x = copy_ild(a);
334+ int32_t b1 = a;
335+ int64_t b2 = a;
336+ uint32_t b3 = a;
337+ uint64_t b4 = a;
338+ printf("cvtswl %016llx%016llx %08lx\n",
339+ x.x1, x.x0, (long)(uint32_t)b1);
340+ printf("cvtsxl %016llx%016llx %016llx\n",
341+ x.x1, x.x0, (long long)(uint64_t)b2);
342+ printf("cvtuwl %016llx%016llx %08lx\n",
343+ x.x1, x.x0, (long)b3);
344+ printf("cvtuxl %016llx%016llx %016llx\n",
345+ x.x1, x.x0, (long long)b4);
346+}
347+
348+void cvtlf(float a)
349+{
350+ uint32_t ax = copy_if(a);
351+ long double b = a;
352+ u128_t bx = copy_ild(b);
353+ printf("cvtlf %08lx %016llx%016llx\n", (long)ax, bx.x1, bx.x0);
354+}
355+
356+void cvtld(double a)
357+{
358+ uint64_t ax = copy_id(a);
359+ long double b = a;
360+ u128_t bx = copy_ild(b);
361+ printf("cvtld %016llx %016llx%016llx\n", (long long)ax, bx.x1, bx.x0);
362+}
363+
364+void cvtfl(long double a)
365+{
366+ u128_t ax = copy_ild(a);
367+ float b = a;
368+ uint32_t bx = copy_if(b);
369+ printf("cvtfl %016llx%016llx %08lx\n", ax.x1, ax.x0, (long)bx);
370+}
371+
372+void cvtdl(long double a)
373+{
374+ u128_t ax = copy_ild(a);
375+ double b = a;
376+ uint64_t bx = copy_id(b);
377+ printf("cvtdl %016llx%016llx %016llx\n", ax.x1, ax.x0, (long long)bx);
378+}
379+
380+void cvts(void)
381+{
382+ int i, j;
383+
384+ {
385+ uint32_t x = 0xad040c5b;
386+ cvtlsw(0);
387+ for (i = 0; i < 31; i++)
388+ cvtlsw(x >> (31 - i));
389+ for (i = 0; i < 31; i++)
390+ cvtlsw(-(x >> (31 - i)));
391+ cvtlsw(0x80000000);
392+ }
393+ {
394+ uint64_t x = 0xb630a248cad9afd2;
395+ cvtlsx(0);
396+ for (i = 0; i < 63; i++)
397+ cvtlsx(x >> (63 - i));
398+ for (i = 0; i < 63; i++)
399+ cvtlsx(-(x >> (63 - i)));
400+ cvtlsx(0x8000000000000000);
401+ }
402+ {
403+ uint32_t x = 0xad040c5b;
404+ cvtluw(0);
405+ for (i = 0; i < 32; i++)
406+ cvtluw(x >> (31 - i));
407+ }
408+ {
409+ uint64_t x = 0xb630a248cad9afd2;
410+ cvtlux(0);
411+ for (i = 0; i < 64; i++)
412+ cvtlux(x >> (63 - i));
413+ }
414+
415+ for (i = 0; i < 2; i++) {
416+ cvtil(make(i, 32767, 0, 1));
417+ cvtil(make(i, 32767, (uint64_t)1 << 47, 0));
418+ cvtil(make(i, 32767, 123, 456));
419+ cvtil(make(i, 32767, 0, 0));
420+ cvtil(make(i, 16382, -1, -1));
421+ cvtil(make(i, 16383, -1, -1));
422+ cvtil(make(i, 16384, 0x7fffffffffff, -1));
423+ cvtil(make(i, 16384, 0x800000000000, 0));
424+ for (j = 0; j < 68; j++)
425+ cvtil(make(i, 16381 + j, 0xd4822c0a10ec, 0x1fe2f8b2669f5c9d));
426+ }
427+
428+ cvtlf(copy_fi(0x00000000));
429+ cvtlf(copy_fi(0x456789ab));
430+ cvtlf(copy_fi(0x7f800000));
431+ cvtlf(copy_fi(0x7f923456));
432+ cvtlf(copy_fi(0x7fdbcdef));
433+ cvtlf(copy_fi(0x80000000));
434+ cvtlf(copy_fi(0xabcdef12));
435+ cvtlf(copy_fi(0xff800000));
436+ cvtlf(copy_fi(0xff923456));
437+ cvtlf(copy_fi(0xffdbcdef));
438+
439+ cvtld(copy_di(0x0000000000000000));
440+ cvtld(copy_di(0x456789abcdef0123));
441+ cvtld(copy_di(0x7ff0000000000000));
442+ cvtld(copy_di(0x7ff123456789abcd));
443+ cvtld(copy_di(0x7ffabcdef1234567));
444+ cvtld(copy_di(0x8000000000000000));
445+ cvtld(copy_di(0xcdef123456789abc));
446+ cvtld(copy_di(0xfff0000000000000));
447+ cvtld(copy_di(0xfff123456789abcd));
448+ cvtld(copy_di(0xfffabcdef1234567));
449+
450+ for (i = 0; i < 2; i++) { \
451+ cvtfl(make(i, 0, 0, 0));
452+ cvtfl(make(i, 16232, -1, -1));
453+ cvtfl(make(i, 16233, 0, 0));
454+ cvtfl(make(i, 16233, 0, 1));
455+ cvtfl(make(i, 16383, 0xab0ffd000000, 0));
456+ cvtfl(make(i, 16383, 0xab0ffd000001, 0));
457+ cvtfl(make(i, 16383, 0xab0ffeffffff, 0));
458+ cvtfl(make(i, 16383, 0xab0fff000000, 0));
459+ cvtfl(make(i, 16383, 0xab0fff000001, 0));
460+ cvtfl(make(i, 16510, 0xfffffeffffff, -1));
461+ cvtfl(make(i, 16510, 0xffffff000000, 0));
462+ cvtfl(make(i, 16511, 0, 0));
463+ cvtfl(make(i, 32767, 0, 0));
464+ cvtfl(make(i, 32767, 0, 1));
465+ cvtfl(make(i, 32767, 0x4cbe01ac5f40, 0x75cee3c6afbb00b5));
466+ cvtfl(make(i, 32767, 0x800000000000, 1));
467+ cvtfl(make(i, 32767, 0xa11caaaf6a52, 0x696033e871eab099));
468+ }
469+
470+ for (i = 0; i < 2; i++) {
471+ cvtdl(make(i, 0, 0, 0));
472+ cvtdl(make(i, 15307, -1, -1));
473+ cvtdl(make(i, 15308, 0, 0));
474+ cvtdl(make(i, 15308, 0, 1));
475+ cvtdl(make(i, 16383, 0xabc123abc0ff, 0xe800000000000000));
476+ cvtdl(make(i, 16383, 0xabc123abc0ff, 0xe800000000000001));
477+ cvtdl(make(i, 16383, 0xabc123abc0ff, 0xf7ffffffffffffff));
478+ cvtdl(make(i, 16383, 0xabc123abc0ff, 0xf800000000000000));
479+ cvtdl(make(i, 16383, 0xabc123abc0ff, 0xf800000000000001));
480+ cvtdl(make(i, 17406, 0xffffffffffff, 0xf7ffffffffffffff));
481+ cvtdl(make(i, 17406, 0xffffffffffff, 0xf800000000000000));
482+ cvtdl(make(i, 17407, 0, 0));
483+ cvtdl(make(i, 32767, 0, 0));
484+ cvtdl(make(i, 32767, 0, 1));
485+ cvtdl(make(i, 32767, 0x4cbe01ac5f40, 0x75cee3c6afbb00b5));
486+ cvtdl(make(i, 32767, 0x800000000000, 1));
487+ cvtdl(make(i, 32767, 0xa11caaaf6a52, 0x696033e871eab099));
488+ }
489+}
490+
491+void tests(void)
492+{
493+ cmps();
494+ nanz();
495+ adds();
496+ muls();
497+ divs();
498+ cvts();
499+}
500+
501+int main()
502+{
503+#ifdef __aarch64__
504+ tests();
505+#else
506+ printf("This test program is intended for a little-endian architecture\n"
507+ "with an IEEE-standard 128-bit long double.\n");
508+#endif
509+ return 0;
510+}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t