753 lines
		
	
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			753 lines
		
	
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* TCC runtime library. 
 | |
|    Parts of this code are (c) 2002 Fabrice Bellard 
 | |
| 
 | |
|    Copyright (C) 1987, 1988, 1992, 1994, 1995 Free Software Foundation, Inc.
 | |
| 
 | |
| This file is free software; you can redistribute it and/or modify it
 | |
| under the terms of the GNU General Public License as published by the
 | |
| Free Software Foundation; either version 2, or (at your option) any
 | |
| later version.
 | |
| 
 | |
| In addition to the permissions in the GNU General Public License, the
 | |
| Free Software Foundation gives you unlimited permission to link the
 | |
| compiled version of this file into combinations with other programs,
 | |
| and to distribute those combinations without any restriction coming
 | |
| from the use of this file.  (The General Public License restrictions
 | |
| do apply in other respects; for example, they cover modification of
 | |
| the file, and distribution when not linked into a combine
 | |
| executable.)
 | |
| 
 | |
| This file is distributed in the hope that it will be useful, but
 | |
| WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
| General Public License for more details.
 | |
| 
 | |
| You should have received a copy of the GNU General Public License
 | |
| along with this program; see the file COPYING.  If not, write to
 | |
| the Free Software Foundation, 59 Temple Place - Suite 330,
 | |
| Boston, MA 02111-1307, USA.  
 | |
| */
 | |
| 
 | |
| #include <stdint.h>
 | |
| 
 | |
| #define W_TYPE_SIZE   32
 | |
| #define BITS_PER_UNIT 8
 | |
| 
 | |
| typedef int Wtype;
 | |
| typedef unsigned int UWtype;
 | |
| typedef unsigned int USItype;
 | |
| typedef long long DWtype;
 | |
| typedef unsigned long long UDWtype;
 | |
| 
 | |
| struct DWstruct {
 | |
|     Wtype low, high;
 | |
| };
 | |
| 
 | |
| typedef union
 | |
| {
 | |
|   struct DWstruct s;
 | |
|   DWtype ll;
 | |
| } DWunion;
 | |
| 
 | |
| typedef long double XFtype;
 | |
| #define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
 | |
| #define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
 | |
| 
 | |
| /* the following deal with IEEE single-precision numbers */
 | |
| #define EXCESS		126
 | |
| #define SIGNBIT		0x80000000
 | |
| #define HIDDEN		(1 << 23)
 | |
| #define SIGN(fp)	((fp) & SIGNBIT)
 | |
| #define EXP(fp)		(((fp) >> 23) & 0xFF)
 | |
| #define MANT(fp)	(((fp) & 0x7FFFFF) | HIDDEN)
 | |
| #define PACK(s,e,m)	((s) | ((e) << 23) | (m))
 | |
| 
 | |
| /* the following deal with IEEE double-precision numbers */
 | |
| #define EXCESSD		1022
 | |
| #define HIDDEND		(1 << 20)
 | |
| #define EXPD(fp)	(((fp.l.upper) >> 20) & 0x7FF)
 | |
| #define SIGND(fp)	((fp.l.upper) & SIGNBIT)
 | |
| #define MANTD(fp)	(((((fp.l.upper) & 0xFFFFF) | HIDDEND) << 10) | \
 | |
| 				(fp.l.lower >> 22))
 | |
| #define HIDDEND_LL	((long long)1 << 52)
 | |
| #define MANTD_LL(fp)	((fp.ll & (HIDDEND_LL-1)) | HIDDEND_LL)
 | |
| #define PACKD_LL(s,e,m)	(((long long)((s)+((e)<<20))<<32)|(m))
 | |
| 
 | |
| /* the following deal with x86 long double-precision numbers */
 | |
| #define EXCESSLD	16382
 | |
| #define EXPLD(fp)	(fp.l.upper & 0x7fff)
 | |
| #define SIGNLD(fp)	((fp.l.upper) & 0x8000)
 | |
| 
 | |
| /* only for x86 */
 | |
| union ldouble_long {
 | |
|     long double ld;
 | |
|     struct {
 | |
|         unsigned long long lower;
 | |
|         unsigned short upper;
 | |
|     } l;
 | |
| };
 | |
| 
 | |
