1828 lines
47 KiB
C
1828 lines
47 KiB
C
/* Fold a constant sub-tree into a single node for C-compiler
|
||
Copyright (C) 1987, 1988 Free Software Foundation, Inc.
|
||
|
||
This file is part of GNU CC.
|
||
|
||
GNU CC 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; either version 1, or (at your option)
|
||
any later version.
|
||
|
||
GNU CC is distributed in the hope that it will be useful,
|
||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
GNU General Public License for more details.
|
||
|
||
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 arbitary 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.
|
||
@@ The routines that translate from the ap rep should
|
||
@@ warn if precision et. al. is lost.
|
||
@@ This would also make life easier when this technology is used
|
||
@@ for cross-compilers. */
|
||
|
||
|
||
/* There are only two entry points in this file:
|
||
fold and combine.
|
||
|
||
fold takes a tree as argument and returns a simplified tree.
|
||
|
||
combine takes a tree code for an arithmetic operation
|
||
and two operands that are trees for constant values
|
||
and returns the result of the specified operation on those values,
|
||
also as a tree. */
|
||
|
||
#include <stdio.h>
|
||
#include <setjmp.h>
|
||
#include "config.h"
|
||
#include "tree.h"
|
||
|
||
static void lshift_double ();
|
||
static void rshift_double ();
|
||
static void lrotate_double ();
|
||
static void rrotate_double ();
|
||
|
||
/* To do constant folding on INTEGER_CST nodes requires 64-bit arithmetic.
|
||
We do that by representing the 64-bit integer as 8 shorts,
|
||
with only 8 bits stored in each short, as a positive number. */
|
||
|
||
/* Unpack a 64-bit integer into 8 shorts.
|
||
LOW and HI are the integer, as two `int' pieces.
|
||
SHORTS points to the array of shorts. */
|
||
|
||
static void
|
||
encode (shorts, low, hi)
|
||
short *shorts;
|
||
int low, hi;
|
||
{
|
||
shorts[0] = low & 0xff;
|
||
shorts[1] = (low >> 8) & 0xff;
|
||
shorts[2] = (low >> 16) & 0xff;
|
||
shorts[3] = (low >> 24) & 0xff;
|
||
shorts[4] = hi & 0xff;
|
||
shorts[5] = (hi >> 8) & 0xff;
|
||
shorts[6] = (hi >> 16) & 0xff;
|
||
shorts[7] = (hi >> 24) & 0xff;
|
||
}
|
||
|
||
/* Pack an array of 8 shorts into a 64-bit integer.
|
||
SHORTS points to the array of shorts.
|
||
The integer is stored into *LOW and *HI as two `int' pieces. */
|
||
|
||
static void
|
||
decode (shorts, low, hi)
|
||
short *shorts;
|
||
int *low, *hi;
|
||
{
|
||
*low = (shorts[3] << 24) | (shorts[2] << 16) | (shorts[1] << 8) | shorts[0];
|
||
*hi = (shorts[7] << 24) | (shorts[6] << 16) | (shorts[5] << 8) | shorts[4];
|
||
}
|
||
|
||
/* Make the integer constant T valid for its type
|
||
by setting to 0 or 1 all the bits in the constant
|
||
that don't belong in the type. */
|
||
|
||
static void
|
||
force_fit_type (t)
|
||
tree t;
|
||
{
|
||
register int prec = TYPE_PRECISION (TREE_TYPE (t));
|
||
|
||
if (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE)
|
||
prec = BITS_PER_WORD;
|
||
|
||
/* First clear all bits that are beyond the type's precision. */
|
||
|
||
if (prec == 2 * HOST_BITS_PER_INT)
|
||
;
|
||
else if (prec > HOST_BITS_PER_INT)
|
||
{
|
||
TREE_INT_CST_HIGH (t)
|
||
&= ~((-1) << (prec - HOST_BITS_PER_INT));
|
||
}
|
||
else
|
||
{
|
||
TREE_INT_CST_HIGH (t) = 0;
|
||
if (prec < HOST_BITS_PER_INT)
|
||
TREE_INT_CST_LOW (t)
|
||
&= ~((-1) << prec);
|
||
}
|
||
|
||
/* If it's a signed type and value's sign bit is set, extend the sign. */
|
||
|
||
if (! TREE_UNSIGNED (TREE_TYPE (t))
|
||
&& prec != 2 * HOST_BITS_PER_INT
|
||
&& (prec > HOST_BITS_PER_INT
|
||
? TREE_INT_CST_HIGH (t) & (1 << (prec - HOST_BITS_PER_INT - 1))
|
||
: TREE_INT_CST_LOW (t) & (1 << (prec - 1))))
|
||
{
|
||
/* Value is negative:
|
||
set to 1 all the bits that are outside this type's precision. */
|
||
if (prec > HOST_BITS_PER_INT)
|
||
{
|
||
TREE_INT_CST_HIGH (t)
|
||
|= ((-1) << (prec - HOST_BITS_PER_INT));
|
||
}
|
||
else
|
||
{
|
||
TREE_INT_CST_HIGH (t) = -1;
|
||
if (prec < HOST_BITS_PER_INT)
|
||
TREE_INT_CST_LOW (t)
|
||
|= ((-1) << prec);
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Add two 64-bit integers with 64-bit result.
|
||
Each argument is given as two `int' pieces.
|
||
One argument is L1 and H1; the other, L2 and H2.
|
||
The value is stored as two `int' pieces in *LV and *HV.
|
||
We use the 8-shorts representation internally. */
|
||
|
||
static void
|
||
add_double (l1, h1, l2, h2, lv, hv)
|
||
int l1, h1, l2, h2;
|
||
int *lv, *hv;
|
||
{
|
||
short arg1[8];
|
||
short arg2[8];
|
||
register int carry = 0;
|
||
register int i;
|
||
|
||
encode (arg1, l1, h1);
|
||
encode (arg2, l2, h2);
|
||
|
||
for (i = 0; i < 8; i++)
|
||
{
|
||
carry += arg1[i] + arg2[i];
|
||
arg1[i] = carry & 0xff;
|
||
carry >>= 8;
|
||
}
|
||
|
||
decode (arg1, lv, hv);
|
||
}
|
||
|
||
/* Negate a 64-bit integers with 64-bit result.
|
||
The argument is given as two `int' pieces in L1 and H1.
|
||
The value is stored as two `int' pieces in *LV and *HV.
|
||
We use the 8-shorts representation internally. */
|
||
|
||
static void
|
||
neg_double (l1, h1, lv, hv)
|
||
int l1, h1;
|
||
int *lv, *hv;
|
||
{
|
||
if (l1 == 0)
|
||
{
|
||
*lv = 0;
|
||
*hv = - h1;
|
||
}
|
||
else
|
||
{
|
||
*lv = - l1;
|
||
*hv = ~ h1;
|
||
}
|
||
}
|
||
|
||
/* Multiply two 64-bit integers with 64-bit result.
|
||
Each argument is given as two `int' pieces.
|
||
One argument is L1 and H1; the other, L2 and H2.
|
||
The value is stored as two `int' pieces in *LV and *HV.
|
||
We use the 8-shorts representation internally. */
|
||
|
||
static void
|
||
mul_double (l1, h1, l2, h2, lv, hv)
|
||
int l1, h1, l2, h2;
|
||
int *lv, *hv;
|
||
{
|
||
short arg1[8];
|
||
short arg2[8];
|
||
short prod[16];
|
||
register int carry = 0;
|
||
register int i, j, k;
|
||
|
||
/* These two cases are used extensively, arising from pointer
|
||
combinations. */
|
||
if (h2 == 0)
|
||
{
|
||
if (l2 == 2)
|
||
{
|
||
unsigned temp = l1 + l1;
|
||
*hv = h1 * 2 + (temp < l1);
|
||
*lv = temp;
|
||
return;
|
||
}
|
||
if (l2 == 4)
|
||
{
|
||
unsigned temp = l1 + l1;
|
||
h1 = h1 * 4 + (temp < l1) << 1;
|
||
l1 = temp;
|
||
temp += temp;
|
||
h1 += (temp < l1);
|
||
*lv = temp;
|
||
*hv = h1;
|
||
return;
|
||
}
|
||
if (l2 == 8)
|
||
{
|
||
unsigned temp = l1 + l1;
|
||
h1 = h1 * 8 + (temp < l1) << 2;
|
||
l1 = temp;
|
||
temp += temp;
|
||
h1 += (temp < l1) << 1;
|
||
l1 = temp;
|
||
temp += temp;
|
||
h1 += (temp < l1);
|
||
*lv = temp;
|
||
*hv = h1;
|
||
return;
|
||
}
|
||
}
|
||
|
||
encode (arg1, l1, h1);
|
||
encode (arg2, l2, h2);
|
||
|
||
bzero (prod, sizeof prod);
|
||
|
||
for (i = 0; i < 8; i++)
|
||
for (j = 0; j < 8; j++)
|
||
{
|
||
k = i + j;
|
||
carry = arg1[i] * arg2[j];
|
||
while (carry)
|
||
{
|
||
carry += prod[k];
|
||
prod[k] = carry & 0xff;
|
||
carry >>= 8;
|
||
k++;
|
||
}
|
||
}
|
||
|
||
decode (prod, lv, hv); /* @@decode ignores prod[8] -> prod[15] */
|
||
}
|
||
|
||
/* Shift the 64-bit integer in L1, H1 left by COUNT places
|
||
keeping only PREC bits of result.
|
||
Shift right if COUNT is negative.
|
||
ARITH nonzero specifies arithmetic shifting; otherwise use logical shift.
|
||
Store the value as two `int' pieces in *LV and *HV. */
|
||
|
||
static void
|
||
lshift_double (l1, h1, count, prec, lv, hv, arith)
|
||
int l1, h1, count, prec;
|
||
int *lv, *hv;
|
||
int arith;
|
||
{
|
||
short arg1[8];
|
||
register int i;
|
||
register int carry;
|
||
|
||
if (count < 0)
|
||
{
|
||
rshift_double (l1, h1, - count, prec, lv, hv, arith);
|
||
return;
|
||
}
|
||
|
||
encode (arg1, l1, h1);
|
||
if (prec < HOST_BITS_PER_INT)
|
||
count &= (1 << prec) - 1;
|
||
|
||
while (count > 0)
|
||
{
|
||
carry = 0;
|
||
for (i = 0; i < 8; i++)
|
||
{
|
||
carry += arg1[i] << 1;
|
||
arg1[i] = carry & 0xff;
|
||
carry >>= 8;
|
||
}
|
||
count--;
|
||
}
|
||
|
||
decode (arg1, lv, hv);
|
||
}
|
||
|
||
/* Shift the 64-bit integer in L1, H1 right by COUNT places
|
||
keeping only PREC bits of result. COUNT must be positive.
|
||
ARITH nonzero specifies arithmetic shifting; otherwise use logical shift.
|
||
Store the value as two `int' pieces in *LV and *HV. */
|
||
|
||
static void
|
||
rshift_double (l1, h1, count, prec, lv, hv, arith)
|
||
int l1, h1, count, prec;
|
||
int *lv, *hv;
|
||
int arith;
|
||
{
|
||
short arg1[8];
|
||
register int i;
|
||
register int carry;
|
||
|
||
encode (arg1, l1, h1);
|
||
if (prec < HOST_BITS_PER_INT)
|
||
count &= (1 << prec) - 1;
|
||
|
||
carry = arith && arg1[7] >> 7;
|
||
while (count > 0)
|
||
{
|
||
for (i = 7; i >= 0; i--)
|
||
{
|
||
carry <<= 8;
|
||
carry += arg1[i];
|
||
arg1[i] = (carry >> 1) & 0xff;
|
||
}
|
||
count--;
|
||
}
|
||
|
||
decode (arg1, lv, hv);
|
||
}
|
||
|
||
/* Rotate the 64-bit 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 `int' pieces in *LV and *HV. */
|
||
|
||
static void
|
||
lrotate_double (l1, h1, count, prec, lv, hv)
|
||
int l1, h1, count, prec;
|
||
int *lv, *hv;
|
||
{
|
||
short arg1[8];
|
||
register int i;
|
||
register int carry;
|
||
|
||
if (count < 0)
|
||
{
|
||
rrotate_double (l1, h1, - count, prec, lv, hv);
|
||
return;
|
||
}
|
||
|
||
encode (arg1, l1, h1);
|
||
if (prec < HOST_BITS_PER_INT)
|
||
count &= (1 << prec) - 1;
|
||
|
||
carry = arg1[7] >> 7;
|
||
while (count > 0)
|
||
{
|
||
for (i = 0; i < 8; i++)
|
||
{
|
||
carry += arg1[i] << 1;
|
||
arg1[i] = carry & 0xff;
|
||
carry >>= 8;
|
||
}
|
||
count--;
|
||
}
|
||
|
||
decode (arg1, lv, hv);
|
||
}
|
||
|
||
/* Rotate the 64-bit integer in L1, H1 left by COUNT places
|
||
keeping only PREC bits of result. COUNT must be positive.
|
||
Store the value as two `int' pieces in *LV and *HV. */
|
||
|
||
static void
|
||
rrotate_double (l1, h1, count, prec, lv, hv)
|
||
int l1, h1, count, prec;
|
||
int *lv, *hv;
|
||
{
|
||
short arg1[8];
|
||
register int i;
|
||
register int carry;
|
||
|
||
encode (arg1, l1, h1);
|
||
if (prec < HOST_BITS_PER_INT)
|
||
count &= (1 << prec) - 1;
|
||
|
||
carry = arg1[0] & 1;
|
||
while (count > 0)
|
||
{
|
||
for (i = 7; i >= 0; i--)
|
||
{
|
||
carry <<= 8;
|
||
carry += arg1[i];
|
||
arg1[i] = (carry >> 1) & 0xff;
|
||
}
|
||
count--;
|
||
}
|
||
|
||
decode (arg1, lv, hv);
|
||
}
|
||
|
||
/* Divide 64 bit integer LNUM, HNUM by 64 bit integer LDEN, HDEN
|
||
for a quotient (stored in *LQUO, *HQUO) and remainder (in *LREM, *HREM).
|
||
CODE is a tree code for a kind of division, one of
|
||
TRUNC_DIV_EXPR, FLOOR_DIV_EXPR, CEIL_DIV_EXPR, ROUND_DIV_EXPR
|
||
or EXACT_DIV_EXPR
|
||
It controls how the quotient is rounded to a integer.
|
||
UNS nonzero says do unsigned division. */
|
||
|
||
static void
|
||
div_and_round_double (code, uns,
|
||
lnum_orig, hnum_orig, lden_orig, hden_orig,
|
||
lquo, hquo, lrem, hrem)
|
||
enum tree_code code;
|
||
int uns;
|
||
int lnum_orig, hnum_orig; /* num == numerator == dividend */
|
||
int lden_orig, hden_orig; /* den == denominator == divisor */
|
||
int *lquo, *hquo, *lrem, *hrem;
|
||
{
|
||
int quo_neg = 0;
|
||
short num[9], den[8], quo[8]; /* extra element for scaling. */
|
||
register int i, j, work;
|
||
register int carry = 0;
|
||
int lnum = lnum_orig, hnum = hnum_orig;
|
||
int lden = lden_orig, hden = hden_orig;
|
||
|
||
if ((hden == 0) && (lden == 0))
|
||
abort ();
|
||
|
||
/* calculate quotient sign and convert operands to unsigned. */
|
||
if (!uns)
|
||
{
|
||
if (hden < 0)
|
||
{
|
||
quo_neg = ~ quo_neg;
|
||
neg_double (lden, hden, &lden, &hden);
|
||
}
|
||
if (hnum < 0)
|
||
{
|
||
quo_neg = ~ quo_neg;
|
||
neg_double (lnum, hnum, &lnum, &hnum);
|
||
}
|
||
}
|
||
|
||
if (hnum == 0 && hden == 0)
|
||
{ /* single precision */
|
||
*hquo = *hrem = 0;
|
||
*lquo = (unsigned) lnum / lden; /* rounds toward zero since positive args */
|
||
goto finish_up;
|
||
}
|
||
|
||
if (hnum == 0)
|
||
{ /* trivial case: dividend < divisor */
|
||
/* hden != 0 already checked. */
|
||
*hquo = *lquo = 0;
|
||
*hrem = hnum;
|
||
*lrem = lnum;
|
||
goto finish_up;
|
||
}
|
||
|
||
bzero (quo, sizeof quo);
|
||
|
||
bzero (num, sizeof num); /* to zero 9th element */
|
||
bzero (den, sizeof den);
|
||
|
||
encode (num, lnum, hnum);
|
||
encode (den, lden, hden);
|
||
|
||
if (hden == 0)
|
||
{ /* simpler algorithm */
|
||
/* hnum != 0 already checked. */
|
||
for (i = 7; i >= 0; i--)
|
||
{
|
||
work = num[i] + (carry << 8);
|
||
quo[i] = work / lden;
|
||
carry = work % lden;
|
||
}
|
||
}
|
||
else { /* full double precision,
|
||
with thanks to Don Knuth's
|
||
"Semi-Numericial Algorithms". */
|
||
#define BASE 256
|
||
int quo_est, scale, num_hi_sig, den_hi_sig, quo_hi_sig;
|
||
|
||
/* Find the highest non-zero divisor digit. */
|
||
for (i = 7; ; i--)
|
||
if (den[i] != 0) {
|
||
den_hi_sig = i;
|
||
break;
|
||
}
|
||
for (i = 7; ; 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. */
|
||
|
||
scale = BASE / (den[den_hi_sig] + 1);
|
||
if (scale > 1) { /* scale divisor and dividend */
|
||
carry = 0;
|
||
for (i = 0; i <= 8; i++) {
|
||
work = (num[i] * scale) + carry;
|
||
num[i] = work & 0xff;
|
||
carry = work >> 8;
|
||
if (num[i] != 0) num_hi_sig = i;
|
||
}
|
||
carry = 0;
|
||
for (i = 0; i <= 7; i++) {
|
||
work = (den[i] * scale) + carry;
|
||
den[i] = work & 0xff;
|
||
carry = work >> 8;
|
||
if (den[i] != 0) den_hi_sig = i;
|
||
}
|
||
}
|
||
|
||
/* Main loop */
|
||
for (i = quo_hi_sig; i > 0; i--) {
|
||
/* quess 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. */
|
||
|
||
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]);
|
||
if (num[num_hi] != den[den_hi_sig]) {
|
||
quo_est = work / den[den_hi_sig];
|
||
}
|
||
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]))) {
|
||
quo_est--;
|
||
}
|
||
|
||
/* try quo_est as the quotient digit, by multiplying the
|
||
divisor by quo_est and subtracting from the remaining dividend. */
|
||
|
||
carry = 0;
|
||
|
||
for (j = 0; j <= den_hi_sig; j++) {
|
||
int digit;
|
||
|
||
work = num[i + j] - (quo_est * den[j]) + carry;
|
||
digit = work & 0xff;
|
||
carry = work >> 8;
|
||
if (digit < 0) {
|
||
digit += BASE;
|
||
carry--;
|
||
}
|
||
num[i + j] = digit;
|
||
}
|
||
|
||
/* if quo_est was high by one, then num[i] went negative and
|
||
we need to correct things. */
|
||
|
||
if (num[num_hi] < 0) {
|
||
quo_est--;
|
||
carry = 0; /* add divisor back in */
|
||
for (j = 0; j <= den_hi_sig; j++) {
|
||
work = num[i + j] + den[j] + carry;
|
||
if (work > BASE) {
|
||
work -= BASE;
|
||
carry = 1;
|
||
}
|
||
else {
|
||
carry = 0;
|
||
}
|
||
num[i + j] = work;
|
||
}
|
||
num [num_hi] += carry;
|
||
}
|
||
|
||
/* store the quotient digit. */
|
||
quo[i - 1] = quo_est;
|
||
}
|
||
}
|
||
|
||
decode (quo, lquo, hquo);
|
||
|
||
finish_up:
|
||
/* if result is negative, make it so. */
|
||
if (quo_neg)
|
||
neg_double (*lquo, *hquo, lquo, hquo);
|
||
|
||
/* compute trial remainder: rem = num - (quo * den) */
|
||
mul_double (*lquo, *hquo, lden_orig, hden_orig, lrem, hrem);
|
||
neg_double (*lrem, *hrem, lrem, hrem);
|
||
add_double (lnum_orig, hnum_orig, *lrem, *hrem, lrem, hrem);
|
||
|
||
switch (code)
|
||
{
|
||
case TRUNC_DIV_EXPR:
|
||
case TRUNC_MOD_EXPR: /* round toward zero */
|
||
case EXACT_DIV_EXPR: /* for this one, it shouldn't matter */
|
||
return;
|
||
|
||
case FLOOR_DIV_EXPR:
|
||
case FLOOR_MOD_EXPR: /* round toward negative infinity */
|
||
if (quo_neg && (*lrem != 0 || *hrem != 0)) /* ratio < 0 && rem != 0 */
|
||
{
|
||
/* quo = quo - 1; */
|
||
add_double (*lquo, *hquo, -1, -1, lquo, hquo);
|
||
}
|
||
else return;
|
||
break;
|
||
|
||
case CEIL_DIV_EXPR:
|
||
case CEIL_MOD_EXPR: /* round toward positive infinity */
|
||
if (!quo_neg && (*lrem != 0 || *hrem != 0)) /* ratio > 0 && rem != 0 */
|
||
{
|
||
add_double (*lquo, *hquo, 1, 0, lquo, hquo);
|
||
}
|
||
else return;
|
||
break;
|
||
|
||
case ROUND_DIV_EXPR:
|
||
case ROUND_MOD_EXPR: /* round to closest integer */
|
||
{
|
||
int labs_rem = *lrem, habs_rem = *hrem;
|
||
int labs_den = lden, habs_den = hden, ltwice, htwice;
|
||
|
||
/* get absolute values */
|
||
if (*hrem < 0) neg_double (*lrem, *hrem, &labs_rem, &habs_rem);
|
||
if (hden < 0) neg_double (lden, hden, &labs_den, &habs_den);
|
||
|
||
/* if (2 * abs (lrem) >= abs (lden)) */
|
||
mul_double (2, 0, labs_rem, habs_rem, <wice, &htwice);
|
||
if (((unsigned) habs_den < (unsigned) htwice)
|
||
|| (((unsigned) habs_den == (unsigned) htwice)
|
||
&& ((unsigned) labs_den < (unsigned) ltwice)))
|
||
{
|
||
if (*hquo < 0)
|
||
/* quo = quo - 1; */
|
||
add_double (*lquo, *hquo, -1, -1, lquo, hquo);
|
||
else
|
||
/* quo = quo + 1; */
|
||
add_double (*lquo, *hquo, 1, 0, lquo, hquo);
|
||
}
|
||
else return;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
abort ();
|
||
}
|
||
|
||
/* compute true remainder: rem = num - (quo * den) */
|
||
mul_double (*lquo, *hquo, lden_orig, hden_orig, lrem, hrem);
|
||
neg_double (*lrem, *hrem, lrem, hrem);
|
||
add_double (lnum_orig, hnum_orig, *lrem, *hrem, lrem, hrem);
|
||
}
|
||
|
||
/* Split a tree IN into a constant and a variable part
|
||
that could be combined with CODE to make IN.
|
||
CODE must be a commutative arithmetic operation.
|
||
Store the constant part into *CONP and the variable in &VARP.
|
||
Return 1 if this was done; zero means the tree IN did not decompose
|
||
this way.
|
||
|
||
If CODE is PLUS_EXPR we also split trees that use MINUS_EXPR.
|
||
Therefore, we must tell the caller whether the variable part
|
||
was subtracted. We do this by storing 1 or -1 into *VARSIGNP.
|
||
The value stored is the coefficient for the variable term.
|
||
The constant term we return should always be added;
|
||
we negate it if necessary. */
|
||
|
||
static int
|
||
split_tree (in, code, varp, conp, varsignp)
|
||
tree in;
|
||
enum tree_code code;
|
||
tree *varp, *conp;
|
||
int *varsignp;
|
||
{
|
||
register tree outtype = TREE_TYPE (in);
|
||
*varp = 0;
|
||
*conp = 0;
|
||
|
||
/* Strip any conversions that don't change the machine mode. */
|
||
while ((TREE_CODE (in) == NOP_EXPR
|
||
|| TREE_CODE (in) == CONVERT_EXPR)
|
||
&& (TYPE_MODE (TREE_TYPE (in))
|
||
== TYPE_MODE (TREE_TYPE (TREE_OPERAND (in, 0)))))
|
||
in = TREE_OPERAND (in, 0);
|
||
|
||
if (TREE_CODE (in) == code
|
||
|| (TREE_CODE (TREE_TYPE (in)) != REAL_TYPE
|
||
/* We can associate addition and subtraction together
|
||
(even though the C standard doesn't say so)
|
||
for integers because the value is not affected.
|
||
For reals, the value might be affected, so we can't. */
|
||
&&
|
||
((code == PLUS_EXPR && TREE_CODE (in) == MINUS_EXPR)
|
||
|| (code == MINUS_EXPR && TREE_CODE (in) == PLUS_EXPR))))
|
||
{
|
||
enum tree_code code = TREE_CODE (TREE_OPERAND (in, 0));
|
||
if (code == INTEGER_CST)
|
||
{
|
||
*conp = TREE_OPERAND (in, 0);
|
||
*varp = TREE_OPERAND (in, 1);
|
||
if (TREE_TYPE (*varp) != outtype)
|
||
*varp = convert (outtype, *varp);
|
||
*varsignp = (TREE_CODE (in) == MINUS_EXPR) ? -1 : 1;
|
||
return 1;
|
||
}
|
||
if (TREE_LITERAL (TREE_OPERAND (in, 1)))
|
||
{
|
||
*conp = TREE_OPERAND (in, 1);
|
||
*varp = TREE_OPERAND (in, 0);
|
||
*varsignp = 1;
|
||
if (TREE_TYPE (*varp) != outtype)
|
||
*varp = convert (outtype, *varp);
|
||
if (TREE_CODE (in) == MINUS_EXPR)
|
||
{
|
||
/* If operation is subtraction and constant is second,
|
||
must negate it to get an additive constant.
|
||
And this cannot be done unless it is a manifest constant.
|
||
It could also be the address of a static variable.
|
||
We cannot negate that, so give up. */
|
||
if (TREE_CODE (*conp) == INTEGER_CST)
|
||
*conp = combine (MINUS_EXPR, integer_zero_node, *conp);
|
||
else
|
||
return 0;
|
||
}
|
||
return 1;
|
||
}
|
||
if (TREE_LITERAL (TREE_OPERAND (in, 0)))
|
||
{
|
||
*conp = TREE_OPERAND (in, 0);
|
||
*varp = TREE_OPERAND (in, 1);
|
||
if (TREE_TYPE (*varp) != outtype)
|
||
*varp = convert (outtype, *varp);
|
||
*varsignp = (TREE_CODE (in) == MINUS_EXPR) ? -1 : 1;
|
||
return 1;
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/* Combine two constants NUM and ARG2 under operation CODE
|
||
to produce a new constant.
|
||
We assume ARG1 and ARG2 have the same data type,
|
||
or at least are the same kind of constant and the same machine mode. */
|
||
|
||
/* Handle floating overflow for `combine'. */
|
||
static jmp_buf combine_error;
|
||
|
||
tree
|
||
combine (code, arg1, arg2)
|
||
enum tree_code code;
|
||
register tree arg1, arg2;
|
||
{
|
||
if (TREE_CODE (arg1) == INTEGER_CST)
|
||
{
|
||
register int int1l = TREE_INT_CST_LOW (arg1);
|
||
register int int1h = TREE_INT_CST_HIGH (arg1);
|
||
int int2l = TREE_INT_CST_LOW (arg2);
|
||
int int2h = TREE_INT_CST_HIGH (arg2);
|
||
int low, hi;
|
||
int garbagel, garbageh;
|
||
register tree t;
|
||
int uns = TREE_UNSIGNED (TREE_TYPE (arg1));
|
||
|
||
switch (code)
|
||
{
|
||
case BIT_IOR_EXPR:
|
||
t = build_int_2 (int1l | int2l, int1h | int2h);
|
||
break;
|
||
|
||
case BIT_XOR_EXPR:
|
||
t = build_int_2 (int1l ^ int2l, int1h ^ int2h);
|
||
break;
|
||
|
||
case BIT_AND_EXPR:
|
||
t = build_int_2 (int1l & int2l, int1h & int2h);
|
||
break;
|
||
|
||
case BIT_ANDTC_EXPR:
|
||
t = build_int_2 (int1l & ~int2l, int1h & ~int2h);
|
||
break;
|
||
|
||
case RSHIFT_EXPR:
|
||
int2l = - int2l;
|
||
case LSHIFT_EXPR:
|
||
lshift_double (int1l, int1h, int2l,
|
||
TYPE_PRECISION (TREE_TYPE (arg1)),
|
||
&low, &hi,
|
||
!uns);
|
||
t = build_int_2 (low, hi);
|
||
break;
|
||
|
||
case RROTATE_EXPR:
|
||
int2l = - int2l;
|
||
case LROTATE_EXPR:
|
||
lrotate_double (int1l, int1h, int2l,
|
||
TYPE_PRECISION (TREE_TYPE (arg1)),
|
||
&low, &hi);
|
||
t = build_int_2 (low, hi);
|
||
break;
|
||
|
||
case PLUS_EXPR:
|
||
if (int1h == 0)
|
||
{
|
||
int2l += int1l;
|
||
if ((unsigned) int2l < int1l)
|
||
int2h += 1;
|
||
t = build_int_2 (int2l, int2h);
|
||
break;
|
||
}
|
||
if (int2h == 0)
|
||
{
|
||
int1l += int2l;
|
||
if ((unsigned) int1l < int2l)
|
||
int1h += 1;
|
||
t = build_int_2 (int1l, int1h);
|
||
break;
|
||
}
|
||
add_double (int1l, int1h, int2l, int2h, &low, &hi);
|
||
t = build_int_2 (low, hi);
|
||
break;
|
||
|
||
case MINUS_EXPR:
|
||
if (int1h == 0 && int1l == 0)
|
||
{
|
||
t = build_int_2 (- int2l, - int2h);
|
||
break;
|
||
}
|
||
if (int2h == 0 && int2l == 0)
|
||
{
|
||
t = build_int_2 (int1l, int1h);
|
||
break;
|
||
}
|
||
neg_double (int2l, int2h, &int2l, &int2h);
|
||
add_double (int1l, int1h, int2l, int2h, &low, &hi);
|
||
t = build_int_2 (low, hi);
|
||
break;
|
||
|
||
case MULT_EXPR:
|
||
/* Optimize simple cases. */
|
||
if (int1h == 0)
|
||
{
|
||
unsigned 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:
|
||
temp = int2l + int2l;
|
||
int2h = int2h * 2 + (temp < int2l);
|
||
t = build_int_2 (temp, int2h);
|
||
goto got_it;
|
||
case 3:
|
||
temp = int2l + int2l + int2l;
|
||
int2h = int2h * 3 + (temp < int2l);
|
||
t = build_int_2 (temp, int2h);
|
||
goto got_it;
|
||
case 4:
|
||
temp = int2l + int2l;
|
||
int2h = int2h * 4 + (temp < int2l) << 1;
|
||
int2l = temp;
|
||
temp += temp;
|
||
int2h += (temp < int2l);
|
||
t = build_int_2 (temp, int2h);
|
||
goto got_it;
|
||
case 8:
|
||
temp = int2l + int2l;
|
||
int2h = int2h * 8 + (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;
|
||
}
|
||
}
|
||
|
||
mul_double (int1l, int1h, int2l, int2h, &low, &hi);
|
||
t = build_int_2 (low, hi);
|
||
break;
|
||
|
||
case TRUNC_DIV_EXPR: case ROUND_DIV_EXPR:
|
||
case FLOOR_DIV_EXPR: case CEIL_DIV_EXPR:
|
||
case EXACT_DIV_EXPR:
|
||
if (int2h == 0 && int2l == 1)
|
||
{
|
||
t = build_int_2 (int1l, int1h);
|
||
break;
|
||
}
|
||
if (int1l == int2l && int1h == int2h)
|
||
{
|
||
if ((int1l | int1h) == 0)
|
||
abort ();
|
||
t = build_int_2 (1, 0);
|
||
break;
|
||
}
|
||
div_and_round_double (code, uns, int1l, int1h, int2l, int2h,
|
||
&low, &hi, &garbagel, &garbageh);
|
||
t = build_int_2 (low, hi);
|
||
break;
|
||
|
||
case TRUNC_MOD_EXPR: case ROUND_MOD_EXPR:
|
||
case FLOOR_MOD_EXPR: case CEIL_MOD_EXPR:
|
||
div_and_round_double (code, uns, int1l, int1h, int2l, int2h,
|
||
&garbagel, &garbageh, &low, &hi);
|
||
t = build_int_2 (low, hi);
|
||
break;
|
||
|
||
case MIN_EXPR:
|
||
case MAX_EXPR:
|
||
if (uns)
|
||
{
|
||
low = (((unsigned) int1h < (unsigned) int2h)
|
||
|| (((unsigned) int1h == (unsigned) int2h)
|
||
&& ((unsigned) int1l < (unsigned) int2l)));
|
||
}
|
||
else
|
||
{
|
||
low = ((int1h < int2h)
|
||
|| ((int1h == int2h)
|
||
&& ((unsigned) int1l < (unsigned) int2l)));
|
||
}
|
||
if (low == (code == MIN_EXPR))
|
||
t = build_int_2 (int1l, int1h);
|
||
else
|
||
t = build_int_2 (int2l, int2h);
|
||
break;
|
||
|
||
default:
|
||
abort ();
|
||
}
|
||
got_it:
|
||
TREE_TYPE (t) = TREE_TYPE (arg1);
|
||
force_fit_type (t);
|
||
return t;
|
||
}
|
||
#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
|
||
if (TREE_CODE (arg1) == REAL_CST)
|
||
{
|
||
register REAL_VALUE_TYPE d1 = TREE_REAL_CST (arg1);
|
||
register REAL_VALUE_TYPE d2 = TREE_REAL_CST (arg2);
|
||
register REAL_VALUE_TYPE value;
|
||
|
||
if (setjmp (combine_error))
|
||
return build (code, TREE_TYPE (arg1), arg1, arg2);
|
||
set_float_handler (combine_error);
|
||
|
||
#ifdef REAL_ARITHMETIC
|
||
REAL_ARITHMETIC (value, code, d1, d2);
|
||
#else
|
||
switch (code)
|
||
{
|
||
case PLUS_EXPR:
|
||
value = d1 + d2;
|
||
break;
|
||
|
||
case MINUS_EXPR:
|
||
value = d1 - d2;
|
||
break;
|
||
|
||
case MULT_EXPR:
|
||
value = d1 * d2;
|
||
break;
|
||
|
||
case RDIV_EXPR:
|
||
if (d2 == 0)
|
||
abort ();
|
||
|
||
value = d1 / d2;
|
||
break;
|
||
|
||
case MIN_EXPR:
|
||
value = d1 < d2 ? d1 : d2;
|
||
break;
|
||
|
||
case MAX_EXPR:
|
||
value = d1 > d2 ? d1 : d2;
|
||
break;
|
||
|
||
default:
|
||
abort ();
|
||
}
|
||
#endif /* no REAL_ARITHMETIC */
|
||
set_float_handler (0);
|
||
return build_real (TREE_TYPE (arg1), value);
|
||
}
|
||
#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
|
||
if (TREE_CODE (arg1) == COMPLEX_CST)
|
||
{
|
||
register tree r1 = TREE_REALPART (arg1);
|
||
register tree i1 = TREE_IMAGPART (arg1);
|
||
register tree r2 = TREE_REALPART (arg2);
|
||
register tree i2 = TREE_IMAGPART (arg2);
|
||
register tree t;
|
||
|
||
switch (code)
|
||
{
|
||
case PLUS_EXPR:
|
||
t = build_complex (combine (PLUS_EXPR, r1, r2),
|
||
combine (PLUS_EXPR, i1, i2));
|
||
break;
|
||
|
||
case MINUS_EXPR:
|
||
t = build_complex (combine (MINUS_EXPR, r1, r2),
|
||
combine (MINUS_EXPR, i1, i2));
|
||
break;
|
||
|
||
case MULT_EXPR:
|
||
t = build_complex (combine (MINUS_EXPR,
|
||
combine (MULT_EXPR, r1, r2),
|
||
combine (MULT_EXPR, i1, i2)),
|
||
combine (PLUS_EXPR,
|
||
combine (MULT_EXPR, r1, i2),
|
||
combine (MULT_EXPR, i1, r2)));
|
||
break;
|
||
|
||
case RDIV_EXPR:
|
||
{
|
||
register tree magsquared
|
||
= combine (PLUS_EXPR,
|
||
combine (MULT_EXPR, r2, r2),
|
||
combine (MULT_EXPR, i2, i2));
|
||
t = build_complex (combine (RDIV_EXPR,
|
||
combine (PLUS_EXPR,
|
||
combine (MULT_EXPR, r1, r2),
|
||
combine (MULT_EXPR, i1, i2)),
|
||
magsquared),
|
||
combine (RDIV_EXPR,
|
||
combine (MINUS_EXPR,
|
||
combine (MULT_EXPR, i1, r2),
|
||
combine (MULT_EXPR, r1, i2)),
|
||
magsquared));
|
||
}
|
||
break;
|
||
|
||
default:
|
||
abort ();
|
||
}
|
||
TREE_TYPE (t) = TREE_TYPE (arg1);
|
||
return t;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/* Given T, a tree representing type conversion of a constant,
|
||
return a constant tree representing the result of conversion. */
|
||
|
||
static tree
|
||
fold_convert (t)
|
||
register tree t;
|
||
{
|
||
register tree arg1 = TREE_OPERAND (t, 0);
|
||
register tree type = TREE_TYPE (t);
|
||
|
||
if (TREE_CODE (type) == POINTER_TYPE
|
||
|| TREE_CODE (type) == INTEGER_TYPE
|
||
|| TREE_CODE (type) == ENUMERAL_TYPE)
|
||
{
|
||
if (TREE_CODE (arg1) == INTEGER_CST)
|
||
{
|
||
/* Given an integer constant, make new constant with new type,
|
||
appropriately sign-extended or truncated. */
|
||
t = build_int_2 (TREE_INT_CST_LOW (arg1),
|
||
TREE_INT_CST_HIGH (arg1));
|
||
TREE_TYPE (t) = type;
|
||
force_fit_type (t);
|
||
}
|
||
#if !defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
|
||
else if (TREE_CODE (arg1) == REAL_CST)
|
||
{
|
||
if (REAL_VALUES_LESS (real_value_from_int_cst (TYPE_MAX_VALUE (type)),
|
||
TREE_REAL_CST (arg1))
|
||
|| REAL_VALUES_LESS (TREE_REAL_CST (arg1),
|
||
real_value_from_int_cst (TYPE_MIN_VALUE (type))))
|
||
{
|
||
warning ("real constant out of range for integer conversion");
|
||
return t;
|
||
}
|
||
#ifndef REAL_ARITHMETIC
|
||
{
|
||
REAL_VALUE_TYPE d;
|
||
int low, high;
|
||
int half_word = 1 << (HOST_BITS_PER_INT / 2);
|
||
|
||
d = TREE_REAL_CST (arg1);
|
||
if (d < 0)
|
||
d = -d;
|
||
|
||
high = (int) (d / half_word / half_word);
|
||
d -= (REAL_VALUE_TYPE) high * half_word * half_word;
|
||
low = (unsigned) d;
|
||
if (TREE_REAL_CST (arg1) < 0)
|
||
neg_double (low, high, &low, &high);
|
||
t = build_int_2 (low, high);
|
||
}
|
||
#else
|
||
{
|
||
int low, high;
|
||
REAL_VALUE_TO_INT (low, high, TREE_REAL_CST (arg1));
|
||
t = build_int_2 (low, high);
|
||
}
|
||
#endif
|
||
TREE_TYPE (t) = type;
|
||
force_fit_type (t);
|
||
}
|
||
#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
|
||
TREE_TYPE (t) = type;
|
||
}
|
||
else if (TREE_CODE (type) == REAL_TYPE)
|
||
{
|
||
#if !defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
|
||
if (TREE_CODE (arg1) == INTEGER_CST)
|
||
return build_real_from_int_cst (type, arg1);
|
||
#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
|
||
if (TREE_CODE (arg1) == REAL_CST)
|
||
return build_real (type, TREE_REAL_CST (arg1));
|
||
}
|
||
TREE_LITERAL (t) = 1;
|
||
return t;
|
||
}
|
||
|
||
/* Return nonzero if two constants (that are not manifest constants)
|
||
are necessarily equal. It detects only the easiest, common case of
|
||
equality. */
|
||
|
||
static int
|
||
operand_equal_p (arg0, arg1)
|
||
tree arg0, arg1;
|
||
{
|
||
while ((TREE_CODE (arg0) == NOP_EXPR
|
||
|| TREE_CODE (arg0) == CONVERT_EXPR)
|
||
&& TYPE_MODE (TREE_TYPE (arg0)) == TYPE_MODE (TREE_TYPE (TREE_OPERAND (arg0, 0))))
|
||
arg0 = TREE_OPERAND (arg0, 0);
|
||
while ((TREE_CODE (arg1) == NOP_EXPR
|
||
|| TREE_CODE (arg1) == CONVERT_EXPR)
|
||
&& TYPE_MODE (TREE_TYPE (arg1)) == TYPE_MODE (TREE_TYPE (TREE_OPERAND (arg1, 0))))
|
||
arg1 = TREE_OPERAND (arg1, 0);
|
||
|
||
if (TREE_CODE (arg0) == TREE_CODE (arg1)
|
||
&& TREE_CODE (arg0) == ADDR_EXPR
|
||
&& TREE_OPERAND (arg0, 0) == TREE_OPERAND (arg1, 0))
|
||
return 1;
|
||
return 0;
|
||
}
|
||
|
||
#if !defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
|
||
|
||
/* Return 1 if ARG is a real constant with value zero.
|
||
This function is not defined in the case where it is impossible
|
||
to tell whether a real constant is zero (for cross-compilation). */
|
||
|
||
static int
|
||
real_zerop (arg)
|
||
tree arg;
|
||
{
|
||
#ifdef REAL_IS_NOT_DOUBLE
|
||
tree t1 = build_real_from_int_cst (TREE_TYPE (arg), integer_zero_node);
|
||
return REAL_VALUES_EQUAL (TREE_REAL_CST (arg), TREE_REAL_CST (t1));
|
||
#else
|
||
return TREE_REAL_CST (arg) == 0;
|
||
#endif
|
||
}
|
||
#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
|
||
|
||
/* Perform constant folding and related simplification of EXPR.
|
||
The related simplifications include x*1 => x, x*0 => 0, etc.,
|
||
and application of the associative law.
|
||
NOP_EXPR conversions may be removed freely (as long as we
|
||
are careful not to change the C type of the overall expression)
|
||
We cannot simplify through a CONVERT_EXPR, FIX_EXPR or FLOAT_EXPR,
|
||
but we can constant-fold them if they have constant operands. */
|
||
|
||
tree
|
||
fold (expr)
|
||
tree expr;
|
||
{
|
||
register tree t = expr;
|
||
tree type = TREE_TYPE (expr);
|
||
register tree arg0, arg1;
|
||
register enum tree_code code = TREE_CODE (t);
|
||
register int kind;
|
||
|
||
/* WINS will be nonzero when the switch is done
|
||
if all operands are constant.
|
||
|
||
LOSES will be nonzero when the switch is done
|
||
if any operand is volatile.
|
||
This inhibits optimizations such as (foo () * 0) => 0.
|
||
But identity-element optimizations such as
|
||
(foo () * 1) => (foo ()) can be done even if LOSES is set. */
|
||
|
||
int wins = 1;
|
||
int loses = 0;
|
||
|
||
/* Return right away if already constant. */
|
||
if (TREE_LITERAL (t))
|
||
{
|
||
if (code == CONST_DECL)
|
||
return DECL_INITIAL (t);
|
||
return t;
|
||
}
|
||
|
||
kind = *tree_code_type[(int) code];
|
||
if (kind == 'e' || kind == 'r')
|
||
{
|
||
register int len = tree_code_length[(int) code];
|
||
register int i;
|
||
for (i = 0; i < len; i++)
|
||
{
|
||
if (TREE_OPERAND (t, i) == 0)
|
||
continue; /* Valid for CALL_EXPR, at least. */
|
||
if (TREE_CODE (TREE_OPERAND (t, i)) != INTEGER_CST
|
||
#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
|
||
&& TREE_CODE (TREE_OPERAND (t, i)) != REAL_CST
|
||
#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
|
||
)
|
||
/* Note that TREE_LITERAL isn't enough:
|
||
static var addresses are constant but we can't
|
||
do arithmetic on them. */
|
||
wins = 0;
|
||
if (TREE_VOLATILE (TREE_OPERAND (t, i)))
|
||
loses = 1;
|
||
}
|
||
arg0 = TREE_OPERAND (t, 0);
|
||
if (len > 1)
|
||
arg1 = TREE_OPERAND (t, 1);
|
||
}
|
||
|
||
/* Now WINS and LOSES are set as described above,
|
||
ARG0 is the first operand of EXPR,
|
||
and ARG1 is the second operand (if it has more than one operand). */
|
||
|
||
switch (code)
|
||
{
|
||
case INTEGER_CST:
|
||
case REAL_CST:
|
||
case STRING_CST:
|
||
case COMPLEX_CST:
|
||
case CONSTRUCTOR:
|
||
return t;
|
||
|
||
case CONST_DECL:
|
||
return fold (DECL_INITIAL (t));
|
||
|
||
case NOP_EXPR:
|
||
case FLOAT_EXPR:
|
||
case CONVERT_EXPR:
|
||
case FIX_TRUNC_EXPR:
|
||
/* Other kinds of FIX are not handled properly by fold_convert. */
|
||
if (!wins)
|
||
{
|
||
TREE_LITERAL (t) = TREE_LITERAL (arg0);
|
||
return t;
|
||
}
|
||
return fold_convert (t);
|
||
|
||
#if 0 /* This loses on &"foo"[0]. */
|
||
case ARRAY_REF:
|
||
{
|
||
int i;
|
||
|
||
/* Fold an expression like: "foo"[2] */
|
||
if (TREE_CODE (arg0) == STRING_CST
|
||
&& TREE_CODE (arg1) == INTEGER_CST
|
||
&& !TREE_INT_CST_HIGH (arg1)
|
||
&& (i = TREE_INT_CST_LOW (arg1)) < TREE_STRING_LENGTH (arg0))
|
||
{
|
||
t = build_int_2 (TREE_STRING_POINTER (arg0)[i], 0);
|
||
TREE_TYPE (t) = TREE_TYPE (TREE_TYPE (arg0));
|
||
force_fit_type (t);
|
||
}
|
||
}
|
||
return t;
|
||
#endif /* 0 */
|
||
|
||
case RANGE_EXPR:
|
||
TREE_LITERAL (t) = wins;
|
||
return t;
|
||
|
||
case NEGATE_EXPR:
|
||
if (wins)
|
||
{
|
||
if (TREE_CODE (arg0) == INTEGER_CST)
|
||
{
|
||
if (TREE_INT_CST_LOW (arg0) == 0)
|
||
t = build_int_2 (0, - TREE_INT_CST_HIGH (arg0));
|
||
else
|
||
t = build_int_2 (- TREE_INT_CST_LOW (arg0),
|
||
~ TREE_INT_CST_HIGH (arg0));
|
||
TREE_TYPE (t) = type;
|
||
force_fit_type (t);
|
||
}
|
||
else if (TREE_CODE (arg0) == REAL_CST)
|
||
t = build_real (type, REAL_VALUE_NEGATE (TREE_REAL_CST (arg0)));
|
||
TREE_TYPE (t) = type;
|
||
}
|
||
return t;
|
||
|
||
case ABS_EXPR:
|
||
if (wins)
|
||
{
|
||
if (TREE_CODE (arg0) == INTEGER_CST)
|
||
{
|
||
if (! TREE_UNSIGNED (type)
|
||
&& TREE_INT_CST_HIGH (arg0) < 0)
|
||
{
|
||
if (TREE_INT_CST_LOW (arg0) == 0)
|
||
t = build_int_2 (0, - TREE_INT_CST_HIGH (arg0));
|
||
else
|
||
t = build_int_2 (- TREE_INT_CST_LOW (arg0),
|
||
~ TREE_INT_CST_HIGH (arg0));
|
||
}
|
||
}
|
||
else if (TREE_CODE (arg0) == REAL_CST)
|
||
{
|
||
if (
|
||
#if defined (REAL_IS_NOT_DOUBLE)
|
||
REAL_VALUES_LESS (TREE_REAL_CST (arg0),
|
||
REAL_VALUE_ATOF ("0.0"))
|
||
#else
|
||
REAL_VALUES_LESS (TREE_REAL_CST (arg0), 0)
|
||
#endif
|
||
)
|
||
t = build_real (type,
|
||
REAL_VALUE_NEGATE (TREE_REAL_CST (arg0)));
|
||
}
|
||
TREE_TYPE (t) = type;
|
||
}
|
||
return t;
|
||
|
||
case BIT_NOT_EXPR:
|
||
if (wins)
|
||
{
|
||
if (TREE_CODE (arg0) == INTEGER_CST)
|
||
t = build_int_2 (~ TREE_INT_CST_LOW (arg0),
|
||
~ TREE_INT_CST_HIGH (arg0));
|
||
TREE_TYPE (t) = type;
|
||
force_fit_type (t);
|
||
}
|
||
return t;
|
||
|
||
case PLUS_EXPR:
|
||
if (integer_zerop (arg0))
|
||
return convert (type, arg1);
|
||
if (integer_zerop (arg1))
|
||
return convert (type, arg0);
|
||
associate:
|
||
/* In most languages, can't associate operations on floats
|
||
through parentheses. Rather than remember where the parentheses
|
||
were, we don't associate floats at all. It shouldn't matter much. */
|
||
if (TREE_CODE (type) == REAL_TYPE)
|
||
goto binary;
|
||
/* The varsign == -1 cases happen only for addition and subtraction.
|
||
It says that the arg that was split was really CON minus VAR.
|
||
The rest of the code applies to all associative operations. */
|
||
if (!wins)
|
||
{
|
||
tree var, con, tem;
|
||
int varsign;
|
||
|
||
if (split_tree (arg0, code, &var, &con, &varsign))
|
||
{
|
||
if (varsign == -1)
|
||
{
|
||
/* EXPR is (CON-VAR) +- ARG1. */
|
||
/* If it is + and VAR==ARG1, return just CONST. */
|
||
if (code == PLUS_EXPR && operand_equal_p (var, arg1))
|
||
return convert (TREE_TYPE (t), con);
|
||
|
||
/* Otherwise return (CON +- ARG1) - VAR. */
|
||
TREE_SET_CODE (t, MINUS_EXPR);
|
||
TREE_OPERAND (t, 1) = var;
|
||
TREE_OPERAND (t, 0)
|
||
= fold (build (code, TREE_TYPE (t), con, arg1));
|
||
}
|
||
else
|
||
{
|
||
/* EXPR is (VAR+CON) +- ARG1. */
|
||
/* If it is - and VAR==ARG1, return just CONST. */
|
||
if (code == MINUS_EXPR && operand_equal_p (var, arg1))
|
||
return convert (TREE_TYPE (t), con);
|
||
|
||
/* Otherwise return VAR +- (ARG1 +- CON). */
|
||
TREE_OPERAND (t, 1) = tem
|
||
= fold (build (code, TREE_TYPE (t), arg1, con));
|
||
TREE_OPERAND (t, 0) = var;
|
||
if (integer_zerop (tem)
|
||
&& (code == PLUS_EXPR || code == MINUS_EXPR))
|
||
return var;
|
||
/* If we have x +/- (c - d) [c an explicit integer]
|
||
change it to x -/+ (d - c) since if d is relocatable
|
||
then the latter can be a single immediate insn
|
||
and the former cannot. */
|
||
if (TREE_CODE (tem) == MINUS_EXPR
|
||
&& TREE_CODE (TREE_OPERAND (tem, 0)) == INTEGER_CST)
|
||
{
|
||
tree tem1 = TREE_OPERAND (tem, 1);
|
||
TREE_OPERAND (tem, 1) = TREE_OPERAND (tem, 0);
|
||
TREE_OPERAND (tem, 0) = tem1;
|
||
TREE_SET_CODE (t,
|
||
(code == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR));
|
||
}
|
||
}
|
||
return t;
|
||
}
|
||
|
||
if (split_tree (arg1, code, &var, &con, &varsign))
|
||
{
|
||
/* EXPR is ARG0 +- (CON +- VAR). */
|
||
if (varsign == -1)
|
||
TREE_SET_CODE (t,
|
||
(code == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR));
|
||
if (TREE_CODE (t) == MINUS_EXPR && operand_equal_p (var, arg0))
|
||
return convert (TREE_TYPE (t), con);
|
||
TREE_OPERAND (t, 0)
|
||
= fold (build (code, TREE_TYPE (t), arg0, con));
|
||
TREE_OPERAND (t, 1) = var;
|
||
if (integer_zerop (TREE_OPERAND (t, 0))
|
||
&& TREE_CODE (t) == PLUS_EXPR)
|
||
return convert (TREE_TYPE (t), var);
|
||
return t;
|
||
}
|
||
}
|
||
binary:
|
||
#if defined (REAL_IS_NOT_DOUBLE) && ! defined (REAL_ARITHMETIC)
|
||
if (TREE_CODE (arg1) == REAL_CST)
|
||
return t;
|
||
#endif /* REAL_IS_NOT_DOUBLE, and no REAL_ARITHMETIC */
|
||
{
|
||
register tree t1 = NULL_TREE;
|
||
if (wins)
|
||
t1 = combine (code, arg0, arg1);
|
||
if (t1 != NULL_TREE) return t1;
|
||
return t;
|
||
}
|
||
|
||
case MINUS_EXPR:
|
||
if (! wins && integer_zerop (arg0))
|
||
return build (NEGATE_EXPR, type, arg1);
|
||
if (integer_zerop (arg1))
|
||
return convert (type, arg0);
|
||
/* Fold &x - &x. This can happen from &x.foo - &x. */
|
||
if (operand_equal_p (arg0, arg1))
|
||
return convert (TREE_TYPE (t), integer_zero_node);
|
||
goto associate;
|
||
|
||
case MULT_EXPR:
|
||
if (!loses && integer_zerop (arg0))
|
||
return convert (type, arg0);
|
||
if (!loses && integer_zerop (arg1))
|
||
return convert (type, arg1);
|
||
if (integer_onep (arg0))
|
||
return convert (type, arg1);
|
||
if (integer_onep (arg1))
|
||
return convert (type, arg0);
|
||
goto associate;
|
||
|
||
case BIT_IOR_EXPR:
|
||
if (!loses && integer_all_onesp (arg0))
|
||
return convert (type, arg0);
|
||
if (!loses && integer_all_onesp (arg1))
|
||
return convert (type, arg1);
|
||
case BIT_XOR_EXPR:
|
||
if (integer_zerop (arg0))
|
||
return convert (type, arg1);
|
||
if (integer_zerop (arg1))
|
||
return convert (type, arg0);
|
||
goto associate;
|
||
|
||
case BIT_AND_EXPR:
|
||
if (integer_all_onesp (arg0))
|
||
return convert (type, arg1);
|
||
if (integer_all_onesp (arg1))
|
||
return convert (type, arg0);
|
||
if (!loses && integer_zerop (arg0))
|
||
return convert (type, arg0);
|
||
if (!loses && integer_zerop (arg1))
|
||
return convert (type, arg1);
|
||
/* Simplify ((int)c & 0x377) into (int)c, if c is unsigned char. */
|
||
if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == NOP_EXPR
|
||
&& TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg1, 0))))
|
||
{
|
||
int prec = TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg1, 0)));
|
||
if (prec < BITS_PER_WORD && prec < HOST_BITS_PER_INT
|
||
&& (~TREE_INT_CST_LOW (arg0) & ((1 << prec) - 1)) == 0)
|
||
return build (NOP_EXPR, type, TREE_OPERAND (arg1, 0));
|
||
}
|
||
if (TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg0) == NOP_EXPR
|
||
&& TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg0, 0))))
|
||
{
|
||
int prec = TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0)));
|
||
if (prec < BITS_PER_WORD && prec < HOST_BITS_PER_INT
|
||
&& (~TREE_INT_CST_LOW (arg1) & ((1 << prec) - 1)) == 0)
|
||
return build (NOP_EXPR, type, TREE_OPERAND (arg0, 0));
|
||
}
|
||
goto associate;
|
||
|
||
case BIT_ANDTC_EXPR:
|
||
if (integer_all_onesp (arg0))
|
||
return convert (type, arg1);
|
||
if (integer_zerop (arg1))
|
||
return convert (type, arg0);
|
||
if (!loses && integer_zerop (arg0))
|
||
return convert (type, arg0);
|
||
if (!loses && integer_all_onesp (arg1))
|
||
return combine (code, arg1, arg1);
|
||
goto binary;
|
||
|
||
case TRUNC_DIV_EXPR:
|
||
case ROUND_DIV_EXPR:
|
||
case FLOOR_DIV_EXPR:
|
||
case CEIL_DIV_EXPR:
|
||
case EXACT_DIV_EXPR:
|
||
case RDIV_EXPR:
|
||
if (integer_onep (arg1))
|
||
return convert (type, arg0);
|
||
if (integer_zerop (arg1))
|
||
return t;
|
||
#if !defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
|
||
if (TREE_CODE (arg1) == REAL_CST
|
||
&& real_zerop (arg1))
|
||
return t;
|
||
#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
|
||
|
||
goto binary;
|
||
|
||
case CEIL_MOD_EXPR:
|
||
case FLOOR_MOD_EXPR:
|
||
case ROUND_MOD_EXPR:
|
||
case TRUNC_MOD_EXPR:
|
||
if (!loses && integer_onep (arg1))
|
||
return combine (code, arg1, arg1);
|
||
if (integer_zerop (arg1))
|
||
return t;
|
||
goto binary;
|
||
|
||
case LSHIFT_EXPR:
|
||
case RSHIFT_EXPR:
|
||
case LROTATE_EXPR:
|
||
case RROTATE_EXPR:
|
||
if (integer_zerop (arg1))
|
||
return convert (type, arg0);
|
||
goto binary;
|
||
|
||
case MIN_EXPR: case MAX_EXPR:
|
||
goto associate;
|
||
|
||
case TRUTH_NOT_EXPR:
|
||
/* Note that the operand of this must be an int
|
||
and its values must be 0 or 1.
|
||
("true" is a fixed value perhaps depending on the language,
|
||
but we don't handle values other than 1 correctly yet.) */
|
||
if (TREE_CODE (arg0) == INTEGER_CST)
|
||
{
|
||
t = build_int_2 ((TREE_INT_CST_LOW (arg0) == 0
|
||
&& TREE_INT_CST_HIGH (arg0) == 0),
|
||
0);
|
||
TREE_TYPE (t) = integer_type_node;
|
||
}
|
||
return t;
|
||
|
||
case TRUTH_ANDIF_EXPR:
|
||
/* Note that the operands of this must be ints
|
||
and their values must be 0 or 1.
|
||
("true" is a fixed value perhaps depending on the language.) */
|
||
/* If first arg is constant zero, return it. */
|
||
if (TREE_CODE (arg0) == INTEGER_CST && integer_zerop (arg0))
|
||
return arg0;
|
||
case TRUTH_AND_EXPR:
|
||
/* If either arg is constant true, drop it. */
|
||
if (TREE_CODE (arg0) == INTEGER_CST && ! integer_zerop (arg0))
|
||
return arg1;
|
||
if (TREE_CODE (arg1) == INTEGER_CST && ! integer_zerop (arg1))
|
||
return arg0;
|
||
/* Both known to be zero => return zero. */
|
||
if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)
|
||
return arg0;
|
||
return t;
|
||
|
||
case TRUTH_ORIF_EXPR:
|
||
/* Note that the operands of this must be ints
|
||
and their values must be 0 or true.
|
||
("true" is a fixed value perhaps depending on the language.) */
|
||
/* If first arg is constant true, return it. */
|
||
if (TREE_CODE (arg0) == INTEGER_CST && ! integer_zerop (arg0))
|
||
return arg0;
|
||
case TRUTH_OR_EXPR:
|
||
/* If either arg is constant zero, drop it. */
|
||
if (TREE_CODE (arg0) == INTEGER_CST && integer_zerop (arg0))
|
||
return arg1;
|
||
if (TREE_CODE (arg1) == INTEGER_CST && integer_zerop (arg1))
|
||
return arg0;
|
||
/* Both known to be true => return true. */
|
||
if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)
|
||
return arg0;
|
||
return t;
|
||
|
||
case EQ_EXPR:
|
||
case NE_EXPR:
|
||
case LT_EXPR:
|
||
case GT_EXPR:
|
||
case LE_EXPR:
|
||
case GE_EXPR:
|
||
/* If one arg is a constant integer, put it last. */
|
||
if (TREE_CODE (arg0) == INTEGER_CST
|
||
&& TREE_CODE (arg1) != INTEGER_CST)
|
||
{
|
||
TREE_OPERAND (t, 0) = arg1;
|
||
TREE_OPERAND (t, 1) = arg0;
|
||
arg0 = TREE_OPERAND (t, 0);
|
||
arg1 = TREE_OPERAND (t, 1);
|
||
switch (code)
|
||
{
|
||
case GT_EXPR:
|
||
code = LT_EXPR;
|
||
break;
|
||
case GE_EXPR:
|
||
code = LE_EXPR;
|
||
break;
|
||
case LT_EXPR:
|
||
code = GT_EXPR;
|
||
break;
|
||
case LE_EXPR:
|
||
code = GE_EXPR;
|
||
break;
|
||
}
|
||
TREE_SET_CODE (t, code);
|
||
}
|
||
|
||
/* Convert foo++ == CONST into ++foo == CONST + INCR.
|
||
First, see if one arg is constant; find the constant arg
|
||
and the other one. */
|
||
{
|
||
tree constop = 0, varop;
|
||
tree *constoploc;
|
||
|
||
if (TREE_LITERAL (arg1))
|
||
constoploc = &TREE_OPERAND (t, 1), constop = arg1, varop = arg0;
|
||
if (TREE_LITERAL (arg0))
|
||
constoploc = &TREE_OPERAND (t, 0), constop = arg0, varop = arg1;
|
||
|
||
if (constop && TREE_CODE (varop) == POSTINCREMENT_EXPR)
|
||
{
|
||
tree newconst
|
||
= fold (build (PLUS_EXPR, TREE_TYPE (t),
|
||
constop, TREE_OPERAND (varop, 1)));
|
||
/* This optimization is invalid for ordered comparisons
|
||
if CONST+INCR overflows!
|
||
We can assume that address + integer will not overflow. */
|
||
if (TREE_CODE (newconst) != INTEGER_CST
|
||
|| ! tree_int_cst_lt (newconst, constop)
|
||
|| code == EQ_EXPR || code == NE_EXPR)
|
||
{
|
||
TREE_SET_CODE (varop, PREINCREMENT_EXPR);
|
||
*constoploc = newconst;
|
||
return t;
|
||
}
|
||
}
|
||
else if (constop && TREE_CODE (varop) == POSTDECREMENT_EXPR)
|
||
{
|
||
tree newconst
|
||
= fold (build (MINUS_EXPR, TREE_TYPE (t),
|
||
constop, TREE_OPERAND (varop, 1)));
|
||
if (TREE_CODE (newconst) != INTEGER_CST
|
||
|| tree_int_cst_lt (newconst, constop)
|
||
|| code == EQ_EXPR || code == NE_EXPR)
|
||
{
|
||
TREE_SET_CODE (varop, PREDECREMENT_EXPR);
|
||
*constoploc = newconst;
|
||
return t;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Change X >= CST to X > (CST - 1) if CST is positive. */
|
||
if (TREE_CODE (arg1) == INTEGER_CST
|
||
&& TREE_CODE (arg0) != INTEGER_CST
|
||
&& ! tree_int_cst_lt (arg1, integer_one_node))
|
||
{
|
||
switch (TREE_CODE (t))
|
||
{
|
||
case GE_EXPR:
|
||
code = GT_EXPR;
|
||
TREE_SET_CODE (t, code);
|
||
arg1 = combine (MINUS_EXPR, arg1, integer_one_node);
|
||
TREE_OPERAND (t, 1) = arg1;
|
||
break;
|
||
|
||
case LT_EXPR:
|
||
code = LE_EXPR;
|
||
TREE_SET_CODE (t, code);
|
||
arg1 = combine (MINUS_EXPR, arg1, integer_one_node);
|
||
TREE_OPERAND (t, 1) = arg1;
|
||
}
|
||
}
|
||
|
||
/* An unsigned comparison against 0 can be simplified. */
|
||
if (integer_zerop (arg1)
|
||
&& (TREE_CODE (TREE_TYPE (arg1)) == INTEGER_TYPE
|
||
|| TREE_CODE (TREE_TYPE (arg1)) == POINTER_TYPE)
|
||
&& TREE_UNSIGNED (TREE_TYPE (arg1)))
|
||
{
|
||
switch (TREE_CODE (t))
|
||
{
|
||
case GT_EXPR:
|
||
TREE_SET_CODE (t, NE_EXPR);
|
||
break;
|
||
case LE_EXPR:
|
||
TREE_SET_CODE (t, EQ_EXPR);
|
||
break;
|
||
case GE_EXPR:
|
||
return build (COMPOUND_EXPR, integer_type_node,
|
||
arg0, integer_one_node);
|
||
case LT_EXPR:
|
||
return build (COMPOUND_EXPR, integer_type_node,
|
||
arg0, integer_zero_node);
|
||
}
|
||
}
|
||
|
||
/* To compute GT, swap the arguments and do LT.
|
||
To compute GE, do LT and invert the result.
|
||
To compute LE, swap the arguments, do LT and invert the result.
|
||
To compute NE, do EQ and invert the result. */
|
||
if (code == LE_EXPR || code == GT_EXPR)
|
||
{
|
||
register tree temp = arg0;
|
||
arg0 = arg1;
|
||
arg1 = temp;
|
||
}
|
||
|
||
/* Compute a result for LT or EQ if args permit;
|
||
otherwise return T. */
|
||
if (TREE_CODE (arg0) == INTEGER_CST
|
||
&& TREE_CODE (arg1) == INTEGER_CST)
|
||
{
|
||
if (code == EQ_EXPR || code == NE_EXPR)
|
||
t = build_int_2
|
||
(TREE_INT_CST_LOW (arg0) == TREE_INT_CST_LOW (arg1)
|
||
&& TREE_INT_CST_HIGH (arg0) == TREE_INT_CST_HIGH (arg1),
|
||
0);
|
||
else
|
||
t = build_int_2 ((TREE_UNSIGNED (TREE_TYPE (arg0))
|
||
? INT_CST_LT_UNSIGNED (arg0, arg1)
|
||
: INT_CST_LT (arg0, arg1)),
|
||
0);
|
||
}
|
||
else if (TREE_CODE (arg1) == INTEGER_CST
|
||
&& TREE_LITERAL (arg0)
|
||
&& TREE_CODE (arg0) == ADDR_EXPR
|
||
&& (code == EQ_EXPR || code == NE_EXPR))
|
||
{
|
||
t = build_int_2 (0, 0);
|
||
}
|
||
else if (TREE_CODE (arg0) == REAL_CST
|
||
&& TREE_CODE (arg1) == REAL_CST)
|
||
{
|
||
if (code == EQ_EXPR || code == NE_EXPR)
|
||
t = build_int_2 (REAL_VALUES_EQUAL (TREE_REAL_CST (arg0),
|
||
TREE_REAL_CST (arg1)),
|
||
0);
|
||
else
|
||
t = build_int_2 (REAL_VALUES_LESS (TREE_REAL_CST (arg0),
|
||
TREE_REAL_CST (arg1)),
|
||
0);
|
||
}
|
||
else
|
||
return t;
|
||
|
||
/* If what we want is other than LT or EQ, invert the result. */
|
||
if (code == GE_EXPR || code == LE_EXPR || code == NE_EXPR)
|
||
TREE_INT_CST_LOW (t) ^= 1;
|
||
TREE_TYPE (t) = type;
|
||
return t;
|
||
|
||
case COND_EXPR:
|
||
if (TREE_LITERAL (arg0))
|
||
return TREE_OPERAND (expr, (integer_zerop (arg0) ? 2 : 1));
|
||
return t;
|
||
|
||
default:
|
||
return t;
|
||
} /* switch (code) */
|
||
}
|