[gforth] / gforth / engine / support.c  

gforth: gforth/engine/support.c

Diff for /gforth/engine/support.c between version 1.16 and 1.17

version 1.16, Mon Oct 30 15:29:48 2006 UTC version 1.17, Wed Nov 1 22:37:23 2006 UTC
Line 457 
Line 457 
   return retval;    return retval;
 }  }
   
 /* mixed division; should usually be faster than gcc's  /* mixed division support; should usually be faster than gcc's
    double-by-double division (and gcc typically does not generate     double-by-double division (and gcc typically does not generate
    double-by-single division because of exception handling issues. If     double-by-single division because of exception handling issues. If
    the architecture has double-by-single division, you should define     the architecture has double-by-single division, you should define
    ASM_SM_SLASH_REM[4] and ASM_UM_SLASH_MOD[4] appropriately. */     ASM_SM_SLASH_REM and ASM_UM_SLASH_MOD appropriately. */
   
 #if !defined(ASM_UM_SLASH_MOD)  /* Type definitions for longlong.h (according to the comments at the start):
 static Cell nlz(UCell x)     declarations taken from libgcc2.h */
   
   typedef unsigned int UQItype    __attribute__ ((mode (QI)));
   typedef          int SItype     __attribute__ ((mode (SI)));
   typedef unsigned int USItype    __attribute__ ((mode (SI)));
   typedef          int DItype     __attribute__ ((mode (DI)));
   typedef unsigned int UDItype    __attribute__ ((mode (DI)));
   typedef UCell UWtype;
   #if (SIZEOF_CHAR_P == 4)
   typedef unsigned int UHWtype __attribute__ ((mode (HI)));
   #endif
   #if (SIZEOF_CHAR_P == 8)
   typedef USItype UHWtype;
   #endif
   #ifndef BUGGY_LONG_LONG
   typedef UDCell UDWtype;
   #endif
   #define W_TYPE_SIZE (SIZEOF_CHAR_P * 8)
   
   #include "longlong.h"
   
   static Cell MAYBE_UNUSED nlz(UCell x)
      /* number of leading zeros, adapted from "Hacker's Delight" */       /* number of leading zeros, adapted from "Hacker's Delight" */
 {  {
    Cell n;     Cell n;
   
   #if !defined(COUNT_LEADING_ZEROS_0)
    if (x == 0) return(CELL_BITS);     if (x == 0) return(CELL_BITS);
   #endif
   #if defined(count_leading_zeros)
      count_leading_zeros(n,x);
   #else
   #warning "count_leading_zeros undefined (should not happen)"
    n = 0;     n = 0;
 #if (SIZEOF_CHAR_P > 4)  #if (SIZEOF_CHAR_P > 4)
    if (x <= 0xffffffff) {n+=32; x <<= 32;}     if (x <= 0xffffffff) {n+=32; x <<= 32;}
Line 479 
Line 506 
    if (x <= 0x0FFFFFFF) {n = n + 4; x = x << 4;}     if (x <= 0x0FFFFFFF) {n = n + 4; x = x << 4;}
    if (x <= 0x3FFFFFFF) {n = n + 2; x = x << 2;}     if (x <= 0x3FFFFFFF) {n = n + 2; x = x << 2;}
    if (x <= 0x7FFFFFFF) {n = n + 1;}     if (x <= 0x7FFFFFFF) {n = n + 1;}
   #endif
    return n;     return n;
 }  }
   
   #if !defined(ASM_UM_SLASH_MOD)
 UDCell umdiv (UDCell u, UCell v)  UDCell umdiv (UDCell u, UCell v)
 /* Divide unsigned double by single precision using shifts and subtracts.  /* Divide unsigned double by single precision using shifts and subtracts.
    Return quotient in lo, remainder in hi. */     Return quotient in lo, remainder in hi. */
 {  {
 #if 0    UDCell res;
   #if defined(udiv_qrnnd)
     UCell q,r,u0,u1;
     UCell MAYBE_UNUSED lz;
   
     vm_ud2twoCell(u,u0,u1);
     if (v==0)
       throw(BALL_DIVZERO);
     if (u1>=v)
       throw(BALL_RESULTRANGE);
   #if UDIV_NEEDS_NORMALIZATION
     lz = nlz(v);
     v <<= lz;
     u <<= lz;
     vm_ud2twoCell(u,u0,u1);
   #endif
     udiv_qrnnd(q,r,u1,u0,v);
   #if UDIV_NEEDS_NORMALIZATION
     r >>= lz;
   #endif
     vm_twoCell2ud(q,r,res);
   #else /* !(defined(udiv_qrnnd) */
   #warning "udiv_qrnnd undefined (should not happen)"
   /* simple restoring subtract-and-shift algorithm, might be faster on Alpha */    /* simple restoring subtract-and-shift algorithm, might be faster on Alpha */
   int i = CELL_BITS, c = 0;    int i = CELL_BITS, c = 0;
   UCell q = 0;    UCell q = 0;
   Ucell h, l;    Ucell h, l;
   UDCell res;  
   
   vm_ud2twoCell(u,l,h);    vm_ud2twoCell(u,l,h);
   if (v==0)    if (v==0)
Line 514 
Line 564 
       q <<= 1;        q <<= 1;
     }      }
   vm_twoCell2ud(q,h,res);    vm_twoCell2ud(q,h,res);
 #else  #endif /* !(defined(udiv_qrnnd) && */
   /* adapted from "Hacker's Delight", Figure 9-3,  
      http://www.hackersdelight.org/HDcode/divlu.cc, which in turn is  
      adapted from Knuth's TAoCP Vol 2., Sect 4.3.1, Algorithm D */  
   UCell u1, u0;  
   UDCell res;  
   UCell b = ((UCell)1)<<HALFCELL_BITS; /* Number base. */  
   UCell un1, un0,        /* Norm. dividend LSD's. */  
         vn1, vn0,        /* Norm. divisor digits. */  
         q1, q0,          /* Quotient digits. */  
         un32, un21, un10,/* Dividend digit pairs. */  
         rhat;            /* A remainder. */  
   Cell s;                /* Shift amount for norm. */  
   
   vm_ud2twoCell(u,u0,u1);  
   if (v==0)  
     throw(BALL_DIVZERO);  
   if (u1 >= v) /* overflow */  
     throw(BALL_RESULTRANGE);  
   s = nlz(v);               /* 0 <= s <= CELL_BITS-1. */  
   v = v << s;               /* Normalize divisor. */  
   vn1 = v >> HALFCELL_BITS; /* Break divisor up into */  
   vn0 = v & HALFCELL_MASK;  /* two half-cell digits. */  
   
   un32 = (u1 << s) | ((u0 >> (CELL_BITS-s)) & ((-s) >> (CELL_BITS-1)));  
   un10 = u0 << s;           /* Shift dividend left. */  
   
   un1 = un10 >> HALFCELL_BITS; /* Break right half of */  
   un0 = un10 & HALFCELL_MASK;  /* dividend into two digits. */  
   
   q1 = un32/vn1;            /* Compute the first */  
   rhat = un32 - q1*vn1;     /* quotient digit, q1. */  
  again1:  
   if (q1 >= b || q1*vn0 > b*rhat + un1) {  
     q1 = q1 - 1;  
     rhat = rhat + vn1;  
     if (rhat < b) goto again1;}  
   
   un21 = un32*b + un1 - q1*v;  /* Multiply and subtract. */  
   
   q0 = un21/vn1;            /* Compute the second */  
   rhat = un21 - q0*vn1;     /* quotient digit, q0. */  
  again2:  
   if (q0 >= b || q0*vn0 > b*rhat + un0) {  
     q0 = q0 - 1;  
     rhat = rhat + vn1;  
     if (rhat < b) goto again2;}  
   
   vm_twoCell2ud(q1*b + q0 /* quotient */,  
                 (un21*b + un0 - q0*v) >> s /* remainder */,  
                 res);  
 #endif  
   return res;    return res;
 }  }
 #endif  #endif
