/* $Id: level0.h,v 1.3 2000/11/03 21:00:25 karim Exp $ Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP 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. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, see . */ /* This file defines some "level 0" kernel functions for Intel x386 */ /* It is intended for use with an external "asm" definition */ #ifndef ASMINLINE #define LOCAL_OVERFLOW #define SAVE_OVERFLOW #define LOCAL_HIREMAINDER #define SAVE_HIREMAINDER BEGINEXTERN extern ulong overflow; extern ulong hiremainder; extern long addll(ulong x, ulong y); extern long addllx(ulong x, ulong y); extern long subll(ulong x, ulong y); extern long subllx(ulong x, ulong y); extern long shiftl(ulong x, ulong y); extern long shiftlr(ulong x, ulong y); extern long mulll(ulong x, ulong y); extern long addmul(ulong x, ulong y); extern long divll(ulong x, ulong y); extern int bfffo(ulong x); ENDEXTERN #else /* ASMINLINE */ /* $Id: level0.h,v 1.3 2000/11/03 21:00:25 karim Exp $ */ /* Written by Bruno Haible, 1996-1998. */ /* This file can assume the GNU C extensions. (It is included only if __GNUC__ is defined.) */ /* Use local variables whenever possible. */ #define LOCAL_HIREMAINDER register ulong hiremainder #define SAVE_OVERFLOW \ { ulong _temp_overf = overflow; \ extern ulong overflow; \ overflow = _temp_overf; } #define LOCAL_OVERFLOW ulong overflow #define SAVE_HIREMAINDER \ { ulong _temp_hirem = hiremainder; \ extern ulong hiremainder; \ hiremainder = _temp_hirem; } /* The global variable `hiremainder' is still necessary for the 2nd value of divss, divis, divsi. The global variable `overflow' is not necessary. */ extern ulong overflow; extern ulong hiremainder; /* Different assemblers have different syntax for the "shldl" and "shrdl" instructions. */ #if defined(__EMX__) || defined(__DJGCC__) || defined(__GO32__) || (defined(linux) && !defined(__ELF__)) || defined(__386BSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(NeXT) || defined(__CYGWIN32__) || defined(__MINGW32__) || defined(COHERENT) # define SHCL "%%cl," #else # define SHCL #endif #define addll(a,b) \ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("addl %3,%0 ; adcl %1,%1" \ : "=r" (__value), "=r" (overflow) \ : "0" (__arg1), "g" (__arg2), "1" ((ulong)0) \ : "cc"); \ __value; \ }) #define addllx(a,b) \ ({ ulong __value, __arg1 = (a), __arg2 = (b), __temp; \ __asm__ ("subl %5,%2 ; adcl %4,%0 ; adcl %1,%1" \ : "=r" (__value), "=r" (overflow), "=r" (__temp) \ : "0" (__arg1), "g" (__arg2), "g" (overflow), "1" ((ulong)0), "2" ((ulong)0) \ : "cc"); \ __value; \ }) #define subll(a,b) \ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("subl %3,%0 ; adcl %1,%1" \ : "=r" (__value), "=r" (overflow) \ : "0" (__arg1), "g" (__arg2), "1" ((ulong)0) \ : "cc"); \ __value; \ }) #define subllx(a,b) \ ({ ulong __value, __arg1 = (a), __arg2 = (b), __temp; \ __asm__ ("subl %5,%2 ; sbbl %4,%0 ; adcl %1,%1" \ : "=r" (__value), "=r" (overflow), "=r" (__temp) \ : "0" (__arg1), "g" (__arg2), "g" (overflow), "1" ((ulong)0), "2" ((ulong)0) \ : "cc"); \ __value; \ }) #if 1 #define shiftl(a,c) \ ({ ulong __valuelo = (a), __count = (c), __valuehi; \ __asm__ ("shldl "SHCL"%2,%0" /* shift %0 left by %cl bits, feeding in %2 from the right */ \ : "=q" (__valuehi) \ : "0" ((ulong)0), "q" (__valuelo), "c" /* %ecx */ (__count)); \ hiremainder = __valuehi; \ __valuelo << __count; \ }) #define shiftlr(a,c) \ ({ ulong __valuehi = (a), __count = (c), __valuelo; \ __asm__ ("shrdl "SHCL"%2,%0" /* shift %0 right by %cl bits, feeding in %2 from the left */ \ : "=q" (__valuelo) \ : "0" ((ulong)0), "q" (__valuehi), "c" /* %ecx */ (__count)); \ hiremainder = __valuelo; \ __valuehi >> __count; \ }) #else #define shiftl(a,c) \ ({ ulong __valuelo = (a), __count = (c), __valuehi; \ __asm__ ("shldl "SHCL"%2,%0" /* shift %0 left by %cl bits, feeding in %2 from the right */ \ : "=d" (hiremainder) \ : "0" ((ulong)0), "q" (__valuelo), "c" /* %ecx */ (__count)); \ __valuelo << __count; \ }) #define shiftlr(a,c) \ ({ ulong __valuehi = (a), __count = (c), __valuelo; \ __asm__ ("shrdl "SHCL"%2,%0" /* shift %0 right by %cl bits, feeding in %2 from the left */ \ : "=d" (hiremainder) \ : "0" ((ulong)0), "q" (__valuehi), "c" /* %ecx */ (__count)); \ __valuehi >> __count; \ }) #endif #define mulll(a,b) \ ({ ulong __valuelo, __arg1 = (a), __arg2 = (b); \ __asm__ ("mull %3" \ : "=a" /* %eax */ (__valuelo), "=d" /* %edx */ (hiremainder) \ : "0" (__arg1), "rm" (__arg2)); \ __valuelo; \ }) #define addmul(a,b) \ ({ ulong __valuelo, __arg1 = (a), __arg2 = (b), __temp; \ __asm__ ("mull %4 ; addl %5,%0 ; adcl %6,%1" \ : "=a" /* %eax */ (__valuelo), "=&d" /* %edx */ (hiremainder), "=r" (__temp) \ : "0" (__arg1), "rm" (__arg2), "g" (hiremainder), "2" ((ulong)0)); \ __valuelo; \ }) #define addmullow(a,b) \ ({ ulong __valuelo, __arg1 = (a), __arg2 = (b), __temp; \ __asm__ ("mull %3 ; addl %4,%0" \ : "=a" /* %eax */ (__valuelo), "=&d" /* %edx */ (__temp) \ : "0" (__arg1), "rm" (__arg2), "g" (hiremainder)); \ __valuelo; \ }) #define divll(a,b) \ ({ ulong __value, __arg1 = (a), __arg2 = (b); \ __asm__ ("divl %4" \ : "=a" /* %eax */ (__value), "=d" /* %edx */ (hiremainder) \ : "0" /* %eax */ (__arg1), "1" /* %edx */ (hiremainder), "g" (__arg2)); \ __value; \ }) #ifndef _ASMI386INLINE_H_ # define _ASMI386INLINE_H_ # ifdef INLINE static inline int bfffo(ulong x) { int leading_one_position; __asm__ ("bsrl %1,%0" : "=r" (leading_one_position) : "rm" (x)); return 31-leading_one_position; } # endif #endif #endif /* ASMINLINE */ /* $Id: level1.h,v 1.6 2000/11/03 21:00:26 karim Exp $ Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP 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. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* This file defines some "level 1" kernel functions */ /* These functions can be inline, with gcc */ /* If not gcc, they are defined externally with "level1.c" */ /* level1.c includes this file and never needs to be changed */ /* The following seven lines are necessary for level0.c and level1.c */ #ifdef LEVEL1 # undef INLINE # define INLINE #endif #ifdef LEVEL0 # undef INLINE #endif #ifndef INLINE void addsii(long x, GEN y, GEN z); long addssmod(long a, long b, long p); void addssz(long x, long y, GEN z); void affii(GEN x, GEN y); void affsi(long s, GEN x); void affsr(long s, GEN x); GEN cgetg(long x, long y); GEN cgeti(long x); GEN cgetr(long x); int cmpir(GEN x, GEN y); int cmpsr(long x, GEN y); int divise(GEN x, GEN y); long divisii(GEN x, long y, GEN z); void divisz(GEN x, long y, GEN z); void divrrz(GEN x, GEN y, GEN z); void divsiz(long x, GEN y, GEN z); GEN divss(long x, long y); long divssmod(long a, long b, long p); void divssz(long x, long y, GEN z); void dvmdiiz(GEN x, GEN y, GEN z, GEN t); GEN dvmdis(GEN x, long y, GEN *z); void dvmdisz(GEN x, long y, GEN z, GEN t); GEN dvmdsi(long x, GEN y, GEN *z); void dvmdsiz(long x, GEN y, GEN z, GEN t); GEN dvmdss(long x, long y, GEN *z); void dvmdssz(long x, long y, GEN z, GEN t); ulong evallg(ulong x); ulong evallgef(ulong x); ulong evalvalp(ulong x); ulong evalexpo(ulong x); #ifndef __M68K__ long expi(GEN x); #endif double gtodouble(GEN x); GEN icopy(GEN x); GEN icopy_av(GEN x, GEN y); long itos(GEN x); GEN modis(GEN x, long y); GEN mpabs(GEN x); GEN mpadd(GEN x, GEN y); void mpaff(GEN x, GEN y); int mpcmp(GEN x, GEN y); GEN mpcopy(GEN x); GEN mpdiv(GEN x, GEN y); int mpdivis(GEN x, GEN y, GEN z); GEN mpmul(GEN x, GEN y); GEN mpneg(GEN x); GEN mpsub(GEN x, GEN y); void mulsii(long x, GEN y, GEN z); long mulssmod(ulong a, ulong b, ulong c); void mulssz(long x, long y, GEN z); GEN new_chunk(long x); void resiiz(GEN x, GEN y, GEN z); GEN resis(GEN x, long y); GEN ressi(long x, GEN y); GEN shiftr(GEN x, long n); long smodis(GEN x, long y); GEN stoi(long x); GEN subii(GEN x, GEN y); GEN subir(GEN x, GEN y); GEN subri(GEN x, GEN y); GEN subrr(GEN x, GEN y); GEN subsi(long x, GEN y); GEN subsr(long x, GEN y); long subssmod(long a, long b, long p); GEN utoi(ulong x); long vali(GEN x); #else /* defined(INLINE) */ INLINE ulong evallg(ulong x) { if (x & ~LGBITS) err(errlg); return m_evallg(x); } INLINE ulong evallgef(ulong x) { if (x & ~LGEFBITS) err(errlgef); return m_evallgef(x); } INLINE ulong evalvalp(ulong x) { const long v = m_evalvalp(x); if (v & ~VALPBITS) err(errvalp); return v; } INLINE ulong evalexpo(ulong x) { const long v = m_evalexpo(x); if (v & ~EXPOBITS) err(errexpo); return v; } INLINE GEN new_chunk(long x) { const GEN z = ((GEN) avma) - x; if ((ulong)x > (ulong)((GEN)avma-(GEN)bot)) err(errpile); #ifdef MEMSTEP checkmemory(z); #endif #ifdef _WIN32 if (win32ctrlc) dowin32ctrlc(); #endif avma = (long)z; return z; } /* THE FOLLOWING ONES ARE IN mp.s */ # ifndef __M68K__ INLINE GEN cgetg(long x, long y) { const GEN z = new_chunk(x); z[0] = evaltyp(y) | evallg(x); return z; } INLINE GEN cgeti(long x) { const GEN z = new_chunk(x); z[0] = evaltyp(t_INT) | evallg(x); return z; } INLINE GEN cgetr(long x) { const GEN z = new_chunk(x); z[0] = evaltyp(t_REAL) | evallg(x); return z; } # endif /* __M68K__ */ /* cannot do memcpy because sometimes x and y overlap */ INLINE GEN mpcopy(GEN x) { register long lx = lg(x); const GEN y = new_chunk(lx); while (--lx >= 0) y[lx]=x[lx]; return y; } INLINE GEN icopy(GEN x) { register long lx = lgefint(x); const GEN y = cgeti(lx); while (--lx > 0) y[lx]=x[lx]; return y; } /* copy integer x as if we had avma = av */ INLINE GEN icopy_av(GEN x, GEN y) { register long lx = lgefint(x); y -= lx; while (--lx >= 0) y[lx]=x[lx]; return y; } INLINE GEN mpneg(GEN x) { const GEN y=mpcopy(x); setsigne(y,-signe(x)); return y; } INLINE GEN mpabs(GEN x) { const GEN y=mpcopy(x); if (signe(x)<0) setsigne(y,1); return y; } INLINE long smodis(GEN x, long y) { const long av=avma; divis(x,y); avma=av; if (!hiremainder) return 0; return (signe(x)>0) ? hiremainder: (y>0?y:-y)+hiremainder; } INLINE GEN utoi(ulong x) { GEN y; if (!x) return gzero; y=cgeti(3); y[1] = evalsigne(1) | evallgefint(3); y[2] = x; return y; } # ifndef __M68K__ INLINE GEN stoi(long x) { GEN y; if (!x) return gzero; y=cgeti(3); if (x>0) { y[1] = evalsigne(1) | evallgefint(3); y[2] = x; } else { y[1] = evalsigne(-1) | evallgefint(3); y[2] = -x; } return y; } INLINE long itos(GEN x) { const long s=signe(x); long p1; if (!s) return 0; if (lgefint(x)>3) err(affer2); p1=x[2]; if (p1 < 0) err(affer2); return (s>0) ? p1 : -(long)p1; } #endif INLINE GEN stosmall(long x) { if ( (x>0?x:-x) & SMALL_MASK) return stoi(x); return (GEN) (1 | (x<<1)); } # ifndef __M68K__ INLINE void affii(GEN x, GEN y) { long lx; if (x==y) return; lx=lgefint(x); if (lg(y)0) { x[1] = evalsigne(1) | evallgefint(3); x[2] = s; } else { x[1] = evalsigne(-1) | evallgefint(3); x[2] = -s; } } INLINE void affsr(long s, GEN x) { long l; if (!s) { l = -bit_accuracy(lg(x)); x[1]=evalexpo(l); x[2]=0; return; } if (s<0) { x[1] = evalsigne(-1); s = -s; } else x[1] = evalsigne(1); l=bfffo(s); x[1] |= evalexpo((BITS_IN_LONG-1)-l); x[2] = s<0?x:-x),(ulong)(y>0?y:-y)); if (x<0) { hiremainder = -((long)hiremainder); p1 = -p1; } if (y<0) p1 = -p1; SAVE_HIREMAINDER; return stoi(p1); } INLINE GEN dvmdss(long x, long y, GEN *z) { const GEN p1=divss(x,y); *z = stoi(hiremainder); return p1; } INLINE GEN dvmdsi(long x, GEN y, GEN *z) { const GEN p1=divsi(x,y); *z = stoi(hiremainder); return p1; } INLINE GEN dvmdis(GEN x, long y, GEN *z) { const GEN p1=divis(x,y); *z=stoi(hiremainder); return p1; } INLINE void dvmdssz(long x, long y, GEN z, GEN t) { const long av=avma; const GEN p1=divss(x,y); affsi(hiremainder,t); mpaff(p1,z); avma=av; } INLINE void dvmdsiz(long x, GEN y, GEN z, GEN t) { const long av=avma; const GEN p1=divsi(x,y); affsi(hiremainder,t); mpaff(p1,z); avma=av; } INLINE void dvmdisz(GEN x, long y, GEN z, GEN t) { const long av=avma; const GEN p1=divis(x,y); affsi(hiremainder,t); mpaff(p1,z); avma=av; } INLINE void dvmdiiz(GEN x, GEN y, GEN z, GEN t) { const long av=avma; GEN p; mpaff(dvmdii(x,y,&p),z); mpaff(p,t); avma=av; } INLINE GEN modis(GEN x, long y) { return stoi(smodis(x,y)); } INLINE GEN ressi(long x, GEN y) { const long av=avma; divsi(x,y); avma=av; return stoi(hiremainder); } INLINE GEN resis(GEN x, long y) { const long av=avma; divis(x,y); avma=av; return stoi(hiremainder); } INLINE void divisz(GEN x, long y, GEN z) { if (typ(z)==t_INT) gops2gsz(divis,x,y,z); else { const long av=avma; const GEN p1=cgetr(lg(z)); affir(x,p1); affrr(divrs(p1,y),z); avma=av; } } INLINE void divsiz(long x, GEN y, GEN z) { const long av=avma; if (typ(z)==t_INT) gaffect(divsi(x,y),z); else { const long lz=lg(z); const GEN p1=cgetr(lz), p2=cgetr(lz); affsr(x,p1); affir(y,p2); affrr(divrr(p1,p2),z); } avma=av; } INLINE void divssz(long x, long y, GEN z) { const long av=avma; if (typ(z)==t_INT) gaffect(divss(x,y),z); else { const GEN p1=cgetr(lg(z)); affsr(x,p1); affrr(divrs(p1,y),z); } avma=av; } INLINE void divrrz(GEN x, GEN y, GEN z) { const long av=avma; mpaff(divrr(x,y),z); avma=av; } INLINE void resiiz(GEN x, GEN y, GEN z) { const long av=avma; affii(resii(x,y),z); avma=av; } INLINE int divise(GEN x, GEN y) { const long av=avma; const GEN p1=resii(x,y); avma=av; return p1 == gzero; } INLINE int mpcmp(GEN x, GEN y) { if (typ(x)==t_INT) return (typ(y)==t_INT) ? cmpii(x,y) : cmpir(x,y); return (typ(y)==t_INT) ? -cmpir(y,x) : cmprr(x,y); } INLINE GEN mpadd(GEN x, GEN y) { if (typ(x)==t_INT) return (typ(y)==t_INT) ? addii(x,y) : addir(x,y); return (typ(y)==t_INT) ? addir(y,x) : addrr(x,y); } INLINE GEN mpsub(GEN x, GEN y) { if (typ(x)==t_INT) return (typ(y)==t_INT) ? subii(x,y) : subir(x,y); return (typ(y)==t_INT) ? subri(x,y) : subrr(x,y); } INLINE GEN mpmul(GEN x, GEN y) { if (typ(x)==t_INT) return (typ(y)==t_INT) ? mulii(x,y) : mulir(x,y); return (typ(y)==t_INT) ? mulir(y,x) : mulrr(x,y); } INLINE GEN mpdiv(GEN x, GEN y) { if (typ(x)==t_INT) return (typ(y)==t_INT) ? divii(x,y) : divir(x,y); return (typ(y)==t_INT) ? divri(x,y) : divrr(x,y); } INLINE int mpdivis(GEN x, GEN y, GEN z) { const long av=avma; GEN p2; const GEN p1=dvmdii(x,y,&p2); if (signe(p2)) { avma=av; return 0; } affii(p1,z); avma=av; return 1; } /* THE FOLLOWING ONES ARE NOT IN mp.s */ # endif /* !defined(__M68K__) */ INLINE double gtodouble(GEN x) { static long reel4[4]={ evaltyp(t_REAL) | m_evallg(4),0,0,0 }; if (typ(x)==t_REAL) return rtodbl(x); gaffect(x,(GEN)reel4); return rtodbl((GEN)reel4); } INLINE long addssmod(long a, long b, long p) { ulong res = a + b; return (res >= (ulong)p) ? res - p : res; } INLINE long subssmod(long a, long b, long p) { long res = a - b; return (res >= 0) ? res : res + p; } INLINE long mulssmod(ulong a, ulong b, ulong c) { LOCAL_HIREMAINDER; { register ulong x = mulll(a,b); /* alter the doubleword by a multiple of c: */ if (hiremainder>=c) hiremainder %= c; (void)divll(x,c); } return hiremainder; } INLINE long divssmod(long a, long b, long p) { long v1 = 0, v2 = 1, v3, r, oldp = p; while (b > 1) { v3 = v1 - (p / b) * v2; v1 = v2; v2 = v3; r = p % b; p = b; b = r; } if (v2 < 0) v2 += oldp; return mulssmod(a, v2, oldp); } INLINE long expi(GEN x) { const long lx=lgefint(x); return lx==2? -HIGHEXPOBIT: bit_accuracy(lx)-bfffo(x[2])-1; } #endif