| union double_long {
 | |
|     double d;
 | |
| #if 1
 | |
|     struct {
 | |
|         unsigned int lower;
 | |
|         int upper;
 | |
|     } l;
 | |
| #else
 | |
|     struct {
 | |
|         int upper;
 | |
|         unsigned int lower;
 | |
|     } l;
 | |
| #endif
 | |
|     long long ll;
 | |
| };
 | |
| 
 | |
| union float_long {
 | |
|     float f;
 | |
|     unsigned int l;
 | |
| };
 | |
| 
 | |
| /* XXX: we don't support several builtin supports for now */
 | |
| #if !defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_ARM)
 | |
| 
 | |
| /* XXX: use gcc/tcc intrinsic ? */
 | |
| #if defined(TCC_TARGET_I386)
 | |
| #define sub_ddmmss(sh, sl, ah, al, bh, bl) \
 | |
|   __asm__ ("subl %5,%1\n\tsbbl %3,%0"					\
 | |
| 	   : "=r" ((USItype) (sh)),					\
 | |
| 	     "=&r" ((USItype) (sl))					\
 | |
| 	   : "0" ((USItype) (ah)),					\
 | |
| 	     "g" ((USItype) (bh)),					\
 | |
| 	     "1" ((USItype) (al)),					\
 | |
| 	     "g" ((USItype) (bl)))
 | |
| #define umul_ppmm(w1, w0, u, v) \
 | |
|   __asm__ ("mull %3"							\
 | |
| 	   : "=a" ((USItype) (w0)),					\
 | |
| 	     "=d" ((USItype) (w1))					\
 | |
| 	   : "%0" ((USItype) (u)),					\
 | |
| 	     "rm" ((USItype) (v)))
 | |
| #define udiv_qrnnd(q, r, n1, n0, dv) \
 | |
|   __asm__ ("divl %4"							\
 | |
| 	   : "=a" ((USItype) (q)),					\
 | |
| 	     "=d" ((USItype) (r))					\
 | |
| 	   : "0" ((USItype) (n0)),					\
 | |
| 	     "1" ((USItype) (n1)),					\
 | |
| 	     "rm" ((USItype) (dv)))
 | |
| #define count_leading_zeros(count, x) \
 | |
|   do {									\
 | |
|     USItype __cbtmp;							\
 | |
|     __asm__ ("bsrl %1,%0"						\
 | |
| 	     : "=r" (__cbtmp) : "rm" ((USItype) (x)));			\
 | |
|     (count) = __cbtmp ^ 31;						\
 | |
|   } while (0)
 | |
| #else
 | |
| #error unsupported CPU type
 | |
| #endif
 | |
| 
 | |
| /* most of this code is taken from libgcc2.c from gcc */
 | |
| 
 | |
| static UDWtype __udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp)
 | |
