From: hunt Date: Mon, 12 Sep 2005 20:06:41 +0000 (+0000) Subject: 2005-09-12 Martin Hunt X-Git-Tag: release-0.5~193 X-Git-Url: https://sourceware.org/git/?a=commitdiff_plain;h=f2d86d715c06913d8bc6b0ad259323b7dfcf70b2;p=systemtap.git 2005-09-12 Martin Hunt * arith.c (_stp_div64): Check for division by 0 or -1 first. This simplifies things and removes the possibility of x86_64 trying LLONG_MIN/-1 and faulting. (_stp_mod64): Ditto. --- diff --git a/runtime/ChangeLog b/runtime/ChangeLog index b1e9a3c28..e77987101 100644 --- a/runtime/ChangeLog +++ b/runtime/ChangeLog @@ -1,3 +1,10 @@ +2005-09-12 Martin Hunt + + * arith.c (_stp_div64): Check for division by 0 or -1 first. + This simplifies things and removes the possibility of x86_64 + trying LLONG_MIN/-1 and faulting. + (_stp_mod64): Ditto. + 2005-09-10 Frank Ch. Eigler * arith.c: Add some comments explaining why the last change works. diff --git a/runtime/arith.c b/runtime/arith.c index 452c94345..fea7421a2 100644 --- a/runtime/arith.c +++ b/runtime/arith.c @@ -25,70 +25,54 @@ long long _div64 (long long u, long long v); long long _mod64 (long long u, long long v); #endif -/** Divide x by y. In case of overflow or division-by-zero, - * set context error string, and return any old value. +/** Divide x by y. In case of division-by-zero, + * set context error string, and return 0 */ int64_t _stp_div64 (const char **error, int64_t x, int64_t y) { + // check for division-by-zero + if (unlikely (y == 0)) { + if (error) *error = "division by 0"; + return 0; + } + + if (unlikely (y == -1)) + return -x; + #ifdef __LP64__ - if (unlikely (y == 0 || (x == LONG_MIN && y == -1))) { - if (error) *error = "divisor out of range"; - return 0; - } - return x/y; + return x/y; #else - // Note use of ">" and "<" here instead of "<=" and ">=". - // This passes the potentially problematic division overflow - // case of 32-bit LONG_MIN divided by -1 over to the _div64 - // case. - if (likely ((x > LONG_MIN && x < LONG_MAX) && - (y > LONG_MIN && y < LONG_MAX))) { - long xx = (long) x; - long yy = (long) y; - - // check for division-by-zero - if (unlikely (yy == 0)) { - if (error) *error = "division by 0"; - return 0; - } - return xx / yy; - } else - // Note that the 64-bit LONG_MIN divided by -1 case is - // *passed* by the libgcc code without overflow indication. - return _div64 (x, y); + if (likely ((x >= LONG_MIN && x <= LONG_MAX) && + (y >= LONG_MIN && y <= LONG_MAX))) { + return (long)x / (long)y; + } else + return _div64 (x, y); #endif } -/** Modulo x by y. In case of overflow or division-by-zero, - * set context error string, and return any old value. +/** Modulo x by y. In case of division-by-zero, + * set context error string, and return any 0 */ int64_t _stp_mod64 (const char **error, int64_t x, int64_t y) { + // check for division-by-zero + if (unlikely (y == 0)) { + if (error) *error = "division by 0"; + return 0; + } + + if (unlikely (y == 1 || y == -1)) + return 0; + #ifdef __LP64__ - // XXX: is the LONG_MIN%-1 case interesting? - if (unlikely (y == 0 || (x == LONG_MIN && y == -1))) { - if (error) *error = "divisor out of range"; - return 0; - } - return x%y; - + return x%y; #else - // Note again ">" and "<" here instead of "<=" and ">=". - // The implications are not clear here since anything modulo +-1 is 0. - if (likely ((x > LONG_MIN && x < LONG_MAX) && - (y > LONG_MIN && y < LONG_MAX))) { - long xx = (long) x; - long yy = (long) y; - - // check for division-by-zero - if (unlikely (yy == 0)) { - if (error) *error = "division by 0"; - return 0; - } - return xx % yy; - } else - return _mod64 (x,y); + if (likely ((x >= LONG_MIN && x <= LONG_MAX) && + (y >= LONG_MIN && y <= LONG_MAX))) { + return (long)x % (long)y; + } else + return _mod64 (x, y); #endif } @@ -99,18 +83,18 @@ int64_t _stp_mod64 (const char **error, int64_t x, int64_t y) */ int _stp_random_pm (int n) { - static unsigned long seed; - static int initialized_p = 0; + static unsigned long seed; + static int initialized_p = 0; - if (unlikely (! initialized_p)) { - seed = (unsigned long) jiffies; - initialized_p = 1; - } + if (unlikely (! initialized_p)) { + seed = (unsigned long) jiffies; + initialized_p = 1; + } - /* from glibc rand man page */ - seed = seed * 1103515245 + 12345; + /* from glibc rand man page */ + seed = seed * 1103515245 + 12345; - return (seed % (2*n+1)-n); + return (seed % (2*n+1)-n); } #endif /* _STP_TEST_ */ @@ -134,192 +118,191 @@ struct DWstruct {Wtype low, high;}; typedef union { - struct DWstruct s; - DWtype ll; + struct DWstruct s; + DWtype ll; } DWunion; /* these are the i386 versions of these macros from gcc/longlong.h */ -#define umul_ppmm(w1, w0, u, v) \ - __asm__ ("mull %3" \ - : "=a" ((USItype) (w0)), \ - "=d" ((USItype) (w1)) \ - : "%0" ((USItype) (u)), \ - "rm" ((USItype) (v))) +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("mull %3" \ + : "=a" ((USItype) (w0)), \ + "=d" ((USItype) (w1)) \ + : "%0" ((USItype) (u)), \ + "rm" ((USItype) (v))) -#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 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 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 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) +#define count_leading_zeros(count, x) \ + do { \ + USItype __cbtmp; \ + __asm__ ("bsrl %1,%0" \ + : "=r" (__cbtmp) : "rm" ((USItype) (x))); \ + (count) = __cbtmp ^ 31; \ + } while (0) inline UDWtype _stp_udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp) { - const DWunion nn = {.ll = n}; - const DWunion dd = {.ll = d}; - DWunion ww,rr; - UWtype d0, d1, n0, n1, n2; - UWtype q0, q1; - UWtype b, bm; + const DWunion nn = {.ll = n}; + const DWunion dd = {.ll = d}; + DWunion ww,rr; + UWtype d0, d1, n0, n1, n2; + UWtype q0, q1; + UWtype b, bm; - d0 = dd.s.low; - d1 = dd.s.high; - n0 = nn.s.low; - n1 = nn.s.high; + d0 = dd.s.low; + d1 = dd.s.high; + n0 = nn.s.low; + n1 = nn.s.high; - 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 (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 { - if (d1 > n1) { - /* 00 = nn / DD */ - q0 = 0; - q1 = 0; + if (rp != 0) { + rr.s.low = n0; + rr.s.high = 0; + *rp = rr.ll; + } + } 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. */ + /* 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; + /* 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; + q1 = 0; - if (rp != 0) { - rr.s.low = n0; - rr.s.high = n1; - *rp = rr.ll; - } - } else { - UWtype m1, m0; - /* Normalize. */ + if (rp != 0) { + rr.s.low = n0; + rr.s.high = n1; + *rp = rr.ll; + } + } else { + UWtype m1, m0; + /* Normalize. */ - b = W_TYPE_SIZE - bm; + b = W_TYPE_SIZE - bm; - d1 = (d1 << bm) | (d0 >> b); - d0 = d0 << bm; - n2 = n1 >> b; - n1 = (n1 << bm) | (n0 >> b); - n0 = n0 << 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); + 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); - } + if (m1 > n1 || (m1 == n1 && m0 > n0)) { + q0--; + sub_ddmmss (m1, m0, m1, m0, d1, d0); + } - q1 = 0; + 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; + /* 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; + ww.s.low = q0; ww.s.high = q1; + return ww.ll; } long long _div64 (long long u, long long v) { - long c = 0; - DWunion uu = {.ll = u}; - DWunion vv = {.ll = v}; - DWtype w; + long c = 0; + DWunion uu = {.ll = u}; + DWunion vv = {.ll = v}; + DWtype w; - if (uu.s.high < 0) - c = ~c, - uu.ll = -uu.ll; - if (vv.s.high < 0) - c = ~c, - vv.ll = -vv.ll; + if (uu.s.high < 0) + c = ~c, + uu.ll = -uu.ll; + if (vv.s.high < 0) + c = ~c, + vv.ll = -vv.ll; - w = _stp_udivmoddi4 (uu.ll, vv.ll, (UDWtype *) 0); - if (c) - w = -w; + w = _stp_udivmoddi4 (uu.ll, vv.ll, (UDWtype *) 0); + if (c) + w = -w; - return w; + return w; } long long _mod64 (long long u, long long v) { - long c = 0; - DWunion uu = {.ll = u}; - DWunion vv = {.ll = v}; - DWtype w; + long c = 0; + DWunion uu = {.ll = u}; + DWunion vv = {.ll = v}; + DWtype w; - if (uu.s.high < 0) - c = ~c, - uu.ll = -uu.ll; - if (vv.s.high < 0) - vv.ll = -vv.ll; + if (uu.s.high < 0) + c = ~c, + uu.ll = -uu.ll; + if (vv.s.high < 0) + vv.ll = -vv.ll; - (void) _stp_udivmoddi4 (uu.ll, vv.ll, (UDWtype*)&w); - if (c) - w = -w; + (void) _stp_udivmoddi4 (uu.ll, vv.ll, (UDWtype*)&w); + if (c) + w = -w; - return w; + return w; } #endif /* __i386__ */ - #endif /* _ARITH_C_ */