Line 573 
Line 572 
 #if !defined(ASM_SM_SLASH_REM)  #if !defined(ASM_SM_SLASH_REM)
 #if  defined(ASM_UM_SLASH_MOD)  #if  defined(ASM_UM_SLASH_MOD)
 /* define it if it is not defined above */  /* define it if it is not defined above */
 UDCell umdiv (UDCell u, UCell v)  static UDCell MAYBE_UNUSED umdiv (UDCell u, UCell v)
 {  {
   UDCell res;    UDCell res;
   UCell u0,u1;    UCell u0,u1;
Line 588 
Line 587 
 #define dnegate(x) (-(x))  #define dnegate(x) (-(x))
 #endif  #endif
   
 DCell smdiv (DCell num, Cell denom)     /* symmetric divide procedure, mixed prec */  DCell smdiv (DCell num, Cell denom)
        /* symmetric divide procedure, mixed prec */
 {  {
   DCell res;    DCell res;
   #if defined(sdiv_qrnnd)
   #warning "using sdiv_qrnnd"
     Cell u1,q,r
     UCell u0;
     UCell MAYBE_UNUSED lz;
   
     vm_d2twoCell(u,u0,u1);
     if (v==0)
       throw(BALL_DIVZERO);
     if (u1>=v)
       throw(BALL_RESULTRANGE);
     sdiv_qrnnd(q,r,u1,u0,v);
     vm_twoCell2d(q,r,res);
   #else
   UDCell ures;    UDCell ures;
   UCell l, q, r;    UCell l, q, r;
   Cell h;    Cell h;
Line 614 
Line 628 
   if (h<0)    if (h<0)
     r = -r;      r = -r;
   vm_twoCell2d(q,r,res);    vm_twoCell2d(q,r,res);
   #endif
   return res;    return res;
 }  }
   
 DCell fmdiv (DCell num, Cell denom)     /* floored divide procedure, mixed prec */  DCell fmdiv (DCell num, Cell denom)
        /* floored divide procedure, mixed prec */
 {  {
   /* I have this technique from Andrew Haley */    /* I have this technique from Andrew Haley */
   DCell res;    DCell res;


Generate output suitable for use with a patch program
Legend:
Removed from v.1.16  
changed lines
  Added in v.1.17

CVS Admin

Powered by ViewCVS 1.0-dev
(Powered by ViewCVS)

ViewCVS and CVS Help