| {
 | |
|   DWunion ww;
 | |
|   DWunion nn, dd;
 | |
|   DWunion rr;
 | |
|   UWtype d0, d1, n0, n1, n2;
 | |
|   UWtype q0, q1;
 | |
|   UWtype b, bm;
 | |
| 
 | |
|   nn.ll = n;
 | |
|   dd.ll = d;
 | |
| 
 | |
|   d0 = dd.s.low;
 | |
|   d1 = dd.s.high;
 | |
|   n0 = nn.s.low;
 | |
|   n1 = nn.s.high;
 | |
| 
 | |
| #if !defined(UDIV_NEEDS_NORMALIZATION)
 | |
|   if (d1 == 0)
 | |
|     {
 | |
|       if (d0 > n1)
 | |
| 	{
 | |
| 	  /* 0q = nn / 0D */
 | |
| 
 | |
| 	  udiv_qrnnd (q0, n0, n1, n0, d0);
 | |
| 	  q1 = 0;
 | |
| 
 | |
| 	  /* Remainder in n0.  */
 | |
| 	}
 | |
|       else
 | |
| 	{
 | |
| 	  /* qq = NN / 0d */
 | |
| 
 | |
| 	  if (d0 == 0)
 | |
| 	    d0 = 1 / d0;	/* Divide intentionally by zero.  */
 | |
| 
 | |
| 	  udiv_qrnnd (q1, n1, 0, n1, d0);
 | |
| 	  udiv_qrnnd (q0, n0, n1, n0, d0);
 | |
| 
 | |
| 	  /* Remainder in n0.  */
 | |
| 	}
 | |
| 
 | |
|       if (rp != 0)
 | |
| 	{
 | |
| 	  rr.s.low = n0;
 | |
| 	  rr.s.high = 0;
 | |
| 	  *rp = rr.ll;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
| #else /* UDIV_NEEDS_NORMALIZATION */
 | |
| 
 | |
|   if (d1 == 0)
 | |
|     {
 | |
|       if (d0 > n1)
 | |
| 	{
 | |
| 	  /* 0q = nn / 0D */
 | |
| 
 | |
| 	  count_leading_zeros (bm, d0);
 | |
| 
 | |
| 	  if (bm != 0)
 | |
| 	    {
 | |
| 	      /* Normalize, i.e. make the most significant bit of the
 | |
| 		 denominator set.  */
 | |
| 
 | |
| 	      d0 = d0 << bm;
 | |
| 	      n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm));
 | |
| 	      n0 = n0 << bm;
 | |
| 	    }
 | |
| 
 | |
| 	  udiv_qrnnd (q0, n0, n1, n0, d0);
 | |
| 	  q1 = 0;
 | |
| 
 | |
| 	  /* Remainder in n0 >> bm.  */
 | |
| 	}
 | |
|       else
 | |
| 	{
 | |
| 	  /* qq = NN / 0d */
 | |
| 
 | |
| 	  if (d0 == 0)
 | |
| 	    d0 = 1 / d0;	/* Divide intentionally by zero.  */
 | |
| 
 | |
| 	  count_leading_zeros (bm, d0);
 | |
| 
 | |
| 	  if (bm == 0)
 | |
| 	    {
 | |
| 	      /* From (n1 >= d0) /\ (the most significant bit of d0 is set),
 | |
| 		 conclude (the most significant bit of n1 is set) /\ (the
 | |
| 		 leading quotient digit q1 = 1).
 | |
| 
 | |
| 		 This special case is necessary, not an optimization.
 | |
| 		 (Shifts counts of W_TYPE_SIZE are undefined.)  */
 | |
| 
 | |
| 	      n1 -= d0;
 | |
| 	      q1 = 1;
 | |
| 	    }
 | |
| 	  else
 | |
| 	    {
 | |
| 	      /* Normalize.  */
 | |
| 
 | |
| 	      b = W_TYPE_SIZE - bm;
 | |
| 
 | |
| 	      d0 = d0 << bm;
 | |
| 	      n2 = n1 >> b;
 | |
| 	      n1 = (n1 << bm) | (n0 >> b);
 | |
| 	      n0 = n0 << bm;
 | |
| 
 | |
| 	      udiv_qrnnd (q1, n1, n2, n1, d0);
 | |
| 	    }
 | |
| 
 | |
| 	  /* n1 != d0...  */
 | |
| 
 | |
| 	  udiv_qrnnd (q0, n0, n1, n0, d0);
 | |
| 
 | |
| 	  /* Remainder in n0 >> bm.  */
 | |
| 	}
 | |
| 
 | |
|       if (rp != 0)
 | |
| 	{
 | |
| 	  rr.s.low = n0 >> bm;
 | |
| 	  rr.s.high = 0;
 | |
| 	  *rp = rr.ll;
 | |
| 	}
 | |
|     }
 | |
| #endif /* UDIV_NEEDS_NORMALIZATION */
 | |
| 
 | |
|   else
 | |
|     {
 | |
|       if (d1 > n1)
 | |
| 	{
 | |
| 	  /* 00 = nn / DD */
 | |
| 
 | |
| 	  q0 = 0;
 | |
| 	  q1 = 0;
 | |
| 
 | |
| 	  /* Remainder in n1n0.  */
 | |
| 	  if (rp != 0)
 | |
| 	    {
 | |
| 	      rr.s.low = n0;
 | |
| 	      rr.s.high = n1;
 | |
| 	      *rp = rr.ll;
 | |
| 	    }
 | |
| 	}
 | |
|       else
 | |
| 	{
 | |
| 	  /* 0q = NN / dd */
 | |
| 
 | |
| 	  count_leading_zeros (bm, d1);
 | |
| 	  if (bm == 0)
 | |
| 	    {
 | |
| 	      /* From (n1 >= d1) /\ (the most significant bit of d1 is set),
 | |
| 		 conclude (the most significant bit of n1 is set) /\ (the
 | |
| 		 quotient digit q0 = 0 or 1).
 | |
| 
 | |
| 		 This special case is necessary, not an optimization.  */
 | |
| 
 | |
| 	      /* The condition on the next line takes advantage of that
 | |
| 		 n1 >= d1 (true due to program flow).  */
 | |
| 	      if (n1 > d1 || n0 >= d0)
 | |
| 		{
 | |
| 		  q0 = 1;
 | |
| 		  sub_ddmmss (n1, n0, n1, n0, d1, d0);
 | |
| 		}
 | |
| 	      else
 | |
| 		q0 = 0;
 | |
| 
 | |
| 	      q1 = 0;
 | |
| 
 | |
| 	      if (rp != 0)
 | |
| 		{
 | |
| 		  rr.s.low = n0;
 | |
| 		  rr.s.high = n1;
 | |
| 		  *rp = rr.ll;
 | |
| 		}
 | |
| 	    }
 | |
| 	  else
 | |
| 	    {
 | |
| 	      UWtype m1, m0;
 | |
| 	      /* Normalize.  */
 | |
| 
 | |
| 	      b = W_TYPE_SIZE - bm;
 | |
| 
 | |
| 	      d1 = (d1 << bm) | (d0 >> b);
 | |
| 	      d0 = d0 << bm;
 | |
| 	      n2 = n1 >> b;
 | |
| 	      n1 = (n1 << bm) | (n0 >> b);
 | |
| 	      n0 = n0 << bm;
 | |
| 
 | |
| 	      udiv_qrnnd (q0, n1, n2, n1, d1);
 | |
| 	      umul_ppmm (m1, m0, q0, d0);
 | |
| 
 | |
| 	      if (m1 > n1 || (m1 == n1 && m0 > n0))
 | |
| 		{
 | |
| 		  q0--;
 | |
| 		  sub_ddmmss (m1, m0, m1, m0, d1, d0);
 | |
| 		}
 | |
| 
 | |
| 	      q1 = 0;
 | |
| 
 | |
| 	      /* Remainder in (n1n0 - m1m0) >> bm.  */
 | |
| 	      if (rp != 0)
 | |
| 		{
 | |
| 		  sub_ddmmss (n1, n0, n1, n0, m1, m0);
 | |
| 		  rr.s.low = (n1 << b) | (n0 >> bm);
 | |
| 		  rr.s.high = n1 >> bm;
 | |
| 		  *rp = rr.ll;
 | |
| 		}
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   ww.s.low = q0;
 | |
|   ww.s.high = q1;
 | |
|   return ww.ll;
 | |
| }
 | |
| 
 | |
| #define __negdi2(a) (-(a))
 | |
| 
 | |
| long long __divdi3(long long u, long long v)
 | |
| {
 | |
|     int c = 0;
 | |
|     DWunion uu, vv;
 | |
|     DWtype w;
 | |
|     
 | |
|     uu.ll = u;
 | |
|     vv.ll = v;
 | |
|     
 | |
|     if (uu.s.high < 0) {
 | |
|         c = ~c;
 | |
|         uu.ll = __negdi2 (uu.ll);
 | |
|     }
 | |
|     if (vv.s.high < 0) {
 | |
|         c = ~c;
 | |
|         vv.ll = __negdi2 (vv.ll);
 | |
|     }
 | |
|     w = __udivmoddi4 (uu.ll, vv.ll, (UDWtype *) 0);
 | |
|     if (c)
 | |
|         w = __negdi2 (w);
 | |
|     return w;
 | |
| }
 | |
| 
 | |
| long long __moddi3(long long u, long long v)
 | |
| {
 | |
|     int c = 0;
 | |
|     DWunion uu, vv;
 | |
|     DWtype w;
 | |
|     
 | |
|     uu.ll = u;
 | |
|     vv.ll = v;
 | |
|     
 | |
|     if (uu.s.high < 0) {
 | |
|         c = ~c;
 | |
|         uu.ll = __negdi2 (uu.ll);
 | |
|     }
 | |
|     if (vv.s.high < 0)
 | |
|         vv.ll = __negdi2 (vv.ll);
 | |
|     
 | |
|     __udivmoddi4 (uu.ll, vv.ll, (UDWtype *) &w);
 | |
|     if (c)
 | |
|         w = __negdi2 (w);
 | |
|     return w;
 | |
| }
 | |
| 
 | |
| unsigned long long __udivdi3(unsigned long long u, unsigned long long v)
 | |
| {
 | |
|     return __udivmoddi4 (u, v, (UDWtype *) 0);
 | |
| }
 | |
| 
 | |
| unsigned long long __umoddi3(unsigned long long u, unsigned long long v)
 | |
| {
 | |
|     UDWtype w;
 | |
|     
 | |
|     __udivmoddi4 (u, v, &w);
 | |
|     return w;
 | |
| }
 | |
| 
 | |
| /* XXX: fix tcc's code generator to do this instead */
 | |
| long long __ashrdi3(long long a, int b)
 | |
| {
 | |
| #ifdef __TINYC__
 | |
|     DWunion u;
 | |
|     u.ll = a;
 | |
|     if (b >= 32) {
 | |
|         u.s.low = u.s.high >> (b - 32);
 | |
|         u.s.high = u.s.high >> 31;
 | |
|     } else if (b != 0) {
 | |
|         u.s.low = ((unsigned)u.s.low >> b) | (u.s.high << (32 - b));
 | |
|         u.s.high = u.s.high >> b;
 | |
|     }
 | |
|     return u.ll;
 | |
| #else
 | |
|     return a >> b;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /* XXX: fix tcc's code generator to do this instead */
 | |
| unsigned long long __lshrdi3(unsigned long long a, int b)
 | |
| {
 | |
| #ifdef __TINYC__
 | |
|     DWunion u;
 | |
|     u.ll = a;
 | |
|     if (b >= 32) {
 | |
|         u.s.low = (unsigned)u.s.high >> (b - 32);
 | |
|         u.s.high = 0;
 | |
|     } else if (b != 0) {
 | |
|         u.s.low = ((unsigned)u.s.low >> b) | (u.s.high << (32 - b));
 | |
|         u.s.high = (unsigned)u.s.high >> b;
 | |
|     }
 | |
|     return u.ll;
 | |
| #else
 | |
|     return a >> b;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /* XXX: fix tcc's code generator to do this instead */
 | |
| long long __ashldi3(long long a, int b)
 | |
| {
 | |
| #ifdef __TINYC__
 | |
|     DWunion u;
 | |
|     u.ll = a;
 | |
|     if (b >= 32) {
 | |
|         u.s.high = (unsigned)u.s.low << (b - 32);
 | |
|         u.s.low = 0;
 | |
|     } else if (b != 0) {
 | |
|         u.s.high = ((unsigned)u.s.high << b) | ((unsigned)u.s.low >> (32 - b));
 | |
|         u.s.low = (unsigned)u.s.low << b;
 | |
|     }
 | |
|     return u.ll;
 | |
| #else
 | |
|     return a << b;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| #ifndef COMMIT_4ad186c5ef61_IS_FIXED
 | |
| long long __tcc_cvt_ftol(long double x)
 | |
| {
 | |
|     unsigned c0, c1;
 | |
|     long long ret;
 | |
|     __asm__ __volatile__ ("fnstcw %0" : "=m" (c0));
 | |
|     c1 = c0 | 0x0C00;
 | |
|     __asm__ __volatile__ ("fldcw %0" : : "m" (c1));
 | |
|     __asm__ __volatile__ ("fistpll %0"  : "=m" (ret));
 | |
|     __asm__ __volatile__ ("fldcw %0" : : "m" (c0));
 | |
|     return ret;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #endif /* !__x86_64__ */
 | |
| 
 | |
| /* XXX: fix tcc's code generator to do this instead */
 | |
| float __floatundisf(unsigned long long a)
 | |
| {
 | |
|     DWunion uu; 
 | |
|     XFtype r;
 | |
| 
 | |
|     uu.ll = a;
 | |
|     if (uu.s.high >= 0) {
 | |
|         return (float)uu.ll;
 | |
|     } else {
 | |
|         r = (XFtype)uu.ll;
 | |
|         r += 18446744073709551616.0;
 | |
|         return (float)r;
 | |
|     }
 | |
| }
 | |
| 
 | |
| double __floatundidf(unsigned long long a)
 | |
| {
 | |
|     DWunion uu; 
 | |
|     XFtype r;
 | |
| 
 | |
|     uu.ll = a;
 | |
|     if (uu.s.high >= 0) {
 | |
|         return (double)uu.ll;
 | |
|     } else {
 | |
|         r = (XFtype)uu.ll;
 | |
|         r += 18446744073709551616.0;
 | |
|         return (double)r;
 | |
|     }
 | |
| }
 | |
| 
 | |
| long double __floatundixf(unsigned long long a)
 | |
| {
 | |
|     DWunion uu; 
 | |
|     XFtype r;
 | |
| 
 | |
|     uu.ll = a;
 | |
|     if (uu.s.high >= 0) {
 | |
|         return (long double)uu.ll;
 | |
|     } else {
 | |
|         r = (XFtype)uu.ll;
 | |
|         r += 18446744073709551616.0;
 | |
|         return (long double)r;
 | |
|     }
 | |
| }
 | |
| 
 | |
| unsigned long long __fixunssfdi (float a1)
 | |
| {
 | |
|     register union float_long fl1;
 | |
|     register int exp;
 | |
|     register unsigned long l;
 | |
| 
 | |
|     fl1.f = a1;
 | |
| 
 | |
|     if (fl1.l == 0)
 | |
| 	return (0);
 | |
| 
 | |
|     exp = EXP (fl1.l) - EXCESS - 24;
 | |
| 
 | |
|     l = MANT(fl1.l);
 | |
|     if (exp >= 41)
 | |
| 	return (unsigned long long)-1;
 | |
|     else if (exp >= 0)
 | |
|         return (unsigned long long)l << exp;
 | |
|     else if (exp >= -23)
 | |
|         return l >> -exp;
 | |
|     else
 | |
|         return 0;
 | |
| }
 | |
| 
 | |
| unsigned long long __fixunsdfdi (double a1)
 | |
| {
 | |
|     register union double_long dl1;
 | |
|     register int exp;
 | |
|     register unsigned long long l;
 | |
| 
 | |
|     dl1.d = a1;
 | |
| 
 | |
|     if (dl1.ll == 0)
 | |
| 	return (0);
 | |
| 
 | |
|     exp = EXPD (dl1) - EXCESSD - 53;
 | |
| 
 | |
|     l = MANTD_LL(dl1);
 | |
| 
 | |
|     if (exp >= 12)
 | |
| 	return (unsigned long long)-1;
 | |
|     else if (exp >= 0)
 | |
|         return l << exp;
 | |
|     else if (exp >= -52)
 | |
|         return l >> -exp;
 | |
|     else
 | |
|         return 0;
 | |
| }
 | |
| 
 | |
| unsigned long long __fixunsxfdi (long double a1)
 | |
| {
 | |
|     register union ldouble_long dl1;
 | |
|     register int exp;
 | |
|     register unsigned long long l;
 | |
| 
 | |
|     dl1.ld = a1;
 | |
| 
 | |
|     if (dl1.l.lower == 0 && dl1.l.upper == 0)
 | |
| 	return (0);
 | |
| 
 | |
|     exp = EXPLD (dl1) - EXCESSLD - 64;
 | |
| 
 | |
|     l = dl1.l.lower;
 | |
| 
 | |
|     if (exp > 0)
 | |
| 	return (unsigned long long)-1;
 | |
|     else if (exp >= -63) 
 | |
|         return l >> -exp;
 | |
|     else
 | |
|         return 0;
 | |
| }
 | |
| 
 | |
| long long __fixsfdi (float a1)
 | |
| {
 | |
|     long long ret; int s;
 | |
|     ret = __fixunssfdi((s = a1 >= 0) ? a1 : -a1);
 | |
|     return s ? ret : -ret;
 | |
| }
 | |
| 
 | |
| long long __fixdfdi (double a1)
 | |
| {
 | |
|     long long ret; int s;
 | |
|     ret = __fixunsdfdi((s = a1 >= 0) ? a1 : -a1);
 | |
|     return s ? ret : -ret;
 | |
| }
 | |
| 
 | |
| long long __fixxfdi (long double a1)
 | |
| {
 | |
|     long long ret; int s;
 | |
|     ret = __fixunsxfdi((s = a1 >= 0) ? a1 : -a1);
 | |
|     return s ? ret : -ret;
 | |
| }
 | |
| 
 | |
| #if defined(TCC_TARGET_X86_64) && !defined(_WIN64)
 | |
| 
 | |
| #ifndef __TINYC__
 | |
| #include <stdlib.h>
 | |
| #include <stdio.h>
 | |
| #include <string.h>
 | |
| #else
 | |
| /* Avoid including stdlib.h because it is not easily available when
 | |
|    cross compiling */
 | |
| #include <stddef.h> /* size_t definition is needed for a x86_64-tcc to parse memset() */
 | |
| extern void *malloc(unsigned long long);
 | |
| extern void *memset(void *s, int c, size_t n);
 | |
| extern void free(void*);
 | |
| extern void abort(void);
 | |
| #endif
 | |
| 
 | |
| enum __va_arg_type {
 | |
|     __va_gen_reg, __va_float_reg, __va_stack
 | |
| };
 | |
| 
 | |
| //This should be in sync with the declaration on our include/stdarg.h
 | |
| /* GCC compatible definition of va_list. */
 | |
| typedef struct {
 | |
|     unsigned int gp_offset;
 | |
|     unsigned int fp_offset;
 | |
|     union {
 | |
|         unsigned int overflow_offset;
 | |
|         char *overflow_arg_area;
 | |
|     };
 | |
|     char *reg_save_area;
 | |
| } __va_list_struct;
 | |
| 
 | |
| #undef __va_start
 | |
| #undef __va_arg
 | |
| #undef __va_copy
 | |
| #undef __va_end
 | |
| 
 | |
| void __va_start(__va_list_struct *ap, void *fp)
 | |
| {
 | |
|     memset(ap, 0, sizeof(__va_list_struct));
 | |
|     *ap = *(__va_list_struct *)((char *)fp - 16);
 | |
|     ap->overflow_arg_area = (char *)fp + ap->overflow_offset;
 | |
|     ap->reg_save_area = (char *)fp - 176 - 16;
 | |
| }
 | |
| 
 | |
| void *__va_arg(__va_list_struct *ap,
 | |
|                enum __va_arg_type arg_type,
 | |
|                int size, int align)
 | |
| {
 | |
|     size = (size + 7) & ~7;
 | |
|     align = (align + 7) & ~7;
 | |
|     switch (arg_type) {
 | |
|     case __va_gen_reg:
 | |
|         if (ap->gp_offset + size <= 48) {
 | |
|             ap->gp_offset += size;
 | |
|             return ap->reg_save_area + ap->gp_offset - size;
 | |
|         }
 | |
|         goto use_overflow_area;
 | |
| 
 | |
|     case __va_float_reg:
 | |
|         if (ap->fp_offset < 128 + 48) {
 | |
|             ap->fp_offset += 16;
 | |
|             return ap->reg_save_area + ap->fp_offset - 16;
 | |
|         }
 | |
|         size = 8;
 | |
|         goto use_overflow_area;
 | |
| 
 | |
|     case __va_stack:
 | |
|     use_overflow_area:
 | |
|         ap->overflow_arg_area += size;
 | |
|         ap->overflow_arg_area = (char*)((intptr_t)(ap->overflow_arg_area + align - 1) & -(intptr_t)align);
 | |
|         return ap->overflow_arg_area - size;
 | |
| 
 | |
|     default:
 | |
| #ifndef __TINYC__
 | |
|         fprintf(stderr, "unknown ABI type for __va_arg\n");
 | |
| #endif
 | |
|         abort();
 | |
|     }
 | |
| }
 | |
| 
 | |
| #endif /* __x86_64__ */
 | |
| 
 | |
| /* Flushing for tccrun */
 | |
| #if defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_I386)
 | |
| 
 | |
| void __clear_cache(void *beginning, void *end)
 | |
| {
 | |
| }
 | |
| 
 | |
| #elif defined(TCC_TARGET_ARM)
 | |
| 
 | |
| #define _GNU_SOURCE
 | |
| #include <unistd.h>
 | |
| #include <sys/syscall.h>
 | |
| #include <stdio.h>
 | |
| 
 | |
| void __clear_cache(void *beginning, void *end)
 | |
| {
 | |
| /* __ARM_NR_cacheflush is kernel private and should not be used in user space.
 | |
|  * However, there is no ARM asm parser in tcc so we use it for now */
 | |
| #if 1
 | |
|     syscall(__ARM_NR_cacheflush, beginning, end, 0);
 | |
| #else
 | |
|     __asm__ ("push {r7}\n\t"
 | |
|              "mov r7, #0xf0002\n\t"
 | |
|              "mov r2, #0\n\t"
 | |
|              "swi 0\n\t"
 | |
|              "pop {r7}\n\t"
 | |
|              "ret");
 | |
| #endif
 | |
| }
 | |
| 
 | |
| #else
 | |
| #warning __clear_cache not defined for this architecture, avoid using tcc -run
 | |
| #endif
 |