History

Add ARM aeabi functions needed to run tcctest

Add implementation for float / integer conversion functions: __aeabi_d2lz, __aeabi_d2ulz, __aeabi_f2lz, __aeabi_f2ulz, __aeabi_l2d, __aeabi_l2f, __aeabi_ul2d, __aeabi_ul2f Add implementation for long long helper functions: __aeabi_ldivmod, __aeabi_uldivmod, __aeabi_llsl, __aeabi_llsr, __aeabi_lasr Add implementation for integer division functions: __aeabi_uidiv, __aeabi_uidivmod, __aeabi_idiv, __aeabi_idivmod,

Thomas Preud'homme committed 13 years ago

Commit f2dbcf71 parent 389c25c3 files · +509 −1Browse files

Unified · Split

3 files
  1. lib/Makefile +1 −1
  2. lib/armeabi.c +441 −0
  3. tests/tcctest.c +67 −0
lib/Makefile+1−1
@@ -45,7 +45,7 @@ cross : TCC = $(TOP)/$(TARGET)-tcc$(EXESUF) · 44 unmodified lines
4545
4646 I386_O = libtcc1.o alloca86.o alloca86-bt.o $(BCHECK_O)
4747 X86_64_O = libtcc1.o alloca86_64.o
48−ARM_O = libtcc1.o
48+ARM_O = libtcc1.o armeabi.o
4949 WIN32_O = $(I386_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o
5050 WIN64_O = $(X86_64_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o
5151
lib/armeabi.c+441−0
@@ -0,0 +1,441 @@
1+#include<limits.h>
2+
3+/* We rely on the little endianness and EABI calling convention for this to
4+ work */
5+
6+typedef struct double_unsigned_struct {
7+ unsigned low;
8+ unsigned high;
9+} double_unsigned_struct;
10+
11+typedef struct unsigned_int_struct {
12+ unsigned low;
13+ int high;
14+} unsigned_int_struct;
15+
16+#define REGS_RETURN(name, type) \
17+ void name ## _return(type ret) {}
18+
19+
20+/* Float helper functions */
21+
22+#define FLOAT_EXP_BITS 8
23+#define FLOAT_FRAC_BITS 23
24+
25+#define DOUBLE_EXP_BITS 11
26+#define DOUBLE_FRAC_BITS 52
27+
28+#define ONE_EXP(type) ((1 << (type ## _EXP_BITS - 1)) - 1)
29+
30+REGS_RETURN(unsigned_int_struct, unsigned_int_struct)
31+REGS_RETURN(double_unsigned_struct, double_unsigned_struct)
32+
33+/* float -> integer: (sign) 1.fraction x 2^(exponent - exp_for_one) */
34+
35+
36+/* float to [unsigned] long long conversion */
37+#define DEFINE__AEABIT_F2XLZ(name, with_sign) \
38+void __aeabi_ ## name(unsigned val) \
39+{ \
40+ int exp, high_shift, sign; \
41+ double_unsigned_struct ret; \
42+ \
43+ /* compute sign */ \
44+ sign = val >> 31; \
45+ \
46+ /* compute real exponent */ \
47+ exp = val >> FLOAT_FRAC_BITS; \
48+ exp &= (1 << FLOAT_EXP_BITS) - 1; \
49+ exp -= ONE_EXP(FLOAT); \
50+ \
51+ /* undefined behavior if truncated value cannot be represented */ \
52+ if (with_sign) { \
53+ if (exp > 62) /* |val| too big, double cannot represent LLONG_MAX */ \
54+ return; \
55+ } else { \
56+ if ((sign && exp >= 0) || exp > 63) /* if val < 0 || val too big */ \
57+ return; \
58+ } \
59+ \
60+ val &= (1 << FLOAT_FRAC_BITS) - 1; \
61+ if (exp >= 32) { \
62+ ret.high = 1 << (exp - 32); \
63+ if (exp - 32 >= FLOAT_FRAC_BITS) { \
64+ ret.high |= val << (exp - 32 - FLOAT_FRAC_BITS); \
65+ ret.low = 0; \
66+ } else { \
67+ high_shift = FLOAT_FRAC_BITS - (exp - 32); \
68+ ret.high |= val >> high_shift; \
69+ ret.low = val << (32 - high_shift); \
70+ } \
71+ } else { \
72+ ret.high = 0; \
73+ ret.low = 1 << exp; \
74+ if (exp > FLOAT_FRAC_BITS) \
75+ ret.low |= val << (exp - FLOAT_FRAC_BITS); \
76+ else \
77+ ret.low = val >> (FLOAT_FRAC_BITS - exp); \
78+ } \
79+ \
80+ /* encode negative integer using 2's complement */ \
81+ if (with_sign && sign) { \
82+ ret.low = ~ret.low; \
83+ ret.high = ~ret.high; \
84+ if (ret.low == UINT_MAX) { \
85+ ret.low = 0; \
86+ ret.high++; \
87+ } else \
88+ ret.low++; \
89+ } \
90+ \
91+ double_unsigned_struct_return(ret); \
92+}
93+
94+/* float to unsigned long long conversion */
95+DEFINE__AEABIT_F2XLZ(f2ulz, 0)
96+
97+/* float to long long conversion */
98+DEFINE__AEABIT_F2XLZ(f2lz, 1)
99+
100+/* double to [unsigned] long long conversion */
101+#define DEFINE__AEABIT_D2XLZ(name, with_sign) \
102+void __aeabi_ ## name(double_unsigned_struct val) \
103+{ \
104+ int exp, high_shift, sign; \
105+ double_unsigned_struct ret; \
106+ \
107+ /* compute sign */ \
108+ sign = val.high >> 31; \
109+ \
110+ /* compute real exponent */ \
111+ exp = (val.high >> (DOUBLE_FRAC_BITS - 32)); \
112+ exp &= (1 << DOUBLE_EXP_BITS) - 1; \
113+ exp -= ONE_EXP(DOUBLE); \
114+ \
115+ /* undefined behavior if truncated value cannot be represented */ \
116+ if (with_sign) { \
117+ if (exp > 62) /* |val| too big, double cannot represent LLONG_MAX */ \
118+ return; \
119+ } else { \
120+ if ((sign && exp >= 0) || exp > 63) /* if val < 0 || val too big */ \
121+ return; \
122+ } \
123+ \
124+ val.high &= (1 << (DOUBLE_FRAC_BITS - 32)) - 1; \
125+ if (exp >= 32) { \
126+ ret.high = 1 << (exp - 32); \
127+ if (exp >= DOUBLE_FRAC_BITS) { \
128+ high_shift = exp - DOUBLE_FRAC_BITS; \
129+ ret.high |= val.high << high_shift; \
130+ ret.high |= val.low >> (32 - high_shift); \
131+ ret.low = val.low << high_shift; \
132+ } else { \
133+ high_shift = DOUBLE_FRAC_BITS - exp; \
134+ ret.high |= val.high >> high_shift; \
135+ ret.low = val.high << (32 - high_shift); \
136+ ret.low |= val.low >> high_shift; \
137+ } \
138+ } else { \
139+ ret.high = 0; \
140+ ret.low = 1 << exp; \
141+ if (exp > DOUBLE_FRAC_BITS - 32) { \
142+ high_shift = exp - DOUBLE_FRAC_BITS - 32; \
143+ ret.low |= val.high << high_shift; \
144+ ret.low |= val.low >> (32 - high_shift); \
145+ } else \
146+ ret.low = val.high >> (DOUBLE_FRAC_BITS - 32 - exp); \
147+ } \
148+ \
149+ /* encode negative integer using 2's complement */ \
150+ if (with_sign && sign) { \
151+ ret.low = ~ret.low; \
152+ ret.high = ~ret.high; \
153+ if (ret.low == UINT_MAX) { \
154+ ret.low = 0; \
155+ ret.high++; \
156+ } else \
157+ ret.low++; \
158+ } \
159+ \
160+ double_unsigned_struct_return(ret); \
161+}
162+
163+/* double to unsigned long long conversion */
164+DEFINE__AEABIT_D2XLZ(d2ulz, 0)
165+
166+/* double to long long conversion */
167+DEFINE__AEABIT_D2XLZ(d2lz, 1)
168+
169+/* long long to float conversion */
170+#define DEFINE__AEABI_XL2F(name, with_sign) \
171+unsigned __aeabi_ ## name(unsigned long long v) \
172+{ \
173+ int s /* shift */, sign = 0; \
174+ unsigned p = 0 /* power */, ret; \
175+ double_unsigned_struct val; \
176+ \
177+ /* fraction in negative float is encoded in 1's complement */ \
178+ if (with_sign && (v & (1 << 63))) { \
179+ sign = 1; \
180+ v = ~v + 1; \
181+ } \
182+ val.low = v; \
183+ val.high = v >> 32; \
184+ /* fill fraction bits */ \
185+ for (s = 31, p = 1 << 31; p && !(val.high & p); s--, p >>= 1); \
186+ if (p) { \
187+ ret = val.high & (p - 1); \
188+ if (s < FLOAT_FRAC_BITS) { \
189+ ret <<= FLOAT_FRAC_BITS - s; \
190+ ret |= val.low >> (32 - (FLOAT_FRAC_BITS - s)); \
191+ } else \
192+ ret >>= s - FLOAT_FRAC_BITS; \
193+ s += 32; \
194+ } else { \
195+ for (s = 31, p = 1 << 31; p && !(val.low & p); s--, p >>= 1); \
196+ if (p) { \
197+ ret = val.low & (p - 1); \
198+ if (s <= FLOAT_FRAC_BITS) \
199+ ret <<= FLOAT_FRAC_BITS - s; \
200+ else \
201+ ret >>= s - FLOAT_FRAC_BITS; \
202+ } else \
203+ return 0; \
204+ } \
205+ \
206+ /* fill exponent bits */ \
207+ ret |= (s + ONE_EXP(FLOAT)) << FLOAT_FRAC_BITS; \
208+ \
209+ /* fill sign bit */ \
210+ ret |= sign << 31; \
211+ \
212+ return ret; \
213+}
214+
215+/* unsigned long long to float conversion */
216+DEFINE__AEABI_XL2F(ul2f, 0)
217+
218+/* long long to float conversion */
219+DEFINE__AEABI_XL2F(l2f, 0)
220+
221+/* long long to double conversion */
222+#define __AEABI_XL2D(name, with_sign) \
223+void __aeabi_ ## name(unsigned long long v) \
224+{ \
225+ int s, high_shift, sign = 0; \
226+ unsigned tmp, p = 0; \
227+ double_unsigned_struct val, ret; \
228+ \
229+ /* fraction in negative float is encoded in 1's complement */ \
230+ if (with_sign && (v & (1ULL << 63))) { \
231+ sign = 1; \
232+ v = ~v + 1; \
233+ } \
234+ val.low = v; \
235+ val.high = v >> 32; \
236+ \
237+ /* fill fraction bits */ \
238+ for (s = 31, p = 1 << 31; p && !(val.high & p); s--, p >>= 1); \
239+ if (p) { \
240+ tmp = val.high & (p - 1); \
241+ if (s < DOUBLE_FRAC_BITS - 32) { \
242+ high_shift = DOUBLE_FRAC_BITS - 32 - s; \
243+ ret.high = tmp << high_shift; \
244+ ret.high |= val.low >> (32 - high_shift); \
245+ ret.low = val.low << high_shift; \
246+ } else { \
247+ high_shift = s - (DOUBLE_FRAC_BITS - 32); \
248+ ret.high = tmp >> high_shift; \
249+ ret.low = tmp << (32 - high_shift); \
250+ ret.low |= val.low >> high_shift; \
251+ } \
252+ s += 32; \
253+ } else { \
254+ for (s = 31, p = 1 << 31; p && !(val.low & p); s--, p >>= 1); \
255+ if (p) { \
256+ tmp = val.low & (p - 1); \
257+ if (s <= DOUBLE_FRAC_BITS - 32) { \
258+ high_shift = DOUBLE_FRAC_BITS - 32 - s; \
259+ ret.high = tmp << high_shift; \
260+ ret.low = 0; \
261+ } else { \
262+ high_shift = s - (DOUBLE_FRAC_BITS - 32); \
263+ ret.high = tmp >> high_shift; \
264+ ret.low = tmp << (32 - high_shift); \
265+ } \
266+ } else { \
267+ ret.high = ret.low = 0; \
268+ double_unsigned_struct_return(ret); \
269+ } \
270+ } \
271+ \
272+ /* fill exponent bits */ \
273+ ret.high |= (s + ONE_EXP(DOUBLE)) << (DOUBLE_FRAC_BITS - 32); \
274+ \
275+ /* fill sign bit */ \
276+ ret.high |= sign << 31; \
277+ \
278+ double_unsigned_struct_return(ret); \
279+}
280+
281+/* unsigned long long to double conversion */
282+__AEABI_XL2D(ul2d, 0)
283+
284+/* long long to double conversion */
285+__AEABI_XL2D(l2d, 1)
286+
287+
288+/* Long long helper functions */
289+
290+/* TODO: add error in case of den == 0 (see §4.3.1 and §4.3.2) */
291+
292+#define define_aeabi_xdivmod_signed_type(basetype, type) \
293+typedef struct type { \
294+ basetype quot; \
295+ unsigned basetype rem; \
296+} type
297+
298+#define define_aeabi_xdivmod_unsigned_type(basetype, type) \
299+typedef struct type { \
300+ basetype quot; \
301+ basetype rem; \
302+} type
303+
304+#define AEABI_UXDIVMOD(name,type, rettype, typemacro) \
305+static inline rettype aeabi_ ## name (type num, type den) \
306+{ \
307+ rettype ret; \
308+ type quot = 0; \
309+ \
310+ /* Increase quotient while it is less than numerator */ \
311+ while (num >= den) { \
312+ type q = 1; \
313+ \
314+ /* Find closest power of two */ \
315+ while ((q << 1) * den <= num && q * den <= typemacro ## _MAX / 2) \
316+ q <<= 1; \
317+ \
318+ /* Compute difference between current quotient and numerator */ \
319+ num -= q * den; \
320+ quot += q; \
321+ } \
322+ ret.quot = quot; \
323+ ret.rem = num; \
324+ return ret; \
325+}
326+
327+#define __AEABI_XDIVMOD(name, type, uiname, rettype, urettype, typemacro) \
328+void __aeabi_ ## name(type numerator, type denominator) \
329+{ \
330+ unsigned type num, den; \
331+ urettype uxdiv_ret; \
332+ rettype ret; \
333+ \
334+ num = numerator & typemacro ## _MAX; \
335+ den = denominator & typemacro ## _MAX; \
336+ uxdiv_ret = aeabi_ ## uiname(num, den); \
337+ /* signs differ */ \
338+ if ((numerator & typemacro ## _MIN) != (denominator & typemacro ## _MIN)) \
339+ ret.quot = uxdiv_ret.quot * -1; \
340+ else \
341+ ret.quot = uxdiv_ret.quot; \
342+ if (numerator & typemacro ## _MIN) \
343+ ret.rem = uxdiv_ret.rem * -1; \
344+ else \
345+ ret.rem = uxdiv_ret.rem; \
346+ \
347+ rettype ## _return(ret); \
348+}
349+
350+define_aeabi_xdivmod_signed_type(long long, lldiv_t);
351+define_aeabi_xdivmod_unsigned_type(unsigned long long, ulldiv_t);
352+define_aeabi_xdivmod_signed_type(int, idiv_t);
353+define_aeabi_xdivmod_unsigned_type(unsigned, uidiv_t);
354+
355+REGS_RETURN(lldiv_t, lldiv_t)
356+REGS_RETURN(ulldiv_t, ulldiv_t)
357+REGS_RETURN(idiv_t, idiv_t)
358+REGS_RETURN(uidiv_t, uidiv_t)
359+
360+AEABI_UXDIVMOD(uldivmod, unsigned long long, ulldiv_t, ULONG)
361+
362+__AEABI_XDIVMOD(ldivmod, long long, uldivmod, lldiv_t, ulldiv_t, LLONG)
363+
364+void __aeabi_uldivmod(unsigned long long num, unsigned long long den)
365+{
366+ ulldiv_t_return(aeabi_uldivmod(num, den));
367+}
368+
369+void __aeabi_llsl(double_unsigned_struct val, int shift)
370+{
371+ double_unsigned_struct ret;
372+
373+ if (shift >= 32) {
374+ val.high = val.low;
375+ val.low = 0;
376+ shift -= 32;
377+ }
378+ if (shift > 0) {
379+ ret.low = val.low << shift;
380+ ret.high = (val.high << shift) | (val.low >> (32 - shift));
381+ double_unsigned_struct_return(ret);
382+ return;
383+ }
384+ double_unsigned_struct_return(val);
385+}
386+
387+#define aeabi_lsr(val, shift, fill, type) \
388+ type ## _struct ret; \
389+ \
390+ if (shift >= 32) { \
391+ val.low = val.high; \
392+ val.high = fill; \
393+ shift -= 32; \
394+ } \
395+ if (shift > 0) { \
396+ ret.high = val.high >> shift; \
397+ ret.low = (val.high << (32 - shift)) | (val.low >> shift); \
398+ type ## _struct_return(ret); \
399+ return; \
400+ } \
401+ type ## _struct_return(val);
402+
403+void __aeabi_llsr(double_unsigned_struct val, int shift)
404+{
405+ aeabi_lsr(val, shift, 0, double_unsigned);
406+}
407+
408+void __aeabi_lasr(unsigned_int_struct val, int shift)
409+{
410+ aeabi_lsr(val, shift, val.high >> 31, unsigned_int);
411+}
412+
413+
414+/* Integer division functions */
415+
416+AEABI_UXDIVMOD(uidivmod, unsigned, uidiv_t, UINT)
417+
418+int __aeabi_idiv(int numerator, int denominator)
419+{
420+ unsigned num, den;
421+ uidiv_t ret;
422+
423+ num = numerator & INT_MAX;
424+ den = denominator & INT_MAX;
425+ ret = aeabi_uidivmod(num, den);
426+ if ((numerator & INT_MIN) != (denominator & INT_MIN)) /* signs differ */
427+ ret.quot *= -1;
428+ return ret.quot;
429+}
430+
431+unsigned __aeabi_uidiv(unsigned num, unsigned den)
432+{
433+ return aeabi_uidivmod(num, den).quot;
434+}
435+
436+__AEABI_XDIVMOD(idivmod, int, uidivmod, idiv_t, uidiv_t, INT)
437+
438+void __aeabi_uidivmod(unsigned num, unsigned den)
439+{
440+ uidiv_t_return(aeabi_uidivmod(num, den));
441+}
tests/tcctest.c+67−0
@@ -59,6 +59,7 @@ · 58 unmodified lines
5959
6060 #include "tcclib.h"
6161
62+void intdiv_test();
6263 void string_test();
6364 void expr_test();
6465 void macro_test();
@@ -167,6 +168,71 @@ int qq(int x) · 102 unmodified lines
167168 #define wq_spin_lock spin_lock
168169 #define TEST2() wq_spin_lock(a)
169170
171+#define UINT_MAX ((unsigned) -1)
172+
173+void intdiv_test(void)
174+{
175+ printf("18/21=%u\n", 18/21);
176+ printf("18%21=%u\n", 18%21);
177+ printf("41/21=%u\n", 41/21);
178+ printf("41%21=%u\n", 41%21);
179+ printf("42/21=%u\n", 42/21);
180+ printf("42%21=%u\n", 42%21);
181+ printf("43/21=%u\n", 43/21);
182+ printf("43%21=%u\n", 43%21);
183+ printf("126/21=%u\n", 126/21);
184+ printf("12%/21=%u\n", 126%21);
185+ printf("131/21=%u\n", 131/21);
186+ printf("131%21=%u\n", 131%21);
187+ printf("(UINT_MAX/2+3)/2=%u\n", (UINT_MAX/2+3)/2);
188+ printf("(UINT_MAX/2+3)%2=%u\n", (UINT_MAX/2+3)%2);
189+
190+ printf("18/-21=%u\n", 18/-21);
191+ printf("18%-21=%u\n", 18%-21);
192+ printf("41/-21=%u\n", 41/-21);
193+ printf("41%-21=%u\n", 41%-21);
194+ printf("42/-21=%u\n", 42/-21);
195+ printf("42%-21=%u\n", 42%-21);
196+ printf("43/-21=%u\n", 43/-21);
197+ printf("43%-21=%u\n", 43%-21);
198+ printf("126/-21=%u\n", 126/-21);
199+ printf("12%/-21=%u\n", 126%-21);
200+ printf("131/-21=%u\n", 131/-21);
201+ printf("131%-21=%u\n", 131%-21);
202+ printf("(UINT_MAX/2+3)/-2=%u\n", (UINT_MAX/2+3)/-2);
203+ printf("(UINT_MAX/2+3)%-2=%u\n", (UINT_MAX/2+3)%-2);
204+
205+ printf("-18/21=%u\n", -18/21);
206+ printf("-18%21=%u\n", -18%21);
207+ printf("-41/21=%u\n", -41/21);
208+ printf("-41%21=%u\n", -41%21);
209+ printf("-42/21=%u\n", -42/21);
210+ printf("-42%21=%u\n", -42%21);
211+ printf("-43/21=%u\n", -43/21);
212+ printf("-43%21=%u\n", -43%21);
213+ printf("-126/21=%u\n", -126/21);
214+ printf("-12%/21=%u\n", -126%21);
215+ printf("-131/21=%u\n", -131/21);
216+ printf("-131%21=%u\n", -131%21);
217+ printf("-(UINT_MAX/2+3)/2=%u\n", (0-(UINT_MAX/2+3))/2);
218+ printf("-(UINT_MAX/2+3)%2=%u\n", (0-(UINT_MAX/2+3))%2);
219+
220+ printf("-18/-21=%u\n", -18/-21);
221+ printf("-18%-21=%u\n", -18%-21);
222+ printf("-41/-21=%u\n", -41/-21);
223+ printf("-41%-21=%u\n", -41%-21);
224+ printf("-42/-21=%u\n", -42/-21);
225+ printf("-42%-21=%u\n", -42%-21);
226+ printf("-43/-21=%u\n", -43/-21);
227+ printf("-43%-21=%u\n", -43%-21);
228+ printf("-126/-21=%u\n", -126/-21);
229+ printf("-12%/-21=%u\n", -126%-21);
230+ printf("-131/-21=%u\n", -131/-21);
231+ printf("-131%-21=%u\n", -131%-21);
232+ printf("-(UINT_MAX/2+3)/-2=%u\n", (0-(UINT_MAX/2+3))/-2);
233+ printf("-(UINT_MAX/2+3)%-2=%u\n", (0-(UINT_MAX/2+3))%-2);
234+}
235+
170236 void macro_test(void)
171237 {
172238 printf("macro:\n");
@@ -619,6 +685,7 @@ int main(int argc, char **argv) · 446 unmodified lines
619685 math_cmp_test();
620686 callsave_test();
621687 builtin_frame_address_test();
688+ intdiv_test();
622689 return 0;
623690 }
624691