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
45 45
46I386_O = libtcc1.o alloca86.o alloca86-bt.o $(BCHECK_O)46I386_O = libtcc1.o alloca86.o alloca86-bt.o $(BCHECK_O)
47X86_64_O = libtcc1.o alloca86_64.o47X86_64_O = libtcc1.o alloca86_64.o
48ARM_O = libtcc1.o48ARM_O = libtcc1.o armeabi.o
49WIN32_O = $(I386_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o49WIN32_O = $(I386_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o
50WIN64_O = $(X86_64_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o50WIN64_O = $(X86_64_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o
51 51
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
6typedef struct double_unsigned_struct {
7 unsigned low;
8 unsigned high;
9} double_unsigned_struct;
10
11typedef 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
30REGS_RETURN(unsigned_int_struct, unsigned_int_struct)
31REGS_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) \
38void __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 */
95DEFINE__AEABIT_F2XLZ(f2ulz, 0)
96
97/* float to long long conversion */
98DEFINE__AEABIT_F2XLZ(f2lz, 1)
99
100/* double to [unsigned] long long conversion */
101#define DEFINE__AEABIT_D2XLZ(name, with_sign) \
102void __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 */
164DEFINE__AEABIT_D2XLZ(d2ulz, 0)
165
166/* double to long long conversion */
167DEFINE__AEABIT_D2XLZ(d2lz, 1)
168
169/* long long to float conversion */
170#define DEFINE__AEABI_XL2F(name, with_sign) \
171unsigned __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 */
216DEFINE__AEABI_XL2F(ul2f, 0)
217
218/* long long to float conversion */
219DEFINE__AEABI_XL2F(l2f, 0)
220
221/* long long to double conversion */
222#define __AEABI_XL2D(name, with_sign) \
223void __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) \
293typedef struct type { \
294 basetype quot; \
295 unsigned basetype rem; \
296} type
297
298#define define_aeabi_xdivmod_unsigned_type(basetype, type) \
299typedef struct type { \
300 basetype quot; \
301 basetype rem; \
302} type
303
304#define AEABI_UXDIVMOD(name,type, rettype, typemacro) \
305static 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) \
328void __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
350define_aeabi_xdivmod_signed_type(long long, lldiv_t);
351define_aeabi_xdivmod_unsigned_type(unsigned long long, ulldiv_t);
352define_aeabi_xdivmod_signed_type(int, idiv_t);
353define_aeabi_xdivmod_unsigned_type(unsigned, uidiv_t);
354
355REGS_RETURN(lldiv_t, lldiv_t)
356REGS_RETURN(ulldiv_t, ulldiv_t)
357REGS_RETURN(idiv_t, idiv_t)
358REGS_RETURN(uidiv_t, uidiv_t)
359
360AEABI_UXDIVMOD(uldivmod, unsigned long long, ulldiv_t, ULONG)
361
362__AEABI_XDIVMOD(ldivmod, long long, uldivmod, lldiv_t, ulldiv_t, LLONG)
363
364void __aeabi_uldivmod(unsigned long long num, unsigned long long den)
365{
366 ulldiv_t_return(aeabi_uldivmod(num, den));
367}
368
369void __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
403void __aeabi_llsr(double_unsigned_struct val, int shift)
404{
405 aeabi_lsr(val, shift, 0, double_unsigned);
406}
407
408void __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
416AEABI_UXDIVMOD(uidivmod, unsigned, uidiv_t, UINT)
417
418int __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
431unsigned __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
438void __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
59 59
60#include "tcclib.h"60#include "tcclib.h"
61 61
62void intdiv_test();
62void string_test();63void string_test();
63void expr_test();64void expr_test();
64void macro_test();65void macro_test();
@@ -167,6 +168,71 @@ int qq(int x) · 102 unmodified lines
167#define wq_spin_lock spin_lock168#define wq_spin_lock spin_lock
168#define TEST2() wq_spin_lock(a)169#define TEST2() wq_spin_lock(a)
169 170
171#define UINT_MAX ((unsigned) -1)
172
173void 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
170void macro_test(void)236void macro_test(void)
171{237{
172 printf("macro:\n"); 238 printf("macro:\n");
@@ -619,6 +685,7 @@ int main(int argc, char **argv) · 446 unmodified lines
619 math_cmp_test();685 math_cmp_test();
620 callsave_test();686 callsave_test();
621 builtin_frame_address_test();687 builtin_frame_address_test();
688 intdiv_test();
622 return 0; 689 return 0;
623}690}
624 691