summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhunt <hunt>2005-09-12 20:06:41 +0000
committerhunt <hunt>2005-09-12 20:06:41 +0000
commitf2d86d715c06913d8bc6b0ad259323b7dfcf70b2 (patch)
tree0487bc91b030539293d760b1a884e42601b6e522
parentd7ce99e8299f9807852fd2f8727284bb2da7b1f8 (diff)
downloadsystemtap-steved-f2d86d715c06913d8bc6b0ad259323b7dfcf70b2.tar.gz
systemtap-steved-f2d86d715c06913d8bc6b0ad259323b7dfcf70b2.tar.xz
systemtap-steved-f2d86d715c06913d8bc6b0ad259323b7dfcf70b2.zip
2005-09-12 Martin Hunt <hunt@redhat.com>
* 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.
-rw-r--r--runtime/ChangeLog7
-rw-r--r--runtime/arith.c393
2 files changed, 195 insertions, 205 deletions
diff --git a/runtime/ChangeLog b/runtime/ChangeLog
index b1e9a3c2..e7798710 100644
--- a/runtime/ChangeLog
+++ b/runtime/ChangeLog
@@ -1,3 +1,10 @@
+2005-09-12 Martin Hunt <hunt@redhat.com>
+
+ * 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 <fche@elastic.org>
* arith.c: Add some comments explaining why the last change works.
diff --git a/runtime/arith.c b/runtime/arith.c
index 452c9434..fea7421a 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_ */