aboutsummaryrefslogtreecommitdiff
path: root/gcc/fold-const.c
diff options
context:
space:
mode:
authorTorbjorn Granlund <tege@gnu.org>1994-06-15 02:23:14 +0000
committerTorbjorn Granlund <tege@gnu.org>1994-06-15 02:23:14 +0000
commit37bdb7e3147c67ba3e41ff7d6c4ddb848775fe22 (patch)
tree7f4131b6f6da8fbc845712d6904193f1c805fa0f /gcc/fold-const.c
parent4c9a05bc5560ebb1144228bccb5312871a3089f7 (diff)
downloadgcc-37bdb7e3147c67ba3e41ff7d6c4ddb848775fe22.zip
gcc-37bdb7e3147c67ba3e41ff7d6c4ddb848775fe22.tar.gz
gcc-37bdb7e3147c67ba3e41ff7d6c4ddb848775fe22.tar.bz2
(encode, decode): Use 4 HOST_WIDE_INTs for encoded value with HOST_BITS_PER_WIDE_INT/2 bits in each.
(encode, decode): Use 4 HOST_WIDE_INTs for encoded value with HOST_BITS_PER_WIDE_INT/2 bits in each. (LOWPART, HIGHPART): New macros. (BASE): Move definition outside of div_and_round_double. (add_double, mul_double, lshift_double, rshift_double): Rewrite. (lrotate_double): Use LOWPART, HIGHPART, and BASE. (rrotate_double): Likewise. (div_and_round_double): Major changes to code for general case. Now it actually produces non-garbage results for large operands. (div_and_round_double): Simplify condition for special code used when divisor < BASE. (const_binop): Delete special cases for multiplying by 0, 1, 2, 4, 8. (fold, case *_DIV_EXPR): Don't try to optimize for overflow. From-SVN: r7473
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r--gcc/fold-const.c530
1 files changed, 192 insertions, 338 deletions
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index c520514..90d5c05 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -17,8 +17,6 @@ You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-/*@@ Fix lossage on folding division of big integers. */
-
/*@@ This file should be rewritten to use an arbitrary precision
@@ representation for "struct tree_int_cst" and "struct tree_real_cst".
@@ Perhaps the routines could also be used for bc/dc, and made a lib.
@@ -48,8 +46,8 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Handle floating overflow for `const_binop'. */
static jmp_buf float_error;
-static void encode PROTO((short *, HOST_WIDE_INT, HOST_WIDE_INT));
-static void decode PROTO((short *, HOST_WIDE_INT *, HOST_WIDE_INT *));
+static void encode PROTO((HOST_WIDE_INT *, HOST_WIDE_INT, HOST_WIDE_INT));
+static void decode PROTO((HOST_WIDE_INT *, HOST_WIDE_INT *, HOST_WIDE_INT *));
static int div_and_round_double PROTO((enum tree_code, int, HOST_WIDE_INT,
HOST_WIDE_INT, HOST_WIDE_INT,
HOST_WIDE_INT, HOST_WIDE_INT *,
@@ -94,46 +92,41 @@ static tree strip_compound_expr PROTO((tree, tree));
#define overflow_sum_sign(a, b, sum) ((~((a) ^ (b)) & ((a) ^ (sum))) < 0)
/* To do constant folding on INTEGER_CST nodes requires two-word arithmetic.
- We do that by representing the two-word integer as MAX_SHORTS shorts,
- with only 8 bits stored in each short, as a positive number. */
+ We do that by representing the two-word integer in 4 words, with only
+ HOST_BITS_PER_WIDE_INT/2 bits stored in each word, as a positive number. */
+
+#define LOWPART(x) \
+ ((x) & (((unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT/2)) - 1))
+#define HIGHPART(x) \
+ ((unsigned HOST_WIDE_INT) (x) >> HOST_BITS_PER_WIDE_INT/2)
+#define BASE ((unsigned HOST_WIDE_INT) 1 << HOST_BITS_PER_WIDE_INT/2)
-/* Unpack a two-word integer into MAX_SHORTS shorts.
+/* Unpack a two-word integer into 4 words.
LOW and HI are the integer, as two `HOST_WIDE_INT' pieces.
- SHORTS points to the array of shorts. */
+ WORDS points to the array of HOST_WIDE_INTs. */
static void
-encode (shorts, low, hi)
- short *shorts;
+encode (words, low, hi)
+ HOST_WIDE_INT *words;
HOST_WIDE_INT low, hi;
{
- register int i;
-
- for (i = 0; i < MAX_SHORTS / 2; i++)
- {
- shorts[i] = (low >> (i * 8)) & 0xff;
- shorts[i + MAX_SHORTS / 2] = (hi >> (i * 8) & 0xff);
- }
+ words[0] = LOWPART (low);
+ words[1] = HIGHPART (low);
+ words[2] = LOWPART (hi);
+ words[3] = HIGHPART (hi);
}
-/* Pack an array of MAX_SHORTS shorts into a two-word integer.
- SHORTS points to the array of shorts.
+/* Pack an array of 4 words into a two-word integer.
+ WORDS points to the array of words.
The integer is stored into *LOW and *HI as two `HOST_WIDE_INT' pieces. */
static void
-decode (shorts, low, hi)
- short *shorts;
+decode (words, low, hi)
+ HOST_WIDE_INT *words;
HOST_WIDE_INT *low, *hi;
{
- register int i;
- HOST_WIDE_INT lv = 0, hv = 0;
-
- for (i = 0; i < MAX_SHORTS / 2; i++)
- {
- lv |= (HOST_WIDE_INT) shorts[i] << (i * 8);
- hv |= (HOST_WIDE_INT) shorts[i + MAX_SHORTS / 2] << (i * 8);
- }
-
- *low = lv, *hi = hv;
+ *low = words[0] | words[1] * BASE;
+ *hi = words[2] | words[3] * BASE;
}
/* Make the integer constant T valid for its type
@@ -225,38 +218,27 @@ force_fit_type (t, overflow)
/* Add two doubleword integers with doubleword result.
Each argument is given as two `HOST_WIDE_INT' pieces.
One argument is L1 and H1; the other, L2 and H2.
- The value is stored as two `HOST_WIDE_INT' pieces in *LV and *HV.
- We use the 8-shorts representation internally. */
+ The value is stored as two `HOST_WIDE_INT' pieces in *LV and *HV. */
int
add_double (l1, h1, l2, h2, lv, hv)
HOST_WIDE_INT l1, h1, l2, h2;
HOST_WIDE_INT *lv, *hv;
{
- short arg1[MAX_SHORTS];
- short arg2[MAX_SHORTS];
- register int carry = 0;
- register int i;
-
- encode (arg1, l1, h1);
- encode (arg2, l2, h2);
+ HOST_WIDE_INT l, h;
- for (i = 0; i < MAX_SHORTS; i++)
- {
- carry += arg1[i] + arg2[i];
- arg1[i] = carry & 0xff;
- carry >>= 8;
- }
+ l = l1 + l2;
+ h = h1 + h2 + ((unsigned HOST_WIDE_INT) l < l1);
- decode (arg1, lv, hv);
- return overflow_sum_sign (h1, h2, *hv);
+ *lv = l;
+ *hv = h;
+ return overflow_sum_sign (h1, h2, h);
}
/* Negate a doubleword integer with doubleword result.
Return nonzero if the operation overflows, assuming it's signed.
The argument is given as two `HOST_WIDE_INT' pieces in L1 and H1.
- The value is stored as two `HOST_WIDE_INT' pieces in *LV and *HV.
- We use the 8-shorts representation internally. */
+ The value is stored as two `HOST_WIDE_INT' pieces in *LV and *HV. */
int
neg_double (l1, h1, lv, hv)
@@ -281,86 +263,46 @@ neg_double (l1, h1, lv, hv)
Return nonzero if the operation overflows, assuming it's signed.
Each argument is given as two `HOST_WIDE_INT' pieces.
One argument is L1 and H1; the other, L2 and H2.
- The value is stored as two `HOST_WIDE_INT' pieces in *LV and *HV.
- We use the 8-shorts representation internally. */
+ The value is stored as two `HOST_WIDE_INT' pieces in *LV and *HV. */
int
mul_double (l1, h1, l2, h2, lv, hv)
HOST_WIDE_INT l1, h1, l2, h2;
HOST_WIDE_INT *lv, *hv;
{
- short arg1[MAX_SHORTS];
- short arg2[MAX_SHORTS];
- short prod[MAX_SHORTS * 2];
- register int carry = 0;
+ HOST_WIDE_INT arg1[4];
+ HOST_WIDE_INT arg2[4];
+ HOST_WIDE_INT prod[4 * 2];
+ register unsigned HOST_WIDE_INT carry;
register int i, j, k;
HOST_WIDE_INT toplow, tophigh, neglow, neghigh;
- /* These cases are used extensively, arising from pointer combinations. */
- if (h2 == 0)
- {
- if (l2 == 2)
- {
- int overflow = left_shift_overflows (h1, 1);
- unsigned HOST_WIDE_INT temp = l1 + l1;
- *hv = (h1 << 1) + (temp < l1);
- *lv = temp;
- return overflow;
- }
- if (l2 == 4)
- {
- int overflow = left_shift_overflows (h1, 2);
- unsigned HOST_WIDE_INT temp = l1 + l1;
- h1 = (h1 << 2) + ((temp < l1) << 1);
- l1 = temp;
- temp += temp;
- h1 += (temp < l1);
- *lv = temp;
- *hv = h1;
- return overflow;
- }
- if (l2 == 8)
- {
- int overflow = left_shift_overflows (h1, 3);
- unsigned HOST_WIDE_INT temp = l1 + l1;
- h1 = (h1 << 3) + ((temp < l1) << 2);
- l1 = temp;
- temp += temp;
- h1 += (temp < l1) << 1;
- l1 = temp;
- temp += temp;
- h1 += (temp < l1);
- *lv = temp;
- *hv = h1;
- return overflow;
- }
- }
-
encode (arg1, l1, h1);
encode (arg2, l2, h2);
bzero ((char *) prod, sizeof prod);
- for (i = 0; i < MAX_SHORTS; i++)
- for (j = 0; j < MAX_SHORTS; j++)
- {
- k = i + j;
- carry = arg1[i] * arg2[j];
- while (carry)
- {
- carry += prod[k];
- prod[k] = carry & 0xff;
- carry >>= 8;
- k++;
- }
- }
+ for (i = 0; i < 4; i++)
+ {
+ carry = 0;
+ for (j = 0; j < 4; j++)
+ {
+ k = i + j;
+ /* This product is <= 0xFFFE0001, the sum <= 0xFFFF0000. */
+ carry += arg1[i] * arg2[j];
+ /* Since prod[p] < 0xFFFF, this sum <= 0xFFFFFFFF. */
+ carry += prod[k];
+ prod[k] = LOWPART (carry);
+ carry = HIGHPART (carry);
+ }
+ prod[i + 4] = carry;
+ }
- decode (prod, lv, hv); /* This ignores
- prod[MAX_SHORTS] -> prod[MAX_SHORTS*2-1] */
+ decode (prod, lv, hv); /* This ignores prod[4] through prod[4*2-1] */
/* Check for overflow by calculating the top half of the answer in full;
it should agree with the low half's sign bit. */
- decode (prod+MAX_SHORTS, &toplow, &tophigh);
+ decode (prod+4, &toplow, &tophigh);
if (h1 < 0)
{
neg_double (l2, h2, &neglow, &neghigh);
@@ -387,34 +329,26 @@ lshift_double (l1, h1, count, prec, lv, hv, arith)
HOST_WIDE_INT *lv, *hv;
int arith;
{
- short arg1[MAX_SHORTS];
- register int i;
- register int carry;
-
if (count < 0)
{
rshift_double (l1, h1, - count, prec, lv, hv, arith);
return;
}
+
+ if (count >= prec)
+ count = (unsigned HOST_WIDE_INT) count & prec;
- encode (arg1, l1, h1);
-
- if (count > prec)
- count = prec;
-
- while (count > 0)
+ if (count >= HOST_BITS_PER_WIDE_INT)
{
- carry = 0;
- for (i = 0; i < MAX_SHORTS; i++)
- {
- carry += arg1[i] << 1;
- arg1[i] = carry & 0xff;
- carry >>= 8;
- }
- count--;
+ *hv = (unsigned HOST_WIDE_INT) l1 << count - HOST_BITS_PER_WIDE_INT;
+ *lv = 0;
+ }
+ else
+ {
+ *hv = (((unsigned HOST_WIDE_INT) h1 << count)
+ | ((unsigned HOST_WIDE_INT) l1 >> HOST_BITS_PER_WIDE_INT - count - 1 >> 1));
+ *lv = (unsigned HOST_WIDE_INT) l1 << count;
}
-
- decode (arg1, lv, hv);
}
/* Shift the doubleword integer in L1, H1 right by COUNT places
@@ -429,31 +363,30 @@ rshift_double (l1, h1, count, prec, lv, hv, arith)
HOST_WIDE_INT *lv, *hv;
int arith;
{
- short arg1[MAX_SHORTS];
- register int i;
- register int carry;
+ unsigned HOST_WIDE_INT signmask;
+ signmask = (arith
+ ? -((unsigned HOST_WIDE_INT) h1 >> (HOST_BITS_PER_WIDE_INT - 1))
+ : 0);
- encode (arg1, l1, h1);
+ if (count >= prec)
+ count = (unsigned HOST_WIDE_INT) count % prec;
- if (count > prec)
- count = prec;
-
- while (count > 0)
+ if (count >= HOST_BITS_PER_WIDE_INT)
{
- carry = arith && arg1[7] >> 7;
- for (i = MAX_SHORTS - 1; i >= 0; i--)
- {
- carry <<= 8;
- carry += arg1[i];
- arg1[i] = (carry >> 1) & 0xff;
- }
- count--;
+ *hv = signmask;
+ *lv = ((signmask << 2 * HOST_BITS_PER_WIDE_INT - count - 1 << 1)
+ | ((unsigned HOST_WIDE_INT) h1 >> count - HOST_BITS_PER_WIDE_INT));
+ }
+ else
+ {
+ *lv = (((unsigned HOST_WIDE_INT) l1 >> count)
+ | ((unsigned HOST_WIDE_INT) h1 << HOST_BITS_PER_WIDE_INT - count - 1 << 1));
+ *hv = ((signmask << HOST_BITS_PER_WIDE_INT - count)
+ | ((unsigned HOST_WIDE_INT) h1 >> count));
}
-
- decode (arg1, lv, hv);
}
-/* Rotate the doubldword integer in L1, H1 left by COUNT places
+/* Rotate the doubleword integer in L1, H1 left by COUNT places
keeping only PREC bits of result.
Rotate right if COUNT is negative.
Store the value as two `HOST_WIDE_INT' pieces in *LV and *HV. */
@@ -464,7 +397,7 @@ lrotate_double (l1, h1, count, prec, lv, hv)
int prec;
HOST_WIDE_INT *lv, *hv;
{
- short arg1[MAX_SHORTS];
+ HOST_WIDE_INT arg1[4];
register int i;
register int carry;
@@ -479,14 +412,14 @@ lrotate_double (l1, h1, count, prec, lv, hv)
if (count > prec)
count = prec;
- carry = arg1[MAX_SHORTS - 1] >> 7;
+ carry = arg1[4 - 1] >> 16 - 1;
while (count > 0)
{
- for (i = 0; i < MAX_SHORTS; i++)
+ for (i = 0; i < 4; i++)
{
carry += arg1[i] << 1;
- arg1[i] = carry & 0xff;
- carry >>= 8;
+ arg1[i] = LOWPART (carry);
+ carry = HIGHPART (carry);
}
count--;
}
@@ -504,7 +437,7 @@ rrotate_double (l1, h1, count, prec, lv, hv)
int prec;
HOST_WIDE_INT *lv, *hv;
{
- short arg1[MAX_SHORTS];
+ HOST_WIDE_INT arg1[4];
register int i;
register int carry;
@@ -516,11 +449,11 @@ rrotate_double (l1, h1, count, prec, lv, hv)
carry = arg1[0] & 1;
while (count > 0)
{
- for (i = MAX_SHORTS - 1; i >= 0; i--)
+ for (i = 4 - 1; i >= 0; i--)
{
- carry <<= 8;
+ carry *= BASE;
carry += arg1[i];
- arg1[i] = (carry >> 1) & 0xff;
+ arg1[i] = LOWPART (carry >> 1);
}
count--;
}
@@ -548,9 +481,10 @@ div_and_round_double (code, uns,
HOST_WIDE_INT *lquo, *hquo, *lrem, *hrem;
{
int quo_neg = 0;
- short num[MAX_SHORTS + 1]; /* extra element for scaling. */
- short den[MAX_SHORTS], quo[MAX_SHORTS];
- register int i, j, work;
+ HOST_WIDE_INT num[4 + 1]; /* extra element for scaling. */
+ HOST_WIDE_INT den[4], quo[4];
+ register int i, j;
+ unsigned HOST_WIDE_INT work;
register int carry = 0;
HOST_WIDE_INT lnum = lnum_orig;
HOST_WIDE_INT hnum = hnum_orig;
@@ -603,38 +537,29 @@ div_and_round_double (code, uns,
encode (num, lnum, hnum);
encode (den, lden, hden);
- /* This code requires more than just hden == 0.
- We also have to require that we don't need more than three bytes
- to hold CARRY. If we ever did need four bytes to hold it, we
- would lose part of it when computing WORK on the next round. */
- if (hden == 0 && (((unsigned HOST_WIDE_INT) lden << 8) >> 8) == lden)
- { /* simpler algorithm */
+ /* Special code for when the divisor < BASE. */
+ if (hden == 0 && lden < BASE)
+ {
/* hnum != 0 already checked. */
- for (i = MAX_SHORTS - 1; i >= 0; i--)
+ for (i = 4 - 1; i >= 0; i--)
{
- work = num[i] + (carry << 8);
+ work = num[i] + carry * BASE;
quo[i] = work / (unsigned HOST_WIDE_INT) lden;
carry = work % (unsigned HOST_WIDE_INT) lden;
}
}
- else { /* full double precision,
- with thanks to Don Knuth's
- "Seminumerical Algorithms". */
-#define BASE 256
- int quo_est, scale, num_hi_sig, den_hi_sig, quo_hi_sig;
+ else
+ {
+ /* Full double precision division,
+ with thanks to Don Knuth's "Seminumerical Algorithms". */
+ int quo_est, scale, num_hi_sig, den_hi_sig;
/* Find the highest non-zero divisor digit. */
- for (i = MAX_SHORTS - 1; ; i--)
+ for (i = 4 - 1; ; i--)
if (den[i] != 0) {
den_hi_sig = i;
break;
}
- for (i = MAX_SHORTS - 1; ; i--)
- if (num[i] != 0) {
- num_hi_sig = i;
- break;
- }
- quo_hi_sig = num_hi_sig - den_hi_sig + 1;
/* Insure that the first digit of the divisor is at least BASE/2.
This is required by the quotient digit estimation algorithm. */
@@ -642,43 +567,40 @@ div_and_round_double (code, uns,
scale = BASE / (den[den_hi_sig] + 1);
if (scale > 1) { /* scale divisor and dividend */
carry = 0;
- for (i = 0; i <= MAX_SHORTS - 1; i++) {
+ for (i = 0; i <= 4 - 1; i++) {
work = (num[i] * scale) + carry;
- num[i] = work & 0xff;
- carry = work >> 8;
- if (num[i] != 0) num_hi_sig = i;
- }
+ num[i] = LOWPART (work);
+ carry = HIGHPART (work);
+ } num[4] = carry;
carry = 0;
- for (i = 0; i <= MAX_SHORTS - 1; i++) {
+ for (i = 0; i <= 4 - 1; i++) {
work = (den[i] * scale) + carry;
- den[i] = work & 0xff;
- carry = work >> 8;
+ den[i] = LOWPART (work);
+ carry = HIGHPART (work);
if (den[i] != 0) den_hi_sig = i;
}
}
+ num_hi_sig = 4;
+
/* Main loop */
- for (i = quo_hi_sig; i > 0; i--) {
+ for (i = num_hi_sig - den_hi_sig - 1; i >= 0; i--) {
/* guess the next quotient digit, quo_est, by dividing the first
two remaining dividend digits by the high order quotient digit.
quo_est is never low and is at most 2 high. */
+ unsigned HOST_WIDE_INT tmp;
- int num_hi; /* index of highest remaining dividend digit */
-
- num_hi = i + den_hi_sig;
-
- work = (num[num_hi] * BASE) + (num_hi > 0 ? num[num_hi - 1] : 0);
- if (num[num_hi] != den[den_hi_sig]) {
+ num_hi_sig = i + den_hi_sig + 1;
+ work = num[num_hi_sig] * BASE + num[num_hi_sig - 1];
+ if (num[num_hi_sig] != den[den_hi_sig])
quo_est = work / den[den_hi_sig];
- }
- else {
+ else
quo_est = BASE - 1;
- }
/* refine quo_est so it's usually correct, and at most one high. */
- while ((den[den_hi_sig - 1] * quo_est)
- > (((work - (quo_est * den[den_hi_sig])) * BASE)
- + ((num_hi - 1) > 0 ? num[num_hi - 2] : 0)))
+ tmp = work - quo_est * den[den_hi_sig];
+ if (tmp < BASE
+ && den[den_hi_sig - 1] * quo_est > (tmp * BASE + num[num_hi_sig - 2]))
quo_est--;
/* Try QUO_EST as the quotient digit, by multiplying the
@@ -686,48 +608,33 @@ div_and_round_double (code, uns,
Keep in mind that QUO_EST is the I - 1st digit. */
carry = 0;
-
for (j = 0; j <= den_hi_sig; j++)
{
- int digit;
-
- work = num[i + j - 1] - (quo_est * den[j]) + carry;
- digit = work & 0xff;
- carry = work >> 8;
- if (digit < 0)
- {
- digit += BASE;
- carry--;
- }
- num[i + j - 1] = digit;
+ work = quo_est * den[j] + carry;
+ carry = HIGHPART (work);
+ work = num[i + j] - LOWPART (work);
+ num[i + j] = LOWPART (work);
+ carry += HIGHPART (work) != 0;
}
/* if quo_est was high by one, then num[i] went negative and
we need to correct things. */
- if (num[num_hi] < 0)
+ if (num[num_hi_sig] < carry)
{
quo_est--;
carry = 0; /* add divisor back in */
for (j = 0; j <= den_hi_sig; j++)
{
- work = num[i + j - 1] + den[j] + carry;
- if (work > BASE)
- {
- work -= BASE;
- carry = 1;
- }
- else
- {
- carry = 0;
- }
- num[i + j - 1] = work;
+ work = num[i + j] + den[j] + carry;
+ carry = HIGHPART (work);
+ num[i + j] = LOWPART (work);
}
- num [num_hi] += carry;
+ num [num_hi_sig] += carry;
}
/* store the quotient digit. */
- quo[i - 1] = quo_est;
+ quo[i] = quo_est;
}
}
@@ -1179,72 +1086,6 @@ const_binop (code, arg1, arg2, notrunc)
break;
case MULT_EXPR:
- /* Optimize simple cases. */
- if (int1h == 0)
- {
- unsigned HOST_WIDE_INT temp;
-
- switch (int1l)
- {
- case 0:
- t = build_int_2 (0, 0);
- goto got_it;
- case 1:
- t = build_int_2 (int2l, int2h);
- goto got_it;
- case 2:
- overflow = left_shift_overflows (int2h, 1);
- temp = int2l + int2l;
- int2h = (int2h << 1) + (temp < int2l);
- t = build_int_2 (temp, int2h);
- goto got_it;
-#if 0 /* This code can lose carries. */
- case 3:
- temp = int2l + int2l + int2l;
- int2h = int2h * 3 + (temp < int2l);
- t = build_int_2 (temp, int2h);
- goto got_it;
-#endif
- case 4:
- overflow = left_shift_overflows (int2h, 2);
- temp = int2l + int2l;
- int2h = (int2h << 2) + ((temp < int2l) << 1);
- int2l = temp;
- temp += temp;
- int2h += (temp < int2l);
- t = build_int_2 (temp, int2h);
- goto got_it;
- case 8:
- overflow = left_shift_overflows (int2h, 3);
- temp = int2l + int2l;
- int2h = (int2h << 3) + ((temp < int2l) << 2);
- int2l = temp;
- temp += temp;
- int2h += (temp < int2l) << 1;
- int2l = temp;
- temp += temp;
- int2h += (temp < int2l);
- t = build_int_2 (temp, int2h);
- goto got_it;
- default:
- break;
- }
- }
-
- if (int2h == 0)
- {
- if (int2l == 0)
- {
- t = build_int_2 (0, 0);
- break;
- }
- if (int2l == 1)
- {
- t = build_int_2 (int1l, int1h);
- break;
- }
- }
-
overflow = mul_double (int1l, int1h, int2l, int2h, &low, &hi);
t = build_int_2 (low, hi);
break;
@@ -4060,56 +3901,22 @@ fold (expr)
if (integer_zerop (arg1))
return t;
- /* If we have ((a / C1) / C2) where both division are the same type, tr
+ /* If we have ((a / C1) / C2) where both division are the same type, try
to simplify. First see if C1 * C2 overflows or not. */
if (TREE_CODE (arg0) == code && TREE_CODE (arg1) == INTEGER_CST
&& TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
{
- tem = const_binop (MULT_EXPR, TREE_OPERAND (arg0, 1), arg1, 0);
+ tree new_divisor;
- /* If it overflows, the result is +/- 1 or zero, depending on
- the signs of the constants and remaining operand and on which
- division operation is being performed. */
+ new_divisor = const_binop (MULT_EXPR, TREE_OPERAND (arg0, 1), arg1, 0);
+ tem = const_binop (FLOOR_DIV_EXPR, new_divisor, arg1, 0);
- if (TREE_OVERFLOW (tem))
+ if (TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1)) == TREE_INT_CST_LOW (tem)
+ && TREE_INT_CST_HIGH (TREE_OPERAND (arg0, 1)) == TREE_INT_CST_HIGH (tem))
{
- /* 1 if C1 * C2 is negative (i.e., C1 and C2 have
- different signs). */
- int c_neg = ((tree_int_cst_sgn (arg1) < 0)
- == (tree_int_cst_sgn (TREE_OPERAND (arg0, 1)) < 0));
-
- switch (code)
- {
- case EXACT_DIV_EXPR:
- /* If this overflowed, it couldn't have been exact. */
- abort ();
-
- case TRUNC_DIV_EXPR:
- return omit_one_operand (type, integer_zero_node,
- TREE_OPERAND (arg0, 0));
-
- case FLOOR_DIV_EXPR:
- /* -1 or zero, depending on signs of remaining
- operand and constants. */
- tem = build (c_neg ? GE_EXPR : LE_EXPR, integer_type_node,
- TREE_OPERAND (arg0, 0),
- convert (type, integer_zero_node));
- return fold (build (NEGATE_EXPR, type,
- convert (type, fold (tem))));
-
- case CEIL_DIV_EXPR:
- /* Zero or 1, depending on signs of remaining
- operand and constants. */
- tem = build (c_neg ? LE_EXPR : GE_EXPR, integer_type_node,
- TREE_OPERAND (arg0, 0),
- convert (type, integer_zero_node));
-
- return convert (type, fold (tem));
- }
+ /* If no overflow, divide by C1*C2. */
+ return fold (build (code, type, TREE_OPERAND (arg0, 0), new_divisor));
}
- else
- /* If no overflow, divide by C1*C2. */
- return fold (build (code, type, TREE_OPERAND (arg0, 0), tem));
}
/* Look for ((a * C1) / C3) or (((a * C1) + C2) / C3),
@@ -4187,6 +3994,53 @@ fold (expr)
}
}
+ /* Note that this transformation might sometimes cause division-by-zero
+ to pass unnoticed. For example when C=2 and y=31. If that is unacceptable,
+ we could restrict the optimization to the case when log == 0. */
+
+ if ((code == FLOOR_DIV_EXPR || code == TRUNC_DIV_EXPR)
+ && TREE_CODE (arg1) == LSHIFT_EXPR)
+ {
+ int log;
+ if (TREE_CODE (TREE_OPERAND (arg1, 0)) == INTEGER_CST
+ && (log = exact_log2 (TREE_INT_CST_LOW (TREE_OPERAND (arg1, 0)))) >= 0
+ && TREE_INT_CST_HIGH (TREE_OPERAND (arg1, 0)) == 0)
+ {
+ tree cnt;
+ cnt = log == 0 ? TREE_OPERAND (arg1, 1)
+ : fold (build (PLUS_EXPR, TREE_TYPE (TREE_OPERAND (arg1, 1)),
+ TREE_OPERAND (arg1, 1),
+ build_int_2 (log, 0)));
+
+ if (TREE_UNSIGNED (type) || code == FLOOR_DIV_EXPR)
+ {
+ /* (x / (C << y)) where C = 1 << log => x >> (y + log) */
+ /* BUG: First TYPE here should always be unsigned to get logical
+ shift. How do we do that? */
+ return fold (build (RSHIFT_EXPR, type, arg0, cnt));
+ }
+
+ /* (x / (C << y)) when C = 1 << log =>
+ => (ashiftrt (plus x (and (ashiftrt x 31)
+ (not (lshift -1 cnt)))) cnt),
+ where cnt is y + log */
+ /* BUG: Several TYPE arguments here might be wrong. */
+ return
+ fold (build (RSHIFT_EXPR, type,
+ fold (build (PLUS_EXPR, type,
+ arg0,
+ fold (build (BIT_AND_EXPR, type,
+ fold (build (RSHIFT_EXPR, type,
+ arg0,
+ build_int_2 (TYPE_PRECISION (type) - 1, 0))),
+ fold (build1 (BIT_NOT_EXPR, type,
+ fold (build (LSHIFT_EXPR, type,
+ build_int_2 (~0, ~0),
+ cnt)))))))),
+ cnt));
+ }
+ }
+
goto binary;
case CEIL_MOD_EXPR: