/* Fold a constant sub-tree into a single node for C-compiler
- Copyright (C) 1987, 88, 92-96, 1997 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 92-98, 1999 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ for cross-compilers. */
-/* The entry points in this file are fold, size_int, size_binop
+/* The entry points in this file are fold, size_int_wide, size_binop
and force_fit_type.
fold takes a tree as argument and returns a simplified tree.
forces the value to fit the type. It returns an overflow indicator. */
#include "config.h"
-#include <stdio.h>
+#include "system.h"
#include <setjmp.h>
#include "flags.h"
#include "tree.h"
-
-/* Handle floating overflow for `const_binop'. */
-static jmp_buf float_error;
+#include "rtl.h"
+#include "toplev.h"
static void encode PROTO((HOST_WIDE_INT *,
HOST_WIDE_INT, HOST_WIDE_INT));
static tree fold_truthop PROTO((enum tree_code, tree, tree, tree));
static tree strip_compound_expr PROTO((tree, tree));
static int multiple_of_p PROTO((tree, tree, tree));
+static tree constant_boolean_node PROTO((int, tree));
+static int count_cond PROTO((tree, int));
+static void const_binop_1 PROTO((PTR));
+static void fold_convert_1 PROTO((PTR));
#ifndef BRANCH_COST
#define BRANCH_COST 1
low = TREE_INT_CST_LOW (t);
high = TREE_INT_CST_HIGH (t);
- if (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE)
+ if (POINTER_TYPE_P (TREE_TYPE (t)))
prec = POINTER_SIZE;
else
prec = TYPE_PRECISION (TREE_TYPE (t));
if (count >= HOST_BITS_PER_WIDE_INT)
{
- *hv = (unsigned HOST_WIDE_INT) l1 << count - HOST_BITS_PER_WIDE_INT;
+ *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));
+ | ((unsigned HOST_WIDE_INT) l1 >> (HOST_BITS_PER_WIDE_INT - count - 1) >> 1));
*lv = (unsigned HOST_WIDE_INT) l1 << count;
}
}
void
rshift_double (l1, h1, count, prec, lv, hv, arith)
HOST_WIDE_INT l1, h1, count;
- int prec;
+ int prec ATTRIBUTE_UNUSED;
HOST_WIDE_INT *lv, *hv;
int arith;
{
if (count >= HOST_BITS_PER_WIDE_INT)
{
*hv = signmask;
- *lv = ((signmask << 2 * HOST_BITS_PER_WIDE_INT - count - 1 << 1)
- | ((unsigned HOST_WIDE_INT) h1 >> count - HOST_BITS_PER_WIDE_INT));
+ *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 << (HOST_BITS_PER_WIDE_INT - count - 1) << 1));
+ *hv = ((signmask << (HOST_BITS_PER_WIDE_INT - count))
| ((unsigned HOST_WIDE_INT) h1 >> count));
}
}
encode (den, lden, hden);
/* Special code for when the divisor < BASE. */
- if (hden == 0 && lden < BASE)
+ if (hden == 0 && lden < (HOST_WIDE_INT) BASE)
{
/* hnum != 0 already checked. */
for (i = 4 - 1; i >= 0; i--)
enum machine_mode mode;
REAL_VALUE_TYPE *r;
{
+ jmp_buf float_error;
union
{
double d;
*r = y.d;
return 1;
}
+
+
+/* Convert C9X hexadecimal floating point string constant S. Return
+ real value type in mode MODE. This function uses the host computer's
+ fp arithmetic when there is no REAL_ARITHMETIC. */
+
+REAL_VALUE_TYPE
+real_hex_to_f (s, mode)
+ char *s;
+ enum machine_mode mode;
+{
+ REAL_VALUE_TYPE ip;
+ char *p = s;
+ unsigned HOST_WIDE_INT low, high;
+ int frexpon, expon, shcount, nrmcount, k;
+ int sign, expsign, decpt, isfloat, isldouble, gotp, lost;
+ char c;
+
+ isldouble = 0;
+ isfloat = 0;
+ frexpon = 0;
+ expon = 0;
+ expsign = 1;
+ ip = 0.0;
+
+ while (*p == ' ' || *p == '\t')
+ ++p;
+
+ /* Sign, if any, comes first. */
+ sign = 1;
+ if (*p == '-')
+ {
+ sign = -1;
+ ++p;
+ }
+
+ /* The string is supposed to start with 0x or 0X . */
+ if (*p == '0')
+ {
+ ++p;
+ if (*p == 'x' || *p == 'X')
+ ++p;
+ else
+ abort ();
+ }
+ else
+ abort ();
+
+ while (*p == '0')
+ ++p;
+
+ high = 0;
+ low = 0;
+ lost = 0; /* Nonzero low order bits shifted out and discarded. */
+ frexpon = 0; /* Bits after the decimal point. */
+ expon = 0; /* Value of exponent. */
+ decpt = 0; /* How many decimal points. */
+ gotp = 0; /* How many P's. */
+ shcount = 0;
+ while ((c = *p) != '\0')
+ {
+ if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')
+ || (c >= 'a' && c <= 'f'))
+ {
+ k = c & 0x7f;
+ if (k >= 'a')
+ k = k - 'a' + 10;
+ else if (k >= 'A')
+ k = k - 'A' + 10;
+ else
+ k = k - '0';
+
+ if ((high & 0xf0000000) == 0)
+ {
+ high = (high << 4) + ((low >> 28) & 15);
+ low = (low << 4) + k;
+ shcount += 4;
+ if (decpt)
+ frexpon += 4;
+ }
+ else
+ {
+ /* Record nonzero lost bits. */
+ lost |= k;
+ if (!decpt)
+ frexpon -= 4;
+ }
+ ++p;
+ }
+ else if ( c == '.')
+ {
+ ++decpt;
+ ++p;
+ }
+ else if (c == 'p' || c == 'P')
+ {
+ ++gotp;
+ ++p;
+ /* Sign of exponent. */
+ if (*p == '-')
+ {
+ expsign = -1;
+ ++p;
+ }
+ /* Value of exponent.
+ The exponent field is a decimal integer. */
+ while (isdigit(*p))
+ {
+ k = (*p++ & 0x7f) - '0';
+ expon = 10 * expon + k;
+ }
+ expon *= expsign;
+ /* F suffix is ambiguous in the significand part
+ so it must appear after the decimal exponent field. */
+ if (*p == 'f' || *p == 'F')
+ {
+ isfloat = 1;
+ ++p;
+ break;
+ }
+ }
+ else if (c == 'l' || c == 'L')
+ {
+ isldouble = 1;
+ ++p;
+ break;
+ }
+ else
+ break;
+ }
+ /* Abort if last character read was not legitimate. */
+ c = *p;
+ if ((c != '\0' && c != ' ' && c != '\n' && c != '\r') || (decpt > 1))
+ abort ();
+ /* There must be either one decimal point or one p. */
+ if (decpt == 0 && gotp == 0)
+ abort ();
+ shcount -= 4;
+ if ((high == 0) && (low == 0))
+ {
+ return dconst0;
+ }
+
+ /* Normalize. */
+ nrmcount = 0;
+ if (high == 0)
+ {
+ high = low;
+ low = 0;
+ nrmcount += 32;
+ }
+ /* Leave a high guard bit for carry-out. */
+ if ((high & 0x80000000) != 0)
+ {
+ lost |= low & 1;
+ low = (low >> 1) | (high << 31);
+ high = high >> 1;
+ nrmcount -= 1;
+ }
+ if ((high & 0xffff8000) == 0)
+ {
+ high = (high << 16) + ((low >> 16) & 0xffff);
+ low = low << 16;
+ nrmcount += 16;
+ }
+ while ((high & 0xc0000000) == 0)
+ {
+ high = (high << 1) + ((low >> 31) & 1);
+ low = low << 1;
+ nrmcount += 1;
+ }
+ if (isfloat || GET_MODE_SIZE(mode) == UNITS_PER_WORD)
+ {
+ /* Keep 24 bits precision, bits 0x7fffff80.
+ Rounding bit is 0x40. */
+ lost = lost | low | (high & 0x3f);
+ low = 0;
+ if (high & 0x40)
+ {
+ if ((high & 0x80) || lost)
+ high += 0x40;
+ }
+ high &= 0xffffff80;
+ }
+ else
+ {
+ /* We need real.c to do long double formats, so here default
+ to double precision. */
+#if HOST_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
+ /* IEEE double.
+ Keep 53 bits precision, bits 0x7fffffff fffffc00.
+ Rounding bit is low word 0x200. */
+ lost = lost | (low & 0x1ff);
+ if (low & 0x200)
+ {
+ if ((low & 0x400) || lost)
+ {
+ low = (low + 0x200) & 0xfffffc00;
+ if (low == 0)
+ high += 1;
+ }
+ }
+ low &= 0xfffffc00;
+#else
+ /* Assume it's a VAX with 56-bit significand,
+ bits 0x7fffffff ffffff80. */
+ lost = lost | (low & 0x7f);
+ if (low & 0x40)
+ {
+ if ((low & 0x80) || lost)
+ {
+ low = (low + 0x40) & 0xffffff80;
+ if (low == 0)
+ high += 1;
+ }
+ }
+ low &= 0xffffff80;
+#endif
+ }
+ ip = (double) high;
+ ip = REAL_VALUE_LDEXP (ip, 32) + (double) low;
+ /* Apply shifts and exponent value as power of 2. */
+ ip = REAL_VALUE_LDEXP (ip, expon - (nrmcount + frexpon));
+
+ if (sign < 0)
+ ip = -ip;
+ return ip;
+}
+
#endif /* no REAL_ARITHMETIC */
\f
/* Split a tree IN into a constant and a variable part
}
if (TREE_TYPE (arg1) == sizetype && hi == 0
- && low >= 0 && low <= TREE_INT_CST_LOW (TYPE_MAX_VALUE (sizetype))
+ && low >= 0
+ && (TYPE_MAX_VALUE (sizetype) == NULL
+ || low <= TREE_INT_CST_LOW (TYPE_MAX_VALUE (sizetype)))
&& ! overflow
&& ! TREE_OVERFLOW (arg1) && ! TREE_OVERFLOW (arg2))
t = size_int (low);
return t;
}
+struct cb_args
+{
+ /* Input */
+ tree arg1;
+ REAL_VALUE_TYPE d1, d2;
+ enum tree_code code;
+ /* Output */
+ tree t;
+};
+
+static void
+const_binop_1 (data)
+ PTR data;
+{
+ struct cb_args * args = (struct cb_args *) data;
+ REAL_VALUE_TYPE value;
+
+#ifdef REAL_ARITHMETIC
+ REAL_ARITHMETIC (value, args->code, args->d1, args->d2);
+#else
+ switch (args->code)
+ {
+ case PLUS_EXPR:
+ value = args->d1 + args->d2;
+ break;
+
+ case MINUS_EXPR:
+ value = args->d1 - args->d2;
+ break;
+
+ case MULT_EXPR:
+ value = args->d1 * args->d2;
+ break;
+
+ case RDIV_EXPR:
+#ifndef REAL_INFINITY
+ if (args->d2 == 0)
+ abort ();
+#endif
+
+ value = args->d1 / args->d2;
+ break;
+
+ case MIN_EXPR:
+ value = MIN (args->d1, args->d2);
+ break;
+
+ case MAX_EXPR:
+ value = MAX (args->d1, args->d2);
+ break;
+
+ default:
+ abort ();
+ }
+#endif /* no REAL_ARITHMETIC */
+ args->t =
+ build_real (TREE_TYPE (args->arg1),
+ real_value_truncate (TYPE_MODE (TREE_TYPE (args->arg1)),
+ value));
+}
+
/* Combine two constants ARG1 and ARG2 under operation CODE
to produce a new constant.
We assume ARG1 and ARG2 have the same data type,
REAL_VALUE_TYPE d1;
REAL_VALUE_TYPE d2;
int overflow = 0;
- REAL_VALUE_TYPE value;
tree t;
+ struct cb_args args;
d1 = TREE_REAL_CST (arg1);
d2 = TREE_REAL_CST (arg2);
return arg1;
else if (REAL_VALUE_ISNAN (d2))
return arg2;
- else if (setjmp (float_error))
+
+ /* Setup input for const_binop_1() */
+ args.arg1 = arg1;
+ args.d1 = d1;
+ args.d2 = d2;
+ args.code = code;
+
+ if (do_float_handler (const_binop_1, (PTR) &args))
{
- t = copy_node (arg1);
- overflow = 1;
- goto got_float;
+ /* Receive output from const_binop_1() */
+ t = args.t;
}
-
- set_float_handler (float_error);
-
-#ifdef REAL_ARITHMETIC
- REAL_ARITHMETIC (value, code, d1, d2);
-#else
- switch (code)
+ else
{
- case PLUS_EXPR:
- value = d1 + d2;
- break;
-
- case MINUS_EXPR:
- value = d1 - d2;
- break;
-
- case MULT_EXPR:
- value = d1 * d2;
- break;
-
- case RDIV_EXPR:
-#ifndef REAL_INFINITY
- if (d2 == 0)
- abort ();
-#endif
-
- value = d1 / d2;
- break;
-
- case MIN_EXPR:
- value = MIN (d1, d2);
- break;
-
- case MAX_EXPR:
- value = MAX (d1, d2);
- break;
-
- default:
- abort ();
+ /* We got an exception from const_binop_1() */
+ t = copy_node (arg1);
+ overflow = 1;
}
-#endif /* no REAL_ARITHMETIC */
- t = build_real (TREE_TYPE (arg1),
- real_value_truncate (TYPE_MODE (TREE_TYPE (arg1)), value));
- got_float:
- set_float_handler (NULL_PTR);
TREE_OVERFLOW (t)
= (force_fit_type (t, overflow)
return 0;
}
\f
-/* Return an INTEGER_CST with value V and type from `sizetype'. */
+/* Return an INTEGER_CST with value V . The type is determined by bit_p:
+ if it is zero, the type is taken from sizetype; if it is one, the type
+ is taken from bitsizetype. */
tree
-size_int (number)
- unsigned HOST_WIDE_INT number;
+size_int_wide (number, high, bit_p)
+ unsigned HOST_WIDE_INT number, high;
+ int bit_p;
{
register tree t;
/* Type-size nodes already made for small sizes. */
- static tree size_table[2*HOST_BITS_PER_WIDE_INT + 1];
+ static tree size_table[2*HOST_BITS_PER_WIDE_INT + 1][2];
- if (number < 2*HOST_BITS_PER_WIDE_INT + 1
- && size_table[number] != 0)
- return size_table[number];
- if (number < 2*HOST_BITS_PER_WIDE_INT + 1)
+ if (number < 2*HOST_BITS_PER_WIDE_INT + 1 && ! high
+ && size_table[number][bit_p] != 0)
+ return size_table[number][bit_p];
+ if (number < 2*HOST_BITS_PER_WIDE_INT + 1 && ! high)
{
push_obstacks_nochange ();
/* Make this a permanent node. */
end_temporary_allocation ();
t = build_int_2 (number, 0);
- TREE_TYPE (t) = sizetype;
- size_table[number] = t;
+ TREE_TYPE (t) = bit_p ? bitsizetype : sizetype;
+ size_table[number][bit_p] = t;
pop_obstacks ();
}
else
{
- t = build_int_2 (number, 0);
- TREE_TYPE (t) = sizetype;
+ t = build_int_2 (number, high);
+ TREE_TYPE (t) = bit_p ? bitsizetype : sizetype;
TREE_OVERFLOW (t) = TREE_CONSTANT_OVERFLOW (t) = force_fit_type (t, 0);
}
return t;
return fold (build (code, sizetype, arg0, arg1));
}
+
+/* Combine operands OP1 and OP2 with arithmetic operation CODE.
+ CODE is a tree code. Data type is taken from `ssizetype',
+ If the operands are constant, so is the result. */
+
+tree
+ssize_binop (code, arg0, arg1)
+ enum tree_code code;
+ tree arg0, arg1;
+{
+ /* Handle the special case of two integer constants faster. */
+ if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)
+ {
+ /* And some specific cases even faster than that. */
+ if (code == PLUS_EXPR && integer_zerop (arg0))
+ return arg1;
+ else if ((code == MINUS_EXPR || code == PLUS_EXPR)
+ && integer_zerop (arg1))
+ return arg0;
+ else if (code == MULT_EXPR && integer_onep (arg0))
+ return arg1;
+
+ /* Handle general case of two integer constants. We convert
+ arg0 to ssizetype because int_const_binop uses its type for the
+ return value. */
+ arg0 = convert (ssizetype, arg0);
+ return int_const_binop (code, arg0, arg1, 0, 0);
+ }
+
+ if (arg0 == error_mark_node || arg1 == error_mark_node)
+ return error_mark_node;
+
+ return fold (build (code, ssizetype, arg0, arg1));
+}
\f
+struct fc_args
+{
+ /* Input */
+ tree arg1, type;
+ /* Output */
+ tree t;
+};
+
+static void
+fold_convert_1 (data)
+ PTR data;
+{
+ struct fc_args * args = (struct fc_args *) data;
+
+ args->t = build_real (args->type,
+ real_value_truncate (TYPE_MODE (args->type),
+ TREE_REAL_CST (args->arg1)));
+}
+
/* Given T, a tree representing type conversion of ARG1, a constant,
return a constant tree representing the result of conversion. */
register tree type = TREE_TYPE (t);
int overflow = 0;
- if (TREE_CODE (type) == POINTER_TYPE || INTEGRAL_TYPE_P (type))
+ if (POINTER_TYPE_P (type) || INTEGRAL_TYPE_P (type))
{
if (TREE_CODE (arg1) == INTEGER_CST)
{
if ARG1 is a too-large unsigned value and T is signed.
But don't indicate an overflow if converting a pointer. */
TREE_OVERFLOW (t)
- = (TREE_OVERFLOW (arg1)
- || (force_fit_type (t,
- (TREE_INT_CST_HIGH (arg1) < 0
- & (TREE_UNSIGNED (type)
- < TREE_UNSIGNED (TREE_TYPE (arg1)))))
- && TREE_CODE (TREE_TYPE (arg1)) != POINTER_TYPE));
+ = ((force_fit_type (t,
+ (TREE_INT_CST_HIGH (arg1) < 0
+ && (TREE_UNSIGNED (type)
+ < TREE_UNSIGNED (TREE_TYPE (arg1)))))
+ && ! POINTER_TYPE_P (TREE_TYPE (arg1)))
+ || TREE_OVERFLOW (arg1));
TREE_CONSTANT_OVERFLOW (t)
= TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg1);
}
REAL_VALUE_TYPE l;
REAL_VALUE_TYPE u;
tree type1 = TREE_TYPE (arg1);
+ int no_upper_bound;
x = TREE_REAL_CST (arg1);
l = real_value_from_int_cst (type1, TYPE_MIN_VALUE (type));
- u = real_value_from_int_cst (type1, TYPE_MAX_VALUE (type));
+
+ no_upper_bound = (TYPE_MAX_VALUE (type) == NULL);
+ if (!no_upper_bound)
+ u = real_value_from_int_cst (type1, TYPE_MAX_VALUE (type));
+
/* See if X will be in range after truncation towards 0.
To compensate for truncation, move the bounds away from 0,
but reject if X exactly equals the adjusted bounds. */
#ifdef REAL_ARITHMETIC
REAL_ARITHMETIC (l, MINUS_EXPR, l, dconst1);
- REAL_ARITHMETIC (u, PLUS_EXPR, u, dconst1);
+ if (!no_upper_bound)
+ REAL_ARITHMETIC (u, PLUS_EXPR, u, dconst1);
#else
l--;
- u++;
+ if (!no_upper_bound)
+ u++;
#endif
/* If X is a NaN, use zero instead and show we have an overflow.
Otherwise, range check. */
if (REAL_VALUE_ISNAN (x))
overflow = 1, x = dconst0;
- else if (! (REAL_VALUES_LESS (l, x) && REAL_VALUES_LESS (x, u)))
+ else if (! (REAL_VALUES_LESS (l, x)
+ && !no_upper_bound
+ && REAL_VALUES_LESS (x, u)))
overflow = 1;
#ifndef REAL_ARITHMETIC
#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
if (TREE_CODE (arg1) == REAL_CST)
{
+ struct fc_args args;
+
if (REAL_VALUE_ISNAN (TREE_REAL_CST (arg1)))
{
t = arg1;
TREE_TYPE (arg1) = type;
return t;
}
- else if (setjmp (float_error))
+
+ /* Setup input for fold_convert_1() */
+ args.arg1 = arg1;
+ args.type = type;
+
+ if (do_float_handler (fold_convert_1, (PTR) &args))
+ {
+ /* Receive output from fold_convert_1() */
+ t = args.t;
+ }
+ else
{
+ /* We got an exception from fold_convert_1() */
overflow = 1;
t = copy_node (arg1);
- goto got_it;
}
- set_float_handler (float_error);
- t = build_real (type, real_value_truncate (TYPE_MODE (type),
- TREE_REAL_CST (arg1)));
- set_float_handler (NULL_PTR);
-
- got_it:
TREE_OVERFLOW (t)
= TREE_OVERFLOW (arg1) | force_fit_type (t, overflow);
TREE_CONSTANT_OVERFLOW (t)
return t;
}
\f
-/* Return an expr equal to X but certainly not valid as an lvalue.
- Also make sure it is not valid as an null pointer constant. */
+/* Return an expr equal to X but certainly not valid as an lvalue. */
tree
non_lvalue (x)
|| TREE_CODE (x) == REAL_CST
|| TREE_CODE (x) == STRING_CST
|| TREE_CODE (x) == ADDR_EXPR)
- {
- if (TREE_CODE (x) == INTEGER_CST && integer_zerop (x))
- {
- /* Use NOP_EXPR instead of NON_LVALUE_EXPR
- so convert_for_assignment won't strip it.
- This is so this 0 won't be treated as a null pointer constant. */
- result = build1 (NOP_EXPR, TREE_TYPE (x), x);
- TREE_CONSTANT (result) = TREE_CONSTANT (x);
- return result;
- }
- return x;
- }
+ return x;
result = build1 (NON_LVALUE_EXPR, TREE_TYPE (x), x);
TREE_CONSTANT (result) = TREE_CONSTANT (x);
default:
return 0;
}
+
+ case 'e':
+ if (TREE_CODE (arg0) == RTL_EXPR)
+ return rtx_equal_p (RTL_EXPR_RTL (arg0), RTL_EXPR_RTL (arg1));
+ return 0;
default:
return 0;
tree other;
{
int unsignedp1, unsignedpo;
- tree primarg1, primother;
+ tree primarg0, primarg1, primother;
unsigned correct_width;
if (operand_equal_p (arg0, arg1, 0))
|| ! INTEGRAL_TYPE_P (TREE_TYPE (arg1)))
return 0;
+ /* Discard any conversions that don't change the modes of ARG0 and ARG1
+ and see if the inner values are the same. This removes any
+ signedness comparison, which doesn't matter here. */
+ primarg0 = arg0, primarg1 = arg1;
+ STRIP_NOPS (primarg0); STRIP_NOPS (primarg1);
+ if (operand_equal_p (primarg0, primarg1, 0))
+ return 1;
+
/* Duplicate what shorten_compare does to ARG1 and see if that gives the
actual comparison operand, ARG0.
default:
break;
}
- /* fall through (???) */
+ /* fall through - ??? */
case '<':
{
if (TREE_CODE_CLASS (code) == '<')
{
if (FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (arg, 0)))
- && code != NE_EXPR && code != EQ_EXPR)
+ && !flag_fast_math && code != NE_EXPR && code != EQ_EXPR)
return build1 (TRUTH_NOT_EXPR, type, arg);
else
return build (invert_tree_comparison (code), type,
int unsignedp;
{
tree result = build (BIT_FIELD_REF, type, inner,
- size_int (bitsize), size_int (bitpos));
+ size_int (bitsize), bitsize_int (bitpos, 0L));
TREE_UNSIGNED (result) = unsignedp;
tree lhs, rhs;
{
int lbitpos, lbitsize, rbitpos, rbitsize;
- int lnbitpos, lnbitsize, rnbitpos, rnbitsize;
+ int lnbitpos, lnbitsize, rnbitpos = 0, rnbitsize = 0;
tree type = TREE_TYPE (lhs);
tree signed_type, unsigned_type;
int const_p = TREE_CODE (rhs) == INTEGER_CST;
- enum machine_mode lmode, rmode, lnmode, rnmode;
+ enum machine_mode lmode, rmode, lnmode, rnmode = VOIDmode;
int lunsignedp, runsignedp;
int lvolatilep = 0, rvolatilep = 0;
int alignment;
- tree linner, rinner;
+ tree linner, rinner = NULL_TREE;
tree mask;
tree offset;
convert (unsigned_type, rhs),
size_int (lbitsize), 0)))
{
- warning ("comparison is always %s due to width of bitfield",
- code == NE_EXPR ? "one" : "zero");
+ warning ("comparison is always %d due to width of bitfield",
+ code == NE_EXPR);
return convert (compare_type,
(code == NE_EXPR
? integer_one_node : integer_zero_node));
size_int (lbitsize - 1), 0);
if (! integer_zerop (tem) && ! integer_all_onesp (tem))
{
- warning ("comparison is always %s due to width of bitfield",
- code == NE_EXPR ? "one" : "zero");
+ warning ("comparison is always %d due to width of bitfield",
+ code == NE_EXPR);
return convert (compare_type,
(code == NE_EXPR
? integer_one_node : integer_zero_node));
*PMASK is set to the mask used. This is either contained in a
BIT_AND_EXPR or derived from the width of the field.
- *PAND_MASK is set the the mask found in a BIT_AND_EXPR, if any.
+ *PAND_MASK is set to the mask found in a BIT_AND_EXPR, if any.
Return 0 if this is not a component reference or is one that we can't
do anything with. */
return 0;
/* Set SGN[01] to -1 if ARG[01] is a lower bound, 1 for upper, and 0
- for neither. Then compute our result treating them as never equal
- and comparing bounds to non-bounds as above. */
+ for neither. In real maths, we cannot assume open ended ranges are
+ the same. But, this is computer arithmetic, where numbers are finite.
+ We can therefore make the transformation of any unbounded range with
+ the value Z, Z being greater than any representable number. This permits
+ us to treat unbounded ranges as equal. */
sgn0 = arg0 != 0 ? 0 : (upper0_p ? 1 : -1);
sgn1 = arg1 != 0 ? 0 : (upper1_p ? 1 : -1);
switch (code)
{
- case EQ_EXPR: case NE_EXPR:
- result = (code == NE_EXPR);
+ case EQ_EXPR:
+ result = sgn0 == sgn1;
+ break;
+ case NE_EXPR:
+ result = sgn0 != sgn1;
break;
- case LT_EXPR: case LE_EXPR:
+ case LT_EXPR:
result = sgn0 < sgn1;
break;
- case GT_EXPR: case GE_EXPR:
+ case LE_EXPR:
+ result = sgn0 <= sgn1;
+ break;
+ case GT_EXPR:
result = sgn0 > sgn1;
break;
+ case GE_EXPR:
+ result = sgn0 >= sgn1;
+ break;
default:
abort ();
}
tree *plow, *phigh;
{
enum tree_code code;
- tree arg0, arg1, type;
+ tree arg0, arg1, type = NULL_TREE;
+ tree orig_type = NULL_TREE;
int in_p, n_in_p;
tree low, high, n_low, n_high;
while (1)
{
code = TREE_CODE (exp);
- arg0 = TREE_OPERAND (exp, 0), arg1 = TREE_OPERAND (exp, 1);
- if (TREE_CODE_CLASS (code) == '<' || TREE_CODE_CLASS (code) == '1'
- || TREE_CODE_CLASS (code) == '2')
- type = TREE_TYPE (arg0);
+
+ if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code)))
+ {
+ arg0 = TREE_OPERAND (exp, 0);
+ if (TREE_CODE_CLASS (code) == '<'
+ || TREE_CODE_CLASS (code) == '1'
+ || TREE_CODE_CLASS (code) == '2')
+ type = TREE_TYPE (arg0);
+ if (TREE_CODE_CLASS (code) == '2'
+ || TREE_CODE_CLASS (code) == '<'
+ || (TREE_CODE_CLASS (code) == 'e'
+ && tree_code_length[(int) code] > 1))
+ arg1 = TREE_OPERAND (exp, 1);
+ }
+
+ /* Set ORIG_TYPE as soon as TYPE is non-null so that we do not
+ lose a cast by accident. */
+ if (type != NULL_TREE && orig_type == NULL_TREE)
+ orig_type = type;
switch (code)
{
continue;
case NOP_EXPR: case NON_LVALUE_EXPR: case CONVERT_EXPR:
+ if (TYPE_PRECISION (type) > TYPE_PRECISION (orig_type))
+ break;
+
if (! INTEGRAL_TYPE_P (type)
|| (low != 0 && ! int_fits_type_p (low, type))
|| (high != 0 && ! int_fits_type_p (high, type)))
if (TREE_UNSIGNED (type) && ! TREE_UNSIGNED (TREE_TYPE (exp)))
{
tree equiv_type = type_for_mode (TYPE_MODE (type), 1);
- tree high_positive
- = fold (build (RSHIFT_EXPR, type,
- convert (type,
- TYPE_MAX_VALUE (equiv_type)),
- convert (type, integer_one_node)));
+ tree high_positive;
+
+ /* A range without an upper bound is, naturally, unbounded.
+ Since convert would have cropped a very large value, use
+ the max value for the destination type. */
+
+ high_positive = TYPE_MAX_VALUE (equiv_type);
+ if (!high_positive)
+ {
+ high_positive = TYPE_MAX_VALUE (type);
+ if (!high_positive)
+ abort();
+ }
+ high_positive = fold (build (RSHIFT_EXPR, type,
+ convert (type, high_positive),
+ convert (type, integer_one_node)));
/* If the low bound is specified, "and" the range with the
range for which the original unsigned value will be
&& operand_equal_p (lhs, rhs, 0))
{
/* If simple enough, just rewrite. Otherwise, make a SAVE_EXPR
- unless we are at top level, in which case we can't do this. */
+ unless we are at top level or LHS contains a PLACEHOLDER_EXPR, in
+ which cases we can't do this. */
if (simple_operand_p (lhs))
return build (TREE_CODE (exp) == TRUTH_ANDIF_EXPR
? TRUTH_AND_EXPR : TRUTH_OR_EXPR,
TREE_TYPE (exp), TREE_OPERAND (exp, 0),
TREE_OPERAND (exp, 1));
- else if (current_function_decl != 0)
+ else if (current_function_decl != 0
+ && ! contains_placeholder_p (lhs))
{
tree common = save_expr (lhs);
TREE_TYPE (exp), lhs, rhs);
}
}
- else
- return 0;
+
+ return 0;
}
\f
/* Subroutine for fold_truthop: C is an INTEGER_CST interpreted as a P
tree ll_mask, lr_mask, rl_mask, rr_mask;
tree ll_and_mask, lr_and_mask, rl_and_mask, rr_and_mask;
tree l_const, r_const;
- tree type, result;
+ tree lntype, rntype, result;
int first_bit, end_bit;
int volatilep;
lnbitsize = GET_MODE_BITSIZE (lnmode);
lnbitpos = first_bit & ~ (lnbitsize - 1);
- type = type_for_size (lnbitsize, 1);
+ lntype = type_for_size (lnbitsize, 1);
xll_bitpos = ll_bitpos - lnbitpos, xrl_bitpos = rl_bitpos - lnbitpos;
if (BYTES_BIG_ENDIAN)
xrl_bitpos = lnbitsize - xrl_bitpos - rl_bitsize;
}
- ll_mask = const_binop (LSHIFT_EXPR, convert (type, ll_mask),
+ ll_mask = const_binop (LSHIFT_EXPR, convert (lntype, ll_mask),
size_int (xll_bitpos), 0);
- rl_mask = const_binop (LSHIFT_EXPR, convert (type, rl_mask),
+ rl_mask = const_binop (LSHIFT_EXPR, convert (lntype, rl_mask),
size_int (xrl_bitpos), 0);
if (l_const)
{
- l_const = convert (type, l_const);
+ l_const = convert (lntype, l_const);
l_const = unextend (l_const, ll_bitsize, ll_unsignedp, ll_and_mask);
l_const = const_binop (LSHIFT_EXPR, l_const, size_int (xll_bitpos), 0);
if (! integer_zerop (const_binop (BIT_AND_EXPR, l_const,
fold (build1 (BIT_NOT_EXPR,
- type, ll_mask)),
+ lntype, ll_mask)),
0)))
{
- warning ("comparison is always %s",
- wanted_code == NE_EXPR ? "one" : "zero");
+ warning ("comparison is always %d", wanted_code == NE_EXPR);
return convert (truth_type,
wanted_code == NE_EXPR
}
if (r_const)
{
- r_const = convert (type, r_const);
+ r_const = convert (lntype, r_const);
r_const = unextend (r_const, rl_bitsize, rl_unsignedp, rl_and_mask);
r_const = const_binop (LSHIFT_EXPR, r_const, size_int (xrl_bitpos), 0);
if (! integer_zerop (const_binop (BIT_AND_EXPR, r_const,
fold (build1 (BIT_NOT_EXPR,
- type, rl_mask)),
+ lntype, rl_mask)),
0)))
{
- warning ("comparison is always %s",
- wanted_code == NE_EXPR ? "one" : "zero");
-
+ warning ("comparison is always %d", wanted_code == NE_EXPR);
+
return convert (truth_type,
wanted_code == NE_EXPR
? integer_one_node : integer_zero_node);
rnbitsize = GET_MODE_BITSIZE (rnmode);
rnbitpos = first_bit & ~ (rnbitsize - 1);
+ rntype = type_for_size (rnbitsize, 1);
xlr_bitpos = lr_bitpos - rnbitpos, xrr_bitpos = rr_bitpos - rnbitpos;
if (BYTES_BIG_ENDIAN)
xrr_bitpos = rnbitsize - xrr_bitpos - rr_bitsize;
}
- lr_mask = const_binop (LSHIFT_EXPR, convert (type, lr_mask),
+ lr_mask = const_binop (LSHIFT_EXPR, convert (rntype, lr_mask),
size_int (xlr_bitpos), 0);
- rr_mask = const_binop (LSHIFT_EXPR, convert (type, rr_mask),
+ rr_mask = const_binop (LSHIFT_EXPR, convert (rntype, rr_mask),
size_int (xrr_bitpos), 0);
/* Make a mask that corresponds to both fields being compared.
- Do this for both items being compared. If the masks agree,
- we can do this by masking both and comparing the masked
+ Do this for both items being compared. If the operands are the
+ same size and the bits being compared are in the same position
+ then we can do this by masking both and comparing the masked
results. */
ll_mask = const_binop (BIT_IOR_EXPR, ll_mask, rl_mask, 0);
lr_mask = const_binop (BIT_IOR_EXPR, lr_mask, rr_mask, 0);
- if (operand_equal_p (ll_mask, lr_mask, 0) && lnbitsize == rnbitsize)
+ if (lnbitsize == rnbitsize && xll_bitpos == xlr_bitpos)
{
- lhs = make_bit_field_ref (ll_inner, type, lnbitsize, lnbitpos,
+ lhs = make_bit_field_ref (ll_inner, lntype, lnbitsize, lnbitpos,
ll_unsignedp || rl_unsignedp);
- rhs = make_bit_field_ref (lr_inner, type, rnbitsize, rnbitpos,
- lr_unsignedp || rr_unsignedp);
if (! all_ones_mask_p (ll_mask, lnbitsize))
- {
- lhs = build (BIT_AND_EXPR, type, lhs, ll_mask);
- rhs = build (BIT_AND_EXPR, type, rhs, ll_mask);
- }
+ lhs = build (BIT_AND_EXPR, lntype, lhs, ll_mask);
+
+ rhs = make_bit_field_ref (lr_inner, rntype, rnbitsize, rnbitpos,
+ lr_unsignedp || rr_unsignedp);
+ if (! all_ones_mask_p (lr_mask, rnbitsize))
+ rhs = build (BIT_AND_EXPR, rntype, rhs, lr_mask);
+
return build (wanted_code, truth_type, lhs, rhs);
}
/* There is still another way we can do something: If both pairs of
fields being compared are adjacent, we may be able to make a wider
- field containing them both. */
+ field containing them both.
+
+ Note that we still must mask the lhs/rhs expressions. Furthermore,
+ the mask must be shifted to account for the shift done by
+ make_bit_field_ref. */
if ((ll_bitsize + ll_bitpos == rl_bitpos
&& lr_bitsize + lr_bitpos == rr_bitpos)
|| (ll_bitpos == rl_bitpos + rl_bitsize
&& lr_bitpos == rr_bitpos + rr_bitsize))
- return build (wanted_code, truth_type,
- make_bit_field_ref (ll_inner, type,
- ll_bitsize + rl_bitsize,
- MIN (ll_bitpos, rl_bitpos),
- ll_unsignedp),
- make_bit_field_ref (lr_inner, type,
- lr_bitsize + rr_bitsize,
- MIN (lr_bitpos, rr_bitpos),
- lr_unsignedp));
+ {
+ tree type;
+
+ lhs = make_bit_field_ref (ll_inner, lntype, ll_bitsize + rl_bitsize,
+ MIN (ll_bitpos, rl_bitpos), ll_unsignedp);
+ rhs = make_bit_field_ref (lr_inner, rntype, lr_bitsize + rr_bitsize,
+ MIN (lr_bitpos, rr_bitpos), lr_unsignedp);
+
+ ll_mask = const_binop (RSHIFT_EXPR, ll_mask,
+ size_int (MIN (xll_bitpos, xrl_bitpos)), 0);
+ lr_mask = const_binop (RSHIFT_EXPR, lr_mask,
+ size_int (MIN (xlr_bitpos, xrr_bitpos)), 0);
+
+ /* Convert to the smaller type before masking out unwanted bits. */
+ type = lntype;
+ if (lntype != rntype)
+ {
+ if (lnbitsize > rnbitsize)
+ {
+ lhs = convert (rntype, lhs);
+ ll_mask = convert (rntype, ll_mask);
+ type = rntype;
+ }
+ else if (lnbitsize < rnbitsize)
+ {
+ rhs = convert (lntype, rhs);
+ lr_mask = convert (lntype, lr_mask);
+ type = lntype;
+ }
+ }
+
+ if (! all_ones_mask_p (ll_mask, ll_bitsize + rl_bitsize))
+ lhs = build (BIT_AND_EXPR, type, lhs, ll_mask);
+
+ if (! all_ones_mask_p (lr_mask, lr_bitsize + rr_bitsize))
+ rhs = build (BIT_AND_EXPR, type, rhs, lr_mask);
+
+ return build (wanted_code, truth_type, lhs, rhs);
+ }
return 0;
}
}
else
{
- warning ("`and' of mutually exclusive equal-tests is always zero");
+ warning ("`and' of mutually exclusive equal-tests is always 0");
return convert (truth_type, integer_zero_node);
}
}
reference we will make. Unless the mask is all ones the width of
that field, perform the mask operation. Then compare with the
merged constant. */
- result = make_bit_field_ref (ll_inner, type, lnbitsize, lnbitpos,
+ result = make_bit_field_ref (ll_inner, lntype, lnbitsize, lnbitpos,
ll_unsignedp || rl_unsignedp);
ll_mask = const_binop (BIT_IOR_EXPR, ll_mask, rl_mask, 0);
if (! all_ones_mask_p (ll_mask, lnbitsize))
- result = build (BIT_AND_EXPR, type, result, ll_mask);
+ result = build (BIT_AND_EXPR, lntype, result, ll_mask);
return build (wanted_code, truth_type, result,
const_binop (BIT_IOR_EXPR, l_const, r_const, 0));
tree t;
tree s;
{
- tree type = TREE_TYPE (t);
enum tree_code code = TREE_CODE (t);
/* See if this is the COMPOUND_EXPR we want to eliminate. */
return t;
}
\f
+/* Return a node which has the indicated constant VALUE (either 0 or
+ 1), and is of the indicated TYPE. */
+
+static tree
+constant_boolean_node (value, type)
+ int value;
+ tree type;
+{
+ if (type == integer_type_node)
+ return value ? integer_one_node : integer_zero_node;
+ else if (TREE_CODE (type) == BOOLEAN_TYPE)
+ return truthvalue_conversion (value ? integer_one_node :
+ integer_zero_node);
+ else
+ {
+ tree t = build_int_2 (value, 0);
+ TREE_TYPE (t) = type;
+ return t;
+ }
+}
+
+/* Utility function for the following routine, to see how complex a nesting of
+ COND_EXPRs can be. EXPR is the expression and LIMIT is a count beyond which
+ we don't care (to avoid spending too much time on complex expressions.). */
+
+static int
+count_cond (expr, lim)
+ tree expr;
+ int lim;
+{
+ int true, false;
+
+ if (TREE_CODE (expr) != COND_EXPR)
+ return 0;
+ else if (lim <= 0)
+ return 0;
+
+ true = count_cond (TREE_OPERAND (expr, 1), lim - 1);
+ false = count_cond (TREE_OPERAND (expr, 2), lim - 1 - true);
+ return MIN (lim, 1 + true + false);
+}
+\f
/* 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.
tree t1 = NULL_TREE;
tree tem;
tree type = TREE_TYPE (expr);
- register tree arg0, arg1;
+ register tree arg0 = NULL_TREE, arg1 = NULL_TREE;
register enum tree_code code = TREE_CODE (t);
register int kind;
int invert;
return t;
}
+#ifdef MAX_INTEGER_COMPUTATION_MODE
+ check_max_integer_computation_mode (expr);
+#endif
+
kind = TREE_CODE_CLASS (code);
if (code == NOP_EXPR || code == FLOAT_EXPR || code == CONVERT_EXPR)
{
else if ((TREE_CODE (arg1) == COND_EXPR
|| (TREE_CODE_CLASS (TREE_CODE (arg1)) == '<'
&& TREE_CODE_CLASS (code) != '<'))
- && (! TREE_SIDE_EFFECTS (arg0) || current_function_decl != 0))
+ && (TREE_CODE (arg0) != COND_EXPR
+ || count_cond (arg0, 25) + count_cond (arg1, 25) <= 25)
+ && (! TREE_SIDE_EFFECTS (arg0)
+ || (current_function_decl != 0
+ && ! contains_placeholder_p (arg0))))
{
tree test, true_value, false_value;
+ tree lhs = 0, rhs = 0;
if (TREE_CODE (arg1) == COND_EXPR)
{
to make this SAVE_EXPR. Since we do this optimization
primarily to see if we do end up with constant and this
SAVE_EXPR interferes with later optimizations, suppressing
- it when we can is important. */
+ it when we can is important.
+
+ If we are not in a function, we can't make a SAVE_EXPR, so don't
+ try to do so. Don't try to see if the result is a constant
+ if an arm is a COND_EXPR since we get exponential behavior
+ in that case. */
- if (TREE_CODE (arg0) != SAVE_EXPR
+ if (TREE_CODE (arg0) != SAVE_EXPR && ! TREE_CONSTANT (arg0)
+ && current_function_decl != 0
&& ((TREE_CODE (arg0) != VAR_DECL
&& TREE_CODE (arg0) != PARM_DECL)
|| TREE_SIDE_EFFECTS (arg0)))
{
- tree lhs = fold (build (code, type, arg0, true_value));
- tree rhs = fold (build (code, type, arg0, false_value));
+ if (TREE_CODE (true_value) != COND_EXPR)
+ lhs = fold (build (code, type, arg0, true_value));
- if (TREE_CONSTANT (lhs) || TREE_CONSTANT (rhs))
- return fold (build (COND_EXPR, type, test, lhs, rhs));
+ if (TREE_CODE (false_value) != COND_EXPR)
+ rhs = fold (build (code, type, arg0, false_value));
- if (current_function_decl != 0)
- arg0 = save_expr (arg0);
+ if ((lhs == 0 || ! TREE_CONSTANT (lhs))
+ && (rhs == 0 || !TREE_CONSTANT (rhs)))
+ arg0 = save_expr (arg0), lhs = rhs = 0;
}
- test = fold (build (COND_EXPR, type, test,
- fold (build (code, type, arg0, true_value)),
- fold (build (code, type, arg0, false_value))));
+ if (lhs == 0)
+ lhs = fold (build (code, type, arg0, true_value));
+ if (rhs == 0)
+ rhs = fold (build (code, type, arg0, false_value));
+
+ test = fold (build (COND_EXPR, type, test, lhs, rhs));
+
if (TREE_CODE (arg0) == SAVE_EXPR)
return build (COMPOUND_EXPR, type,
convert (void_type_node, arg0),
else if ((TREE_CODE (arg0) == COND_EXPR
|| (TREE_CODE_CLASS (TREE_CODE (arg0)) == '<'
&& TREE_CODE_CLASS (code) != '<'))
- && (! TREE_SIDE_EFFECTS (arg1) || current_function_decl != 0))
+ && (TREE_CODE (arg1) != COND_EXPR
+ || count_cond (arg0, 25) + count_cond (arg1, 25) <= 25)
+ && (! TREE_SIDE_EFFECTS (arg1)
+ || (current_function_decl != 0
+ && ! contains_placeholder_p (arg1))))
{
tree test, true_value, false_value;
+ tree lhs = 0, rhs = 0;
if (TREE_CODE (arg0) == COND_EXPR)
{
false_value = convert (testtype, integer_zero_node);
}
- if (TREE_CODE (arg1) != SAVE_EXPR
+ if (TREE_CODE (arg1) != SAVE_EXPR && ! TREE_CONSTANT (arg0)
+ && current_function_decl != 0
&& ((TREE_CODE (arg1) != VAR_DECL
&& TREE_CODE (arg1) != PARM_DECL)
|| TREE_SIDE_EFFECTS (arg1)))
{
- tree lhs = fold (build (code, type, true_value, arg1));
- tree rhs = fold (build (code, type, false_value, arg1));
+ if (TREE_CODE (true_value) != COND_EXPR)
+ lhs = fold (build (code, type, true_value, arg1));
- if (TREE_CONSTANT (lhs) || TREE_CONSTANT (rhs)
- || TREE_CONSTANT (arg1))
- return fold (build (COND_EXPR, type, test, lhs, rhs));
+ if (TREE_CODE (false_value) != COND_EXPR)
+ rhs = fold (build (code, type, false_value, arg1));
- if (current_function_decl != 0)
- arg1 = save_expr (arg1);
+ if ((lhs == 0 || ! TREE_CONSTANT (lhs))
+ && (rhs == 0 || !TREE_CONSTANT (rhs)))
+ arg1 = save_expr (arg1), lhs = rhs = 0;
}
- test = fold (build (COND_EXPR, type, test,
- fold (build (code, type, true_value, arg1)),
- fold (build (code, type, false_value, arg1))));
+ if (lhs == 0)
+ lhs = fold (build (code, type, true_value, arg1));
+
+ if (rhs == 0)
+ rhs = fold (build (code, type, false_value, arg1));
+
+ test = fold (build (COND_EXPR, type, test, lhs, rhs));
if (TREE_CODE (arg1) == SAVE_EXPR)
return build (COMPOUND_EXPR, type,
convert (void_type_node, arg1),
&& ! final_ptr)
return convert (final_type, TREE_OPERAND (TREE_OPERAND (t, 0), 0));
+ /* If we have a sign-extension of a zero-extended value, we can
+ replace that by a single zero-extension. */
+ if (inside_int && inter_int && final_int
+ && inside_prec < inter_prec && inter_prec < final_prec
+ && inside_unsignedp && !inter_unsignedp)
+ return convert (final_type, TREE_OPERAND (TREE_OPERAND (t, 0), 0));
+
/* Two conversions in a row are not needed unless:
- some conversion is floating-point (overstrict for now), or
- the intermediate type is narrower than both initial and
goto bit_ior;
}
- /* (A * C) + (B * C) -> (A+B) * C. Since we are most concerned
- about the case where C is a constant, just try one of the
- four possibilities. */
-
- if (TREE_CODE (arg0) == MULT_EXPR && TREE_CODE (arg1) == MULT_EXPR
- && operand_equal_p (TREE_OPERAND (arg0, 1),
- TREE_OPERAND (arg1, 1), 0))
- return fold (build (MULT_EXPR, type,
- fold (build (PLUS_EXPR, type,
- TREE_OPERAND (arg0, 0),
- TREE_OPERAND (arg1, 0))),
- TREE_OPERAND (arg0, 1)));
+ if (TREE_CODE (arg0) == MULT_EXPR && TREE_CODE (arg1) == MULT_EXPR)
+ {
+ tree arg00, arg01, arg10, arg11;
+ tree alt0, alt1, same;
+
+ /* (A * C) + (B * C) -> (A+B) * C.
+ We are most concerned about the case where C is a constant,
+ but other combinations show up during loop reduction. Since
+ it is not difficult, try all four possibilities. */
+
+ arg00 = TREE_OPERAND (arg0, 0);
+ arg01 = TREE_OPERAND (arg0, 1);
+ arg10 = TREE_OPERAND (arg1, 0);
+ arg11 = TREE_OPERAND (arg1, 1);
+ same = NULL_TREE;
+
+ if (operand_equal_p (arg01, arg11, 0))
+ same = arg01, alt0 = arg00, alt1 = arg10;
+ else if (operand_equal_p (arg00, arg10, 0))
+ same = arg00, alt0 = arg01, alt1 = arg11;
+ else if (operand_equal_p (arg00, arg11, 0))
+ same = arg00, alt0 = arg01, alt1 = arg10;
+ else if (operand_equal_p (arg01, arg10, 0))
+ same = arg01, alt0 = arg00, alt1 = arg11;
+
+ if (same)
+ return fold (build (MULT_EXPR, type,
+ fold (build (PLUS_EXPR, type, alt0, alt1)),
+ same));
+ }
}
/* In IEEE floating point, x+0 may not equal x. */
else if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
if (real_onep (arg1))
return non_lvalue (convert (type, arg0));
/* x*2 is x+x */
- if (! wins && real_twop (arg1) && current_function_decl != 0)
+ if (! wins && real_twop (arg1) && current_function_decl != 0
+ && ! contains_placeholder_p (arg0))
{
tree arg = save_expr (arg0);
return build (PLUS_EXPR, type, arg, arg);
tree01 = TREE_OPERAND (arg0, 1);
tree11 = TREE_OPERAND (arg1, 1);
+ STRIP_NOPS (tree01);
+ STRIP_NOPS (tree11);
code01 = TREE_CODE (tree01);
code11 = TREE_CODE (tree11);
if (code01 == INTEGER_CST
== TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0)))))
return build (LROTATE_EXPR, type, TREE_OPERAND (arg0, 0),
code0 == LSHIFT_EXPR ? tree01 : tree11);
- else if (code11 == MINUS_EXPR
- && TREE_CODE (TREE_OPERAND (tree11, 0)) == INTEGER_CST
- && TREE_INT_CST_HIGH (TREE_OPERAND (tree11, 0)) == 0
- && TREE_INT_CST_LOW (TREE_OPERAND (tree11, 0))
- == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0)))
- && operand_equal_p (tree01, TREE_OPERAND (tree11, 1), 0))
- return build (code0 == LSHIFT_EXPR ? LROTATE_EXPR : RROTATE_EXPR,
- type, TREE_OPERAND (arg0, 0), tree01);
- else if (code01 == MINUS_EXPR
- && TREE_CODE (TREE_OPERAND (tree01, 0)) == INTEGER_CST
- && TREE_INT_CST_HIGH (TREE_OPERAND (tree01, 0)) == 0
- && TREE_INT_CST_LOW (TREE_OPERAND (tree01, 0))
- == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0)))
- && operand_equal_p (tree11, TREE_OPERAND (tree01, 1), 0))
- return build (code0 != LSHIFT_EXPR ? LROTATE_EXPR : RROTATE_EXPR,
- type, TREE_OPERAND (arg0, 0), tree11);
+ else if (code11 == MINUS_EXPR)
+ {
+ tree tree110, tree111;
+ tree110 = TREE_OPERAND (tree11, 0);
+ tree111 = TREE_OPERAND (tree11, 1);
+ STRIP_NOPS (tree110);
+ STRIP_NOPS (tree111);
+ if (TREE_CODE (tree110) == INTEGER_CST
+ && TREE_INT_CST_HIGH (tree110) == 0
+ && (TREE_INT_CST_LOW (tree110)
+ == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0))))
+ && operand_equal_p (tree01, tree111, 0))
+ return build ((code0 == LSHIFT_EXPR
+ ? LROTATE_EXPR
+ : RROTATE_EXPR),
+ type, TREE_OPERAND (arg0, 0), tree01);
+ }
+ else if (code01 == MINUS_EXPR)
+ {
+ tree tree010, tree011;
+ tree010 = TREE_OPERAND (tree01, 0);
+ tree011 = TREE_OPERAND (tree01, 1);
+ STRIP_NOPS (tree010);
+ STRIP_NOPS (tree011);
+ if (TREE_CODE (tree010) == INTEGER_CST
+ && TREE_INT_CST_HIGH (tree010) == 0
+ && (TREE_INT_CST_LOW (tree010)
+ == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0))))
+ && operand_equal_p (tree11, tree011, 0))
+ return build ((code0 != LSHIFT_EXPR
+ ? LROTATE_EXPR
+ : RROTATE_EXPR),
+ type, TREE_OPERAND (arg0, 0), tree11);
+ }
}
goto associate;
if (operand_equal_p (arg0, arg1, 0))
return arg0;
if (INTEGRAL_TYPE_P (type)
+ && TYPE_MAX_VALUE (type)
&& operand_equal_p (arg1, TYPE_MAX_VALUE (type), 1))
return omit_one_operand (type, arg1, arg0);
goto associate;
First, see if one arg is constant; find the constant arg
and the other one. */
{
- tree constop = 0, varop;
+ tree constop = 0, varop = NULL_TREE;
int constopnum = -1;
if (TREE_CONSTANT (arg1))
if CONST+INCR overflows or if foo+incr might overflow.
This optimization is invalid for floating point due to rounding.
For pointer types we assume overflow doesn't happen. */
- if (TREE_CODE (TREE_TYPE (varop)) == POINTER_TYPE
+ if (POINTER_TYPE_P (TREE_TYPE (varop))
|| (! FLOAT_TYPE_P (TREE_TYPE (varop))
&& (code == EQ_EXPR || code == NE_EXPR)))
{
= TREE_INT_CST_LOW (DECL_SIZE
(TREE_OPERAND
(TREE_OPERAND (varop, 0), 1)));
-
+ tree mask, unsigned_type;
+ int precision;
+ tree folded_compare;
+
+ /* First check whether the comparison would come out
+ always the same. If we don't do that we would
+ change the meaning with the masking. */
+ if (constopnum == 0)
+ folded_compare = fold (build (code, type, constop,
+ TREE_OPERAND (varop, 0)));
+ else
+ folded_compare = fold (build (code, type,
+ TREE_OPERAND (varop, 0),
+ constop));
+ if (integer_zerop (folded_compare)
+ || integer_onep (folded_compare))
+ return omit_one_operand (type, folded_compare, varop);
+
+ unsigned_type = type_for_size (size, 1);
+ precision = TYPE_PRECISION (unsigned_type);
+ mask = build_int_2 (~0, ~0);
+ TREE_TYPE (mask) = unsigned_type;
+ force_fit_type (mask, 0);
+ mask = const_binop (RSHIFT_EXPR, mask,
+ size_int (precision - size), 0);
newconst = fold (build (BIT_AND_EXPR,
TREE_TYPE (varop), newconst,
convert (TREE_TYPE (varop),
- build_int_2 (size, 0))));
+ mask)));
}
}
else if (constop && TREE_CODE (varop) == POSTDECREMENT_EXPR)
{
- if (TREE_CODE (TREE_TYPE (varop)) == POINTER_TYPE
+ if (POINTER_TYPE_P (TREE_TYPE (varop))
|| (! FLOAT_TYPE_P (TREE_TYPE (varop))
&& (code == EQ_EXPR || code == NE_EXPR)))
{
= TREE_INT_CST_LOW (DECL_SIZE
(TREE_OPERAND
(TREE_OPERAND (varop, 0), 1)));
-
+ tree mask, unsigned_type;
+ int precision;
+ tree folded_compare;
+
+ if (constopnum == 0)
+ folded_compare = fold (build (code, type, constop,
+ TREE_OPERAND (varop, 0)));
+ else
+ folded_compare = fold (build (code, type,
+ TREE_OPERAND (varop, 0),
+ constop));
+ if (integer_zerop (folded_compare)
+ || integer_onep (folded_compare))
+ return omit_one_operand (type, folded_compare, varop);
+
+ unsigned_type = type_for_size (size, 1);
+ precision = TYPE_PRECISION (unsigned_type);
+ mask = build_int_2 (~0, ~0);
+ TREE_TYPE (mask) = TREE_TYPE (varop);
+ force_fit_type (mask, 0);
+ mask = const_binop (RSHIFT_EXPR, mask,
+ size_int (precision - size), 0);
newconst = fold (build (BIT_AND_EXPR,
TREE_TYPE (varop), newconst,
convert (TREE_TYPE (varop),
- build_int_2 (size, 0))));
+ mask)));
}
case GE_EXPR:
case LE_EXPR:
if (INTEGRAL_TYPE_P (TREE_TYPE (arg0)))
- {
- if (type == integer_type_node)
- return integer_one_node;
-
- t = build_int_2 (1, 0);
- TREE_TYPE (t) = type;
- return t;
- }
+ return constant_boolean_node (1, type);
code = EQ_EXPR;
TREE_SET_CODE (t, code);
break;
/* ... fall through ... */
case GT_EXPR:
case LT_EXPR:
- if (type == integer_type_node)
- return integer_zero_node;
-
- t = build_int_2 (0, 0);
- TREE_TYPE (t) = type;
- return t;
+ return constant_boolean_node (0, type);
default:
abort ();
}
/* An unsigned comparison against 0 can be simplified. */
if (integer_zerop (arg1)
&& (INTEGRAL_TYPE_P (TREE_TYPE (arg1))
- || TREE_CODE (TREE_TYPE (arg1)) == POINTER_TYPE)
+ || POINTER_TYPE_P (TREE_TYPE (arg1)))
&& TREE_UNSIGNED (TREE_TYPE (arg1)))
{
switch (TREE_CODE (t))
&& TREE_INT_CST_LOW (arg1) == ((HOST_WIDE_INT) 1 << (width - 1)) - 1
&& TREE_INT_CST_HIGH (arg1) == 0
&& (INTEGRAL_TYPE_P (TREE_TYPE (arg1))
- || TREE_CODE (TREE_TYPE (arg1)) == POINTER_TYPE)
+ || POINTER_TYPE_P (TREE_TYPE (arg1)))
&& TREE_UNSIGNED (TREE_TYPE (arg1)))
{
switch (TREE_CODE (t))
arg0),
convert (signed_type (TREE_TYPE (arg1)),
integer_zero_node)));
+ default:
+ break;
}
}
}
&& ! (TREE_CONSTANT (cval1) && TREE_CONSTANT (cval2))
&& TREE_TYPE (cval1) == TREE_TYPE (cval2)
&& INTEGRAL_TYPE_P (TREE_TYPE (cval1))
+ && TYPE_MAX_VALUE (TREE_TYPE (cval1))
+ && TYPE_MAX_VALUE (TREE_TYPE (cval2))
&& ! operand_equal_p (TYPE_MIN_VALUE (TREE_TYPE (cval1)),
TYPE_MAX_VALUE (TREE_TYPE (cval2)), 0))
{
return t1 ? t1 : t;
}
- /* If this is a comparison of complex values and either or both
- sizes are a COMPLEX_EXPR, it is best to split up the comparisons
- and join them with a TRUTH_ANDIF_EXPR or TRUTH_ORIF_EXPR. This
- may prevent needless evaluations. */
+ /* If this is a comparison of complex values and either or both sides
+ are a COMPLEX_EXPR or COMPLEX_CST, it is best to split up the
+ comparisons and join them with a TRUTH_ANDIF_EXPR or TRUTH_ORIF_EXPR.
+ This may prevent needless evaluations. */
if ((code == EQ_EXPR || code == NE_EXPR)
&& TREE_CODE (TREE_TYPE (arg0)) == COMPLEX_TYPE
&& (TREE_CODE (arg0) == COMPLEX_EXPR
- || TREE_CODE (arg1) == COMPLEX_EXPR))
+ || TREE_CODE (arg1) == COMPLEX_EXPR
+ || TREE_CODE (arg0) == COMPLEX_CST
+ || TREE_CODE (arg1) == COMPLEX_CST))
{
tree subtype = TREE_TYPE (TREE_TYPE (arg0));
- tree real0 = fold (build1 (REALPART_EXPR, subtype, arg0));
- tree imag0 = fold (build1 (IMAGPART_EXPR, subtype, arg0));
- tree real1 = fold (build1 (REALPART_EXPR, subtype, arg1));
- tree imag1 = fold (build1 (IMAGPART_EXPR, subtype, arg1));
+ tree real0, imag0, real1, imag1;
+
+ arg0 = save_expr (arg0);
+ arg1 = save_expr (arg1);
+ real0 = fold (build1 (REALPART_EXPR, subtype, arg0));
+ imag0 = fold (build1 (IMAGPART_EXPR, subtype, arg0));
+ real1 = fold (build1 (REALPART_EXPR, subtype, arg1));
+ imag1 = fold (build1 (IMAGPART_EXPR, subtype, arg1));
return fold (build ((code == EQ_EXPR ? TRUTH_ANDIF_EXPR
: TRUTH_ORIF_EXPR),
TREE_INT_CST_LOW (t1) ^= 1;
TREE_TYPE (t1) = type;
+ if (TREE_CODE (type) == BOOLEAN_TYPE)
+ return truthvalue_conversion (t1);
return t1;
case COND_EXPR:
t = build (code, type, tem,
TREE_OPERAND (t, 2), TREE_OPERAND (t, 1));
arg0 = tem;
- arg1 = TREE_OPERAND (t, 2);
+ /* arg1 should be the first argument of the new T. */
+ arg1 = TREE_OPERAND (t, 1);
STRIP_NOPS (arg1);
}
}
return pedantic_non_lvalue (convert (type, arg1));
case GE_EXPR:
case GT_EXPR:
+ if (TREE_UNSIGNED (TREE_TYPE (arg1)))
+ arg1 = convert (signed_type (TREE_TYPE (arg1)), arg1);
return pedantic_non_lvalue
(convert (type, fold (build1 (ABS_EXPR,
TREE_TYPE (arg1), arg1))));
case LE_EXPR:
case LT_EXPR:
+ if (TREE_UNSIGNED (TREE_TYPE (arg1)))
+ arg1 = convert (signed_type (TREE_TYPE (arg1)), arg1);
return pedantic_non_lvalue
(fold (build1 (NEGATE_EXPR, type,
convert (type,
t = build (code, type, tem,
TREE_OPERAND (t, 2), TREE_OPERAND (t, 1));
arg0 = tem;
- arg1 = TREE_OPERAND (t, 2);
+ /* arg1 should be the first argument of the new T. */
+ arg1 = TREE_OPERAND (t, 1);
STRIP_NOPS (arg1);
}
}
return t;
/* Don't let (0, 0) be null pointer constant. */
if (integer_zerop (arg1))
- return non_lvalue (arg1);
+ return build1 (NOP_EXPR, TREE_TYPE (arg1), arg1);
return arg1;
case COMPLEX_EXPR:
/* Pull arithmetic ops out of the CLEANUP_POINT_EXPR where
appropriate. */
case CLEANUP_POINT_EXPR:
- if (! TREE_SIDE_EFFECTS (arg0))
+ if (! has_cleanups (arg0))
return TREE_OPERAND (t, 0);
{
{
arg01 = TREE_OPERAND (arg0, 1);
- if (! TREE_SIDE_EFFECTS (arg00))
+ if (TREE_CONSTANT (arg00)
+ || ((code0 == TRUTH_ANDIF_EXPR || code0 == TRUTH_ORIF_EXPR)
+ && ! has_cleanups (arg00)))
return fold (build (code0, type, arg00,
fold (build1 (CLEANUP_POINT_EXPR,
TREE_TYPE (arg01), arg01))));
- if (! TREE_SIDE_EFFECTS (arg01))
+ if (TREE_CONSTANT (arg01))
return fold (build (code0, type,
fold (build1 (CLEANUP_POINT_EXPR,
TREE_TYPE (arg00), arg00)),