forget Delete __va_ld_reg
[tinycc.git] / lib / libtcc1.c
blobb944f4f707f6ef83dc1b0c5b9d3e09f8c8e0985d
1 /* TCC runtime library.
2 Parts of this code are (c) 2002 Fabrice Bellard
4 Copyright (C) 1987, 1988, 1992, 1994, 1995 Free Software Foundation, Inc.
6 This file is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
11 In addition to the permissions in the GNU General Public License, the
12 Free Software Foundation gives you unlimited permission to link the
13 compiled version of this file into combinations with other programs,
14 and to distribute those combinations without any restriction coming
15 from the use of this file. (The General Public License restrictions
16 do apply in other respects; for example, they cover modification of
17 the file, and distribution when not linked into a combine
18 executable.)
20 This file is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 General Public License for more details.
25 You should have received a copy of the GNU General Public License
26 along with this program; see the file COPYING. If not, write to
27 the Free Software Foundation, 59 Temple Place - Suite 330,
28 Boston, MA 02111-1307, USA.
31 #include <stdint.h>
33 #define W_TYPE_SIZE 32
34 #define BITS_PER_UNIT 8
36 typedef int Wtype;
37 typedef unsigned int UWtype;
38 typedef unsigned int USItype;
39 typedef long long DWtype;
40 typedef unsigned long long UDWtype;
42 struct DWstruct {
43 Wtype low, high;
46 typedef union
48 struct DWstruct s;
49 DWtype ll;
50 } DWunion;
52 typedef long double XFtype;
53 #define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
54 #define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
56 /* the following deal with IEEE single-precision numbers */
57 #define EXCESS 126
58 #define SIGNBIT 0x80000000
59 #define HIDDEN (1 << 23)
60 #define SIGN(fp) ((fp) & SIGNBIT)
61 #define EXP(fp) (((fp) >> 23) & 0xFF)
62 #define MANT(fp) (((fp) & 0x7FFFFF) | HIDDEN)
63 #define PACK(s,e,m) ((s) | ((e) << 23) | (m))
65 /* the following deal with IEEE double-precision numbers */
66 #define EXCESSD 1022
67 #define HIDDEND (1 << 20)
68 #define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF)
69 #define SIGND(fp) ((fp.l.upper) & SIGNBIT)
70 #define MANTD(fp) (((((fp.l.upper) & 0xFFFFF) | HIDDEND) << 10) | \
71 (fp.l.lower >> 22))
72 #define HIDDEND_LL ((long long)1 << 52)
73 #define MANTD_LL(fp) ((fp.ll & (HIDDEND_LL-1)) | HIDDEND_LL)
74 #define PACKD_LL(s,e,m) (((long long)((s)+((e)<<20))<<32)|(m))
76 /* the following deal with x86 long double-precision numbers */
77 #define EXCESSLD 16382
78 #define EXPLD(fp) (fp.l.upper & 0x7fff)
79 #define SIGNLD(fp) ((fp.l.upper) & 0x8000)
81 /* only for x86 */
82 union ldouble_long {
83 long double ld;
84 struct {
85 unsigned long long lower;
86 unsigned short upper;
87 } l;
90 union double_long {
91 double d;
92 #if 1
93 struct {
94 unsigned int lower;
95 int upper;
96 } l;
97 #else
98 struct {
99 int upper;
100 unsigned int lower;
101 } l;
102 #endif
103 long long ll;
106 union float_long {
107 float f;
108 long l;
111 /* XXX: we don't support several builtin supports for now */
112 #if !defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_ARM)
114 /* XXX: use gcc/tcc intrinsic ? */
115 #if defined(TCC_TARGET_I386)
116 #define sub_ddmmss(sh, sl, ah, al, bh, bl) \
117 __asm__ ("subl %5,%1\n\tsbbl %3,%0" \
118 : "=r" ((USItype) (sh)), \
119 "=&r" ((USItype) (sl)) \
120 : "0" ((USItype) (ah)), \
121 "g" ((USItype) (bh)), \
122 "1" ((USItype) (al)), \
123 "g" ((USItype) (bl)))
124 #define umul_ppmm(w1, w0, u, v) \
125 __asm__ ("mull %3" \
126 : "=a" ((USItype) (w0)), \
127 "=d" ((USItype) (w1)) \
128 : "%0" ((USItype) (u)), \
129 "rm" ((USItype) (v)))
130 #define udiv_qrnnd(q, r, n1, n0, dv) \
131 __asm__ ("divl %4" \
132 : "=a" ((USItype) (q)), \
133 "=d" ((USItype) (r)) \
134 : "0" ((USItype) (n0)), \
135 "1" ((USItype) (n1)), \
136 "rm" ((USItype) (dv)))
137 #define count_leading_zeros(count, x) \
138 do { \
139 USItype __cbtmp; \
140 __asm__ ("bsrl %1,%0" \
141 : "=r" (__cbtmp) : "rm" ((USItype) (x))); \
142 (count) = __cbtmp ^ 31; \
143 } while (0)
144 #else
145 #error unsupported CPU type
146 #endif
148 /* most of this code is taken from libgcc2.c from gcc */
150 static UDWtype __udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp)
152 DWunion ww;
153 DWunion nn, dd;
154 DWunion rr;
155 UWtype d0, d1, n0, n1, n2;
156 UWtype q0, q1;
157 UWtype b, bm;
159 nn.ll = n;
160 dd.ll = d;
162 d0 = dd.s.low;
163 d1 = dd.s.high;
164 n0 = nn.s.low;
165 n1 = nn.s.high;
167 #if !defined(UDIV_NEEDS_NORMALIZATION)
168 if (d1 == 0)
170 if (d0 > n1)
172 /* 0q = nn / 0D */
174 udiv_qrnnd (q0, n0, n1, n0, d0);
175 q1 = 0;
177 /* Remainder in n0. */
179 else
181 /* qq = NN / 0d */
183 if (d0 == 0)
184 d0 = 1 / d0; /* Divide intentionally by zero. */
186 udiv_qrnnd (q1, n1, 0, n1, d0);
187 udiv_qrnnd (q0, n0, n1, n0, d0);
189 /* Remainder in n0. */
192 if (rp != 0)
194 rr.s.low = n0;
195 rr.s.high = 0;
196 *rp = rr.ll;
200 #else /* UDIV_NEEDS_NORMALIZATION */
202 if (d1 == 0)
204 if (d0 > n1)
206 /* 0q = nn / 0D */
208 count_leading_zeros (bm, d0);
210 if (bm != 0)
212 /* Normalize, i.e. make the most significant bit of the
213 denominator set. */
215 d0 = d0 << bm;
216 n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm));
217 n0 = n0 << bm;
220 udiv_qrnnd (q0, n0, n1, n0, d0);
221 q1 = 0;
223 /* Remainder in n0 >> bm. */
225 else
227 /* qq = NN / 0d */
229 if (d0 == 0)
230 d0 = 1 / d0; /* Divide intentionally by zero. */
232 count_leading_zeros (bm, d0);
234 if (bm == 0)
236 /* From (n1 >= d0) /\ (the most significant bit of d0 is set),
237 conclude (the most significant bit of n1 is set) /\ (the
238 leading quotient digit q1 = 1).
240 This special case is necessary, not an optimization.
241 (Shifts counts of W_TYPE_SIZE are undefined.) */
243 n1 -= d0;
244 q1 = 1;
246 else
248 /* Normalize. */
250 b = W_TYPE_SIZE - bm;
252 d0 = d0 << bm;
253 n2 = n1 >> b;
254 n1 = (n1 << bm) | (n0 >> b);
255 n0 = n0 << bm;
257 udiv_qrnnd (q1, n1, n2, n1, d0);
260 /* n1 != d0... */
262 udiv_qrnnd (q0, n0, n1, n0, d0);
264 /* Remainder in n0 >> bm. */
267 if (rp != 0)
269 rr.s.low = n0 >> bm;
270 rr.s.high = 0;
271 *rp = rr.ll;
274 #endif /* UDIV_NEEDS_NORMALIZATION */
276 else
278 if (d1 > n1)
280 /* 00 = nn / DD */
282 q0 = 0;
283 q1 = 0;
285 /* Remainder in n1n0. */
286 if (rp != 0)
288 rr.s.low = n0;
289 rr.s.high = n1;
290 *rp = rr.ll;
293 else
295 /* 0q = NN / dd */
297 count_leading_zeros (bm, d1);
298 if (bm == 0)
300 /* From (n1 >= d1) /\ (the most significant bit of d1 is set),
301 conclude (the most significant bit of n1 is set) /\ (the
302 quotient digit q0 = 0 or 1).
304 This special case is necessary, not an optimization. */
306 /* The condition on the next line takes advantage of that
307 n1 >= d1 (true due to program flow). */
308 if (n1 > d1 || n0 >= d0)
310 q0 = 1;
311 sub_ddmmss (n1, n0, n1, n0, d1, d0);
313 else
314 q0 = 0;
316 q1 = 0;
318 if (rp != 0)
320 rr.s.low = n0;
321 rr.s.high = n1;
322 *rp = rr.ll;
325 else
327 UWtype m1, m0;
328 /* Normalize. */
330 b = W_TYPE_SIZE - bm;
332 d1 = (d1 << bm) | (d0 >> b);
333 d0 = d0 << bm;
334 n2 = n1 >> b;
335 n1 = (n1 << bm) | (n0 >> b);
336 n0 = n0 << bm;
338 udiv_qrnnd (q0, n1, n2, n1, d1);
339 umul_ppmm (m1, m0, q0, d0);
341 if (m1 > n1 || (m1 == n1 && m0 > n0))
343 q0--;
344 sub_ddmmss (m1, m0, m1, m0, d1, d0);
347 q1 = 0;
349 /* Remainder in (n1n0 - m1m0) >> bm. */
350 if (rp != 0)
352 sub_ddmmss (n1, n0, n1, n0, m1, m0);
353 rr.s.low = (n1 << b) | (n0 >> bm);
354 rr.s.high = n1 >> bm;
355 *rp = rr.ll;
361 ww.s.low = q0;
362 ww.s.high = q1;
363 return ww.ll;
366 #define __negdi2(a) (-(a))
368 long long __divdi3(long long u, long long v)
370 int c = 0;
371 DWunion uu, vv;
372 DWtype w;
374 uu.ll = u;
375 vv.ll = v;
377 if (uu.s.high < 0) {
378 c = ~c;
379 uu.ll = __negdi2 (uu.ll);
381 if (vv.s.high < 0) {
382 c = ~c;
383 vv.ll = __negdi2 (vv.ll);
385 w = __udivmoddi4 (uu.ll, vv.ll, (UDWtype *) 0);
386 if (c)
387 w = __negdi2 (w);
388 return w;
391 long long __moddi3(long long u, long long v)
393 int c = 0;
394 DWunion uu, vv;
395 DWtype w;
397 uu.ll = u;
398 vv.ll = v;
400 if (uu.s.high < 0) {
401 c = ~c;
402 uu.ll = __negdi2 (uu.ll);
404 if (vv.s.high < 0)
405 vv.ll = __negdi2 (vv.ll);
407 __udivmoddi4 (uu.ll, vv.ll, (UDWtype *) &w);
408 if (c)
409 w = __negdi2 (w);
410 return w;
413 unsigned long long __udivdi3(unsigned long long u, unsigned long long v)
415 return __udivmoddi4 (u, v, (UDWtype *) 0);
418 unsigned long long __umoddi3(unsigned long long u, unsigned long long v)
420 UDWtype w;
422 __udivmoddi4 (u, v, &w);
423 return w;
426 /* XXX: fix tcc's code generator to do this instead */
427 long long __ashrdi3(long long a, int b)
429 #ifdef __TINYC__
430 DWunion u;
431 u.ll = a;
432 if (b >= 32) {
433 u.s.low = u.s.high >> (b - 32);
434 u.s.high = u.s.high >> 31;
435 } else if (b != 0) {
436 u.s.low = ((unsigned)u.s.low >> b) | (u.s.high << (32 - b));
437 u.s.high = u.s.high >> b;
439 return u.ll;
440 #else
441 return a >> b;
442 #endif
445 /* XXX: fix tcc's code generator to do this instead */
446 unsigned long long __lshrdi3(unsigned long long a, int b)
448 #ifdef __TINYC__
449 DWunion u;
450 u.ll = a;
451 if (b >= 32) {
452 u.s.low = (unsigned)u.s.high >> (b - 32);
453 u.s.high = 0;
454 } else if (b != 0) {
455 u.s.low = ((unsigned)u.s.low >> b) | (u.s.high << (32 - b));
456 u.s.high = (unsigned)u.s.high >> b;
458 return u.ll;
459 #else
460 return a >> b;
461 #endif
464 /* XXX: fix tcc's code generator to do this instead */
465 long long __ashldi3(long long a, int b)
467 #ifdef __TINYC__
468 DWunion u;
469 u.ll = a;
470 if (b >= 32) {
471 u.s.high = (unsigned)u.s.low << (b - 32);
472 u.s.low = 0;
473 } else if (b != 0) {
474 u.s.high = ((unsigned)u.s.high << b) | ((unsigned)u.s.low >> (32 - b));
475 u.s.low = (unsigned)u.s.low << b;
477 return u.ll;
478 #else
479 return a << b;
480 #endif
483 #endif /* !__x86_64__ */
485 /* XXX: fix tcc's code generator to do this instead */
486 float __floatundisf(unsigned long long a)
488 DWunion uu;
489 XFtype r;
491 uu.ll = a;
492 if (uu.s.high >= 0) {
493 return (float)uu.ll;
494 } else {
495 r = (XFtype)uu.ll;
496 r += 18446744073709551616.0;
497 return (float)r;
501 double __floatundidf(unsigned long long a)
503 DWunion uu;
504 XFtype r;
506 uu.ll = a;
507 if (uu.s.high >= 0) {
508 return (double)uu.ll;
509 } else {
510 r = (XFtype)uu.ll;
511 r += 18446744073709551616.0;
512 return (double)r;
516 long double __floatundixf(unsigned long long a)
518 DWunion uu;
519 XFtype r;
521 uu.ll = a;
522 if (uu.s.high >= 0) {
523 return (long double)uu.ll;
524 } else {
525 r = (XFtype)uu.ll;
526 r += 18446744073709551616.0;
527 return (long double)r;
531 unsigned long long __fixunssfdi (float a1)
533 register union float_long fl1;
534 register int exp;
535 register unsigned long l;
536 int s;
537 fl1.f = a1;
539 if (fl1.l == 0)
540 return 0;
542 exp = EXP (fl1.l) - EXCESS - 24;
544 l = MANT(fl1.l);
545 s = SIGN(fl1.l)? -1: 1;
546 if (exp >= 64)
547 return (unsigned long long)-1;
548 else if (exp >= 0)
549 return ((unsigned long long)l << exp)*s;
550 else if (exp >= -23)
551 return (l >> -exp)*s;
552 else
553 return 0;
556 unsigned long long __fixunsdfdi (double a1)
558 register union double_long dl1;
559 register int exp;
560 register unsigned long long l;
561 int s;
562 dl1.d = a1;
564 if (dl1.ll == 0)
565 return (0);
567 exp = EXPD (dl1) - EXCESSD - 53;
569 l = MANTD_LL(dl1);
570 s = SIGND(dl1)? -1: 1;
571 if (exp >= 64)
572 return (unsigned long long)-1;
573 else if (exp >= 0)
574 return (l << exp)*s;
575 else if (exp >= -52)
576 return (l >> -exp)*s;
577 else
578 return 0;
581 unsigned long long __fixunsxfdi (long double a1)
583 register union ldouble_long dl1;
584 register int exp;
585 register unsigned long long l;
586 int s;
587 dl1.ld = a1;
589 if (dl1.l.lower == 0 && dl1.l.upper == 0)
590 return (0);
592 exp = EXPLD (dl1) - EXCESSLD - 64;
593 s = SIGNLD(dl1)? -1: 1;
594 l = dl1.l.lower;
596 if (exp >= 64)
597 return (unsigned long long)-1;
598 else if (exp >= 0)
599 return ((unsigned long long)l << exp)*s;
600 else if (exp >= -64)
601 return (l >> -exp)*s;
602 else
603 return 0;
606 long long __fixsfdi (float a1)
608 long long ret; int s;
609 ret = __fixunssfdi((s = a1 >= 0) ? a1 : -a1);
610 return s ? ret : -ret;
613 long long __fixdfdi (double a1)
615 long long ret; int s;
616 ret = __fixunsdfdi((s = a1 >= 0) ? a1 : -a1);
617 return s ? ret : -ret;
620 long long __fixxfdi (long double a1)
622 long long ret; int s;
623 ret = __fixunsxfdi((s = a1 >= 0) ? a1 : -a1);
624 return s ? ret : -ret;
627 #if defined(TCC_TARGET_X86_64) && !defined(_WIN64)
629 #ifndef __TINYC__
630 #include <stdlib.h>
631 #include <stdio.h>
632 #include <string.h>
633 #else
634 /* Avoid including stdlib.h because it is not easily available when
635 cross compiling */
636 extern void *malloc(unsigned long long);
637 void *memset(void *s, int c, size_t n);
638 extern void free(void*);
639 extern void abort(void);
640 #endif
642 enum __va_arg_type {
643 __va_gen_reg, __va_float_reg, __va_stack
646 //This should be in sync with the declaration on our include/stdarg.h
647 /* GCC compatible definition of va_list. */
648 typedef struct {
649 unsigned int gp_offset;
650 unsigned int fp_offset;
651 union {
652 unsigned int overflow_offset;
653 char *overflow_arg_area;
655 char *reg_save_area;
656 } __va_list_struct;
658 #undef __va_start
659 #undef __va_arg
660 #undef __va_copy
661 #undef __va_end
663 void __va_start(__va_list_struct *ap, void *fp)
665 memset(ap, 0, sizeof(__va_list_struct));
666 *ap = *(__va_list_struct *)((char *)fp - 16);
667 ap->overflow_arg_area = (char *)fp + ap->overflow_offset;
668 ap->reg_save_area = (char *)fp - 176 - 16;
671 void *__va_arg(__va_list_struct *ap,
672 enum __va_arg_type arg_type,
673 int size, int align)
675 size = (size + 7) & ~7;
676 align = (align + 7) & ~7;
677 switch (arg_type) {
678 case __va_gen_reg:
679 if (ap->gp_offset < 48) {
680 ap->gp_offset += 8;
681 return ap->reg_save_area + ap->gp_offset - 8;
683 size = 8;
684 goto use_overflow_area;
686 case __va_float_reg:
687 if (ap->fp_offset < 128 + 48) {
688 ap->fp_offset += 16;
689 return ap->reg_save_area + ap->fp_offset - 16;
691 size = 8;
692 goto use_overflow_area;
694 case __va_stack:
695 use_overflow_area:
696 ap->overflow_arg_area += size;
697 ap->overflow_arg_area = (char*)((intptr_t)(ap->overflow_arg_area + align - 1) & -(intptr_t)align);
698 return ap->overflow_arg_area - size;
700 default:
701 #ifndef __TINYC__
702 fprintf(stderr, "unknown ABI type for __va_arg\n");
703 #endif
704 abort();
708 #endif /* __x86_64__ */
710 /* Flushing for tccrun */
711 #if defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_I386)
713 void __clear_cache(char *beginning, char *end)
717 #elif defined(TCC_TARGET_ARM)
719 #define _GNU_SOURCE
720 #include <unistd.h>
721 #include <sys/syscall.h>
722 #include <stdio.h>
724 void __clear_cache(char *beginning, char *end)
726 /* __ARM_NR_cacheflush is kernel private and should not be used in user space.
727 * However, there is no ARM asm parser in tcc so we use it for now */
728 #if 1
729 syscall(__ARM_NR_cacheflush, beginning, end, 0);
730 #else
731 __asm__ ("push {r7}\n\t"
732 "mov r7, #0xf0002\n\t"
733 "mov r2, #0\n\t"
734 "swi 0\n\t"
735 "pop {r7}\n\t"
736 "ret");
737 #endif
740 #else
741 #warning __clear_cache not defined for this architecture, avoid using tcc -run
742 #endif