diff options
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r-- | gcc/fold-const.c | 13621 |
1 files changed, 13621 insertions, 0 deletions
diff --git a/gcc/fold-const.c b/gcc/fold-const.c new file mode 100644 index 0000000..ea16eae --- /dev/null +++ b/gcc/fold-const.c @@ -0,0 +1,13621 @@ +/* Fold a constant sub-tree into a single node for C-compiler + Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 + Free Software Foundation, Inc. + +This file is part of GCC. + +GCC 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 2, or (at your option) any later +version. + +GCC 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 GCC; see the file COPYING. If not, write to the Free +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ + +/*@@ This file should be rewritten to use an arbitrary precision + @@ representation for "struct tree_int_cst" and "struct tree_real_cst". + @@ Perhaps the routines could also be used for bc/dc, and made a lib. + @@ 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. */ + +/* 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. + + size_binop takes a tree code for an arithmetic operation + and two operands that are trees, and produces a tree for the + result, assuming the type comes from `sizetype'. + + size_int takes an integer value, and creates a tree constant + with type from `sizetype'. + + force_fit_type takes a constant, an overflowable flag and prior + overflow indicators. It forces the value to fit the type and sets + TREE_OVERFLOW and TREE_CONSTANT_OVERFLOW as appropriate. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "flags.h" +#include "tree.h" +#include "real.h" +#include "rtl.h" +#include "expr.h" +#include "tm_p.h" +#include "toplev.h" +#include "intl.h" +#include "ggc.h" +#include "hashtab.h" +#include "langhooks.h" +#include "md5.h" + +/* Non-zero if we are folding constants inside an initializer; zero + otherwise. */ +int folding_initializer = 0; + +/* The following constants represent a bit based encoding of GCC's + comparison operators. This encoding simplifies transformations + on relational comparison operators, such as AND and OR. */ +enum comparison_code { + COMPCODE_FALSE = 0, + COMPCODE_LT = 1, + COMPCODE_EQ = 2, + COMPCODE_LE = 3, + COMPCODE_GT = 4, + COMPCODE_LTGT = 5, + COMPCODE_GE = 6, + COMPCODE_ORD = 7, + COMPCODE_UNORD = 8, + COMPCODE_UNLT = 9, + COMPCODE_UNEQ = 10, + COMPCODE_UNLE = 11, + COMPCODE_UNGT = 12, + COMPCODE_NE = 13, + COMPCODE_UNGE = 14, + COMPCODE_TRUE = 15 +}; + +static void encode (HOST_WIDE_INT *, unsigned HOST_WIDE_INT, HOST_WIDE_INT); +static void decode (HOST_WIDE_INT *, unsigned HOST_WIDE_INT *, HOST_WIDE_INT *); +static bool negate_mathfn_p (enum built_in_function); +static bool negate_expr_p (tree); +static tree negate_expr (tree); +static tree split_tree (tree, enum tree_code, tree *, tree *, tree *, int); +static tree associate_trees (tree, tree, enum tree_code, tree); +static tree const_binop (enum tree_code, tree, tree, int); +static enum comparison_code comparison_to_compcode (enum tree_code); +static enum tree_code compcode_to_comparison (enum comparison_code); +static tree combine_comparisons (enum tree_code, enum tree_code, + enum tree_code, tree, tree, tree); +static int truth_value_p (enum tree_code); +static int operand_equal_for_comparison_p (tree, tree, tree); +static int twoval_comparison_p (tree, tree *, tree *, int *); +static tree eval_subst (tree, tree, tree, tree, tree); +static tree pedantic_omit_one_operand (tree, tree, tree); +static tree distribute_bit_expr (enum tree_code, tree, tree, tree); +static tree make_bit_field_ref (tree, tree, int, int, int); +static tree optimize_bit_field_compare (enum tree_code, tree, tree, tree); +static tree decode_field_reference (tree, HOST_WIDE_INT *, HOST_WIDE_INT *, + enum machine_mode *, int *, int *, + tree *, tree *); +static int all_ones_mask_p (tree, int); +static tree sign_bit_p (tree, tree); +static int simple_operand_p (tree); +static tree range_binop (enum tree_code, tree, tree, int, tree, int); +static tree range_predecessor (tree); +static tree range_successor (tree); +static tree make_range (tree, int *, tree *, tree *, bool *); +static tree build_range_check (tree, tree, int, tree, tree); +static int merge_ranges (int *, tree *, tree *, int, tree, tree, int, tree, + tree); +static tree fold_range_test (enum tree_code, tree, tree, tree); +static tree fold_cond_expr_with_comparison (tree, tree, tree, tree); +static tree unextend (tree, int, int, tree); +static tree fold_truthop (enum tree_code, tree, tree, tree); +static tree optimize_minmax_comparison (enum tree_code, tree, tree, tree); +static tree extract_muldiv (tree, tree, enum tree_code, tree, bool *); +static tree extract_muldiv_1 (tree, tree, enum tree_code, tree, bool *); +static int multiple_of_p (tree, tree, tree); +static tree fold_binary_op_with_conditional_arg (enum tree_code, tree, + tree, tree, + tree, tree, int); +static bool fold_real_zero_addition_p (tree, tree, int); +static tree fold_mathfn_compare (enum built_in_function, enum tree_code, + tree, tree, tree); +static tree fold_inf_compare (enum tree_code, tree, tree, tree); +static tree fold_div_compare (enum tree_code, tree, tree, tree); +static bool reorder_operands_p (tree, tree); +static tree fold_negate_const (tree, tree); +static tree fold_not_const (tree, tree); +static tree fold_relational_const (enum tree_code, tree, tree, tree); +static int native_encode_expr (tree, unsigned char *, int); +static tree native_interpret_expr (tree, unsigned char *, int); + + +/* We know that A1 + B1 = SUM1, using 2's complement arithmetic and ignoring + overflow. Suppose A, B and SUM have the same respective signs as A1, B1, + and SUM1. Then this yields nonzero if overflow occurred during the + addition. + + Overflow occurs if A and B have the same sign, but A and SUM differ in + sign. Use `^' to test whether signs differ, and `< 0' to isolate the + sign. */ +#define OVERFLOW_SUM_SIGN(a, b, sum) ((~((a) ^ (b)) & ((a) ^ (sum))) < 0) + +/* To do constant folding on INTEGER_CST nodes requires two-word arithmetic. + We do that by representing the two-word integer in 4 words, with only + HOST_BITS_PER_WIDE_INT / 2 bits stored in each word, as a positive + number. The value of the word is LOWPART + HIGHPART * BASE. */ + +#define LOWPART(x) \ + ((x) & (((unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2)) - 1)) +#define HIGHPART(x) \ + ((unsigned HOST_WIDE_INT) (x) >> HOST_BITS_PER_WIDE_INT / 2) +#define BASE ((unsigned HOST_WIDE_INT) 1 << HOST_BITS_PER_WIDE_INT / 2) + +/* Unpack a two-word integer into 4 words. + LOW and HI are the integer, as two `HOST_WIDE_INT' pieces. + WORDS points to the array of HOST_WIDE_INTs. */ + +static void +encode (HOST_WIDE_INT *words, unsigned HOST_WIDE_INT low, HOST_WIDE_INT hi) +{ + words[0] = LOWPART (low); + words[1] = HIGHPART (low); + words[2] = LOWPART (hi); + words[3] = HIGHPART (hi); +} + +/* Pack an array of 4 words into a two-word integer. + WORDS points to the array of words. + The integer is stored into *LOW and *HI as two `HOST_WIDE_INT' pieces. */ + +static void +decode (HOST_WIDE_INT *words, unsigned HOST_WIDE_INT *low, + HOST_WIDE_INT *hi) +{ + *low = words[0] + words[1] * BASE; + *hi = words[2] + words[3] * BASE; +} + +/* T is an INT_CST node. OVERFLOWABLE indicates if we are interested + in overflow of the value, when >0 we are only interested in signed + overflow, for <0 we are interested in any overflow. OVERFLOWED + indicates whether overflow has already occurred. CONST_OVERFLOWED + indicates whether constant overflow has already occurred. We force + T's value to be within range of T's type (by setting to 0 or 1 all + the bits outside the type's range). We set TREE_OVERFLOWED if, + OVERFLOWED is nonzero, + or OVERFLOWABLE is >0 and signed overflow occurs + or OVERFLOWABLE is <0 and any overflow occurs + We set TREE_CONSTANT_OVERFLOWED if, + CONST_OVERFLOWED is nonzero + or we set TREE_OVERFLOWED. + We return either the original T, or a copy. */ + +tree +force_fit_type (tree t, int overflowable, + bool overflowed, bool overflowed_const) +{ + unsigned HOST_WIDE_INT low; + HOST_WIDE_INT high; + unsigned int prec; + int sign_extended_type; + + gcc_assert (TREE_CODE (t) == INTEGER_CST); + + low = TREE_INT_CST_LOW (t); + high = TREE_INT_CST_HIGH (t); + + if (POINTER_TYPE_P (TREE_TYPE (t)) + || TREE_CODE (TREE_TYPE (t)) == OFFSET_TYPE) + prec = POINTER_SIZE; + else + prec = TYPE_PRECISION (TREE_TYPE (t)); + /* Size types *are* sign extended. */ + sign_extended_type = (!TYPE_UNSIGNED (TREE_TYPE (t)) + || (TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE + && TYPE_IS_SIZETYPE (TREE_TYPE (t)))); + + /* First clear all bits that are beyond the type's precision. */ + + if (prec >= 2 * HOST_BITS_PER_WIDE_INT) + ; + else if (prec > HOST_BITS_PER_WIDE_INT) + high &= ~((HOST_WIDE_INT) (-1) << (prec - HOST_BITS_PER_WIDE_INT)); + else + { + high = 0; + if (prec < HOST_BITS_PER_WIDE_INT) + low &= ~((HOST_WIDE_INT) (-1) << prec); + } + + if (!sign_extended_type) + /* No sign extension */; + else if (prec >= 2 * HOST_BITS_PER_WIDE_INT) + /* Correct width already. */; + else if (prec > HOST_BITS_PER_WIDE_INT) + { + /* Sign extend top half? */ + if (high & ((unsigned HOST_WIDE_INT)1 + << (prec - HOST_BITS_PER_WIDE_INT - 1))) + high |= (HOST_WIDE_INT) (-1) << (prec - HOST_BITS_PER_WIDE_INT); + } + else if (prec == HOST_BITS_PER_WIDE_INT) + { + if ((HOST_WIDE_INT)low < 0) + high = -1; + } + else + { + /* Sign extend bottom half? */ + if (low & ((unsigned HOST_WIDE_INT)1 << (prec - 1))) + { + high = -1; + low |= (HOST_WIDE_INT)(-1) << prec; + } + } + + /* If the value changed, return a new node. */ + if (overflowed || overflowed_const + || low != TREE_INT_CST_LOW (t) || high != TREE_INT_CST_HIGH (t)) + { + t = build_int_cst_wide (TREE_TYPE (t), low, high); + + if (overflowed + || overflowable < 0 + || (overflowable > 0 && sign_extended_type)) + { + t = copy_node (t); + TREE_OVERFLOW (t) = 1; + TREE_CONSTANT_OVERFLOW (t) = 1; + } + else if (overflowed_const) + { + t = copy_node (t); + TREE_CONSTANT_OVERFLOW (t) = 1; + } + } + + return t; +} + +/* Add two doubleword integers with doubleword result. + Return nonzero if the operation overflows according to UNSIGNED_P. + Each argument is given as two `HOST_WIDE_INT' pieces. + One argument is L1 and H1; the other, L2 and H2. + The value is stored as two `HOST_WIDE_INT' pieces in *LV and *HV. */ + +int +add_double_with_sign (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, + unsigned HOST_WIDE_INT l2, HOST_WIDE_INT h2, + unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv, + bool unsigned_p) +{ + unsigned HOST_WIDE_INT l; + HOST_WIDE_INT h; + + l = l1 + l2; + h = h1 + h2 + (l < l1); + + *lv = l; + *hv = h; + + if (unsigned_p) + return (unsigned HOST_WIDE_INT) h < (unsigned HOST_WIDE_INT) h1; + else + return OVERFLOW_SUM_SIGN (h1, h2, h); +} + +/* Negate a doubleword integer with doubleword result. + Return nonzero if the operation overflows, assuming it's signed. + The argument is given as two `HOST_WIDE_INT' pieces in L1 and H1. + The value is stored as two `HOST_WIDE_INT' pieces in *LV and *HV. */ + +int +neg_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, + unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv) +{ + if (l1 == 0) + { + *lv = 0; + *hv = - h1; + return (*hv & h1) < 0; + } + else + { + *lv = -l1; + *hv = ~h1; + return 0; + } +} + +/* Multiply two doubleword integers with doubleword result. + Return nonzero if the operation overflows according to UNSIGNED_P. + Each argument is given as two `HOST_WIDE_INT' pieces. + One argument is L1 and H1; the other, L2 and H2. + The value is stored as two `HOST_WIDE_INT' pieces in *LV and *HV. */ + +int +mul_double_with_sign (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, + unsigned HOST_WIDE_INT l2, HOST_WIDE_INT h2, + unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv, + bool unsigned_p) +{ + HOST_WIDE_INT arg1[4]; + HOST_WIDE_INT arg2[4]; + HOST_WIDE_INT prod[4 * 2]; + unsigned HOST_WIDE_INT carry; + int i, j, k; + unsigned HOST_WIDE_INT toplow, neglow; + HOST_WIDE_INT tophigh, neghigh; + + encode (arg1, l1, h1); + encode (arg2, l2, h2); + + memset (prod, 0, sizeof prod); + + for (i = 0; i < 4; i++) + { + carry = 0; + for (j = 0; j < 4; j++) + { + k = i + j; + /* This product is <= 0xFFFE0001, the sum <= 0xFFFF0000. */ + carry += arg1[i] * arg2[j]; + /* Since prod[p] < 0xFFFF, this sum <= 0xFFFFFFFF. */ + carry += prod[k]; + prod[k] = LOWPART (carry); + carry = HIGHPART (carry); + } + prod[i + 4] = carry; + } + + decode (prod, lv, hv); + decode (prod + 4, &toplow, &tophigh); + + /* Unsigned overflow is immediate. */ + if (unsigned_p) + return (toplow | tophigh) != 0; + + /* Check for signed overflow by calculating the signed representation of the + top half of the result; it should agree with the low half's sign bit. */ + if (h1 < 0) + { + neg_double (l2, h2, &neglow, &neghigh); + add_double (neglow, neghigh, toplow, tophigh, &toplow, &tophigh); + } + if (h2 < 0) + { + neg_double (l1, h1, &neglow, &neghigh); + add_double (neglow, neghigh, toplow, tophigh, &toplow, &tophigh); + } + return (*hv < 0 ? ~(toplow & tophigh) : toplow | tophigh) != 0; +} + +/* Shift the doubleword 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 `HOST_WIDE_INT' pieces in *LV and *HV. */ + +void +lshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, + HOST_WIDE_INT count, unsigned int prec, + unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv, int arith) +{ + unsigned HOST_WIDE_INT signmask; + + if (count < 0) + { + rshift_double (l1, h1, -count, prec, lv, hv, arith); + return; + } + + if (SHIFT_COUNT_TRUNCATED) + count %= prec; + + if (count >= 2 * HOST_BITS_PER_WIDE_INT) + { + /* Shifting by the host word size is undefined according to the + ANSI standard, so we must handle this as a special case. */ + *hv = 0; + *lv = 0; + } + else if (count >= HOST_BITS_PER_WIDE_INT) + { + *hv = l1 << (count - HOST_BITS_PER_WIDE_INT); + *lv = 0; + } + else + { + *hv = (((unsigned HOST_WIDE_INT) h1 << count) + | (l1 >> (HOST_BITS_PER_WIDE_INT - count - 1) >> 1)); + *lv = l1 << count; + } + + /* Sign extend all bits that are beyond the precision. */ + + signmask = -((prec > HOST_BITS_PER_WIDE_INT + ? ((unsigned HOST_WIDE_INT) *hv + >> (prec - HOST_BITS_PER_WIDE_INT - 1)) + : (*lv >> (prec - 1))) & 1); + + if (prec >= 2 * HOST_BITS_PER_WIDE_INT) + ; + else if (prec >= HOST_BITS_PER_WIDE_INT) + { + *hv &= ~((HOST_WIDE_INT) (-1) << (prec - HOST_BITS_PER_WIDE_INT)); + *hv |= signmask << (prec - HOST_BITS_PER_WIDE_INT); + } + else + { + *hv = signmask; + *lv &= ~((unsigned HOST_WIDE_INT) (-1) << prec); + *lv |= signmask << prec; + } +} + +/* Shift the doubleword 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 `HOST_WIDE_INT' pieces in *LV and *HV. */ + +void +rshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, + HOST_WIDE_INT count, unsigned int prec, + unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv, + int arith) +{ + unsigned HOST_WIDE_INT signmask; + + signmask = (arith + ? -((unsigned HOST_WIDE_INT) h1 >> (HOST_BITS_PER_WIDE_INT - 1)) + : 0); + + if (SHIFT_COUNT_TRUNCATED) + count %= prec; + + if (count >= 2 * HOST_BITS_PER_WIDE_INT) + { + /* Shifting by the host word size is undefined according to the + ANSI standard, so we must handle this as a special case. */ + *hv = 0; + *lv = 0; + } + else if (count >= HOST_BITS_PER_WIDE_INT) + { + *hv = 0; + *lv = (unsigned HOST_WIDE_INT) h1 >> (count - HOST_BITS_PER_WIDE_INT); + } + else + { + *hv = (unsigned HOST_WIDE_INT) h1 >> count; + *lv = ((l1 >> count) + | ((unsigned HOST_WIDE_INT) h1 << (HOST_BITS_PER_WIDE_INT - count - 1) << 1)); + } + + /* Zero / sign extend all bits that are beyond the precision. */ + + if (count >= (HOST_WIDE_INT)prec) + { + *hv = signmask; + *lv = signmask; + } + else if ((prec - count) >= 2 * HOST_BITS_PER_WIDE_INT) + ; + else if ((prec - count) >= HOST_BITS_PER_WIDE_INT) + { + *hv &= ~((HOST_WIDE_INT) (-1) << (prec - count - HOST_BITS_PER_WIDE_INT)); + *hv |= signmask << (prec - count - HOST_BITS_PER_WIDE_INT); + } + else + { + *hv = signmask; + *lv &= ~((unsigned HOST_WIDE_INT) (-1) << (prec - count)); + *lv |= signmask << (prec - count); + } +} + +/* Rotate the doubleword integer in L1, H1 left by COUNT places + keeping only PREC bits of result. + Rotate right if COUNT is negative. + Store the value as two `HOST_WIDE_INT' pieces in *LV and *HV. */ + +void +lrotate_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, + HOST_WIDE_INT count, unsigned int prec, + unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv) +{ + unsigned HOST_WIDE_INT s1l, s2l; + HOST_WIDE_INT s1h, s2h; + + count %= prec; + if (count < 0) + count += prec; + + lshift_double (l1, h1, count, prec, &s1l, &s1h, 0); + rshift_double (l1, h1, prec - count, prec, &s2l, &s2h, 0); + *lv = s1l | s2l; + *hv = s1h | s2h; +} + +/* Rotate the doubleword integer in L1, H1 left by COUNT places + keeping only PREC bits of result. COUNT must be positive. + Store the value as two `HOST_WIDE_INT' pieces in *LV and *HV. */ + +void +rrotate_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, + HOST_WIDE_INT count, unsigned int prec, + unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv) +{ + unsigned HOST_WIDE_INT s1l, s2l; + HOST_WIDE_INT s1h, s2h; + + count %= prec; + if (count < 0) + count += prec; + + rshift_double (l1, h1, count, prec, &s1l, &s1h, 0); + lshift_double (l1, h1, prec - count, prec, &s2l, &s2h, 0); + *lv = s1l | s2l; + *hv = s1h | s2h; +} + +/* Divide doubleword integer LNUM, HNUM by doubleword 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 an integer. + Return nonzero if the operation overflows. + UNS nonzero says do unsigned division. */ + +int +div_and_round_double (enum tree_code code, int uns, + unsigned HOST_WIDE_INT lnum_orig, /* num == numerator == dividend */ + HOST_WIDE_INT hnum_orig, + unsigned HOST_WIDE_INT lden_orig, /* den == denominator == divisor */ + HOST_WIDE_INT hden_orig, + unsigned HOST_WIDE_INT *lquo, + HOST_WIDE_INT *hquo, unsigned HOST_WIDE_INT *lrem, + HOST_WIDE_INT *hrem) +{ + int quo_neg = 0; + HOST_WIDE_INT num[4 + 1]; /* extra element for scaling. */ + HOST_WIDE_INT den[4], quo[4]; + int i, j; + unsigned HOST_WIDE_INT work; + unsigned HOST_WIDE_INT carry = 0; + unsigned HOST_WIDE_INT lnum = lnum_orig; + HOST_WIDE_INT hnum = hnum_orig; + unsigned HOST_WIDE_INT lden = lden_orig; + HOST_WIDE_INT hden = hden_orig; + int overflow = 0; + + if (hden == 0 && lden == 0) + overflow = 1, lden = 1; + + /* Calculate quotient sign and convert operands to unsigned. */ + if (!uns) + { + if (hnum < 0) + { + quo_neg = ~ quo_neg; + /* (minimum integer) / (-1) is the only overflow case. */ + if (neg_double (lnum, hnum, &lnum, &hnum) + && ((HOST_WIDE_INT) lden & hden) == -1) + overflow = 1; + } + if (hden < 0) + { + quo_neg = ~ quo_neg; + neg_double (lden, hden, &lden, &hden); + } + } + + if (hnum == 0 && hden == 0) + { /* single precision */ + *hquo = *hrem = 0; + /* This unsigned division rounds toward zero. */ + *lquo = lnum / lden; + goto finish_up; + } + + if (hnum == 0) + { /* trivial case: dividend < divisor */ + /* hden != 0 already checked. */ + *hquo = *lquo = 0; + *hrem = hnum; + *lrem = lnum; + goto finish_up; + } + + memset (quo, 0, sizeof quo); + + memset (num, 0, sizeof num); /* to zero 9th element */ + memset (den, 0, sizeof den); + + encode (num, lnum, hnum); + encode (den, lden, hden); + + /* Special code for when the divisor < BASE. */ + if (hden == 0 && lden < (unsigned HOST_WIDE_INT) BASE) + { + /* hnum != 0 already checked. */ + for (i = 4 - 1; i >= 0; i--) + { + work = num[i] + carry * BASE; + quo[i] = work / lden; + carry = work % lden; + } + } + else + { + /* Full double precision division, + with thanks to Don Knuth's "Seminumerical Algorithms". */ + int num_hi_sig, den_hi_sig; + unsigned HOST_WIDE_INT quo_est, scale; + + /* Find the highest nonzero divisor digit. */ + for (i = 4 - 1;; i--) + if (den[i] != 0) + { + den_hi_sig = i; + break; + } + + /* 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 <= 4 - 1; i++) + { + work = (num[i] * scale) + carry; + num[i] = LOWPART (work); + carry = HIGHPART (work); + } + + num[4] = carry; + carry = 0; + for (i = 0; i <= 4 - 1; i++) + { + work = (den[i] * scale) + carry; + den[i] = LOWPART (work); + carry = HIGHPART (work); + if (den[i] != 0) den_hi_sig = i; + } + } + + num_hi_sig = 4; + + /* Main loop */ + for (i = num_hi_sig - den_hi_sig - 1; i >= 0; i--) + { + /* Guess the next quotient digit, quo_est, by dividing the first + two remaining dividend digits by the high order quotient digit. + quo_est is never low and is at most 2 high. */ + unsigned HOST_WIDE_INT tmp; + + num_hi_sig = i + den_hi_sig + 1; + work = num[num_hi_sig] * BASE + num[num_hi_sig - 1]; + if (num[num_hi_sig] != den[den_hi_sig]) + quo_est = work / den[den_hi_sig]; + else + quo_est = BASE - 1; + + /* Refine quo_est so it's usually correct, and at most one high. */ + tmp = work - quo_est * den[den_hi_sig]; + if (tmp < BASE + && (den[den_hi_sig - 1] * quo_est + > (tmp * BASE + num[num_hi_sig - 2]))) + quo_est--; + + /* Try QUO_EST as the quotient digit, by multiplying the + divisor by QUO_EST and subtracting from the remaining dividend. + Keep in mind that QUO_EST is the I - 1st digit. */ + + carry = 0; + for (j = 0; j <= den_hi_sig; j++) + { + work = quo_est * den[j] + carry; + carry = HIGHPART (work); + work = num[i + j] - LOWPART (work); + num[i + j] = LOWPART (work); + carry += HIGHPART (work) != 0; + } + + /* If quo_est was high by one, then num[i] went negative and + we need to correct things. */ + if (num[num_hi_sig] < (HOST_WIDE_INT) carry) + { + quo_est--; + carry = 0; /* add divisor back in */ + for (j = 0; j <= den_hi_sig; j++) + { + work = num[i + j] + den[j] + carry; + carry = HIGHPART (work); + num[i + j] = LOWPART (work); + } + + num [num_hi_sig] += carry; + } + + /* Store the quotient digit. */ + quo[i] = 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 overflow; + + 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, (HOST_WIDE_INT) -1, (HOST_WIDE_INT) -1, + lquo, hquo); + } + else + return overflow; + 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, (HOST_WIDE_INT) 1, (HOST_WIDE_INT) 0, + lquo, hquo); + } + else + return overflow; + break; + + case ROUND_DIV_EXPR: + case ROUND_MOD_EXPR: /* round to closest integer */ + { + unsigned HOST_WIDE_INT labs_rem = *lrem; + HOST_WIDE_INT habs_rem = *hrem; + unsigned HOST_WIDE_INT labs_den = lden, ltwice; + HOST_WIDE_INT habs_den = hden, 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 ((HOST_WIDE_INT) 2, (HOST_WIDE_INT) 0, + labs_rem, habs_rem, <wice, &htwice); + + if (((unsigned HOST_WIDE_INT) habs_den + < (unsigned HOST_WIDE_INT) htwice) + || (((unsigned HOST_WIDE_INT) habs_den + == (unsigned HOST_WIDE_INT) htwice) + && (labs_den < ltwice))) + { + if (*hquo < 0) + /* quo = quo - 1; */ + add_double (*lquo, *hquo, + (HOST_WIDE_INT) -1, (HOST_WIDE_INT) -1, lquo, hquo); + else + /* quo = quo + 1; */ + add_double (*lquo, *hquo, (HOST_WIDE_INT) 1, (HOST_WIDE_INT) 0, + lquo, hquo); + } + else + return overflow; + } + break; + + default: + gcc_unreachable (); + } + + /* 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); + return overflow; +} + +/* If ARG2 divides ARG1 with zero remainder, carries out the division + of type CODE and returns the quotient. + Otherwise returns NULL_TREE. */ + +static tree +div_if_zero_remainder (enum tree_code code, tree arg1, tree arg2) +{ + unsigned HOST_WIDE_INT int1l, int2l; + HOST_WIDE_INT int1h, int2h; + unsigned HOST_WIDE_INT quol, reml; + HOST_WIDE_INT quoh, remh; + tree type = TREE_TYPE (arg1); + int uns = TYPE_UNSIGNED (type); + + int1l = TREE_INT_CST_LOW (arg1); + int1h = TREE_INT_CST_HIGH (arg1); + int2l = TREE_INT_CST_LOW (arg2); + int2h = TREE_INT_CST_HIGH (arg2); + + div_and_round_double (code, uns, int1l, int1h, int2l, int2h, + &quol, &quoh, &reml, &remh); + if (remh != 0 || reml != 0) + return NULL_TREE; + + return build_int_cst_wide (type, quol, quoh); +} + +/* This is non-zero if we should defer warnings about undefined + overflow. This facility exists because these warnings are a + special case. The code to estimate loop iterations does not want + to issue any warnings, since it works with expressions which do not + occur in user code. Various bits of cleanup code call fold(), but + only use the result if it has certain characteristics (e.g., is a + constant); that code only wants to issue a warning if the result is + used. */ + +static int fold_deferring_overflow_warnings; + +/* If a warning about undefined overflow is deferred, this is the + warning. Note that this may cause us to turn two warnings into + one, but that is fine since it is sufficient to only give one + warning per expression. */ + +static const char* fold_deferred_overflow_warning; + +/* If a warning about undefined overflow is deferred, this is the + level at which the warning should be emitted. */ + +static enum warn_strict_overflow_code fold_deferred_overflow_code; + +/* Start deferring overflow warnings. We could use a stack here to + permit nested calls, but at present it is not necessary. */ + +void +fold_defer_overflow_warnings (void) +{ + ++fold_deferring_overflow_warnings; +} + +/* Stop deferring overflow warnings. If there is a pending warning, + and ISSUE is true, then issue the warning if appropriate. STMT is + the statement with which the warning should be associated (used for + location information); STMT may be NULL. CODE is the level of the + warning--a warn_strict_overflow_code value. This function will use + the smaller of CODE and the deferred code when deciding whether to + issue the warning. CODE may be zero to mean to always use the + deferred code. */ + +void +fold_undefer_overflow_warnings (bool issue, tree stmt, int code) +{ + const char *warnmsg; + location_t locus; + + gcc_assert (fold_deferring_overflow_warnings > 0); + --fold_deferring_overflow_warnings; + if (fold_deferring_overflow_warnings > 0) + { + if (fold_deferred_overflow_warning != NULL + && code != 0 + && code < (int) fold_deferred_overflow_code) + fold_deferred_overflow_code = code; + return; + } + + warnmsg = fold_deferred_overflow_warning; + fold_deferred_overflow_warning = NULL; + + if (!issue || warnmsg == NULL) + return; + + /* Use the smallest code level when deciding to issue the + warning. */ + if (code == 0 || code > (int) fold_deferred_overflow_code) + code = fold_deferred_overflow_code; + + if (!issue_strict_overflow_warning (code)) + return; + + if (stmt == NULL_TREE || !EXPR_HAS_LOCATION (stmt)) + locus = input_location; + else + locus = EXPR_LOCATION (stmt); + warning (OPT_Wstrict_overflow, "%H%s", &locus, warnmsg); +} + +/* Stop deferring overflow warnings, ignoring any deferred + warnings. */ + +void +fold_undefer_and_ignore_overflow_warnings (void) +{ + fold_undefer_overflow_warnings (false, NULL_TREE, 0); +} + +/* Whether we are deferring overflow warnings. */ + +bool +fold_deferring_overflow_warnings_p (void) +{ + return fold_deferring_overflow_warnings > 0; +} + +/* This is called when we fold something based on the fact that signed + overflow is undefined. */ + +static void +fold_overflow_warning (const char* gmsgid, enum warn_strict_overflow_code wc) +{ + gcc_assert (!flag_wrapv && !flag_trapv); + if (fold_deferring_overflow_warnings > 0) + { + if (fold_deferred_overflow_warning == NULL + || wc < fold_deferred_overflow_code) + { + fold_deferred_overflow_warning = gmsgid; + fold_deferred_overflow_code = wc; + } + } + else if (issue_strict_overflow_warning (wc)) + warning (OPT_Wstrict_overflow, gmsgid); +} + +/* Return true if the built-in mathematical function specified by CODE + is odd, i.e. -f(x) == f(-x). */ + +static bool +negate_mathfn_p (enum built_in_function code) +{ + switch (code) + { + CASE_FLT_FN (BUILT_IN_ASIN): + CASE_FLT_FN (BUILT_IN_ASINH): + CASE_FLT_FN (BUILT_IN_ATAN): + CASE_FLT_FN (BUILT_IN_ATANH): + CASE_FLT_FN (BUILT_IN_CBRT): + CASE_FLT_FN (BUILT_IN_SIN): + CASE_FLT_FN (BUILT_IN_SINH): + CASE_FLT_FN (BUILT_IN_TAN): + CASE_FLT_FN (BUILT_IN_TANH): + return true; + + default: + break; + } + return false; +} + +/* Check whether we may negate an integer constant T without causing + overflow. */ + +bool +may_negate_without_overflow_p (tree t) +{ + unsigned HOST_WIDE_INT val; + unsigned int prec; + tree type; + + gcc_assert (TREE_CODE (t) == INTEGER_CST); + + type = TREE_TYPE (t); + if (TYPE_UNSIGNED (type)) + return false; + + prec = TYPE_PRECISION (type); + if (prec > HOST_BITS_PER_WIDE_INT) + { + if (TREE_INT_CST_LOW (t) != 0) + return true; + prec -= HOST_BITS_PER_WIDE_INT; + val = TREE_INT_CST_HIGH (t); + } + else + val = TREE_INT_CST_LOW (t); + if (prec < HOST_BITS_PER_WIDE_INT) + val &= ((unsigned HOST_WIDE_INT) 1 << prec) - 1; + return val != ((unsigned HOST_WIDE_INT) 1 << (prec - 1)); +} + +/* Determine whether an expression T can be cheaply negated using + the function negate_expr without introducing undefined overflow. */ + +static bool +negate_expr_p (tree t) +{ + tree type; + + if (t == 0) + return false; + + type = TREE_TYPE (t); + + STRIP_SIGN_NOPS (t); + switch (TREE_CODE (t)) + { + case INTEGER_CST: + if (TYPE_OVERFLOW_WRAPS (type)) + return true; + + /* Check that -CST will not overflow type. */ + return may_negate_without_overflow_p (t); + case BIT_NOT_EXPR: + return (INTEGRAL_TYPE_P (type) + && TYPE_OVERFLOW_WRAPS (type)); + + case REAL_CST: + case NEGATE_EXPR: + return true; + + case COMPLEX_CST: + return negate_expr_p (TREE_REALPART (t)) + && negate_expr_p (TREE_IMAGPART (t)); + + case PLUS_EXPR: + if (FLOAT_TYPE_P (type) && !flag_unsafe_math_optimizations) + return false; + /* -(A + B) -> (-B) - A. */ + if (negate_expr_p (TREE_OPERAND (t, 1)) + && reorder_operands_p (TREE_OPERAND (t, 0), + TREE_OPERAND (t, 1))) + return true; + /* -(A + B) -> (-A) - B. */ + return negate_expr_p (TREE_OPERAND (t, 0)); + + case MINUS_EXPR: + /* We can't turn -(A-B) into B-A when we honor signed zeros. */ + return (! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations) + && reorder_operands_p (TREE_OPERAND (t, 0), + TREE_OPERAND (t, 1)); + + case MULT_EXPR: + if (TYPE_UNSIGNED (TREE_TYPE (t))) + break; + + /* Fall through. */ + + case RDIV_EXPR: + if (! HONOR_SIGN_DEPENDENT_ROUNDING (TYPE_MODE (TREE_TYPE (t)))) + return negate_expr_p (TREE_OPERAND (t, 1)) + || negate_expr_p (TREE_OPERAND (t, 0)); + break; + + case TRUNC_DIV_EXPR: + case ROUND_DIV_EXPR: + case FLOOR_DIV_EXPR: + case CEIL_DIV_EXPR: + case EXACT_DIV_EXPR: + /* In general we can't negate A / B, because if A is INT_MIN and + B is 1, we may turn this into INT_MIN / -1 which is undefined + and actually traps on some architectures. But if overflow is + undefined, we can negate, because - (INT_MIN / 1) is an + overflow. */ + if (INTEGRAL_TYPE_P (TREE_TYPE (t)) + && !TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (t))) + break; + return negate_expr_p (TREE_OPERAND (t, 1)) + || negate_expr_p (TREE_OPERAND (t, 0)); + + case NOP_EXPR: + /* Negate -((double)float) as (double)(-float). */ + if (TREE_CODE (type) == REAL_TYPE) + { + tree tem = strip_float_extensions (t); + if (tem != t) + return negate_expr_p (tem); + } + break; + + case CALL_EXPR: + /* Negate -f(x) as f(-x). */ + if (negate_mathfn_p (builtin_mathfn_code (t))) + return negate_expr_p (TREE_VALUE (TREE_OPERAND (t, 1))); + break; + + case RSHIFT_EXPR: + /* Optimize -((int)x >> 31) into (unsigned)x >> 31. */ + if (TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST) + { + tree op1 = TREE_OPERAND (t, 1); + if (TREE_INT_CST_HIGH (op1) == 0 + && (unsigned HOST_WIDE_INT) (TYPE_PRECISION (type) - 1) + == TREE_INT_CST_LOW (op1)) + return true; + } + break; + + default: + break; + } + return false; +} + +/* Given T, an expression, return a folded tree for -T or NULL_TREE, if no + simplification is possible. + If negate_expr_p would return true for T, NULL_TREE will never be + returned. */ + +static tree +fold_negate_expr (tree t) +{ + tree type = TREE_TYPE (t); + tree tem; + + switch (TREE_CODE (t)) + { + /* Convert - (~A) to A + 1. */ + case BIT_NOT_EXPR: + if (INTEGRAL_TYPE_P (type)) + return fold_build2 (PLUS_EXPR, type, TREE_OPERAND (t, 0), + build_int_cst (type, 1)); + break; + + case INTEGER_CST: + tem = fold_negate_const (t, type); + if (!TREE_OVERFLOW (tem) + || !TYPE_OVERFLOW_TRAPS (type)) + return tem; + break; + + case REAL_CST: + tem = fold_negate_const (t, type); + /* Two's complement FP formats, such as c4x, may overflow. */ + if (! TREE_OVERFLOW (tem) || ! flag_trapping_math) + return tem; + break; + + case COMPLEX_CST: + { + tree rpart = negate_expr (TREE_REALPART (t)); + tree ipart = negate_expr (TREE_IMAGPART (t)); + + if ((TREE_CODE (rpart) == REAL_CST + && TREE_CODE (ipart) == REAL_CST) + || (TREE_CODE (rpart) == INTEGER_CST + && TREE_CODE (ipart) == INTEGER_CST)) + return build_complex (type, rpart, ipart); + } + break; + + case NEGATE_EXPR: + return TREE_OPERAND (t, 0); + + case PLUS_EXPR: + if (! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations) + { + /* -(A + B) -> (-B) - A. */ + if (negate_expr_p (TREE_OPERAND (t, 1)) + && reorder_operands_p (TREE_OPERAND (t, 0), + TREE_OPERAND (t, 1))) + { + tem = negate_expr (TREE_OPERAND (t, 1)); + return fold_build2 (MINUS_EXPR, type, + tem, TREE_OPERAND (t, 0)); + } + + /* -(A + B) -> (-A) - B. */ + if (negate_expr_p (TREE_OPERAND (t, 0))) + { + tem = negate_expr (TREE_OPERAND (t, 0)); + return fold_build2 (MINUS_EXPR, type, + tem, TREE_OPERAND (t, 1)); + } + } + break; + + case MINUS_EXPR: + /* - (A - B) -> B - A */ + if ((! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations) + && reorder_operands_p (TREE_OPERAND (t, 0), TREE_OPERAND (t, 1))) + return fold_build2 (MINUS_EXPR, type, + TREE_OPERAND (t, 1), TREE_OPERAND (t, 0)); + break; + + case MULT_EXPR: + if (TYPE_UNSIGNED (type)) + break; + + /* Fall through. */ + + case RDIV_EXPR: + if (! HONOR_SIGN_DEPENDENT_ROUNDING (TYPE_MODE (type))) + { + tem = TREE_OPERAND (t, 1); + if (negate_expr_p (tem)) + return fold_build2 (TREE_CODE (t), type, + TREE_OPERAND (t, 0), negate_expr (tem)); + tem = TREE_OPERAND (t, 0); + if (negate_expr_p (tem)) + return fold_build2 (TREE_CODE (t), type, + negate_expr (tem), TREE_OPERAND (t, 1)); + } + break; + + case TRUNC_DIV_EXPR: + case ROUND_DIV_EXPR: + case FLOOR_DIV_EXPR: + case CEIL_DIV_EXPR: + case EXACT_DIV_EXPR: + /* In general we can't negate A / B, because if A is INT_MIN and + B is 1, we may turn this into INT_MIN / -1 which is undefined + and actually traps on some architectures. But if overflow is + undefined, we can negate, because - (INT_MIN / 1) is an + overflow. */ + if (!INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_UNDEFINED (type)) + { + const char * const warnmsg = G_("assuming signed overflow does not " + "occur when negating a division"); + tem = TREE_OPERAND (t, 1); + if (negate_expr_p (tem)) + { + if (INTEGRAL_TYPE_P (type) + && (TREE_CODE (tem) != INTEGER_CST + || integer_onep (tem))) + fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_MISC); + return fold_build2 (TREE_CODE (t), type, + TREE_OPERAND (t, 0), negate_expr (tem)); + } + tem = TREE_OPERAND (t, 0); + if (negate_expr_p (tem)) + { + if (INTEGRAL_TYPE_P (type) + && (TREE_CODE (tem) != INTEGER_CST + || tree_int_cst_equal (tem, TYPE_MIN_VALUE (type)))) + fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_MISC); + return fold_build2 (TREE_CODE (t), type, + negate_expr (tem), TREE_OPERAND (t, 1)); + } + } + break; + + case NOP_EXPR: + /* Convert -((double)float) into (double)(-float). */ + if (TREE_CODE (type) == REAL_TYPE) + { + tem = strip_float_extensions (t); + if (tem != t && negate_expr_p (tem)) + return negate_expr (tem); + } + break; + + case CALL_EXPR: + /* Negate -f(x) as f(-x). */ + if (negate_mathfn_p (builtin_mathfn_code (t)) + && negate_expr_p (TREE_VALUE (TREE_OPERAND (t, 1)))) + { + tree fndecl, arg, arglist; + + fndecl = get_callee_fndecl (t); + arg = negate_expr (TREE_VALUE (TREE_OPERAND (t, 1))); + arglist = build_tree_list (NULL_TREE, arg); + return build_function_call_expr (fndecl, arglist); + } + break; + + case RSHIFT_EXPR: + /* Optimize -((int)x >> 31) into (unsigned)x >> 31. */ + if (TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST) + { + tree op1 = TREE_OPERAND (t, 1); + if (TREE_INT_CST_HIGH (op1) == 0 + && (unsigned HOST_WIDE_INT) (TYPE_PRECISION (type) - 1) + == TREE_INT_CST_LOW (op1)) + { + tree ntype = TYPE_UNSIGNED (type) + ? lang_hooks.types.signed_type (type) + : lang_hooks.types.unsigned_type (type); + tree temp = fold_convert (ntype, TREE_OPERAND (t, 0)); + temp = fold_build2 (RSHIFT_EXPR, ntype, temp, op1); + return fold_convert (type, temp); + } + } + break; + + default: + break; + } + + return NULL_TREE; +} + +/* Like fold_negate_expr, but return a NEGATE_EXPR tree, if T can not be + negated in a simpler way. Also allow for T to be NULL_TREE, in which case + return NULL_TREE. */ + +static tree +negate_expr (tree t) +{ + tree type, tem; + + if (t == NULL_TREE) + return NULL_TREE; + + type = TREE_TYPE (t); + STRIP_SIGN_NOPS (t); + + tem = fold_negate_expr (t); + if (!tem) + tem = build1 (NEGATE_EXPR, TREE_TYPE (t), t); + return fold_convert (type, tem); +} + +/* Split a tree IN into a constant, literal and variable parts that could be + combined with CODE to make IN. "constant" means an expression with + TREE_CONSTANT but that isn't an actual constant. CODE must be a + commutative arithmetic operation. Store the constant part into *CONP, + the literal in *LITP and return the variable part. If a part isn't + present, set it to null. If the tree does not decompose in this way, + return the entire tree as the variable part and the other parts as null. + + If CODE is PLUS_EXPR we also split trees that use MINUS_EXPR. In that + case, we negate an operand that was subtracted. Except if it is a + literal for which we use *MINUS_LITP instead. + + If NEGATE_P is true, we are negating all of IN, again except a literal + for which we use *MINUS_LITP instead. + + If IN is itself a literal or constant, return it as appropriate. + + Note that we do not guarantee that any of the three values will be the + same type as IN, but they will have the same signedness and mode. */ + +static tree +split_tree (tree in, enum tree_code code, tree *conp, tree *litp, + tree *minus_litp, int negate_p) +{ + tree var = 0; + + *conp = 0; + *litp = 0; + *minus_litp = 0; + + /* Strip any conversions that don't change the machine mode or signedness. */ + STRIP_SIGN_NOPS (in); + + if (TREE_CODE (in) == INTEGER_CST || TREE_CODE (in) == REAL_CST) + *litp = in; + else if (TREE_CODE (in) == code + || (! FLOAT_TYPE_P (TREE_TYPE (in)) + /* 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)))) + { + tree op0 = TREE_OPERAND (in, 0); + tree op1 = TREE_OPERAND (in, 1); + int neg1_p = TREE_CODE (in) == MINUS_EXPR; + int neg_litp_p = 0, neg_conp_p = 0, neg_var_p = 0; + + /* First see if either of the operands is a literal, then a constant. */ + if (TREE_CODE (op0) == INTEGER_CST || TREE_CODE (op0) == REAL_CST) + *litp = op0, op0 = 0; + else if (TREE_CODE (op1) == INTEGER_CST || TREE_CODE (op1) == REAL_CST) + *litp = op1, neg_litp_p = neg1_p, op1 = 0; + + if (op0 != 0 && TREE_CONSTANT (op0)) + *conp = op0, op0 = 0; + else if (op1 != 0 && TREE_CONSTANT (op1)) + *conp = op1, neg_conp_p = neg1_p, op1 = 0; + + /* If we haven't dealt with either operand, this is not a case we can + decompose. Otherwise, VAR is either of the ones remaining, if any. */ + if (op0 != 0 && op1 != 0) + var = in; + else if (op0 != 0) + var = op0; + else + var = op1, neg_var_p = neg1_p; + + /* Now do any needed negations. */ + if (neg_litp_p) + *minus_litp = *litp, *litp = 0; + if (neg_conp_p) + *conp = negate_expr (*conp); + if (neg_var_p) + var = negate_expr (var); + } + else if (TREE_CONSTANT (in)) + *conp = in; + else + var = in; + + if (negate_p) + { + if (*litp) + *minus_litp = *litp, *litp = 0; + else if (*minus_litp) + *litp = *minus_litp, *minus_litp = 0; + *conp = negate_expr (*conp); + var = negate_expr (var); + } + + return var; +} + +/* Re-associate trees split by the above function. T1 and T2 are either + expressions to associate or null. Return the new expression, if any. If + we build an operation, do it in TYPE and with CODE. */ + +static tree +associate_trees (tree t1, tree t2, enum tree_code code, tree type) +{ + if (t1 == 0) + return t2; + else if (t2 == 0) + return t1; + + /* If either input is CODE, a PLUS_EXPR, or a MINUS_EXPR, don't + try to fold this since we will have infinite recursion. But do + deal with any NEGATE_EXPRs. */ + if (TREE_CODE (t1) == code || TREE_CODE (t2) == code + || TREE_CODE (t1) == MINUS_EXPR || TREE_CODE (t2) == MINUS_EXPR) + { + if (code == PLUS_EXPR) + { + if (TREE_CODE (t1) == NEGATE_EXPR) + return build2 (MINUS_EXPR, type, fold_convert (type, t2), + fold_convert (type, TREE_OPERAND (t1, 0))); + else if (TREE_CODE (t2) == NEGATE_EXPR) + return build2 (MINUS_EXPR, type, fold_convert (type, t1), + fold_convert (type, TREE_OPERAND (t2, 0))); + else if (integer_zerop (t2)) + return fold_convert (type, t1); + } + else if (code == MINUS_EXPR) + { + if (integer_zerop (t2)) + return fold_convert (type, t1); + } + + return build2 (code, type, fold_convert (type, t1), + fold_convert (type, t2)); + } + + return fold_build2 (code, type, fold_convert (type, t1), + fold_convert (type, t2)); +} + +/* Combine two integer constants ARG1 and ARG2 under operation CODE + to produce a new constant. Return NULL_TREE if we don't know how + to evaluate CODE at compile-time. + + If NOTRUNC is nonzero, do not truncate the result to fit the data type. */ + +tree +int_const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc) +{ + unsigned HOST_WIDE_INT int1l, int2l; + HOST_WIDE_INT int1h, int2h; + unsigned HOST_WIDE_INT low; + HOST_WIDE_INT hi; + unsigned HOST_WIDE_INT garbagel; + HOST_WIDE_INT garbageh; + tree t; + tree type = TREE_TYPE (arg1); + int uns = TYPE_UNSIGNED (type); + int is_sizetype + = (TREE_CODE (type) == INTEGER_TYPE && TYPE_IS_SIZETYPE (type)); + int overflow = 0; + + int1l = TREE_INT_CST_LOW (arg1); + int1h = TREE_INT_CST_HIGH (arg1); + int2l = TREE_INT_CST_LOW (arg2); + int2h = TREE_INT_CST_HIGH (arg2); + + switch (code) + { + case BIT_IOR_EXPR: + low = int1l | int2l, hi = int1h | int2h; + break; + + case BIT_XOR_EXPR: + low = int1l ^ int2l, hi = int1h ^ int2h; + break; + + case BIT_AND_EXPR: + low = int1l & int2l, hi = int1h & int2h; + break; + + case RSHIFT_EXPR: + int2l = -int2l; + case LSHIFT_EXPR: + /* It's unclear from the C standard whether shifts can overflow. + The following code ignores overflow; perhaps a C standard + interpretation ruling is needed. */ + lshift_double (int1l, int1h, int2l, TYPE_PRECISION (type), + &low, &hi, !uns); + break; + + case RROTATE_EXPR: + int2l = - int2l; + case LROTATE_EXPR: + lrotate_double (int1l, int1h, int2l, TYPE_PRECISION (type), + &low, &hi); + break; + + case PLUS_EXPR: + overflow = add_double (int1l, int1h, int2l, int2h, &low, &hi); + break; + + case MINUS_EXPR: + neg_double (int2l, int2h, &low, &hi); + add_double (int1l, int1h, low, hi, &low, &hi); + overflow = OVERFLOW_SUM_SIGN (hi, int2h, int1h); + break; + + case MULT_EXPR: + overflow = mul_double (int1l, int1h, int2l, int2h, &low, &hi); + break; + + case TRUNC_DIV_EXPR: + case FLOOR_DIV_EXPR: case CEIL_DIV_EXPR: + case EXACT_DIV_EXPR: + /* This is a shortcut for a common special case. */ + if (int2h == 0 && (HOST_WIDE_INT) int2l > 0 + && ! TREE_CONSTANT_OVERFLOW (arg1) + && ! TREE_CONSTANT_OVERFLOW (arg2) + && int1h == 0 && (HOST_WIDE_INT) int1l >= 0) + { + if (code == CEIL_DIV_EXPR) + int1l += int2l - 1; + + low = int1l / int2l, hi = 0; + break; + } + + /* ... fall through ... */ + + case ROUND_DIV_EXPR: + if (int2h == 0 && int2l == 0) + return NULL_TREE; + if (int2h == 0 && int2l == 1) + { + low = int1l, hi = int1h; + break; + } + if (int1l == int2l && int1h == int2h + && ! (int1l == 0 && int1h == 0)) + { + low = 1, hi = 0; + break; + } + overflow = div_and_round_double (code, uns, int1l, int1h, int2l, int2h, + &low, &hi, &garbagel, &garbageh); + break; + + case TRUNC_MOD_EXPR: + case FLOOR_MOD_EXPR: case CEIL_MOD_EXPR: + /* This is a shortcut for a common special case. */ + if (int2h == 0 && (HOST_WIDE_INT) int2l > 0 + && ! TREE_CONSTANT_OVERFLOW (arg1) + && ! TREE_CONSTANT_OVERFLOW (arg2) + && int1h == 0 && (HOST_WIDE_INT) int1l >= 0) + { + if (code == CEIL_MOD_EXPR) + int1l += int2l - 1; + low = int1l % int2l, hi = 0; + break; + } + + /* ... fall through ... */ + + case ROUND_MOD_EXPR: + if (int2h == 0 && int2l == 0) + return NULL_TREE; + overflow = div_and_round_double (code, uns, + int1l, int1h, int2l, int2h, + &garbagel, &garbageh, &low, &hi); + break; + + case MIN_EXPR: + case MAX_EXPR: + if (uns) + low = (((unsigned HOST_WIDE_INT) int1h + < (unsigned HOST_WIDE_INT) int2h) + || (((unsigned HOST_WIDE_INT) int1h + == (unsigned HOST_WIDE_INT) int2h) + && int1l < int2l)); + else + low = (int1h < int2h + || (int1h == int2h && int1l < int2l)); + + if (low == (code == MIN_EXPR)) + low = int1l, hi = int1h; + else + low = int2l, hi = int2h; + break; + + default: + return NULL_TREE; + } + + t = build_int_cst_wide (TREE_TYPE (arg1), low, hi); + + if (notrunc) + { + /* Propagate overflow flags ourselves. */ + if (((!uns || is_sizetype) && overflow) + | TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2)) + { + t = copy_node (t); + TREE_OVERFLOW (t) = 1; + TREE_CONSTANT_OVERFLOW (t) = 1; + } + else if (TREE_CONSTANT_OVERFLOW (arg1) | TREE_CONSTANT_OVERFLOW (arg2)) + { + t = copy_node (t); + TREE_CONSTANT_OVERFLOW (t) = 1; + } + } + else + t = force_fit_type (t, 1, + ((!uns || is_sizetype) && overflow) + | TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2), + TREE_CONSTANT_OVERFLOW (arg1) + | TREE_CONSTANT_OVERFLOW (arg2)); + + return t; +} + +/* Combine two constants ARG1 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. Return zero if + combining the constants is not allowed in the current operating mode. + + If NOTRUNC is nonzero, do not truncate the result to fit the data type. */ + +static tree +const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc) +{ + /* Sanity check for the recursive cases. */ + if (!arg1 || !arg2) + return NULL_TREE; + + STRIP_NOPS (arg1); + STRIP_NOPS (arg2); + + if (TREE_CODE (arg1) == INTEGER_CST) + return int_const_binop (code, arg1, arg2, notrunc); + + if (TREE_CODE (arg1) == REAL_CST) + { + enum machine_mode mode; + REAL_VALUE_TYPE d1; + REAL_VALUE_TYPE d2; + REAL_VALUE_TYPE value; + REAL_VALUE_TYPE result; + bool inexact; + tree t, type; + + /* The following codes are handled by real_arithmetic. */ + switch (code) + { + case PLUS_EXPR: + case MINUS_EXPR: + case MULT_EXPR: + case RDIV_EXPR: + case MIN_EXPR: + case MAX_EXPR: + break; + + default: + return NULL_TREE; + } + + d1 = TREE_REAL_CST (arg1); + d2 = TREE_REAL_CST (arg2); + + type = TREE_TYPE (arg1); + mode = TYPE_MODE (type); + + /* Don't perform operation if we honor signaling NaNs and + either operand is a NaN. */ + if (HONOR_SNANS (mode) + && (REAL_VALUE_ISNAN (d1) || REAL_VALUE_ISNAN (d2))) + return NULL_TREE; + + /* Don't perform operation if it would raise a division + by zero exception. */ + if (code == RDIV_EXPR + && REAL_VALUES_EQUAL (d2, dconst0) + && (flag_trapping_math || ! MODE_HAS_INFINITIES (mode))) + return NULL_TREE; + + /* If either operand is a NaN, just return it. Otherwise, set up + for floating-point trap; we return an overflow. */ + if (REAL_VALUE_ISNAN (d1)) + return arg1; + else if (REAL_VALUE_ISNAN (d2)) + return arg2; + + inexact = real_arithmetic (&value, code, &d1, &d2); + real_convert (&result, mode, &value); + + /* Don't constant fold this floating point operation if + the result has overflowed and flag_trapping_math. */ + if (flag_trapping_math + && MODE_HAS_INFINITIES (mode) + && REAL_VALUE_ISINF (result) + && !REAL_VALUE_ISINF (d1) + && !REAL_VALUE_ISINF (d2)) + return NULL_TREE; + + /* Don't constant fold this floating point operation if the + result may dependent upon the run-time rounding mode and + flag_rounding_math is set, or if GCC's software emulation + is unable to accurately represent the result. */ + if ((flag_rounding_math + || (REAL_MODE_FORMAT_COMPOSITE_P (mode) + && !flag_unsafe_math_optimizations)) + && (inexact || !real_identical (&result, &value))) + return NULL_TREE; + + t = build_real (type, result); + + TREE_OVERFLOW (t) = TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2); + TREE_CONSTANT_OVERFLOW (t) + = TREE_OVERFLOW (t) + | TREE_CONSTANT_OVERFLOW (arg1) + | TREE_CONSTANT_OVERFLOW (arg2); + return t; + } + + if (TREE_CODE (arg1) == COMPLEX_CST) + { + tree type = TREE_TYPE (arg1); + tree r1 = TREE_REALPART (arg1); + tree i1 = TREE_IMAGPART (arg1); + tree r2 = TREE_REALPART (arg2); + tree i2 = TREE_IMAGPART (arg2); + tree real, imag; + + switch (code) + { + case PLUS_EXPR: + case MINUS_EXPR: + real = const_binop (code, r1, r2, notrunc); + imag = const_binop (code, i1, i2, notrunc); + break; + + case MULT_EXPR: + real = const_binop (MINUS_EXPR, + const_binop (MULT_EXPR, r1, r2, notrunc), + const_binop (MULT_EXPR, i1, i2, notrunc), + notrunc); + imag = const_binop (PLUS_EXPR, + const_binop (MULT_EXPR, r1, i2, notrunc), + const_binop (MULT_EXPR, i1, r2, notrunc), + notrunc); + break; + + case RDIV_EXPR: + { + tree magsquared + = const_binop (PLUS_EXPR, + const_binop (MULT_EXPR, r2, r2, notrunc), + const_binop (MULT_EXPR, i2, i2, notrunc), + notrunc); + tree t1 + = const_binop (PLUS_EXPR, + const_binop (MULT_EXPR, r1, r2, notrunc), + const_binop (MULT_EXPR, i1, i2, notrunc), + notrunc); + tree t2 + = const_binop (MINUS_EXPR, + const_binop (MULT_EXPR, i1, r2, notrunc), + const_binop (MULT_EXPR, r1, i2, notrunc), + notrunc); + + if (INTEGRAL_TYPE_P (TREE_TYPE (r1))) + code = TRUNC_DIV_EXPR; + + real = const_binop (code, t1, magsquared, notrunc); + imag = const_binop (code, t2, magsquared, notrunc); + } + break; + + default: + return NULL_TREE; + } + + if (real && imag) + return build_complex (type, real, imag); + } + + return NULL_TREE; +} + +/* Create a size type INT_CST node with NUMBER sign extended. KIND + indicates which particular sizetype to create. */ + +tree +size_int_kind (HOST_WIDE_INT number, enum size_type_kind kind) +{ + return build_int_cst (sizetype_tab[(int) kind], number); +} + +/* Combine operands OP1 and OP2 with arithmetic operation CODE. CODE + is a tree code. The type of the result is taken from the operands. + Both must be the same type integer type and it must be a size type. + If the operands are constant, so is the result. */ + +tree +size_binop (enum tree_code code, tree arg0, tree arg1) +{ + tree type = TREE_TYPE (arg0); + + if (arg0 == error_mark_node || arg1 == error_mark_node) + return error_mark_node; + + gcc_assert (TREE_CODE (type) == INTEGER_TYPE && TYPE_IS_SIZETYPE (type) + && type == TREE_TYPE (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. */ + return int_const_binop (code, arg0, arg1, 0); + } + + return fold_build2 (code, type, arg0, arg1); +} + +/* Given two values, either both of sizetype or both of bitsizetype, + compute the difference between the two values. Return the value + in signed type corresponding to the type of the operands. */ + +tree +size_diffop (tree arg0, tree arg1) +{ + tree type = TREE_TYPE (arg0); + tree ctype; + + gcc_assert (TREE_CODE (type) == INTEGER_TYPE && TYPE_IS_SIZETYPE (type) + && type == TREE_TYPE (arg1)); + + /* If the type is already signed, just do the simple thing. */ + if (!TYPE_UNSIGNED (type)) + return size_binop (MINUS_EXPR, arg0, arg1); + + ctype = type == bitsizetype ? sbitsizetype : ssizetype; + + /* If either operand is not a constant, do the conversions to the signed + type and subtract. The hardware will do the right thing with any + overflow in the subtraction. */ + if (TREE_CODE (arg0) != INTEGER_CST || TREE_CODE (arg1) != INTEGER_CST) + return size_binop (MINUS_EXPR, fold_convert (ctype, arg0), + fold_convert (ctype, arg1)); + + /* If ARG0 is larger than ARG1, subtract and return the result in CTYPE. + Otherwise, subtract the other way, convert to CTYPE (we know that can't + overflow) and negate (which can't either). Special-case a result + of zero while we're here. */ + if (tree_int_cst_equal (arg0, arg1)) + return build_int_cst (ctype, 0); + else if (tree_int_cst_lt (arg1, arg0)) + return fold_convert (ctype, size_binop (MINUS_EXPR, arg0, arg1)); + else + return size_binop (MINUS_EXPR, build_int_cst (ctype, 0), + fold_convert (ctype, size_binop (MINUS_EXPR, + arg1, arg0))); +} + +/* A subroutine of fold_convert_const handling conversions of an + INTEGER_CST to another integer type. */ + +static tree +fold_convert_const_int_from_int (tree type, tree arg1) +{ + tree t; + + /* Given an integer constant, make new constant with new type, + appropriately sign-extended or truncated. */ + t = build_int_cst_wide (type, TREE_INT_CST_LOW (arg1), + TREE_INT_CST_HIGH (arg1)); + + t = force_fit_type (t, + /* Don't set the overflow when + converting a pointer */ + !POINTER_TYPE_P (TREE_TYPE (arg1)), + (TREE_INT_CST_HIGH (arg1) < 0 + && (TYPE_UNSIGNED (type) + < TYPE_UNSIGNED (TREE_TYPE (arg1)))) + | TREE_OVERFLOW (arg1), + TREE_CONSTANT_OVERFLOW (arg1)); + + return t; +} + +/* A subroutine of fold_convert_const handling conversions a REAL_CST + to an integer type. */ + +static tree +fold_convert_const_int_from_real (enum tree_code code, tree type, tree arg1) +{ + int overflow = 0; + tree t; + + /* The following code implements the floating point to integer + conversion rules required by the Java Language Specification, + that IEEE NaNs are mapped to zero and values that overflow + the target precision saturate, i.e. values greater than + INT_MAX are mapped to INT_MAX, and values less than INT_MIN + are mapped to INT_MIN. These semantics are allowed by the + C and C++ standards that simply state that the behavior of + FP-to-integer conversion is unspecified upon overflow. */ + + HOST_WIDE_INT high, low; + REAL_VALUE_TYPE r; + REAL_VALUE_TYPE x = TREE_REAL_CST (arg1); + + switch (code) + { + case FIX_TRUNC_EXPR: + real_trunc (&r, VOIDmode, &x); + break; + + case FIX_CEIL_EXPR: + real_ceil (&r, VOIDmode, &x); + break; + + case FIX_FLOOR_EXPR: + real_floor (&r, VOIDmode, &x); + break; + + case FIX_ROUND_EXPR: + real_round (&r, VOIDmode, &x); + break; + + default: + gcc_unreachable (); + } + + /* If R is NaN, return zero and show we have an overflow. */ + if (REAL_VALUE_ISNAN (r)) + { + overflow = 1; + high = 0; + low = 0; + } + + /* See if R is less than the lower bound or greater than the + upper bound. */ + + if (! overflow) + { + tree lt = TYPE_MIN_VALUE (type); + REAL_VALUE_TYPE l = real_value_from_int_cst (NULL_TREE, lt); + if (REAL_VALUES_LESS (r, l)) + { + overflow = 1; + high = TREE_INT_CST_HIGH (lt); + low = TREE_INT_CST_LOW (lt); + } + } + + if (! overflow) + { + tree ut = TYPE_MAX_VALUE (type); + if (ut) + { + REAL_VALUE_TYPE u = real_value_from_int_cst (NULL_TREE, ut); + if (REAL_VALUES_LESS (u, r)) + { + overflow = 1; + high = TREE_INT_CST_HIGH (ut); + low = TREE_INT_CST_LOW (ut); + } + } + } + + if (! overflow) + REAL_VALUE_TO_INT (&low, &high, r); + + t = build_int_cst_wide (type, low, high); + + t = force_fit_type (t, -1, overflow | TREE_OVERFLOW (arg1), + TREE_CONSTANT_OVERFLOW (arg1)); + return t; +} + +/* A subroutine of fold_convert_const handling conversions a REAL_CST + to another floating point type. */ + +static tree +fold_convert_const_real_from_real (tree type, tree arg1) +{ + REAL_VALUE_TYPE value; + tree t; + + real_convert (&value, TYPE_MODE (type), &TREE_REAL_CST (arg1)); + t = build_real (type, value); + + TREE_OVERFLOW (t) = TREE_OVERFLOW (arg1); + TREE_CONSTANT_OVERFLOW (t) + = TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg1); + return t; +} + +/* Attempt to fold type conversion operation CODE of expression ARG1 to + type TYPE. If no simplification can be done return NULL_TREE. */ + +static tree +fold_convert_const (enum tree_code code, tree type, tree arg1) +{ + if (TREE_TYPE (arg1) == type) + return arg1; + + if (POINTER_TYPE_P (type) || INTEGRAL_TYPE_P (type)) + { + if (TREE_CODE (arg1) == INTEGER_CST) + return fold_convert_const_int_from_int (type, arg1); + else if (TREE_CODE (arg1) == REAL_CST) + return fold_convert_const_int_from_real (code, type, arg1); + } + else if (TREE_CODE (type) == REAL_TYPE) + { + if (TREE_CODE (arg1) == INTEGER_CST) + return build_real_from_int_cst (type, arg1); + if (TREE_CODE (arg1) == REAL_CST) + return fold_convert_const_real_from_real (type, arg1); + } + return NULL_TREE; +} + +/* Construct a vector of zero elements of vector type TYPE. */ + +static tree +build_zero_vector (tree type) +{ + tree elem, list; + int i, units; + + elem = fold_convert_const (NOP_EXPR, TREE_TYPE (type), integer_zero_node); + units = TYPE_VECTOR_SUBPARTS (type); + + list = NULL_TREE; + for (i = 0; i < units; i++) + list = tree_cons (NULL_TREE, elem, list); + return build_vector (type, list); +} + +/* Convert expression ARG to type TYPE. Used by the middle-end for + simple conversions in preference to calling the front-end's convert. */ + +tree +fold_convert (tree type, tree arg) +{ + tree orig = TREE_TYPE (arg); + tree tem; + + if (type == orig) + return arg; + + if (TREE_CODE (arg) == ERROR_MARK + || TREE_CODE (type) == ERROR_MARK + || TREE_CODE (orig) == ERROR_MARK) + return error_mark_node; + + if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (orig) + || lang_hooks.types_compatible_p (TYPE_MAIN_VARIANT (type), + TYPE_MAIN_VARIANT (orig))) + return fold_build1 (NOP_EXPR, type, arg); + + switch (TREE_CODE (type)) + { + case INTEGER_TYPE: case ENUMERAL_TYPE: case BOOLEAN_TYPE: + case POINTER_TYPE: case REFERENCE_TYPE: + case OFFSET_TYPE: + if (TREE_CODE (arg) == INTEGER_CST) + { + tem = fold_convert_const (NOP_EXPR, type, arg); + if (tem != NULL_TREE) + return tem; + } + if (INTEGRAL_TYPE_P (orig) || POINTER_TYPE_P (orig) + || TREE_CODE (orig) == OFFSET_TYPE) + return fold_build1 (NOP_EXPR, type, arg); + if (TREE_CODE (orig) == COMPLEX_TYPE) + { + tem = fold_build1 (REALPART_EXPR, TREE_TYPE (orig), arg); + return fold_convert (type, tem); + } + gcc_assert (TREE_CODE (orig) == VECTOR_TYPE + && tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (orig))); + return fold_build1 (NOP_EXPR, type, arg); + + case REAL_TYPE: + if (TREE_CODE (arg) == INTEGER_CST) + { + tem = fold_convert_const (FLOAT_EXPR, type, arg); + if (tem != NULL_TREE) + return tem; + } + else if (TREE_CODE (arg) == REAL_CST) + { + tem = fold_convert_const (NOP_EXPR, type, arg); + if (tem != NULL_TREE) + return tem; + } + + switch (TREE_CODE (orig)) + { + case INTEGER_TYPE: + case BOOLEAN_TYPE: case ENUMERAL_TYPE: + case POINTER_TYPE: case REFERENCE_TYPE: + return fold_build1 (FLOAT_EXPR, type, arg); + + case REAL_TYPE: + return fold_build1 (NOP_EXPR, type, arg); + + case COMPLEX_TYPE: + tem = fold_build1 (REALPART_EXPR, TREE_TYPE (orig), arg); + return fold_convert (type, tem); + + default: + gcc_unreachable (); + } + + case COMPLEX_TYPE: + switch (TREE_CODE (orig)) + { + case INTEGER_TYPE: + case BOOLEAN_TYPE: case ENUMERAL_TYPE: + case POINTER_TYPE: case REFERENCE_TYPE: + case REAL_TYPE: + return build2 (COMPLEX_EXPR, type, + fold_convert (TREE_TYPE (type), arg), + fold_convert (TREE_TYPE (type), integer_zero_node)); + case COMPLEX_TYPE: + { + tree rpart, ipart; + + if (TREE_CODE (arg) == COMPLEX_EXPR) + { + rpart = fold_convert (TREE_TYPE (type), TREE_OPERAND (arg, 0)); + ipart = fold_convert (TREE_TYPE (type), TREE_OPERAND (arg, 1)); + return fold_build2 (COMPLEX_EXPR, type, rpart, ipart); + } + + arg = save_expr (arg); + rpart = fold_build1 (REALPART_EXPR, TREE_TYPE (orig), arg); + ipart = fold_build1 (IMAGPART_EXPR, TREE_TYPE (orig), arg); + rpart = fold_convert (TREE_TYPE (type), rpart); + ipart = fold_convert (TREE_TYPE (type), ipart); + return fold_build2 (COMPLEX_EXPR, type, rpart, ipart); + } + + default: + gcc_unreachable (); + } + + case VECTOR_TYPE: + if (integer_zerop (arg)) + return build_zero_vector (type); + gcc_assert (tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (orig))); + gcc_assert (INTEGRAL_TYPE_P (orig) || POINTER_TYPE_P (orig) + || TREE_CODE (orig) == VECTOR_TYPE); + return fold_build1 (VIEW_CONVERT_EXPR, type, arg); + + case VOID_TYPE: + return fold_build1 (NOP_EXPR, type, fold_ignored_result (arg)); + + default: + gcc_unreachable (); + } +} + +/* Return false if expr can be assumed not to be an lvalue, true + otherwise. */ + +static bool +maybe_lvalue_p (tree x) +{ + /* We only need to wrap lvalue tree codes. */ + switch (TREE_CODE (x)) + { + case VAR_DECL: + case PARM_DECL: + case RESULT_DECL: + case LABEL_DECL: + case FUNCTION_DECL: + case SSA_NAME: + + case COMPONENT_REF: + case INDIRECT_REF: + case ALIGN_INDIRECT_REF: + case MISALIGNED_INDIRECT_REF: + case ARRAY_REF: + case ARRAY_RANGE_REF: + case BIT_FIELD_REF: + case OBJ_TYPE_REF: + + case REALPART_EXPR: + case IMAGPART_EXPR: + case PREINCREMENT_EXPR: + case PREDECREMENT_EXPR: + case SAVE_EXPR: + case TRY_CATCH_EXPR: + case WITH_CLEANUP_EXPR: + case COMPOUND_EXPR: + case MODIFY_EXPR: + case TARGET_EXPR: + case COND_EXPR: + case BIND_EXPR: + case MIN_EXPR: + case MAX_EXPR: + break; + + default: + /* Assume the worst for front-end tree codes. */ + if ((int)TREE_CODE (x) >= NUM_TREE_CODES) + break; + return false; + } + + return true; +} + +/* Return an expr equal to X but certainly not valid as an lvalue. */ + +tree +non_lvalue (tree x) +{ + /* While we are in GIMPLE, NON_LVALUE_EXPR doesn't mean anything to + us. */ + if (in_gimple_form) + return x; + + if (! maybe_lvalue_p (x)) + return x; + return build1 (NON_LVALUE_EXPR, TREE_TYPE (x), x); +} + +/* Nonzero means lvalues are limited to those valid in pedantic ANSI C. + Zero means allow extended lvalues. */ + +int pedantic_lvalues; + +/* When pedantic, return an expr equal to X but certainly not valid as a + pedantic lvalue. Otherwise, return X. */ + +static tree +pedantic_non_lvalue (tree x) +{ + if (pedantic_lvalues) + return non_lvalue (x); + else + return x; +} + +/* Given a tree comparison code, return the code that is the logical inverse + of the given code. It is not safe to do this for floating-point + comparisons, except for NE_EXPR and EQ_EXPR, so we receive a machine mode + as well: if reversing the comparison is unsafe, return ERROR_MARK. */ + +enum tree_code +invert_tree_comparison (enum tree_code code, bool honor_nans) +{ + if (honor_nans && flag_trapping_math) + return ERROR_MARK; + + switch (code) + { + case EQ_EXPR: + return NE_EXPR; + case NE_EXPR: + return EQ_EXPR; + case GT_EXPR: + return honor_nans ? UNLE_EXPR : LE_EXPR; + case GE_EXPR: + return honor_nans ? UNLT_EXPR : LT_EXPR; + case LT_EXPR: + return honor_nans ? UNGE_EXPR : GE_EXPR; + case LE_EXPR: + return honor_nans ? UNGT_EXPR : GT_EXPR; + case LTGT_EXPR: + return UNEQ_EXPR; + case UNEQ_EXPR: + return LTGT_EXPR; + case UNGT_EXPR: + return LE_EXPR; + case UNGE_EXPR: + return LT_EXPR; + case UNLT_EXPR: + return GE_EXPR; + case UNLE_EXPR: + return GT_EXPR; + case ORDERED_EXPR: + return UNORDERED_EXPR; + case UNORDERED_EXPR: + return ORDERED_EXPR; + default: + gcc_unreachable (); + } +} + +/* Similar, but return the comparison that results if the operands are + swapped. This is safe for floating-point. */ + +enum tree_code +swap_tree_comparison (enum tree_code code) +{ + switch (code) + { + case EQ_EXPR: + case NE_EXPR: + case ORDERED_EXPR: + case UNORDERED_EXPR: + case LTGT_EXPR: + case UNEQ_EXPR: + return code; + case GT_EXPR: + return LT_EXPR; + case GE_EXPR: + return LE_EXPR; + case LT_EXPR: + return GT_EXPR; + case LE_EXPR: + return GE_EXPR; + case UNGT_EXPR: + return UNLT_EXPR; + case UNGE_EXPR: + return UNLE_EXPR; + case UNLT_EXPR: + return UNGT_EXPR; + case UNLE_EXPR: + return UNGE_EXPR; + default: + gcc_unreachable (); + } +} + + +/* Convert a comparison tree code from an enum tree_code representation + into a compcode bit-based encoding. This function is the inverse of + compcode_to_comparison. */ + +static enum comparison_code +comparison_to_compcode (enum tree_code code) +{ + switch (code) + { + case LT_EXPR: + return COMPCODE_LT; + case EQ_EXPR: + return COMPCODE_EQ; + case LE_EXPR: + return COMPCODE_LE; + case GT_EXPR: + return COMPCODE_GT; + case NE_EXPR: + return COMPCODE_NE; + case GE_EXPR: + return COMPCODE_GE; + case ORDERED_EXPR: + return COMPCODE_ORD; + case UNORDERED_EXPR: + return COMPCODE_UNORD; + case UNLT_EXPR: + return COMPCODE_UNLT; + case UNEQ_EXPR: + return COMPCODE_UNEQ; + case UNLE_EXPR: + return COMPCODE_UNLE; + case UNGT_EXPR: + return COMPCODE_UNGT; + case LTGT_EXPR: + return COMPCODE_LTGT; + case UNGE_EXPR: + return COMPCODE_UNGE; + default: + gcc_unreachable (); + } +} + +/* Convert a compcode bit-based encoding of a comparison operator back + to GCC's enum tree_code representation. This function is the + inverse of comparison_to_compcode. */ + +static enum tree_code +compcode_to_comparison (enum comparison_code code) +{ + switch (code) + { + case COMPCODE_LT: + return LT_EXPR; + case COMPCODE_EQ: + return EQ_EXPR; + case COMPCODE_LE: + return LE_EXPR; + case COMPCODE_GT: + return GT_EXPR; + case COMPCODE_NE: + return NE_EXPR; + case COMPCODE_GE: + return GE_EXPR; + case COMPCODE_ORD: + return ORDERED_EXPR; + case COMPCODE_UNORD: + return UNORDERED_EXPR; + case COMPCODE_UNLT: + return UNLT_EXPR; + case COMPCODE_UNEQ: + return UNEQ_EXPR; + case COMPCODE_UNLE: + return UNLE_EXPR; + case COMPCODE_UNGT: + return UNGT_EXPR; + case COMPCODE_LTGT: + return LTGT_EXPR; + case COMPCODE_UNGE: + return UNGE_EXPR; + default: + gcc_unreachable (); + } +} + +/* Return a tree for the comparison which is the combination of + doing the AND or OR (depending on CODE) of the two operations LCODE + and RCODE on the identical operands LL_ARG and LR_ARG. Take into account + the possibility of trapping if the mode has NaNs, and return NULL_TREE + if this makes the transformation invalid. */ + +tree +combine_comparisons (enum tree_code code, enum tree_code lcode, + enum tree_code rcode, tree truth_type, + tree ll_arg, tree lr_arg) +{ + bool honor_nans = HONOR_NANS (TYPE_MODE (TREE_TYPE (ll_arg))); + enum comparison_code lcompcode = comparison_to_compcode (lcode); + enum comparison_code rcompcode = comparison_to_compcode (rcode); + enum comparison_code compcode; + + switch (code) + { + case TRUTH_AND_EXPR: case TRUTH_ANDIF_EXPR: + compcode = lcompcode & rcompcode; + break; + + case TRUTH_OR_EXPR: case TRUTH_ORIF_EXPR: + compcode = lcompcode | rcompcode; + break; + + default: + return NULL_TREE; + } + + if (!honor_nans) + { + /* Eliminate unordered comparisons, as well as LTGT and ORD + which are not used unless the mode has NaNs. */ + compcode &= ~COMPCODE_UNORD; + if (compcode == COMPCODE_LTGT) + compcode = COMPCODE_NE; + else if (compcode == COMPCODE_ORD) + compcode = COMPCODE_TRUE; + } + else if (flag_trapping_math) + { + /* Check that the original operation and the optimized ones will trap + under the same condition. */ + bool ltrap = (lcompcode & COMPCODE_UNORD) == 0 + && (lcompcode != COMPCODE_EQ) + && (lcompcode != COMPCODE_ORD); + bool rtrap = (rcompcode & COMPCODE_UNORD) == 0 + && (rcompcode != COMPCODE_EQ) + && (rcompcode != COMPCODE_ORD); + bool trap = (compcode & COMPCODE_UNORD) == 0 + && (compcode != COMPCODE_EQ) + && (compcode != COMPCODE_ORD); + + /* In a short-circuited boolean expression the LHS might be + such that the RHS, if evaluated, will never trap. For + example, in ORD (x, y) && (x < y), we evaluate the RHS only + if neither x nor y is NaN. (This is a mixed blessing: for + example, the expression above will never trap, hence + optimizing it to x < y would be invalid). */ + if ((code == TRUTH_ORIF_EXPR && (lcompcode & COMPCODE_UNORD)) + || (code == TRUTH_ANDIF_EXPR && !(lcompcode & COMPCODE_UNORD))) + rtrap = false; + + /* If the comparison was short-circuited, and only the RHS + trapped, we may now generate a spurious trap. */ + if (rtrap && !ltrap + && (code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR)) + return NULL_TREE; + + /* If we changed the conditions that cause a trap, we lose. */ + if ((ltrap || rtrap) != trap) + return NULL_TREE; + } + + if (compcode == COMPCODE_TRUE) + return constant_boolean_node (true, truth_type); + else if (compcode == COMPCODE_FALSE) + return constant_boolean_node (false, truth_type); + else + return fold_build2 (compcode_to_comparison (compcode), + truth_type, ll_arg, lr_arg); +} + +/* Return nonzero if CODE is a tree code that represents a truth value. */ + +static int +truth_value_p (enum tree_code code) +{ + return (TREE_CODE_CLASS (code) == tcc_comparison + || code == TRUTH_AND_EXPR || code == TRUTH_ANDIF_EXPR + || code == TRUTH_OR_EXPR || code == TRUTH_ORIF_EXPR + || code == TRUTH_XOR_EXPR || code == TRUTH_NOT_EXPR); +} + +/* Return nonzero if two operands (typically of the same tree node) + are necessarily equal. If either argument has side-effects this + function returns zero. FLAGS modifies behavior as follows: + + If OEP_ONLY_CONST is set, only return nonzero for constants. + This function tests whether the operands are indistinguishable; + it does not test whether they are equal using C's == operation. + The distinction is important for IEEE floating point, because + (1) -0.0 and 0.0 are distinguishable, but -0.0==0.0, and + (2) two NaNs may be indistinguishable, but NaN!=NaN. + + If OEP_ONLY_CONST is unset, a VAR_DECL is considered equal to itself + even though it may hold multiple values during a function. + This is because a GCC tree node guarantees that nothing else is + executed between the evaluation of its "operands" (which may often + be evaluated in arbitrary order). Hence if the operands themselves + don't side-effect, the VAR_DECLs, PARM_DECLs etc... must hold the + same value in each operand/subexpression. Hence leaving OEP_ONLY_CONST + unset means assuming isochronic (or instantaneous) tree equivalence. + Unless comparing arbitrary expression trees, such as from different + statements, this flag can usually be left unset. + + If OEP_PURE_SAME is set, then pure functions with identical arguments + are considered the same. It is used when the caller has other ways + to ensure that global memory is unchanged in between. */ + +int +operand_equal_p (tree arg0, tree arg1, unsigned int flags) +{ + /* If either is ERROR_MARK, they aren't equal. */ + if (TREE_CODE (arg0) == ERROR_MARK || TREE_CODE (arg1) == ERROR_MARK) + return 0; + + /* If both types don't have the same signedness, then we can't consider + them equal. We must check this before the STRIP_NOPS calls + because they may change the signedness of the arguments. */ + if (TYPE_UNSIGNED (TREE_TYPE (arg0)) != TYPE_UNSIGNED (TREE_TYPE (arg1))) + return 0; + + /* If both types don't have the same precision, then it is not safe + to strip NOPs. */ + if (TYPE_PRECISION (TREE_TYPE (arg0)) != TYPE_PRECISION (TREE_TYPE (arg1))) + return 0; + + STRIP_NOPS (arg0); + STRIP_NOPS (arg1); + + /* In case both args are comparisons but with different comparison + code, try to swap the comparison operands of one arg to produce + a match and compare that variant. */ + if (TREE_CODE (arg0) != TREE_CODE (arg1) + && COMPARISON_CLASS_P (arg0) + && COMPARISON_CLASS_P (arg1)) + { + enum tree_code swap_code = swap_tree_comparison (TREE_CODE (arg1)); + + if (TREE_CODE (arg0) == swap_code) + return operand_equal_p (TREE_OPERAND (arg0, 0), + TREE_OPERAND (arg1, 1), flags) + && operand_equal_p (TREE_OPERAND (arg0, 1), + TREE_OPERAND (arg1, 0), flags); + } + + if (TREE_CODE (arg0) != TREE_CODE (arg1) + /* This is needed for conversions and for COMPONENT_REF. + Might as well play it safe and always test this. */ + || TREE_CODE (TREE_TYPE (arg0)) == ERROR_MARK + || TREE_CODE (TREE_TYPE (arg1)) == ERROR_MARK + || TYPE_MODE (TREE_TYPE (arg0)) != TYPE_MODE (TREE_TYPE (arg1))) + return 0; + + /* If ARG0 and ARG1 are the same SAVE_EXPR, they are necessarily equal. + We don't care about side effects in that case because the SAVE_EXPR + takes care of that for us. In all other cases, two expressions are + equal if they have no side effects. If we have two identical + expressions with side effects that should be treated the same due + to the only side effects being identical SAVE_EXPR's, that will + be detected in the recursive calls below. */ + if (arg0 == arg1 && ! (flags & OEP_ONLY_CONST) + && (TREE_CODE (arg0) == SAVE_EXPR + || (! TREE_SIDE_EFFECTS (arg0) && ! TREE_SIDE_EFFECTS (arg1)))) + return 1; + + /* Next handle constant cases, those for which we can return 1 even + if ONLY_CONST is set. */ + if (TREE_CONSTANT (arg0) && TREE_CONSTANT (arg1)) + switch (TREE_CODE (arg0)) + { + case INTEGER_CST: + return (! TREE_CONSTANT_OVERFLOW (arg0) + && ! TREE_CONSTANT_OVERFLOW (arg1) + && tree_int_cst_equal (arg0, arg1)); + + case REAL_CST: + return (! TREE_CONSTANT_OVERFLOW (arg0) + && ! TREE_CONSTANT_OVERFLOW (arg1) + && REAL_VALUES_IDENTICAL (TREE_REAL_CST (arg0), + TREE_REAL_CST (arg1))); + + case VECTOR_CST: + { + tree v1, v2; + + if (TREE_CONSTANT_OVERFLOW (arg0) + || TREE_CONSTANT_OVERFLOW (arg1)) + return 0; + + v1 = TREE_VECTOR_CST_ELTS (arg0); + v2 = TREE_VECTOR_CST_ELTS (arg1); + while (v1 && v2) + { + if (!operand_equal_p (TREE_VALUE (v1), TREE_VALUE (v2), + flags)) + return 0; + v1 = TREE_CHAIN (v1); + v2 = TREE_CHAIN (v2); + } + + return v1 == v2; + } + + case COMPLEX_CST: + return (operand_equal_p (TREE_REALPART (arg0), TREE_REALPART (arg1), + flags) + && operand_equal_p (TREE_IMAGPART (arg0), TREE_IMAGPART (arg1), + flags)); + + case STRING_CST: + return (TREE_STRING_LENGTH (arg0) == TREE_STRING_LENGTH (arg1) + && ! memcmp (TREE_STRING_POINTER (arg0), + TREE_STRING_POINTER (arg1), + TREE_STRING_LENGTH (arg0))); + + case ADDR_EXPR: + return operand_equal_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1, 0), + 0); + default: + break; + } + + if (flags & OEP_ONLY_CONST) + return 0; + +/* Define macros to test an operand from arg0 and arg1 for equality and a + variant that allows null and views null as being different from any + non-null value. In the latter case, if either is null, the both + must be; otherwise, do the normal comparison. */ +#define OP_SAME(N) operand_equal_p (TREE_OPERAND (arg0, N), \ + TREE_OPERAND (arg1, N), flags) + +#define OP_SAME_WITH_NULL(N) \ + ((!TREE_OPERAND (arg0, N) || !TREE_OPERAND (arg1, N)) \ + ? TREE_OPERAND (arg0, N) == TREE_OPERAND (arg1, N) : OP_SAME (N)) + + switch (TREE_CODE_CLASS (TREE_CODE (arg0))) + { + case tcc_unary: + /* Two conversions are equal only if signedness and modes match. */ + switch (TREE_CODE (arg0)) + { + case NOP_EXPR: + case CONVERT_EXPR: + case FIX_CEIL_EXPR: + case FIX_TRUNC_EXPR: + case FIX_FLOOR_EXPR: + case FIX_ROUND_EXPR: + if (TYPE_UNSIGNED (TREE_TYPE (arg0)) + != TYPE_UNSIGNED (TREE_TYPE (arg1))) + return 0; + break; + default: + break; + } + + return OP_SAME (0); + + + case tcc_comparison: + case tcc_binary: + if (OP_SAME (0) && OP_SAME (1)) + return 1; + + /* For commutative ops, allow the other order. */ + return (commutative_tree_code (TREE_CODE (arg0)) + && operand_equal_p (TREE_OPERAND (arg0, 0), + TREE_OPERAND (arg1, 1), flags) + && operand_equal_p (TREE_OPERAND (arg0, 1), + TREE_OPERAND (arg1, 0), flags)); + + case tcc_reference: + /* If either of the pointer (or reference) expressions we are + dereferencing contain a side effect, these cannot be equal. */ + if (TREE_SIDE_EFFECTS (arg0) + || TREE_SIDE_EFFECTS (arg1)) + return 0; + + switch (TREE_CODE (arg0)) + { + case INDIRECT_REF: + case ALIGN_INDIRECT_REF: + case MISALIGNED_INDIRECT_REF: + case REALPART_EXPR: + case IMAGPART_EXPR: + return OP_SAME (0); + + case ARRAY_REF: + case ARRAY_RANGE_REF: + /* Operands 2 and 3 may be null. */ + return (OP_SAME (0) + && OP_SAME (1) + && OP_SAME_WITH_NULL (2) + && OP_SAME_WITH_NULL (3)); + + case COMPONENT_REF: + /* Handle operand 2 the same as for ARRAY_REF. Operand 0 + may be NULL when we're called to compare MEM_EXPRs. */ + return OP_SAME_WITH_NULL (0) + && OP_SAME (1) + && OP_SAME_WITH_NULL (2); + + case BIT_FIELD_REF: + return OP_SAME (0) && OP_SAME (1) && OP_SAME (2); + + default: + return 0; + } + + case tcc_expression: + switch (TREE_CODE (arg0)) + { + case ADDR_EXPR: + case TRUTH_NOT_EXPR: + return OP_SAME (0); + + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + return OP_SAME (0) && OP_SAME (1); + + case TRUTH_AND_EXPR: + case TRUTH_OR_EXPR: + case TRUTH_XOR_EXPR: + if (OP_SAME (0) && OP_SAME (1)) + return 1; + + /* Otherwise take into account this is a commutative operation. */ + return (operand_equal_p (TREE_OPERAND (arg0, 0), + TREE_OPERAND (arg1, 1), flags) + && operand_equal_p (TREE_OPERAND (arg0, 1), + TREE_OPERAND (arg1, 0), flags)); + + case CALL_EXPR: + /* If the CALL_EXPRs call different functions, then they + clearly can not be equal. */ + if (!OP_SAME (0)) + return 0; + + { + unsigned int cef = call_expr_flags (arg0); + if (flags & OEP_PURE_SAME) + cef &= ECF_CONST | ECF_PURE; + else + cef &= ECF_CONST; + if (!cef) + return 0; + } + + /* Now see if all the arguments are the same. operand_equal_p + does not handle TREE_LIST, so we walk the operands here + feeding them to operand_equal_p. */ + arg0 = TREE_OPERAND (arg0, 1); + arg1 = TREE_OPERAND (arg1, 1); + while (arg0 && arg1) + { + if (! operand_equal_p (TREE_VALUE (arg0), TREE_VALUE (arg1), + flags)) + return 0; + + arg0 = TREE_CHAIN (arg0); + arg1 = TREE_CHAIN (arg1); + } + + /* If we get here and both argument lists are exhausted + then the CALL_EXPRs are equal. */ + return ! (arg0 || arg1); + + default: + return 0; + } + + case tcc_declaration: + /* Consider __builtin_sqrt equal to sqrt. */ + return (TREE_CODE (arg0) == FUNCTION_DECL + && DECL_BUILT_IN (arg0) && DECL_BUILT_IN (arg1) + && DECL_BUILT_IN_CLASS (arg0) == DECL_BUILT_IN_CLASS (arg1) + && DECL_FUNCTION_CODE (arg0) == DECL_FUNCTION_CODE (arg1)); + + default: + return 0; + } + +#undef OP_SAME +#undef OP_SAME_WITH_NULL +} + +/* Similar to operand_equal_p, but see if ARG0 might have been made by + shorten_compare from ARG1 when ARG1 was being compared with OTHER. + + When in doubt, return 0. */ + +static int +operand_equal_for_comparison_p (tree arg0, tree arg1, tree other) +{ + int unsignedp1, unsignedpo; + tree primarg0, primarg1, primother; + unsigned int correct_width; + + if (operand_equal_p (arg0, arg1, 0)) + return 1; + + if (! INTEGRAL_TYPE_P (TREE_TYPE (arg0)) + || ! 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. + + First throw away any conversions to wider types + already present in the operands. */ + + primarg1 = get_narrower (arg1, &unsignedp1); + primother = get_narrower (other, &unsignedpo); + + correct_width = TYPE_PRECISION (TREE_TYPE (arg1)); + if (unsignedp1 == unsignedpo + && TYPE_PRECISION (TREE_TYPE (primarg1)) < correct_width + && TYPE_PRECISION (TREE_TYPE (primother)) < correct_width) + { + tree type = TREE_TYPE (arg0); + + /* Make sure shorter operand is extended the right way + to match the longer operand. */ + primarg1 = fold_convert (lang_hooks.types.signed_or_unsigned_type + (unsignedp1, TREE_TYPE (primarg1)), primarg1); + + if (operand_equal_p (arg0, fold_convert (type, primarg1), 0)) + return 1; + } + + return 0; +} + +/* See if ARG is an expression that is either a comparison or is performing + arithmetic on comparisons. The comparisons must only be comparing + two different values, which will be stored in *CVAL1 and *CVAL2; if + they are nonzero it means that some operands have already been found. + No variables may be used anywhere else in the expression except in the + comparisons. If SAVE_P is true it means we removed a SAVE_EXPR around + the expression and save_expr needs to be called with CVAL1 and CVAL2. + + If this is true, return 1. Otherwise, return zero. */ + +static int +twoval_comparison_p (tree arg, tree *cval1, tree *cval2, int *save_p) +{ + enum tree_code code = TREE_CODE (arg); + enum tree_code_class class = TREE_CODE_CLASS (code); + + /* We can handle some of the tcc_expression cases here. */ + if (class == tcc_expression && code == TRUTH_NOT_EXPR) + class = tcc_unary; + else if (class == tcc_expression + && (code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR + || code == COMPOUND_EXPR)) + class = tcc_binary; + + else if (class == tcc_expression && code == SAVE_EXPR + && ! TREE_SIDE_EFFECTS (TREE_OPERAND (arg, 0))) + { + /* If we've already found a CVAL1 or CVAL2, this expression is + two complex to handle. */ + if (*cval1 || *cval2) + return 0; + + class = tcc_unary; + *save_p = 1; + } + + switch (class) + { + case tcc_unary: + return twoval_comparison_p (TREE_OPERAND (arg, 0), cval1, cval2, save_p); + + case tcc_binary: + return (twoval_comparison_p (TREE_OPERAND (arg, 0), cval1, cval2, save_p) + && twoval_comparison_p (TREE_OPERAND (arg, 1), + cval1, cval2, save_p)); + + case tcc_constant: + return 1; + + case tcc_expression: + if (code == COND_EXPR) + return (twoval_comparison_p (TREE_OPERAND (arg, 0), + cval1, cval2, save_p) + && twoval_comparison_p (TREE_OPERAND (arg, 1), + cval1, cval2, save_p) + && twoval_comparison_p (TREE_OPERAND (arg, 2), + cval1, cval2, save_p)); + return 0; + + case tcc_comparison: + /* First see if we can handle the first operand, then the second. For + the second operand, we know *CVAL1 can't be zero. It must be that + one side of the comparison is each of the values; test for the + case where this isn't true by failing if the two operands + are the same. */ + + if (operand_equal_p (TREE_OPERAND (arg, 0), + TREE_OPERAND (arg, 1), 0)) + return 0; + + if (*cval1 == 0) + *cval1 = TREE_OPERAND (arg, 0); + else if (operand_equal_p (*cval1, TREE_OPERAND (arg, 0), 0)) + ; + else if (*cval2 == 0) + *cval2 = TREE_OPERAND (arg, 0); + else if (operand_equal_p (*cval2, TREE_OPERAND (arg, 0), 0)) + ; + else + return 0; + + if (operand_equal_p (*cval1, TREE_OPERAND (arg, 1), 0)) + ; + else if (*cval2 == 0) + *cval2 = TREE_OPERAND (arg, 1); + else if (operand_equal_p (*cval2, TREE_OPERAND (arg, 1), 0)) + ; + else + return 0; + + return 1; + + default: + return 0; + } +} + +/* ARG is a tree that is known to contain just arithmetic operations and + comparisons. Evaluate the operations in the tree substituting NEW0 for + any occurrence of OLD0 as an operand of a comparison and likewise for + NEW1 and OLD1. */ + +static tree +eval_subst (tree arg, tree old0, tree new0, tree old1, tree new1) +{ + tree type = TREE_TYPE (arg); + enum tree_code code = TREE_CODE (arg); + enum tree_code_class class = TREE_CODE_CLASS (code); + + /* We can handle some of the tcc_expression cases here. */ + if (class == tcc_expression && code == TRUTH_NOT_EXPR) + class = tcc_unary; + else if (class == tcc_expression + && (code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR)) + class = tcc_binary; + + switch (class) + { + case tcc_unary: + return fold_build1 (code, type, + eval_subst (TREE_OPERAND (arg, 0), + old0, new0, old1, new1)); + + case tcc_binary: + return fold_build2 (code, type, + eval_subst (TREE_OPERAND (arg, 0), + old0, new0, old1, new1), + eval_subst (TREE_OPERAND (arg, 1), + old0, new0, old1, new1)); + + case tcc_expression: + switch (code) + { + case SAVE_EXPR: + return eval_subst (TREE_OPERAND (arg, 0), old0, new0, old1, new1); + + case COMPOUND_EXPR: + return eval_subst (TREE_OPERAND (arg, 1), old0, new0, old1, new1); + + case COND_EXPR: + return fold_build3 (code, type, + eval_subst (TREE_OPERAND (arg, 0), + old0, new0, old1, new1), + eval_subst (TREE_OPERAND (arg, 1), + old0, new0, old1, new1), + eval_subst (TREE_OPERAND (arg, 2), + old0, new0, old1, new1)); + default: + break; + } + /* Fall through - ??? */ + + case tcc_comparison: + { + tree arg0 = TREE_OPERAND (arg, 0); + tree arg1 = TREE_OPERAND (arg, 1); + + /* We need to check both for exact equality and tree equality. The + former will be true if the operand has a side-effect. In that + case, we know the operand occurred exactly once. */ + + if (arg0 == old0 || operand_equal_p (arg0, old0, 0)) + arg0 = new0; + else if (arg0 == old1 || operand_equal_p (arg0, old1, 0)) + arg0 = new1; + + if (arg1 == old0 || operand_equal_p (arg1, old0, 0)) + arg1 = new0; + else if (arg1 == old1 || operand_equal_p (arg1, old1, 0)) + arg1 = new1; + + return fold_build2 (code, type, arg0, arg1); + } + + default: + return arg; + } +} + +/* Return a tree for the case when the result of an expression is RESULT + converted to TYPE and OMITTED was previously an operand of the expression + but is now not needed (e.g., we folded OMITTED * 0). + + If OMITTED has side effects, we must evaluate it. Otherwise, just do + the conversion of RESULT to TYPE. */ + +tree +omit_one_operand (tree type, tree result, tree omitted) +{ + tree t = fold_convert (type, result); + + if (TREE_SIDE_EFFECTS (omitted)) + return build2 (COMPOUND_EXPR, type, fold_ignored_result (omitted), t); + + return non_lvalue (t); +} + +/* Similar, but call pedantic_non_lvalue instead of non_lvalue. */ + +static tree +pedantic_omit_one_operand (tree type, tree result, tree omitted) +{ + tree t = fold_convert (type, result); + + if (TREE_SIDE_EFFECTS (omitted)) + return build2 (COMPOUND_EXPR, type, fold_ignored_result (omitted), t); + + return pedantic_non_lvalue (t); +} + +/* Return a tree for the case when the result of an expression is RESULT + converted to TYPE and OMITTED1 and OMITTED2 were previously operands + of the expression but are now not needed. + + If OMITTED1 or OMITTED2 has side effects, they must be evaluated. + If both OMITTED1 and OMITTED2 have side effects, OMITTED1 is + evaluated before OMITTED2. Otherwise, if neither has side effects, + just do the conversion of RESULT to TYPE. */ + +tree +omit_two_operands (tree type, tree result, tree omitted1, tree omitted2) +{ + tree t = fold_convert (type, result); + + if (TREE_SIDE_EFFECTS (omitted2)) + t = build2 (COMPOUND_EXPR, type, omitted2, t); + if (TREE_SIDE_EFFECTS (omitted1)) + t = build2 (COMPOUND_EXPR, type, omitted1, t); + + return TREE_CODE (t) != COMPOUND_EXPR ? non_lvalue (t) : t; +} + + +/* Return a simplified tree node for the truth-negation of ARG. This + never alters ARG itself. We assume that ARG is an operation that + returns a truth value (0 or 1). + + FIXME: one would think we would fold the result, but it causes + problems with the dominator optimizer. */ + +tree +fold_truth_not_expr (tree arg) +{ + tree type = TREE_TYPE (arg); + enum tree_code code = TREE_CODE (arg); + + /* If this is a comparison, we can simply invert it, except for + floating-point non-equality comparisons, in which case we just + enclose a TRUTH_NOT_EXPR around what we have. */ + + if (TREE_CODE_CLASS (code) == tcc_comparison) + { + tree op_type = TREE_TYPE (TREE_OPERAND (arg, 0)); + if (FLOAT_TYPE_P (op_type) + && flag_trapping_math + && code != ORDERED_EXPR && code != UNORDERED_EXPR + && code != NE_EXPR && code != EQ_EXPR) + return NULL_TREE; + else + { + code = invert_tree_comparison (code, + HONOR_NANS (TYPE_MODE (op_type))); + if (code == ERROR_MARK) + return NULL_TREE; + else + return build2 (code, type, + TREE_OPERAND (arg, 0), TREE_OPERAND (arg, 1)); + } + } + + switch (code) + { + case INTEGER_CST: + return constant_boolean_node (integer_zerop (arg), type); + + case TRUTH_AND_EXPR: + return build2 (TRUTH_OR_EXPR, type, + invert_truthvalue (TREE_OPERAND (arg, 0)), + invert_truthvalue (TREE_OPERAND (arg, 1))); + + case TRUTH_OR_EXPR: + return build2 (TRUTH_AND_EXPR, type, + invert_truthvalue (TREE_OPERAND (arg, 0)), + invert_truthvalue (TREE_OPERAND (arg, 1))); + + case TRUTH_XOR_EXPR: + /* Here we can invert either operand. We invert the first operand + unless the second operand is a TRUTH_NOT_EXPR in which case our + result is the XOR of the first operand with the inside of the + negation of the second operand. */ + + if (TREE_CODE (TREE_OPERAND (arg, 1)) == TRUTH_NOT_EXPR) + return build2 (TRUTH_XOR_EXPR, type, TREE_OPERAND (arg, 0), + TREE_OPERAND (TREE_OPERAND (arg, 1), 0)); + else + return build2 (TRUTH_XOR_EXPR, type, + invert_truthvalue (TREE_OPERAND (arg, 0)), + TREE_OPERAND (arg, 1)); + + case TRUTH_ANDIF_EXPR: + return build2 (TRUTH_ORIF_EXPR, type, + invert_truthvalue (TREE_OPERAND (arg, 0)), + invert_truthvalue (TREE_OPERAND (arg, 1))); + + case TRUTH_ORIF_EXPR: + return build2 (TRUTH_ANDIF_EXPR, type, + invert_truthvalue (TREE_OPERAND (arg, 0)), + invert_truthvalue (TREE_OPERAND (arg, 1))); + + case TRUTH_NOT_EXPR: + return TREE_OPERAND (arg, 0); + + case COND_EXPR: + { + tree arg1 = TREE_OPERAND (arg, 1); + tree arg2 = TREE_OPERAND (arg, 2); + /* A COND_EXPR may have a throw as one operand, which + then has void type. Just leave void operands + as they are. */ + return build3 (COND_EXPR, type, TREE_OPERAND (arg, 0), + VOID_TYPE_P (TREE_TYPE (arg1)) + ? arg1 : invert_truthvalue (arg1), + VOID_TYPE_P (TREE_TYPE (arg2)) + ? arg2 : invert_truthvalue (arg2)); + } + + case COMPOUND_EXPR: + return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg, 0), + invert_truthvalue (TREE_OPERAND (arg, 1))); + + case NON_LVALUE_EXPR: + return invert_truthvalue (TREE_OPERAND (arg, 0)); + + case NOP_EXPR: + if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE) + return build1 (TRUTH_NOT_EXPR, type, arg); + + case CONVERT_EXPR: + case FLOAT_EXPR: + return build1 (TREE_CODE (arg), type, + invert_truthvalue (TREE_OPERAND (arg, 0))); + + case BIT_AND_EXPR: + if (!integer_onep (TREE_OPERAND (arg, 1))) + break; + return build2 (EQ_EXPR, type, arg, + build_int_cst (type, 0)); + + case SAVE_EXPR: + return build1 (TRUTH_NOT_EXPR, type, arg); + + case CLEANUP_POINT_EXPR: + return build1 (CLEANUP_POINT_EXPR, type, + invert_truthvalue (TREE_OPERAND (arg, 0))); + + default: + break; + } + + return NULL_TREE; +} + +/* Return a simplified tree node for the truth-negation of ARG. This + never alters ARG itself. We assume that ARG is an operation that + returns a truth value (0 or 1). + + FIXME: one would think we would fold the result, but it causes + problems with the dominator optimizer. */ + +tree +invert_truthvalue (tree arg) +{ + tree tem; + + if (TREE_CODE (arg) == ERROR_MARK) + return arg; + + tem = fold_truth_not_expr (arg); + if (!tem) + tem = build1 (TRUTH_NOT_EXPR, TREE_TYPE (arg), arg); + + return tem; +} + +/* Given a bit-wise operation CODE applied to ARG0 and ARG1, see if both + operands are another bit-wise operation with a common input. If so, + distribute the bit operations to save an operation and possibly two if + constants are involved. For example, convert + (A | B) & (A | C) into A | (B & C) + Further simplification will occur if B and C are constants. + + If this optimization cannot be done, 0 will be returned. */ + +static tree +distribute_bit_expr (enum tree_code code, tree type, tree arg0, tree arg1) +{ + tree common; + tree left, right; + + if (TREE_CODE (arg0) != TREE_CODE (arg1) + || TREE_CODE (arg0) == code + || (TREE_CODE (arg0) != BIT_AND_EXPR + && TREE_CODE (arg0) != BIT_IOR_EXPR)) + return 0; + + if (operand_equal_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1, 0), 0)) + { + common = TREE_OPERAND (arg0, 0); + left = TREE_OPERAND (arg0, 1); + right = TREE_OPERAND (arg1, 1); + } + else if (operand_equal_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1, 1), 0)) + { + common = TREE_OPERAND (arg0, 0); + left = TREE_OPERAND (arg0, 1); + right = TREE_OPERAND (arg1, 0); + } + else if (operand_equal_p (TREE_OPERAND (arg0, 1), TREE_OPERAND (arg1, 0), 0)) + { + common = TREE_OPERAND (arg0, 1); + left = TREE_OPERAND (arg0, 0); + right = TREE_OPERAND (arg1, 1); + } + else if (operand_equal_p (TREE_OPERAND (arg0, 1), TREE_OPERAND (arg1, 1), 0)) + { + common = TREE_OPERAND (arg0, 1); + left = TREE_OPERAND (arg0, 0); + right = TREE_OPERAND (arg1, 0); + } + else + return 0; + + return fold_build2 (TREE_CODE (arg0), type, common, + fold_build2 (code, type, left, right)); +} + +/* Knowing that ARG0 and ARG1 are both RDIV_EXPRs, simplify a binary operation + with code CODE. This optimization is unsafe. */ +static tree +distribute_real_division (enum tree_code code, tree type, tree arg0, tree arg1) +{ + bool mul0 = TREE_CODE (arg0) == MULT_EXPR; + bool mul1 = TREE_CODE (arg1) == MULT_EXPR; + + /* (A / C) +- (B / C) -> (A +- B) / C. */ + if (mul0 == mul1 + && operand_equal_p (TREE_OPERAND (arg0, 1), + TREE_OPERAND (arg1, 1), 0)) + return fold_build2 (mul0 ? MULT_EXPR : RDIV_EXPR, type, + fold_build2 (code, type, + TREE_OPERAND (arg0, 0), + TREE_OPERAND (arg1, 0)), + TREE_OPERAND (arg0, 1)); + + /* (A / C1) +- (A / C2) -> A * (1 / C1 +- 1 / C2). */ + if (operand_equal_p (TREE_OPERAND (arg0, 0), + TREE_OPERAND (arg1, 0), 0) + && TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST + && TREE_CODE (TREE_OPERAND (arg1, 1)) == REAL_CST) + { + REAL_VALUE_TYPE r0, r1; + r0 = TREE_REAL_CST (TREE_OPERAND (arg0, 1)); + r1 = TREE_REAL_CST (TREE_OPERAND (arg1, 1)); + if (!mul0) + real_arithmetic (&r0, RDIV_EXPR, &dconst1, &r0); + if (!mul1) + real_arithmetic (&r1, RDIV_EXPR, &dconst1, &r1); + real_arithmetic (&r0, code, &r0, &r1); + return fold_build2 (MULT_EXPR, type, + TREE_OPERAND (arg0, 0), + build_real (type, r0)); + } + + return NULL_TREE; +} + +/* Return a BIT_FIELD_REF of type TYPE to refer to BITSIZE bits of INNER + starting at BITPOS. The field is unsigned if UNSIGNEDP is nonzero. */ + +static tree +make_bit_field_ref (tree inner, tree type, int bitsize, int bitpos, + int unsignedp) +{ + tree result; + + if (bitpos == 0) + { + tree size = TYPE_SIZE (TREE_TYPE (inner)); + if ((INTEGRAL_TYPE_P (TREE_TYPE (inner)) + || POINTER_TYPE_P (TREE_TYPE (inner))) + && host_integerp (size, 0) + && tree_low_cst (size, 0) == bitsize) + return fold_convert (type, inner); + } + + result = build3 (BIT_FIELD_REF, type, inner, + size_int (bitsize), bitsize_int (bitpos)); + + BIT_FIELD_REF_UNSIGNED (result) = unsignedp; + + return result; +} + +/* Optimize a bit-field compare. + + There are two cases: First is a compare against a constant and the + second is a comparison of two items where the fields are at the same + bit position relative to the start of a chunk (byte, halfword, word) + large enough to contain it. In these cases we can avoid the shift + implicit in bitfield extractions. + + For constants, we emit a compare of the shifted constant with the + BIT_AND_EXPR of a mask and a byte, halfword, or word of the operand being + compared. For two fields at the same position, we do the ANDs with the + similar mask and compare the result of the ANDs. + + CODE is the comparison code, known to be either NE_EXPR or EQ_EXPR. + COMPARE_TYPE is the type of the comparison, and LHS and RHS + are the left and right operands of the comparison, respectively. + + If the optimization described above can be done, we return the resulting + tree. Otherwise we return zero. */ + +static tree +optimize_bit_field_compare (enum tree_code code, tree compare_type, + tree lhs, tree rhs) +{ + HOST_WIDE_INT lbitpos, lbitsize, rbitpos, rbitsize, nbitpos, nbitsize; + tree type = TREE_TYPE (lhs); + tree signed_type, unsigned_type; + int const_p = TREE_CODE (rhs) == INTEGER_CST; + enum machine_mode lmode, rmode, nmode; + int lunsignedp, runsignedp; + int lvolatilep = 0, rvolatilep = 0; + tree linner, rinner = NULL_TREE; + tree mask; + tree offset; + + /* Get all the information about the extractions being done. If the bit size + if the same as the size of the underlying object, we aren't doing an + extraction at all and so can do nothing. We also don't want to + do anything if the inner expression is a PLACEHOLDER_EXPR since we + then will no longer be able to replace it. */ + linner = get_inner_reference (lhs, &lbitsize, &lbitpos, &offset, &lmode, + &lunsignedp, &lvolatilep, false); + if (linner == lhs || lbitsize == GET_MODE_BITSIZE (lmode) || lbitsize < 0 + || offset != 0 || TREE_CODE (linner) == PLACEHOLDER_EXPR) + return 0; + + if (!const_p) + { + /* If this is not a constant, we can only do something if bit positions, + sizes, and signedness are the same. */ + rinner = get_inner_reference (rhs, &rbitsize, &rbitpos, &offset, &rmode, + &runsignedp, &rvolatilep, false); + + if (rinner == rhs || lbitpos != rbitpos || lbitsize != rbitsize + || lunsignedp != runsignedp || offset != 0 + || TREE_CODE (rinner) == PLACEHOLDER_EXPR) + return 0; + } + + /* See if we can find a mode to refer to this field. We should be able to, + but fail if we can't. */ + nmode = get_best_mode (lbitsize, lbitpos, + const_p ? TYPE_ALIGN (TREE_TYPE (linner)) + : MIN (TYPE_ALIGN (TREE_TYPE (linner)), + TYPE_ALIGN (TREE_TYPE (rinner))), + word_mode, lvolatilep || rvolatilep); + if (nmode == VOIDmode) + return 0; + + /* Set signed and unsigned types of the precision of this mode for the + shifts below. */ + signed_type = lang_hooks.types.type_for_mode (nmode, 0); + unsigned_type = lang_hooks.types.type_for_mode (nmode, 1); + + /* Compute the bit position and size for the new reference and our offset + within it. If the new reference is the same size as the original, we + won't optimize anything, so return zero. */ + nbitsize = GET_MODE_BITSIZE (nmode); + nbitpos = lbitpos & ~ (nbitsize - 1); + lbitpos -= nbitpos; + if (nbitsize == lbitsize) + return 0; + + if (BYTES_BIG_ENDIAN) + lbitpos = nbitsize - lbitsize - lbitpos; + + /* Make the mask to be used against the extracted field. */ + mask = build_int_cst (unsigned_type, -1); + mask = force_fit_type (mask, 0, false, false); + mask = fold_convert (unsigned_type, mask); + mask = const_binop (LSHIFT_EXPR, mask, size_int (nbitsize - lbitsize), 0); + mask = const_binop (RSHIFT_EXPR, mask, + size_int (nbitsize - lbitsize - lbitpos), 0); + + if (! const_p) + /* If not comparing with constant, just rework the comparison + and return. */ + return build2 (code, compare_type, + build2 (BIT_AND_EXPR, unsigned_type, + make_bit_field_ref (linner, unsigned_type, + nbitsize, nbitpos, 1), + mask), + build2 (BIT_AND_EXPR, unsigned_type, + make_bit_field_ref (rinner, unsigned_type, + nbitsize, nbitpos, 1), + mask)); + + /* Otherwise, we are handling the constant case. See if the constant is too + big for the field. Warn and return a tree of for 0 (false) if so. We do + this not only for its own sake, but to avoid having to test for this + error case below. If we didn't, we might generate wrong code. + + For unsigned fields, the constant shifted right by the field length should + be all zero. For signed fields, the high-order bits should agree with + the sign bit. */ + + if (lunsignedp) + { + if (! integer_zerop (const_binop (RSHIFT_EXPR, + fold_convert (unsigned_type, rhs), + size_int (lbitsize), 0))) + { + warning (0, "comparison is always %d due to width of bit-field", + code == NE_EXPR); + return constant_boolean_node (code == NE_EXPR, compare_type); + } + } + else + { + tree tem = const_binop (RSHIFT_EXPR, fold_convert (signed_type, rhs), + size_int (lbitsize - 1), 0); + if (! integer_zerop (tem) && ! integer_all_onesp (tem)) + { + warning (0, "comparison is always %d due to width of bit-field", + code == NE_EXPR); + return constant_boolean_node (code == NE_EXPR, compare_type); + } + } + + /* Single-bit compares should always be against zero. */ + if (lbitsize == 1 && ! integer_zerop (rhs)) + { + code = code == EQ_EXPR ? NE_EXPR : EQ_EXPR; + rhs = build_int_cst (type, 0); + } + + /* Make a new bitfield reference, shift the constant over the + appropriate number of bits and mask it with the computed mask + (in case this was a signed field). If we changed it, make a new one. */ + lhs = make_bit_field_ref (linner, unsigned_type, nbitsize, nbitpos, 1); + if (lvolatilep) + { + TREE_SIDE_EFFECTS (lhs) = 1; + TREE_THIS_VOLATILE (lhs) = 1; + } + + rhs = const_binop (BIT_AND_EXPR, + const_binop (LSHIFT_EXPR, + fold_convert (unsigned_type, rhs), + size_int (lbitpos), 0), + mask, 0); + + return build2 (code, compare_type, + build2 (BIT_AND_EXPR, unsigned_type, lhs, mask), + rhs); +} + +/* Subroutine for fold_truthop: decode a field reference. + + If EXP is a comparison reference, we return the innermost reference. + + *PBITSIZE is set to the number of bits in the reference, *PBITPOS is + set to the starting bit number. + + If the innermost field can be completely contained in a mode-sized + unit, *PMODE is set to that mode. Otherwise, it is set to VOIDmode. + + *PVOLATILEP is set to 1 if the any expression encountered is volatile; + otherwise it is not changed. + + *PUNSIGNEDP is set to the signedness of the field. + + *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 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. */ + +static tree +decode_field_reference (tree exp, HOST_WIDE_INT *pbitsize, + HOST_WIDE_INT *pbitpos, enum machine_mode *pmode, + int *punsignedp, int *pvolatilep, + tree *pmask, tree *pand_mask) +{ + tree outer_type = 0; + tree and_mask = 0; + tree mask, inner, offset; + tree unsigned_type; + unsigned int precision; + + /* All the optimizations using this function assume integer fields. + There are problems with FP fields since the type_for_size call + below can fail for, e.g., XFmode. */ + if (! INTEGRAL_TYPE_P (TREE_TYPE (exp))) + return 0; + + /* We are interested in the bare arrangement of bits, so strip everything + that doesn't affect the machine mode. However, record the type of the + outermost expression if it may matter below. */ + if (TREE_CODE (exp) == NOP_EXPR + || TREE_CODE (exp) == CONVERT_EXPR + || TREE_CODE (exp) == NON_LVALUE_EXPR) + outer_type = TREE_TYPE (exp); + STRIP_NOPS (exp); + + if (TREE_CODE (exp) == BIT_AND_EXPR) + { + and_mask = TREE_OPERAND (exp, 1); + exp = TREE_OPERAND (exp, 0); + STRIP_NOPS (exp); STRIP_NOPS (and_mask); + if (TREE_CODE (and_mask) != INTEGER_CST) + return 0; + } + + inner = get_inner_reference (exp, pbitsize, pbitpos, &offset, pmode, + punsignedp, pvolatilep, false); + if ((inner == exp && and_mask == 0) + || *pbitsize < 0 || offset != 0 + || TREE_CODE (inner) == PLACEHOLDER_EXPR) + return 0; + + /* If the number of bits in the reference is the same as the bitsize of + the outer type, then the outer type gives the signedness. Otherwise + (in case of a small bitfield) the signedness is unchanged. */ + if (outer_type && *pbitsize == TYPE_PRECISION (outer_type)) + *punsignedp = TYPE_UNSIGNED (outer_type); + + /* Compute the mask to access the bitfield. */ + unsigned_type = lang_hooks.types.type_for_size (*pbitsize, 1); + precision = TYPE_PRECISION (unsigned_type); + + mask = build_int_cst (unsigned_type, -1); + mask = force_fit_type (mask, 0, false, false); + + mask = const_binop (LSHIFT_EXPR, mask, size_int (precision - *pbitsize), 0); + mask = const_binop (RSHIFT_EXPR, mask, size_int (precision - *pbitsize), 0); + + /* Merge it with the mask we found in the BIT_AND_EXPR, if any. */ + if (and_mask != 0) + mask = fold_build2 (BIT_AND_EXPR, unsigned_type, + fold_convert (unsigned_type, and_mask), mask); + + *pmask = mask; + *pand_mask = and_mask; + return inner; +} + +/* Return nonzero if MASK represents a mask of SIZE ones in the low-order + bit positions. */ + +static int +all_ones_mask_p (tree mask, int size) +{ + tree type = TREE_TYPE (mask); + unsigned int precision = TYPE_PRECISION (type); + tree tmask; + + tmask = build_int_cst (lang_hooks.types.signed_type (type), -1); + tmask = force_fit_type (tmask, 0, false, false); + + return + tree_int_cst_equal (mask, + const_binop (RSHIFT_EXPR, + const_binop (LSHIFT_EXPR, tmask, + size_int (precision - size), + 0), + size_int (precision - size), 0)); +} + +/* Subroutine for fold: determine if VAL is the INTEGER_CONST that + represents the sign bit of EXP's type. If EXP represents a sign + or zero extension, also test VAL against the unextended type. + The return value is the (sub)expression whose sign bit is VAL, + or NULL_TREE otherwise. */ + +static tree +sign_bit_p (tree exp, tree val) +{ + unsigned HOST_WIDE_INT mask_lo, lo; + HOST_WIDE_INT mask_hi, hi; + int width; + tree t; + + /* Tree EXP must have an integral type. */ + t = TREE_TYPE (exp); + if (! INTEGRAL_TYPE_P (t)) + return NULL_TREE; + + /* Tree VAL must be an integer constant. */ + if (TREE_CODE (val) != INTEGER_CST + || TREE_CONSTANT_OVERFLOW (val)) + return NULL_TREE; + + width = TYPE_PRECISION (t); + if (width > HOST_BITS_PER_WIDE_INT) + { + hi = (unsigned HOST_WIDE_INT) 1 << (width - HOST_BITS_PER_WIDE_INT - 1); + lo = 0; + + mask_hi = ((unsigned HOST_WIDE_INT) -1 + >> (2 * HOST_BITS_PER_WIDE_INT - width)); + mask_lo = -1; + } + else + { + hi = 0; + lo = (unsigned HOST_WIDE_INT) 1 << (width - 1); + + mask_hi = 0; + mask_lo = ((unsigned HOST_WIDE_INT) -1 + >> (HOST_BITS_PER_WIDE_INT - width)); + } + + /* We mask off those bits beyond TREE_TYPE (exp) so that we can + treat VAL as if it were unsigned. */ + if ((TREE_INT_CST_HIGH (val) & mask_hi) == hi + && (TREE_INT_CST_LOW (val) & mask_lo) == lo) + return exp; + + /* Handle extension from a narrower type. */ + if (TREE_CODE (exp) == NOP_EXPR + && TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0))) < width) + return sign_bit_p (TREE_OPERAND (exp, 0), val); + + return NULL_TREE; +} + +/* Subroutine for fold_truthop: determine if an operand is simple enough + to be evaluated unconditionally. */ + +static int +simple_operand_p (tree exp) +{ + /* Strip any conversions that don't change the machine mode. */ + STRIP_NOPS (exp); + + return (CONSTANT_CLASS_P (exp) + || TREE_CODE (exp) == SSA_NAME + || (DECL_P (exp) + && ! TREE_ADDRESSABLE (exp) + && ! TREE_THIS_VOLATILE (exp) + && ! DECL_NONLOCAL (exp) + /* Don't regard global variables as simple. They may be + allocated in ways unknown to the compiler (shared memory, + #pragma weak, etc). */ + && ! TREE_PUBLIC (exp) + && ! DECL_EXTERNAL (exp) + /* Loading a static variable is unduly expensive, but global + registers aren't expensive. */ + && (! TREE_STATIC (exp) || DECL_REGISTER (exp)))); +} + +/* The following functions are subroutines to fold_range_test and allow it to + try to change a logical combination of comparisons into a range test. + + For example, both + X == 2 || X == 3 || X == 4 || X == 5 + and + X >= 2 && X <= 5 + are converted to + (unsigned) (X - 2) <= 3 + + We describe each set of comparisons as being either inside or outside + a range, using a variable named like IN_P, and then describe the + range with a lower and upper bound. If one of the bounds is omitted, + it represents either the highest or lowest value of the type. + + In the comments below, we represent a range by two numbers in brackets + preceded by a "+" to designate being inside that range, or a "-" to + designate being outside that range, so the condition can be inverted by + flipping the prefix. An omitted bound is represented by a "-". For + example, "- [-, 10]" means being outside the range starting at the lowest + possible value and ending at 10, in other words, being greater than 10. + The range "+ [-, -]" is always true and hence the range "- [-, -]" is + always false. + + We set up things so that the missing bounds are handled in a consistent + manner so neither a missing bound nor "true" and "false" need to be + handled using a special case. */ + +/* Return the result of applying CODE to ARG0 and ARG1, but handle the case + of ARG0 and/or ARG1 being omitted, meaning an unlimited range. UPPER0_P + and UPPER1_P are nonzero if the respective argument is an upper bound + and zero for a lower. TYPE, if nonzero, is the type of the result; it + must be specified for a comparison. ARG1 will be converted to ARG0's + type if both are specified. */ + +static tree +range_binop (enum tree_code code, tree type, tree arg0, int upper0_p, + tree arg1, int upper1_p) +{ + tree tem; + int result; + int sgn0, sgn1; + + /* If neither arg represents infinity, do the normal operation. + Else, if not a comparison, return infinity. Else handle the special + comparison rules. Note that most of the cases below won't occur, but + are handled for consistency. */ + + if (arg0 != 0 && arg1 != 0) + { + tem = fold_build2 (code, type != 0 ? type : TREE_TYPE (arg0), + arg0, fold_convert (TREE_TYPE (arg0), arg1)); + STRIP_NOPS (tem); + return TREE_CODE (tem) == INTEGER_CST ? tem : 0; + } + + if (TREE_CODE_CLASS (code) != tcc_comparison) + return 0; + + /* Set SGN[01] to -1 if ARG[01] is a lower bound, 1 for upper, and 0 + 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: + result = sgn0 == sgn1; + break; + case NE_EXPR: + result = sgn0 != sgn1; + break; + case LT_EXPR: + result = sgn0 < sgn1; + break; + case LE_EXPR: + result = sgn0 <= sgn1; + break; + case GT_EXPR: + result = sgn0 > sgn1; + break; + case GE_EXPR: + result = sgn0 >= sgn1; + break; + default: + gcc_unreachable (); + } + + return constant_boolean_node (result, type); +} + +/* Given EXP, a logical expression, set the range it is testing into + variables denoted by PIN_P, PLOW, and PHIGH. Return the expression + actually being tested. *PLOW and *PHIGH will be made of the same + type as the returned expression. If EXP is not a comparison, we + will most likely not be returning a useful value and range. Set + *STRICT_OVERFLOW_P to true if the return value is only valid + because signed overflow is undefined; otherwise, do not change + *STRICT_OVERFLOW_P. */ + +static tree +make_range (tree exp, int *pin_p, tree *plow, tree *phigh, + bool *strict_overflow_p) +{ + enum tree_code code; + tree arg0 = NULL_TREE, arg1 = NULL_TREE; + tree exp_type = NULL_TREE, arg0_type = NULL_TREE; + int in_p, n_in_p; + tree low, high, n_low, n_high; + + /* Start with simply saying "EXP != 0" and then look at the code of EXP + and see if we can refine the range. Some of the cases below may not + happen, but it doesn't seem worth worrying about this. We "continue" + the outer loop when we've changed something; otherwise we "break" + the switch, which will "break" the while. */ + + in_p = 0; + low = high = build_int_cst (TREE_TYPE (exp), 0); + + while (1) + { + code = TREE_CODE (exp); + exp_type = TREE_TYPE (exp); + + if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))) + { + if (TREE_CODE_LENGTH (code) > 0) + arg0 = TREE_OPERAND (exp, 0); + if (TREE_CODE_CLASS (code) == tcc_comparison + || TREE_CODE_CLASS (code) == tcc_unary + || TREE_CODE_CLASS (code) == tcc_binary) + arg0_type = TREE_TYPE (arg0); + if (TREE_CODE_CLASS (code) == tcc_binary + || TREE_CODE_CLASS (code) == tcc_comparison + || (TREE_CODE_CLASS (code) == tcc_expression + && TREE_CODE_LENGTH (code) > 1)) + arg1 = TREE_OPERAND (exp, 1); + } + + switch (code) + { + case TRUTH_NOT_EXPR: + in_p = ! in_p, exp = arg0; + continue; + + case EQ_EXPR: case NE_EXPR: + case LT_EXPR: case LE_EXPR: case GE_EXPR: case GT_EXPR: + /* We can only do something if the range is testing for zero + and if the second operand is an integer constant. Note that + saying something is "in" the range we make is done by + complementing IN_P since it will set in the initial case of + being not equal to zero; "out" is leaving it alone. */ + if (low == 0 || high == 0 + || ! integer_zerop (low) || ! integer_zerop (high) + || TREE_CODE (arg1) != INTEGER_CST) + break; + + switch (code) + { + case NE_EXPR: /* - [c, c] */ + low = high = arg1; + break; + case EQ_EXPR: /* + [c, c] */ + in_p = ! in_p, low = high = arg1; + break; + case GT_EXPR: /* - [-, c] */ + low = 0, high = arg1; + break; + case GE_EXPR: /* + [c, -] */ + in_p = ! in_p, low = arg1, high = 0; + break; + case LT_EXPR: /* - [c, -] */ + low = arg1, high = 0; + break; + case LE_EXPR: /* + [-, c] */ + in_p = ! in_p, low = 0, high = arg1; + break; + default: + gcc_unreachable (); + } + + /* If this is an unsigned comparison, we also know that EXP is + greater than or equal to zero. We base the range tests we make + on that fact, so we record it here so we can parse existing + range tests. We test arg0_type since often the return type + of, e.g. EQ_EXPR, is boolean. */ + if (TYPE_UNSIGNED (arg0_type) && (low == 0 || high == 0)) + { + if (! merge_ranges (&n_in_p, &n_low, &n_high, + in_p, low, high, 1, + build_int_cst (arg0_type, 0), + NULL_TREE)) + break; + + in_p = n_in_p, low = n_low, high = n_high; + + /* If the high bound is missing, but we have a nonzero low + bound, reverse the range so it goes from zero to the low bound + minus 1. */ + if (high == 0 && low && ! integer_zerop (low)) + { + in_p = ! in_p; + high = range_binop (MINUS_EXPR, NULL_TREE, low, 0, + integer_one_node, 0); + low = build_int_cst (arg0_type, 0); + } + } + + exp = arg0; + continue; + + case NEGATE_EXPR: + /* (-x) IN [a,b] -> x in [-b, -a] */ + n_low = range_binop (MINUS_EXPR, exp_type, + build_int_cst (exp_type, 0), + 0, high, 1); + n_high = range_binop (MINUS_EXPR, exp_type, + build_int_cst (exp_type, 0), + 0, low, 0); + low = n_low, high = n_high; + exp = arg0; + continue; + + case BIT_NOT_EXPR: + /* ~ X -> -X - 1 */ + exp = build2 (MINUS_EXPR, exp_type, negate_expr (arg0), + build_int_cst (exp_type, 1)); + continue; + + case PLUS_EXPR: case MINUS_EXPR: + if (TREE_CODE (arg1) != INTEGER_CST) + break; + + /* If flag_wrapv and ARG0_TYPE is signed, then we cannot + move a constant to the other side. */ + if (!TYPE_UNSIGNED (arg0_type) + && !TYPE_OVERFLOW_UNDEFINED (arg0_type)) + break; + + /* If EXP is signed, any overflow in the computation is undefined, + so we don't worry about it so long as our computations on + the bounds don't overflow. For unsigned, overflow is defined + and this is exactly the right thing. */ + n_low = range_binop (code == MINUS_EXPR ? PLUS_EXPR : MINUS_EXPR, + arg0_type, low, 0, arg1, 0); + n_high = range_binop (code == MINUS_EXPR ? PLUS_EXPR : MINUS_EXPR, + arg0_type, high, 1, arg1, 0); + if ((n_low != 0 && TREE_OVERFLOW (n_low)) + || (n_high != 0 && TREE_OVERFLOW (n_high))) + break; + + if (TYPE_OVERFLOW_UNDEFINED (arg0_type)) + *strict_overflow_p = true; + + /* Check for an unsigned range which has wrapped around the maximum + value thus making n_high < n_low, and normalize it. */ + if (n_low && n_high && tree_int_cst_lt (n_high, n_low)) + { + low = range_binop (PLUS_EXPR, arg0_type, n_high, 0, + integer_one_node, 0); + high = range_binop (MINUS_EXPR, arg0_type, n_low, 0, + integer_one_node, 0); + + /* If the range is of the form +/- [ x+1, x ], we won't + be able to normalize it. But then, it represents the + whole range or the empty set, so make it + +/- [ -, - ]. */ + if (tree_int_cst_equal (n_low, low) + && tree_int_cst_equal (n_high, high)) + low = high = 0; + else + in_p = ! in_p; + } + else + low = n_low, high = n_high; + + exp = arg0; + continue; + + case NOP_EXPR: case NON_LVALUE_EXPR: case CONVERT_EXPR: + if (TYPE_PRECISION (arg0_type) > TYPE_PRECISION (exp_type)) + break; + + if (! INTEGRAL_TYPE_P (arg0_type) + || (low != 0 && ! int_fits_type_p (low, arg0_type)) + || (high != 0 && ! int_fits_type_p (high, arg0_type))) + break; + + n_low = low, n_high = high; + + if (n_low != 0) + n_low = fold_convert (arg0_type, n_low); + + if (n_high != 0) + n_high = fold_convert (arg0_type, n_high); + + + /* If we're converting arg0 from an unsigned type, to exp, + a signed type, we will be doing the comparison as unsigned. + The tests above have already verified that LOW and HIGH + are both positive. + + So we have to ensure that we will handle large unsigned + values the same way that the current signed bounds treat + negative values. */ + + if (!TYPE_UNSIGNED (exp_type) && TYPE_UNSIGNED (arg0_type)) + { + tree high_positive; + tree equiv_type = lang_hooks.types.type_for_mode + (TYPE_MODE (arg0_type), 1); + + /* 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) ? TYPE_MAX_VALUE (equiv_type) + : TYPE_MAX_VALUE (arg0_type); + + if (TYPE_PRECISION (exp_type) == TYPE_PRECISION (arg0_type)) + high_positive = fold_build2 (RSHIFT_EXPR, arg0_type, + fold_convert (arg0_type, + high_positive), + fold_convert (arg0_type, + integer_one_node)); + + /* If the low bound is specified, "and" the range with the + range for which the original unsigned value will be + positive. */ + if (low != 0) + { + if (! merge_ranges (&n_in_p, &n_low, &n_high, + 1, n_low, n_high, 1, + fold_convert (arg0_type, + integer_zero_node), + high_positive)) + break; + + in_p = (n_in_p == in_p); + } + else + { + /* Otherwise, "or" the range with the range of the input + that will be interpreted as negative. */ + if (! merge_ranges (&n_in_p, &n_low, &n_high, + 0, n_low, n_high, 1, + fold_convert (arg0_type, + integer_zero_node), + high_positive)) + break; + + in_p = (in_p != n_in_p); + } + } + + exp = arg0; + low = n_low, high = n_high; + continue; + + default: + break; + } + + break; + } + + /* If EXP is a constant, we can evaluate whether this is true or false. */ + if (TREE_CODE (exp) == INTEGER_CST) + { + in_p = in_p == (integer_onep (range_binop (GE_EXPR, integer_type_node, + exp, 0, low, 0)) + && integer_onep (range_binop (LE_EXPR, integer_type_node, + exp, 1, high, 1))); + low = high = 0; + exp = 0; + } + + *pin_p = in_p, *plow = low, *phigh = high; + return exp; +} + +/* Given a range, LOW, HIGH, and IN_P, an expression, EXP, and a result + type, TYPE, return an expression to test if EXP is in (or out of, depending + on IN_P) the range. Return 0 if the test couldn't be created. */ + +static tree +build_range_check (tree type, tree exp, int in_p, tree low, tree high) +{ + tree etype = TREE_TYPE (exp); + tree value; + +#ifdef HAVE_canonicalize_funcptr_for_compare + /* Disable this optimization for function pointer expressions + on targets that require function pointer canonicalization. */ + if (HAVE_canonicalize_funcptr_for_compare + && TREE_CODE (etype) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (etype)) == FUNCTION_TYPE) + return NULL_TREE; +#endif + + if (! in_p) + { + value = build_range_check (type, exp, 1, low, high); + if (value != 0) + return invert_truthvalue (value); + + return 0; + } + + if (low == 0 && high == 0) + return build_int_cst (type, 1); + + if (low == 0) + return fold_build2 (LE_EXPR, type, exp, + fold_convert (etype, high)); + + if (high == 0) + return fold_build2 (GE_EXPR, type, exp, + fold_convert (etype, low)); + + if (operand_equal_p (low, high, 0)) + return fold_build2 (EQ_EXPR, type, exp, + fold_convert (etype, low)); + + if (integer_zerop (low)) + { + if (! TYPE_UNSIGNED (etype)) + { + etype = lang_hooks.types.unsigned_type (etype); + high = fold_convert (etype, high); + exp = fold_convert (etype, exp); + } + return build_range_check (type, exp, 1, 0, high); + } + + /* Optimize (c>=1) && (c<=127) into (signed char)c > 0. */ + if (integer_onep (low) && TREE_CODE (high) == INTEGER_CST) + { + unsigned HOST_WIDE_INT lo; + HOST_WIDE_INT hi; + int prec; + + prec = TYPE_PRECISION (etype); + if (prec <= HOST_BITS_PER_WIDE_INT) + { + hi = 0; + lo = ((unsigned HOST_WIDE_INT) 1 << (prec - 1)) - 1; + } + else + { + hi = ((HOST_WIDE_INT) 1 << (prec - HOST_BITS_PER_WIDE_INT - 1)) - 1; + lo = (unsigned HOST_WIDE_INT) -1; + } + + if (TREE_INT_CST_HIGH (high) == hi && TREE_INT_CST_LOW (high) == lo) + { + if (TYPE_UNSIGNED (etype)) + { + etype = lang_hooks.types.signed_type (etype); + exp = fold_convert (etype, exp); + } + return fold_build2 (GT_EXPR, type, exp, + build_int_cst (etype, 0)); + } + } + + /* Optimize (c>=low) && (c<=high) into (c-low>=0) && (c-low<=high-low). + This requires wrap-around arithmetics for the type of the expression. */ + switch (TREE_CODE (etype)) + { + case INTEGER_TYPE: + /* There is no requirement that LOW be within the range of ETYPE + if the latter is a subtype. It must, however, be within the base + type of ETYPE. So be sure we do the subtraction in that type. */ + if (TREE_TYPE (etype)) + etype = TREE_TYPE (etype); + break; + + case ENUMERAL_TYPE: + case BOOLEAN_TYPE: + etype = lang_hooks.types.type_for_size (TYPE_PRECISION (etype), + TYPE_UNSIGNED (etype)); + break; + + default: + break; + } + + /* If we don't have wrap-around arithmetics upfront, try to force it. */ + if (TREE_CODE (etype) == INTEGER_TYPE + && !TYPE_OVERFLOW_WRAPS (etype)) + { + tree utype, minv, maxv; + + /* Check if (unsigned) INT_MAX + 1 == (unsigned) INT_MIN + for the type in question, as we rely on this here. */ + utype = lang_hooks.types.unsigned_type (etype); + maxv = fold_convert (utype, TYPE_MAX_VALUE (etype)); + maxv = range_binop (PLUS_EXPR, NULL_TREE, maxv, 1, + integer_one_node, 1); + minv = fold_convert (utype, TYPE_MIN_VALUE (etype)); + + if (integer_zerop (range_binop (NE_EXPR, integer_type_node, + minv, 1, maxv, 1))) + etype = utype; + else + return 0; + } + + high = fold_convert (etype, high); + low = fold_convert (etype, low); + exp = fold_convert (etype, exp); + + value = const_binop (MINUS_EXPR, high, low, 0); + + if (value != 0 && !TREE_OVERFLOW (value)) + return build_range_check (type, + fold_build2 (MINUS_EXPR, etype, exp, low), + 1, build_int_cst (etype, 0), value); + + return 0; +} + +/* Return the predecessor of VAL in its type, handling the infinite case. */ + +static tree +range_predecessor (tree val) +{ + tree type = TREE_TYPE (val); + + if (INTEGRAL_TYPE_P (type) + && operand_equal_p (val, TYPE_MIN_VALUE (type), 0)) + return 0; + else + return range_binop (MINUS_EXPR, NULL_TREE, val, 0, integer_one_node, 0); +} + +/* Return the successor of VAL in its type, handling the infinite case. */ + +static tree +range_successor (tree val) +{ + tree type = TREE_TYPE (val); + + if (INTEGRAL_TYPE_P (type) + && operand_equal_p (val, TYPE_MAX_VALUE (type), 0)) + return 0; + else + return range_binop (PLUS_EXPR, NULL_TREE, val, 0, integer_one_node, 0); +} + +/* Given two ranges, see if we can merge them into one. Return 1 if we + can, 0 if we can't. Set the output range into the specified parameters. */ + +static int +merge_ranges (int *pin_p, tree *plow, tree *phigh, int in0_p, tree low0, + tree high0, int in1_p, tree low1, tree high1) +{ + int no_overlap; + int subset; + int temp; + tree tem; + int in_p; + tree low, high; + int lowequal = ((low0 == 0 && low1 == 0) + || integer_onep (range_binop (EQ_EXPR, integer_type_node, + low0, 0, low1, 0))); + int highequal = ((high0 == 0 && high1 == 0) + || integer_onep (range_binop (EQ_EXPR, integer_type_node, + high0, 1, high1, 1))); + + /* Make range 0 be the range that starts first, or ends last if they + start at the same value. Swap them if it isn't. */ + if (integer_onep (range_binop (GT_EXPR, integer_type_node, + low0, 0, low1, 0)) + || (lowequal + && integer_onep (range_binop (GT_EXPR, integer_type_node, + high1, 1, high0, 1)))) + { + temp = in0_p, in0_p = in1_p, in1_p = temp; + tem = low0, low0 = low1, low1 = tem; + tem = high0, high0 = high1, high1 = tem; + } + + /* Now flag two cases, whether the ranges are disjoint or whether the + second range is totally subsumed in the first. Note that the tests + below are simplified by the ones above. */ + no_overlap = integer_onep (range_binop (LT_EXPR, integer_type_node, + high0, 1, low1, 0)); + subset = integer_onep (range_binop (LE_EXPR, integer_type_node, + high1, 1, high0, 1)); + + /* We now have four cases, depending on whether we are including or + excluding the two ranges. */ + if (in0_p && in1_p) + { + /* If they don't overlap, the result is false. If the second range + is a subset it is the result. Otherwise, the range is from the start + of the second to the end of the first. */ + if (no_overlap) + in_p = 0, low = high = 0; + else if (subset) + in_p = 1, low = low1, high = high1; + else + in_p = 1, low = low1, high = high0; + } + + else if (in0_p && ! in1_p) + { + /* If they don't overlap, the result is the first range. If they are + equal, the result is false. If the second range is a subset of the + first, and the ranges begin at the same place, we go from just after + the end of the second range to the end of the first. If the second + range is not a subset of the first, or if it is a subset and both + ranges end at the same place, the range starts at the start of the + first range and ends just before the second range. + Otherwise, we can't describe this as a single range. */ + if (no_overlap) + in_p = 1, low = low0, high = high0; + else if (lowequal && highequal) + in_p = 0, low = high = 0; + else if (subset && lowequal) + { + low = range_successor (high1); + high = high0; + in_p = 1; + if (low == 0) + { + /* We are in the weird situation where high0 > high1 but + high1 has no successor. Punt. */ + return 0; + } + } + else if (! subset || highequal) + { + low = low0; + high = range_predecessor (low1); + in_p = 1; + if (high == 0) + { + /* low0 < low1 but low1 has no predecessor. Punt. */ + return 0; + } + } + else + return 0; + } + + else if (! in0_p && in1_p) + { + /* If they don't overlap, the result is the second range. If the second + is a subset of the first, the result is false. Otherwise, + the range starts just after the first range and ends at the + end of the second. */ + if (no_overlap) + in_p = 1, low = low1, high = high1; + else if (subset || highequal) + in_p = 0, low = high = 0; + else + { + low = range_successor (high0); + high = high1; + in_p = 1; + if (low == 0) + { + /* high1 > high0 but high0 has no successor. Punt. */ + return 0; + } + } + } + + else + { + /* The case where we are excluding both ranges. Here the complex case + is if they don't overlap. In that case, the only time we have a + range is if they are adjacent. If the second is a subset of the + first, the result is the first. Otherwise, the range to exclude + starts at the beginning of the first range and ends at the end of the + second. */ + if (no_overlap) + { + if (integer_onep (range_binop (EQ_EXPR, integer_type_node, + range_successor (high0), + 1, low1, 0))) + in_p = 0, low = low0, high = high1; + else + { + /* Canonicalize - [min, x] into - [-, x]. */ + if (low0 && TREE_CODE (low0) == INTEGER_CST) + switch (TREE_CODE (TREE_TYPE (low0))) + { + case ENUMERAL_TYPE: + if (TYPE_PRECISION (TREE_TYPE (low0)) + != GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (low0)))) + break; + /* FALLTHROUGH */ + case INTEGER_TYPE: + if (tree_int_cst_equal (low0, + TYPE_MIN_VALUE (TREE_TYPE (low0)))) + low0 = 0; + break; + case POINTER_TYPE: + if (TYPE_UNSIGNED (TREE_TYPE (low0)) + && integer_zerop (low0)) + low0 = 0; + break; + default: + break; + } + + /* Canonicalize - [x, max] into - [x, -]. */ + if (high1 && TREE_CODE (high1) == INTEGER_CST) + switch (TREE_CODE (TREE_TYPE (high1))) + { + case ENUMERAL_TYPE: + if (TYPE_PRECISION (TREE_TYPE (high1)) + != GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (high1)))) + break; + /* FALLTHROUGH */ + case INTEGER_TYPE: + if (tree_int_cst_equal (high1, + TYPE_MAX_VALUE (TREE_TYPE (high1)))) + high1 = 0; + break; + case POINTER_TYPE: + if (TYPE_UNSIGNED (TREE_TYPE (high1)) + && integer_zerop (range_binop (PLUS_EXPR, NULL_TREE, + high1, 1, + integer_one_node, 1))) + high1 = 0; + break; + default: + break; + } + + /* The ranges might be also adjacent between the maximum and + minimum values of the given type. For + - [{min,-}, x] and - [y, {max,-}] ranges where x + 1 < y + return + [x + 1, y - 1]. */ + if (low0 == 0 && high1 == 0) + { + low = range_successor (high0); + high = range_predecessor (low1); + if (low == 0 || high == 0) + return 0; + + in_p = 1; + } + else + return 0; + } + } + else if (subset) + in_p = 0, low = low0, high = high0; + else + in_p = 0, low = low0, high = high1; + } + + *pin_p = in_p, *plow = low, *phigh = high; + return 1; +} + + +/* Subroutine of fold, looking inside expressions of the form + A op B ? A : C, where ARG0, ARG1 and ARG2 are the three operands + of the COND_EXPR. This function is being used also to optimize + A op B ? C : A, by reversing the comparison first. + + Return a folded expression whose code is not a COND_EXPR + anymore, or NULL_TREE if no folding opportunity is found. */ + +static tree +fold_cond_expr_with_comparison (tree type, tree arg0, tree arg1, tree arg2) +{ + enum tree_code comp_code = TREE_CODE (arg0); + tree arg00 = TREE_OPERAND (arg0, 0); + tree arg01 = TREE_OPERAND (arg0, 1); + tree arg1_type = TREE_TYPE (arg1); + tree tem; + + STRIP_NOPS (arg1); + STRIP_NOPS (arg2); + + /* If we have A op 0 ? A : -A, consider applying the following + transformations: + + A == 0? A : -A same as -A + A != 0? A : -A same as A + A >= 0? A : -A same as abs (A) + A > 0? A : -A same as abs (A) + A <= 0? A : -A same as -abs (A) + A < 0? A : -A same as -abs (A) + + None of these transformations work for modes with signed + zeros. If A is +/-0, the first two transformations will + change the sign of the result (from +0 to -0, or vice + versa). The last four will fix the sign of the result, + even though the original expressions could be positive or + negative, depending on the sign of A. + + Note that all these transformations are correct if A is + NaN, since the two alternatives (A and -A) are also NaNs. */ + if ((FLOAT_TYPE_P (TREE_TYPE (arg01)) + ? real_zerop (arg01) + : integer_zerop (arg01)) + && ((TREE_CODE (arg2) == NEGATE_EXPR + && operand_equal_p (TREE_OPERAND (arg2, 0), arg1, 0)) + /* In the case that A is of the form X-Y, '-A' (arg2) may + have already been folded to Y-X, check for that. */ + || (TREE_CODE (arg1) == MINUS_EXPR + && TREE_CODE (arg2) == MINUS_EXPR + && operand_equal_p (TREE_OPERAND (arg1, 0), + TREE_OPERAND (arg2, 1), 0) + && operand_equal_p (TREE_OPERAND (arg1, 1), + TREE_OPERAND (arg2, 0), 0)))) + switch (comp_code) + { + case EQ_EXPR: + case UNEQ_EXPR: + tem = fold_convert (arg1_type, arg1); + return pedantic_non_lvalue (fold_convert (type, negate_expr (tem))); + case NE_EXPR: + case LTGT_EXPR: + return pedantic_non_lvalue (fold_convert (type, arg1)); + case UNGE_EXPR: + case UNGT_EXPR: + if (flag_trapping_math) + break; + /* Fall through. */ + case GE_EXPR: + case GT_EXPR: + if (TYPE_UNSIGNED (TREE_TYPE (arg1))) + arg1 = fold_convert (lang_hooks.types.signed_type + (TREE_TYPE (arg1)), arg1); + tem = fold_build1 (ABS_EXPR, TREE_TYPE (arg1), arg1); + return pedantic_non_lvalue (fold_convert (type, tem)); + case UNLE_EXPR: + case UNLT_EXPR: + if (flag_trapping_math) + break; + case LE_EXPR: + case LT_EXPR: + if (TYPE_UNSIGNED (TREE_TYPE (arg1))) + arg1 = fold_convert (lang_hooks.types.signed_type + (TREE_TYPE (arg1)), arg1); + tem = fold_build1 (ABS_EXPR, TREE_TYPE (arg1), arg1); + return negate_expr (fold_convert (type, tem)); + default: + gcc_assert (TREE_CODE_CLASS (comp_code) == tcc_comparison); + break; + } + + /* A != 0 ? A : 0 is simply A, unless A is -0. Likewise + A == 0 ? A : 0 is always 0 unless A is -0. Note that + both transformations are correct when A is NaN: A != 0 + is then true, and A == 0 is false. */ + + if (integer_zerop (arg01) && integer_zerop (arg2)) + { + if (comp_code == NE_EXPR) + return pedantic_non_lvalue (fold_convert (type, arg1)); + else if (comp_code == EQ_EXPR) + return build_int_cst (type, 0); + } + + /* Try some transformations of A op B ? A : B. + + A == B? A : B same as B + A != B? A : B same as A + A >= B? A : B same as max (A, B) + A > B? A : B same as max (B, A) + A <= B? A : B same as min (A, B) + A < B? A : B same as min (B, A) + + As above, these transformations don't work in the presence + of signed zeros. For example, if A and B are zeros of + opposite sign, the first two transformations will change + the sign of the result. In the last four, the original + expressions give different results for (A=+0, B=-0) and + (A=-0, B=+0), but the transformed expressions do not. + + The first two transformations are correct if either A or B + is a NaN. In the first transformation, the condition will + be false, and B will indeed be chosen. In the case of the + second transformation, the condition A != B will be true, + and A will be chosen. + + The conversions to max() and min() are not correct if B is + a number and A is not. The conditions in the original + expressions will be false, so all four give B. The min() + and max() versions would give a NaN instead. */ + if (operand_equal_for_comparison_p (arg01, arg2, arg00) + /* Avoid these transformations if the COND_EXPR may be used + as an lvalue in the C++ front-end. PR c++/19199. */ + && (in_gimple_form + || (strcmp (lang_hooks.name, "GNU C++") != 0 + && strcmp (lang_hooks.name, "GNU Objective-C++") != 0) + || ! maybe_lvalue_p (arg1) + || ! maybe_lvalue_p (arg2))) + { + tree comp_op0 = arg00; + tree comp_op1 = arg01; + tree comp_type = TREE_TYPE (comp_op0); + + /* Avoid adding NOP_EXPRs in case this is an lvalue. */ + if (TYPE_MAIN_VARIANT (comp_type) == TYPE_MAIN_VARIANT (type)) + { + comp_type = type; + comp_op0 = arg1; + comp_op1 = arg2; + } + + switch (comp_code) + { + case EQ_EXPR: + return pedantic_non_lvalue (fold_convert (type, arg2)); + case NE_EXPR: + return pedantic_non_lvalue (fold_convert (type, arg1)); + case LE_EXPR: + case LT_EXPR: + case UNLE_EXPR: + case UNLT_EXPR: + /* In C++ a ?: expression can be an lvalue, so put the + operand which will be used if they are equal first + so that we can convert this back to the + corresponding COND_EXPR. */ + if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg1)))) + { + comp_op0 = fold_convert (comp_type, comp_op0); + comp_op1 = fold_convert (comp_type, comp_op1); + tem = (comp_code == LE_EXPR || comp_code == UNLE_EXPR) + ? fold_build2 (MIN_EXPR, comp_type, comp_op0, comp_op1) + : fold_build2 (MIN_EXPR, comp_type, comp_op1, comp_op0); + return pedantic_non_lvalue (fold_convert (type, tem)); + } + break; + case GE_EXPR: + case GT_EXPR: + case UNGE_EXPR: + case UNGT_EXPR: + if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg1)))) + { + comp_op0 = fold_convert (comp_type, comp_op0); + comp_op1 = fold_convert (comp_type, comp_op1); + tem = (comp_code == GE_EXPR || comp_code == UNGE_EXPR) + ? fold_build2 (MAX_EXPR, comp_type, comp_op0, comp_op1) + : fold_build2 (MAX_EXPR, comp_type, comp_op1, comp_op0); + return pedantic_non_lvalue (fold_convert (type, tem)); + } + break; + case UNEQ_EXPR: + if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg1)))) + return pedantic_non_lvalue (fold_convert (type, arg2)); + break; + case LTGT_EXPR: + if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg1)))) + return pedantic_non_lvalue (fold_convert (type, arg1)); + break; + default: + gcc_assert (TREE_CODE_CLASS (comp_code) == tcc_comparison); + break; + } + } + + /* If this is A op C1 ? A : C2 with C1 and C2 constant integers, + we might still be able to simplify this. For example, + if C1 is one less or one more than C2, this might have started + out as a MIN or MAX and been transformed by this function. + Only good for INTEGER_TYPEs, because we need TYPE_MAX_VALUE. */ + + if (INTEGRAL_TYPE_P (type) + && TREE_CODE (arg01) == INTEGER_CST + && TREE_CODE (arg2) == INTEGER_CST) + switch (comp_code) + { + case EQ_EXPR: + /* We can replace A with C1 in this case. */ + arg1 = fold_convert (type, arg01); + return fold_build3 (COND_EXPR, type, arg0, arg1, arg2); + + case LT_EXPR: + /* If C1 is C2 + 1, this is min(A, C2). */ + if (! operand_equal_p (arg2, TYPE_MAX_VALUE (type), + OEP_ONLY_CONST) + && operand_equal_p (arg01, + const_binop (PLUS_EXPR, arg2, + integer_one_node, 0), + OEP_ONLY_CONST)) + return pedantic_non_lvalue (fold_build2 (MIN_EXPR, + type, arg1, arg2)); + break; + + case LE_EXPR: + /* If C1 is C2 - 1, this is min(A, C2). */ + if (! operand_equal_p (arg2, TYPE_MIN_VALUE (type), + OEP_ONLY_CONST) + && operand_equal_p (arg01, + const_binop (MINUS_EXPR, arg2, + integer_one_node, 0), + OEP_ONLY_CONST)) + return pedantic_non_lvalue (fold_build2 (MIN_EXPR, + type, arg1, arg2)); + break; + + case GT_EXPR: + /* If C1 is C2 - 1, this is max(A, C2). */ + if (! operand_equal_p (arg2, TYPE_MIN_VALUE (type), + OEP_ONLY_CONST) + && operand_equal_p (arg01, + const_binop (MINUS_EXPR, arg2, + integer_one_node, 0), + OEP_ONLY_CONST)) + return pedantic_non_lvalue (fold_build2 (MAX_EXPR, + type, arg1, arg2)); + break; + + case GE_EXPR: + /* If C1 is C2 + 1, this is max(A, C2). */ + if (! operand_equal_p (arg2, TYPE_MAX_VALUE (type), + OEP_ONLY_CONST) + && operand_equal_p (arg01, + const_binop (PLUS_EXPR, arg2, + integer_one_node, 0), + OEP_ONLY_CONST)) + return pedantic_non_lvalue (fold_build2 (MAX_EXPR, + type, arg1, arg2)); + break; + case NE_EXPR: + break; + default: + gcc_unreachable (); + } + + return NULL_TREE; +} + + + +#ifndef LOGICAL_OP_NON_SHORT_CIRCUIT +#define LOGICAL_OP_NON_SHORT_CIRCUIT (BRANCH_COST >= 2) +#endif + +/* EXP is some logical combination of boolean tests. See if we can + merge it into some range test. Return the new tree if so. */ + +static tree +fold_range_test (enum tree_code code, tree type, tree op0, tree op1) +{ + int or_op = (code == TRUTH_ORIF_EXPR + || code == TRUTH_OR_EXPR); + int in0_p, in1_p, in_p; + tree low0, low1, low, high0, high1, high; + bool strict_overflow_p = false; + tree lhs = make_range (op0, &in0_p, &low0, &high0, &strict_overflow_p); + tree rhs = make_range (op1, &in1_p, &low1, &high1, &strict_overflow_p); + tree tem; + const char * const warnmsg = G_("assuming signed overflow does not occur " + "when simplifying range test"); + + /* If this is an OR operation, invert both sides; we will invert + again at the end. */ + if (or_op) + in0_p = ! in0_p, in1_p = ! in1_p; + + /* If both expressions are the same, if we can merge the ranges, and we + can build the range test, return it or it inverted. If one of the + ranges is always true or always false, consider it to be the same + expression as the other. */ + if ((lhs == 0 || rhs == 0 || operand_equal_p (lhs, rhs, 0)) + && merge_ranges (&in_p, &low, &high, in0_p, low0, high0, + in1_p, low1, high1) + && 0 != (tem = (build_range_check (type, + lhs != 0 ? lhs + : rhs != 0 ? rhs : integer_zero_node, + in_p, low, high)))) + { + if (strict_overflow_p) + fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_COMPARISON); + return or_op ? invert_truthvalue (tem) : tem; + } + + /* On machines where the branch cost is expensive, if this is a + short-circuited branch and the underlying object on both sides + is the same, make a non-short-circuit operation. */ + else if (LOGICAL_OP_NON_SHORT_CIRCUIT + && lhs != 0 && rhs != 0 + && (code == TRUTH_ANDIF_EXPR + || code == TRUTH_ORIF_EXPR) + && operand_equal_p (lhs, rhs, 0)) + { + /* If simple enough, just rewrite. Otherwise, make a SAVE_EXPR + 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 build2 (code == TRUTH_ANDIF_EXPR + ? TRUTH_AND_EXPR : TRUTH_OR_EXPR, + type, op0, op1); + + else if (lang_hooks.decls.global_bindings_p () == 0 + && ! CONTAINS_PLACEHOLDER_P (lhs)) + { + tree common = save_expr (lhs); + + if (0 != (lhs = build_range_check (type, common, + or_op ? ! in0_p : in0_p, + low0, high0)) + && (0 != (rhs = build_range_check (type, common, + or_op ? ! in1_p : in1_p, + low1, high1)))) + { + if (strict_overflow_p) + fold_overflow_warning (warnmsg, + WARN_STRICT_OVERFLOW_COMPARISON); + return build2 (code == TRUTH_ANDIF_EXPR + ? TRUTH_AND_EXPR : TRUTH_OR_EXPR, + type, lhs, rhs); + } + } + } + + return 0; +} + +/* Subroutine for fold_truthop: C is an INTEGER_CST interpreted as a P + bit value. Arrange things so the extra bits will be set to zero if and + only if C is signed-extended to its full width. If MASK is nonzero, + it is an INTEGER_CST that should be AND'ed with the extra bits. */ + +static tree +unextend (tree c, int p, int unsignedp, tree mask) +{ + tree type = TREE_TYPE (c); + int modesize = GET_MODE_BITSIZE (TYPE_MODE (type)); + tree temp; + + if (p == modesize || unsignedp) + return c; + + /* We work by getting just the sign bit into the low-order bit, then + into the high-order bit, then sign-extend. We then XOR that value + with C. */ + temp = const_binop (RSHIFT_EXPR, c, size_int (p - 1), 0); + temp = const_binop (BIT_AND_EXPR, temp, size_int (1), 0); + + /* We must use a signed type in order to get an arithmetic right shift. + However, we must also avoid introducing accidental overflows, so that + a subsequent call to integer_zerop will work. Hence we must + do the type conversion here. At this point, the constant is either + zero or one, and the conversion to a signed type can never overflow. + We could get an overflow if this conversion is done anywhere else. */ + if (TYPE_UNSIGNED (type)) + temp = fold_convert (lang_hooks.types.signed_type (type), temp); + + temp = const_binop (LSHIFT_EXPR, temp, size_int (modesize - 1), 0); + temp = const_binop (RSHIFT_EXPR, temp, size_int (modesize - p - 1), 0); + if (mask != 0) + temp = const_binop (BIT_AND_EXPR, temp, + fold_convert (TREE_TYPE (c), mask), 0); + /* If necessary, convert the type back to match the type of C. */ + if (TYPE_UNSIGNED (type)) + temp = fold_convert (type, temp); + + return fold_convert (type, const_binop (BIT_XOR_EXPR, c, temp, 0)); +} + +/* Find ways of folding logical expressions of LHS and RHS: + Try to merge two comparisons to the same innermost item. + Look for range tests like "ch >= '0' && ch <= '9'". + Look for combinations of simple terms on machines with expensive branches + and evaluate the RHS unconditionally. + + For example, if we have p->a == 2 && p->b == 4 and we can make an + object large enough to span both A and B, we can do this with a comparison + against the object ANDed with the a mask. + + If we have p->a == q->a && p->b == q->b, we may be able to use bit masking + operations to do this with one comparison. + + We check for both normal comparisons and the BIT_AND_EXPRs made this by + function and the one above. + + CODE is the logical operation being done. It can be TRUTH_ANDIF_EXPR, + TRUTH_AND_EXPR, TRUTH_ORIF_EXPR, or TRUTH_OR_EXPR. + + TRUTH_TYPE is the type of the logical operand and LHS and RHS are its + two operands. + + We return the simplified tree or 0 if no optimization is possible. */ + +static tree +fold_truthop (enum tree_code code, tree truth_type, tree lhs, tree rhs) +{ + /* If this is the "or" of two comparisons, we can do something if + the comparisons are NE_EXPR. If this is the "and", we can do something + if the comparisons are EQ_EXPR. I.e., + (a->b == 2 && a->c == 4) can become (a->new == NEW). + + WANTED_CODE is this operation code. For single bit fields, we can + convert EQ_EXPR to NE_EXPR so we need not reject the "wrong" + comparison for one-bit fields. */ + + enum tree_code wanted_code; + enum tree_code lcode, rcode; + tree ll_arg, lr_arg, rl_arg, rr_arg; + tree ll_inner, lr_inner, rl_inner, rr_inner; + HOST_WIDE_INT ll_bitsize, ll_bitpos, lr_bitsize, lr_bitpos; + HOST_WIDE_INT rl_bitsize, rl_bitpos, rr_bitsize, rr_bitpos; + HOST_WIDE_INT xll_bitpos, xlr_bitpos, xrl_bitpos, xrr_bitpos; + HOST_WIDE_INT lnbitsize, lnbitpos, rnbitsize, rnbitpos; + int ll_unsignedp, lr_unsignedp, rl_unsignedp, rr_unsignedp; + enum machine_mode ll_mode, lr_mode, rl_mode, rr_mode; + enum machine_mode lnmode, rnmode; + 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 lntype, rntype, result; + int first_bit, end_bit; + int volatilep; + tree orig_lhs = lhs, orig_rhs = rhs; + enum tree_code orig_code = code; + + /* Start by getting the comparison codes. Fail if anything is volatile. + If one operand is a BIT_AND_EXPR with the constant one, treat it as if + it were surrounded with a NE_EXPR. */ + + if (TREE_SIDE_EFFECTS (lhs) || TREE_SIDE_EFFECTS (rhs)) + return 0; + + lcode = TREE_CODE (lhs); + rcode = TREE_CODE (rhs); + + if (lcode == BIT_AND_EXPR && integer_onep (TREE_OPERAND (lhs, 1))) + { + lhs = build2 (NE_EXPR, truth_type, lhs, + build_int_cst (TREE_TYPE (lhs), 0)); + lcode = NE_EXPR; + } + + if (rcode == BIT_AND_EXPR && integer_onep (TREE_OPERAND (rhs, 1))) + { + rhs = build2 (NE_EXPR, truth_type, rhs, + build_int_cst (TREE_TYPE (rhs), 0)); + rcode = NE_EXPR; + } + + if (TREE_CODE_CLASS (lcode) != tcc_comparison + || TREE_CODE_CLASS (rcode) != tcc_comparison) + return 0; + + ll_arg = TREE_OPERAND (lhs, 0); + lr_arg = TREE_OPERAND (lhs, 1); + rl_arg = TREE_OPERAND (rhs, 0); + rr_arg = TREE_OPERAND (rhs, 1); + + /* Simplify (x<y) && (x==y) into (x<=y) and related optimizations. */ + if (simple_operand_p (ll_arg) + && simple_operand_p (lr_arg)) + { + tree result; + if (operand_equal_p (ll_arg, rl_arg, 0) + && operand_equal_p (lr_arg, rr_arg, 0)) + { + result = combine_comparisons (code, lcode, rcode, + truth_type, ll_arg, lr_arg); + if (result) + return result; + } + else if (operand_equal_p (ll_arg, rr_arg, 0) + && operand_equal_p (lr_arg, rl_arg, 0)) + { + result = combine_comparisons (code, lcode, + swap_tree_comparison (rcode), + truth_type, ll_arg, lr_arg); + if (result) + return result; + } + } + + code = ((code == TRUTH_AND_EXPR || code == TRUTH_ANDIF_EXPR) + ? TRUTH_AND_EXPR : TRUTH_OR_EXPR); + + /* If the RHS can be evaluated unconditionally and its operands are + simple, it wins to evaluate the RHS unconditionally on machines + with expensive branches. In this case, this isn't a comparison + that can be merged. Avoid doing this if the RHS is a floating-point + comparison since those can trap. */ + + if (BRANCH_COST >= 2 + && ! FLOAT_TYPE_P (TREE_TYPE (rl_arg)) + && simple_operand_p (rl_arg) + && simple_operand_p (rr_arg)) + { + /* Convert (a != 0) || (b != 0) into (a | b) != 0. */ + if (code == TRUTH_OR_EXPR + && lcode == NE_EXPR && integer_zerop (lr_arg) + && rcode == NE_EXPR && integer_zerop (rr_arg) + && TREE_TYPE (ll_arg) == TREE_TYPE (rl_arg)) + return build2 (NE_EXPR, truth_type, + build2 (BIT_IOR_EXPR, TREE_TYPE (ll_arg), + ll_arg, rl_arg), + build_int_cst (TREE_TYPE (ll_arg), 0)); + + /* Convert (a == 0) && (b == 0) into (a | b) == 0. */ + if (code == TRUTH_AND_EXPR + && lcode == EQ_EXPR && integer_zerop (lr_arg) + && rcode == EQ_EXPR && integer_zerop (rr_arg) + && TREE_TYPE (ll_arg) == TREE_TYPE (rl_arg)) + return build2 (EQ_EXPR, truth_type, + build2 (BIT_IOR_EXPR, TREE_TYPE (ll_arg), + ll_arg, rl_arg), + build_int_cst (TREE_TYPE (ll_arg), 0)); + + if (LOGICAL_OP_NON_SHORT_CIRCUIT) + { + if (code != orig_code || lhs != orig_lhs || rhs != orig_rhs) + return build2 (code, truth_type, lhs, rhs); + return NULL_TREE; + } + } + + /* See if the comparisons can be merged. Then get all the parameters for + each side. */ + + if ((lcode != EQ_EXPR && lcode != NE_EXPR) + || (rcode != EQ_EXPR && rcode != NE_EXPR)) + return 0; + + volatilep = 0; + ll_inner = decode_field_reference (ll_arg, + &ll_bitsize, &ll_bitpos, &ll_mode, + &ll_unsignedp, &volatilep, &ll_mask, + &ll_and_mask); + lr_inner = decode_field_reference (lr_arg, + &lr_bitsize, &lr_bitpos, &lr_mode, + &lr_unsignedp, &volatilep, &lr_mask, + &lr_and_mask); + rl_inner = decode_field_reference (rl_arg, + &rl_bitsize, &rl_bitpos, &rl_mode, + &rl_unsignedp, &volatilep, &rl_mask, + &rl_and_mask); + rr_inner = decode_field_reference (rr_arg, + &rr_bitsize, &rr_bitpos, &rr_mode, + &rr_unsignedp, &volatilep, &rr_mask, + &rr_and_mask); + + /* It must be true that the inner operation on the lhs of each + comparison must be the same if we are to be able to do anything. + Then see if we have constants. If not, the same must be true for + the rhs's. */ + if (volatilep || ll_inner == 0 || rl_inner == 0 + || ! operand_equal_p (ll_inner, rl_inner, 0)) + return 0; + + if (TREE_CODE (lr_arg) == INTEGER_CST + && TREE_CODE (rr_arg) == INTEGER_CST) + l_const = lr_arg, r_const = rr_arg; + else if (lr_inner == 0 || rr_inner == 0 + || ! operand_equal_p (lr_inner, rr_inner, 0)) + return 0; + else + l_const = r_const = 0; + + /* If either comparison code is not correct for our logical operation, + fail. However, we can convert a one-bit comparison against zero into + the opposite comparison against that bit being set in the field. */ + + wanted_code = (code == TRUTH_AND_EXPR ? EQ_EXPR : NE_EXPR); + if (lcode != wanted_code) + { + if (l_const && integer_zerop (l_const) && integer_pow2p (ll_mask)) + { + /* Make the left operand unsigned, since we are only interested + in the value of one bit. Otherwise we are doing the wrong + thing below. */ + ll_unsignedp = 1; + l_const = ll_mask; + } + else + return 0; + } + + /* This is analogous to the code for l_const above. */ + if (rcode != wanted_code) + { + if (r_const && integer_zerop (r_const) && integer_pow2p (rl_mask)) + { + rl_unsignedp = 1; + r_const = rl_mask; + } + else + return 0; + } + + /* After this point all optimizations will generate bit-field + references, which we might not want. */ + if (! lang_hooks.can_use_bit_fields_p ()) + return 0; + + /* See if we can find a mode that contains both fields being compared on + the left. If we can't, fail. Otherwise, update all constants and masks + to be relative to a field of that size. */ + first_bit = MIN (ll_bitpos, rl_bitpos); + end_bit = MAX (ll_bitpos + ll_bitsize, rl_bitpos + rl_bitsize); + lnmode = get_best_mode (end_bit - first_bit, first_bit, + TYPE_ALIGN (TREE_TYPE (ll_inner)), word_mode, + volatilep); + if (lnmode == VOIDmode) + return 0; + + lnbitsize = GET_MODE_BITSIZE (lnmode); + lnbitpos = first_bit & ~ (lnbitsize - 1); + lntype = lang_hooks.types.type_for_size (lnbitsize, 1); + xll_bitpos = ll_bitpos - lnbitpos, xrl_bitpos = rl_bitpos - lnbitpos; + + if (BYTES_BIG_ENDIAN) + { + xll_bitpos = lnbitsize - xll_bitpos - ll_bitsize; + xrl_bitpos = lnbitsize - xrl_bitpos - rl_bitsize; + } + + ll_mask = const_binop (LSHIFT_EXPR, fold_convert (lntype, ll_mask), + size_int (xll_bitpos), 0); + rl_mask = const_binop (LSHIFT_EXPR, fold_convert (lntype, rl_mask), + size_int (xrl_bitpos), 0); + + if (l_const) + { + l_const = fold_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, + lntype, ll_mask), + 0))) + { + warning (0, "comparison is always %d", wanted_code == NE_EXPR); + + return constant_boolean_node (wanted_code == NE_EXPR, truth_type); + } + } + if (r_const) + { + r_const = fold_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, + lntype, rl_mask), + 0))) + { + warning (0, "comparison is always %d", wanted_code == NE_EXPR); + + return constant_boolean_node (wanted_code == NE_EXPR, truth_type); + } + } + + /* If the right sides are not constant, do the same for it. Also, + disallow this optimization if a size or signedness mismatch occurs + between the left and right sides. */ + if (l_const == 0) + { + if (ll_bitsize != lr_bitsize || rl_bitsize != rr_bitsize + || ll_unsignedp != lr_unsignedp || rl_unsignedp != rr_unsignedp + /* Make sure the two fields on the right + correspond to the left without being swapped. */ + || ll_bitpos - rl_bitpos != lr_bitpos - rr_bitpos) + return 0; + + first_bit = MIN (lr_bitpos, rr_bitpos); + end_bit = MAX (lr_bitpos + lr_bitsize, rr_bitpos + rr_bitsize); + rnmode = get_best_mode (end_bit - first_bit, first_bit, + TYPE_ALIGN (TREE_TYPE (lr_inner)), word_mode, + volatilep); + if (rnmode == VOIDmode) + return 0; + + rnbitsize = GET_MODE_BITSIZE (rnmode); + rnbitpos = first_bit & ~ (rnbitsize - 1); + rntype = lang_hooks.types.type_for_size (rnbitsize, 1); + xlr_bitpos = lr_bitpos - rnbitpos, xrr_bitpos = rr_bitpos - rnbitpos; + + if (BYTES_BIG_ENDIAN) + { + xlr_bitpos = rnbitsize - xlr_bitpos - lr_bitsize; + xrr_bitpos = rnbitsize - xrr_bitpos - rr_bitsize; + } + + lr_mask = const_binop (LSHIFT_EXPR, fold_convert (rntype, lr_mask), + size_int (xlr_bitpos), 0); + rr_mask = const_binop (LSHIFT_EXPR, fold_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 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 (lnbitsize == rnbitsize && xll_bitpos == xlr_bitpos) + { + lhs = make_bit_field_ref (ll_inner, lntype, lnbitsize, lnbitpos, + ll_unsignedp || rl_unsignedp); + if (! all_ones_mask_p (ll_mask, lnbitsize)) + lhs = build2 (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 = build2 (BIT_AND_EXPR, rntype, rhs, lr_mask); + + return build2 (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. + + 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)) + { + 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 = fold_convert (rntype, lhs); + ll_mask = fold_convert (rntype, ll_mask); + type = rntype; + } + else if (lnbitsize < rnbitsize) + { + rhs = fold_convert (lntype, rhs); + lr_mask = fold_convert (lntype, lr_mask); + type = lntype; + } + } + + if (! all_ones_mask_p (ll_mask, ll_bitsize + rl_bitsize)) + lhs = build2 (BIT_AND_EXPR, type, lhs, ll_mask); + + if (! all_ones_mask_p (lr_mask, lr_bitsize + rr_bitsize)) + rhs = build2 (BIT_AND_EXPR, type, rhs, lr_mask); + + return build2 (wanted_code, truth_type, lhs, rhs); + } + + return 0; + } + + /* Handle the case of comparisons with constants. If there is something in + common between the masks, those bits of the constants must be the same. + If not, the condition is always false. Test for this to avoid generating + incorrect code below. */ + result = const_binop (BIT_AND_EXPR, ll_mask, rl_mask, 0); + if (! integer_zerop (result) + && simple_cst_equal (const_binop (BIT_AND_EXPR, result, l_const, 0), + const_binop (BIT_AND_EXPR, result, r_const, 0)) != 1) + { + if (wanted_code == NE_EXPR) + { + warning (0, "%<or%> of unmatched not-equal tests is always 1"); + return constant_boolean_node (true, truth_type); + } + else + { + warning (0, "%<and%> of mutually exclusive equal-tests is always 0"); + return constant_boolean_node (false, truth_type); + } + } + + /* Construct the expression we will return. First get the component + 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, 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 = build2 (BIT_AND_EXPR, lntype, result, ll_mask); + + return build2 (wanted_code, truth_type, result, + const_binop (BIT_IOR_EXPR, l_const, r_const, 0)); +} + +/* Optimize T, which is a comparison of a MIN_EXPR or MAX_EXPR with a + constant. */ + +static tree +optimize_minmax_comparison (enum tree_code code, tree type, tree op0, tree op1) +{ + tree arg0 = op0; + enum tree_code op_code; + tree comp_const = op1; + tree minmax_const; + int consts_equal, consts_lt; + tree inner; + + STRIP_SIGN_NOPS (arg0); + + op_code = TREE_CODE (arg0); + minmax_const = TREE_OPERAND (arg0, 1); + consts_equal = tree_int_cst_equal (minmax_const, comp_const); + consts_lt = tree_int_cst_lt (minmax_const, comp_const); + inner = TREE_OPERAND (arg0, 0); + + /* If something does not permit us to optimize, return the original tree. */ + if ((op_code != MIN_EXPR && op_code != MAX_EXPR) + || TREE_CODE (comp_const) != INTEGER_CST + || TREE_CONSTANT_OVERFLOW (comp_const) + || TREE_CODE (minmax_const) != INTEGER_CST + || TREE_CONSTANT_OVERFLOW (minmax_const)) + return NULL_TREE; + + /* Now handle all the various comparison codes. We only handle EQ_EXPR + and GT_EXPR, doing the rest with recursive calls using logical + simplifications. */ + switch (code) + { + case NE_EXPR: case LT_EXPR: case LE_EXPR: + { + tree tem = optimize_minmax_comparison (invert_tree_comparison (code, false), + type, op0, op1); + if (tem) + return invert_truthvalue (tem); + return NULL_TREE; + } + + case GE_EXPR: + return + fold_build2 (TRUTH_ORIF_EXPR, type, + optimize_minmax_comparison + (EQ_EXPR, type, arg0, comp_const), + optimize_minmax_comparison + (GT_EXPR, type, arg0, comp_const)); + + case EQ_EXPR: + if (op_code == MAX_EXPR && consts_equal) + /* MAX (X, 0) == 0 -> X <= 0 */ + return fold_build2 (LE_EXPR, type, inner, comp_const); + + else if (op_code == MAX_EXPR && consts_lt) + /* MAX (X, 0) == 5 -> X == 5 */ + return fold_build2 (EQ_EXPR, type, inner, comp_const); + + else if (op_code == MAX_EXPR) + /* MAX (X, 0) == -1 -> false */ + return omit_one_operand (type, integer_zero_node, inner); + + else if (consts_equal) + /* MIN (X, 0) == 0 -> X >= 0 */ + return fold_build2 (GE_EXPR, type, inner, comp_const); + + else if (consts_lt) + /* MIN (X, 0) == 5 -> false */ + return omit_one_operand (type, integer_zero_node, inner); + + else + /* MIN (X, 0) == -1 -> X == -1 */ + return fold_build2 (EQ_EXPR, type, inner, comp_const); + + case GT_EXPR: + if (op_code == MAX_EXPR && (consts_equal || consts_lt)) + /* MAX (X, 0) > 0 -> X > 0 + MAX (X, 0) > 5 -> X > 5 */ + return fold_build2 (GT_EXPR, type, inner, comp_const); + + else if (op_code == MAX_EXPR) + /* MAX (X, 0) > -1 -> true */ + return omit_one_operand (type, integer_one_node, inner); + + else if (op_code == MIN_EXPR && (consts_equal || consts_lt)) + /* MIN (X, 0) > 0 -> false + MIN (X, 0) > 5 -> false */ + return omit_one_operand (type, integer_zero_node, inner); + + else + /* MIN (X, 0) > -1 -> X > -1 */ + return fold_build2 (GT_EXPR, type, inner, comp_const); + + default: + return NULL_TREE; + } +} + +/* T is an integer expression that is being multiplied, divided, or taken a + modulus (CODE says which and what kind of divide or modulus) by a + constant C. See if we can eliminate that operation by folding it with + other operations already in T. WIDE_TYPE, if non-null, is a type that + should be used for the computation if wider than our type. + + For example, if we are dividing (X * 8) + (Y * 16) by 4, we can return + (X * 2) + (Y * 4). We must, however, be assured that either the original + expression would not overflow or that overflow is undefined for the type + in the language in question. + + We also canonicalize (X + 7) * 4 into X * 4 + 28 in the hope that either + the machine has a multiply-accumulate insn or that this is part of an + addressing calculation. + + If we return a non-null expression, it is an equivalent form of the + original computation, but need not be in the original type. + + We set *STRICT_OVERFLOW_P to true if the return values depends on + signed overflow being undefined. Otherwise we do not change + *STRICT_OVERFLOW_P. */ + +static tree +extract_muldiv (tree t, tree c, enum tree_code code, tree wide_type, + bool *strict_overflow_p) +{ + /* To avoid exponential search depth, refuse to allow recursion past + three levels. Beyond that (1) it's highly unlikely that we'll find + something interesting and (2) we've probably processed it before + when we built the inner expression. */ + + static int depth; + tree ret; + + if (depth > 3) + return NULL; + + depth++; + ret = extract_muldiv_1 (t, c, code, wide_type, strict_overflow_p); + depth--; + + return ret; +} + +static tree +extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type, + bool *strict_overflow_p) +{ + tree type = TREE_TYPE (t); + enum tree_code tcode = TREE_CODE (t); + tree ctype = (wide_type != 0 && (GET_MODE_SIZE (TYPE_MODE (wide_type)) + > GET_MODE_SIZE (TYPE_MODE (type))) + ? wide_type : type); + tree t1, t2; + int same_p = tcode == code; + tree op0 = NULL_TREE, op1 = NULL_TREE; + bool sub_strict_overflow_p; + + /* Don't deal with constants of zero here; they confuse the code below. */ + if (integer_zerop (c)) + return NULL_TREE; + + if (TREE_CODE_CLASS (tcode) == tcc_unary) + op0 = TREE_OPERAND (t, 0); + + if (TREE_CODE_CLASS (tcode) == tcc_binary) + op0 = TREE_OPERAND (t, 0), op1 = TREE_OPERAND (t, 1); + + /* Note that we need not handle conditional operations here since fold + already handles those cases. So just do arithmetic here. */ + switch (tcode) + { + case INTEGER_CST: + /* For a constant, we can always simplify if we are a multiply + or (for divide and modulus) if it is a multiple of our constant. */ + if (code == MULT_EXPR + || integer_zerop (const_binop (TRUNC_MOD_EXPR, t, c, 0))) + return const_binop (code, fold_convert (ctype, t), + fold_convert (ctype, c), 0); + break; + + case CONVERT_EXPR: case NON_LVALUE_EXPR: case NOP_EXPR: + /* If op0 is an expression ... */ + if ((COMPARISON_CLASS_P (op0) + || UNARY_CLASS_P (op0) + || BINARY_CLASS_P (op0) + || EXPRESSION_CLASS_P (op0)) + /* ... and is unsigned, and its type is smaller than ctype, + then we cannot pass through as widening. */ + && ((TYPE_UNSIGNED (TREE_TYPE (op0)) + && ! (TREE_CODE (TREE_TYPE (op0)) == INTEGER_TYPE + && TYPE_IS_SIZETYPE (TREE_TYPE (op0))) + && (GET_MODE_SIZE (TYPE_MODE (ctype)) + > GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0))))) + /* ... or this is a truncation (t is narrower than op0), + then we cannot pass through this narrowing. */ + || (GET_MODE_SIZE (TYPE_MODE (type)) + < GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0)))) + /* ... or signedness changes for division or modulus, + then we cannot pass through this conversion. */ + || (code != MULT_EXPR + && (TYPE_UNSIGNED (ctype) + != TYPE_UNSIGNED (TREE_TYPE (op0)))))) + break; + + /* Pass the constant down and see if we can make a simplification. If + we can, replace this expression with the inner simplification for + possible later conversion to our or some other type. */ + if ((t2 = fold_convert (TREE_TYPE (op0), c)) != 0 + && TREE_CODE (t2) == INTEGER_CST + && ! TREE_CONSTANT_OVERFLOW (t2) + && (0 != (t1 = extract_muldiv (op0, t2, code, + code == MULT_EXPR + ? ctype : NULL_TREE, + strict_overflow_p)))) + return t1; + break; + + case ABS_EXPR: + /* If widening the type changes it from signed to unsigned, then we + must avoid building ABS_EXPR itself as unsigned. */ + if (TYPE_UNSIGNED (ctype) && !TYPE_UNSIGNED (type)) + { + tree cstype = (*lang_hooks.types.signed_type) (ctype); + if ((t1 = extract_muldiv (op0, c, code, cstype, strict_overflow_p)) + != 0) + { + t1 = fold_build1 (tcode, cstype, fold_convert (cstype, t1)); + return fold_convert (ctype, t1); + } + break; + } + /* If the constant is negative, we cannot simplify this. */ + if (tree_int_cst_sgn (c) == -1) + break; + /* FALLTHROUGH */ + case NEGATE_EXPR: + if ((t1 = extract_muldiv (op0, c, code, wide_type, strict_overflow_p)) + != 0) + return fold_build1 (tcode, ctype, fold_convert (ctype, t1)); + break; + + case MIN_EXPR: case MAX_EXPR: + /* If widening the type changes the signedness, then we can't perform + this optimization as that changes the result. */ + if (TYPE_UNSIGNED (ctype) != TYPE_UNSIGNED (type)) + break; + + /* MIN (a, b) / 5 -> MIN (a / 5, b / 5) */ + sub_strict_overflow_p = false; + if ((t1 = extract_muldiv (op0, c, code, wide_type, + &sub_strict_overflow_p)) != 0 + && (t2 = extract_muldiv (op1, c, code, wide_type, + &sub_strict_overflow_p)) != 0) + { + if (tree_int_cst_sgn (c) < 0) + tcode = (tcode == MIN_EXPR ? MAX_EXPR : MIN_EXPR); + if (sub_strict_overflow_p) + *strict_overflow_p = true; + return fold_build2 (tcode, ctype, fold_convert (ctype, t1), + fold_convert (ctype, t2)); + } + break; + + case LSHIFT_EXPR: case RSHIFT_EXPR: + /* If the second operand is constant, this is a multiplication + or floor division, by a power of two, so we can treat it that + way unless the multiplier or divisor overflows. Signed + left-shift overflow is implementation-defined rather than + undefined in C90, so do not convert signed left shift into + multiplication. */ + if (TREE_CODE (op1) == INTEGER_CST + && (tcode == RSHIFT_EXPR || TYPE_UNSIGNED (TREE_TYPE (op0))) + /* const_binop may not detect overflow correctly, + so check for it explicitly here. */ + && TYPE_PRECISION (TREE_TYPE (size_one_node)) > TREE_INT_CST_LOW (op1) + && TREE_INT_CST_HIGH (op1) == 0 + && 0 != (t1 = fold_convert (ctype, + const_binop (LSHIFT_EXPR, + size_one_node, + op1, 0))) + && ! TREE_OVERFLOW (t1)) + return extract_muldiv (build2 (tcode == LSHIFT_EXPR + ? MULT_EXPR : FLOOR_DIV_EXPR, + ctype, fold_convert (ctype, op0), t1), + c, code, wide_type, strict_overflow_p); + break; + + case PLUS_EXPR: case MINUS_EXPR: + /* See if we can eliminate the operation on both sides. If we can, we + can return a new PLUS or MINUS. If we can't, the only remaining + cases where we can do anything are if the second operand is a + constant. */ + sub_strict_overflow_p = false; + t1 = extract_muldiv (op0, c, code, wide_type, &sub_strict_overflow_p); + t2 = extract_muldiv (op1, c, code, wide_type, &sub_strict_overflow_p); + if (t1 != 0 && t2 != 0 + && (code == MULT_EXPR + /* If not multiplication, we can only do this if both operands + are divisible by c. */ + || (multiple_of_p (ctype, op0, c) + && multiple_of_p (ctype, op1, c)))) + { + if (sub_strict_overflow_p) + *strict_overflow_p = true; + return fold_build2 (tcode, ctype, fold_convert (ctype, t1), + fold_convert (ctype, t2)); + } + + /* If this was a subtraction, negate OP1 and set it to be an addition. + This simplifies the logic below. */ + if (tcode == MINUS_EXPR) + tcode = PLUS_EXPR, op1 = negate_expr (op1); + + if (TREE_CODE (op1) != INTEGER_CST) + break; + + /* If either OP1 or C are negative, this optimization is not safe for + some of the division and remainder types while for others we need + to change the code. */ + if (tree_int_cst_sgn (op1) < 0 || tree_int_cst_sgn (c) < 0) + { + if (code == CEIL_DIV_EXPR) + code = FLOOR_DIV_EXPR; + else if (code == FLOOR_DIV_EXPR) + code = CEIL_DIV_EXPR; + else if (code != MULT_EXPR + && code != CEIL_MOD_EXPR && code != FLOOR_MOD_EXPR) + break; + } + + /* If it's a multiply or a division/modulus operation of a multiple + of our constant, do the operation and verify it doesn't overflow. */ + if (code == MULT_EXPR + || integer_zerop (const_binop (TRUNC_MOD_EXPR, op1, c, 0))) + { + op1 = const_binop (code, fold_convert (ctype, op1), + fold_convert (ctype, c), 0); + /* We allow the constant to overflow with wrapping semantics. */ + if (op1 == 0 + || (TREE_OVERFLOW (op1) && !TYPE_OVERFLOW_WRAPS (ctype))) + break; + } + else + break; + + /* If we have an unsigned type is not a sizetype, we cannot widen + the operation since it will change the result if the original + computation overflowed. */ + if (TYPE_UNSIGNED (ctype) + && ! (TREE_CODE (ctype) == INTEGER_TYPE && TYPE_IS_SIZETYPE (ctype)) + && ctype != type) + break; + + /* If we were able to eliminate our operation from the first side, + apply our operation to the second side and reform the PLUS. */ + if (t1 != 0 && (TREE_CODE (t1) != code || code == MULT_EXPR)) + return fold_build2 (tcode, ctype, fold_convert (ctype, t1), op1); + + /* The last case is if we are a multiply. In that case, we can + apply the distributive law to commute the multiply and addition + if the multiplication of the constants doesn't overflow. */ + if (code == MULT_EXPR) + return fold_build2 (tcode, ctype, + fold_build2 (code, ctype, + fold_convert (ctype, op0), + fold_convert (ctype, c)), + op1); + + break; + + case MULT_EXPR: + /* We have a special case here if we are doing something like + (C * 8) % 4 since we know that's zero. */ + if ((code == TRUNC_MOD_EXPR || code == CEIL_MOD_EXPR + || code == FLOOR_MOD_EXPR || code == ROUND_MOD_EXPR) + && TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST + && integer_zerop (const_binop (TRUNC_MOD_EXPR, op1, c, 0))) + return omit_one_operand (type, integer_zero_node, op0); + + /* ... fall through ... */ + + case TRUNC_DIV_EXPR: case CEIL_DIV_EXPR: case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: case EXACT_DIV_EXPR: + /* If we can extract our operation from the LHS, do so and return a + new operation. Likewise for the RHS from a MULT_EXPR. Otherwise, + do something only if the second operand is a constant. */ + if (same_p + && (t1 = extract_muldiv (op0, c, code, wide_type, + strict_overflow_p)) != 0) + return fold_build2 (tcode, ctype, fold_convert (ctype, t1), + fold_convert (ctype, op1)); + else if (tcode == MULT_EXPR && code == MULT_EXPR + && (t1 = extract_muldiv (op1, c, code, wide_type, + strict_overflow_p)) != 0) + return fold_build2 (tcode, ctype, fold_convert (ctype, op0), + fold_convert (ctype, t1)); + else if (TREE_CODE (op1) != INTEGER_CST) + return 0; + + /* If these are the same operation types, we can associate them + assuming no overflow. */ + if (tcode == code + && 0 != (t1 = const_binop (MULT_EXPR, fold_convert (ctype, op1), + fold_convert (ctype, c), 0)) + && ! TREE_OVERFLOW (t1)) + return fold_build2 (tcode, ctype, fold_convert (ctype, op0), t1); + + /* If these operations "cancel" each other, we have the main + optimizations of this pass, which occur when either constant is a + multiple of the other, in which case we replace this with either an + operation or CODE or TCODE. + + If we have an unsigned type that is not a sizetype, we cannot do + this since it will change the result if the original computation + overflowed. */ + if ((TYPE_OVERFLOW_UNDEFINED (ctype) + || (TREE_CODE (ctype) == INTEGER_TYPE && TYPE_IS_SIZETYPE (ctype))) + && ((code == MULT_EXPR && tcode == EXACT_DIV_EXPR) + || (tcode == MULT_EXPR + && code != TRUNC_MOD_EXPR && code != CEIL_MOD_EXPR + && code != FLOOR_MOD_EXPR && code != ROUND_MOD_EXPR))) + { + if (integer_zerop (const_binop (TRUNC_MOD_EXPR, op1, c, 0))) + { + if (TYPE_OVERFLOW_UNDEFINED (ctype)) + *strict_overflow_p = true; + return fold_build2 (tcode, ctype, fold_convert (ctype, op0), + fold_convert (ctype, + const_binop (TRUNC_DIV_EXPR, + op1, c, 0))); + } + else if (integer_zerop (const_binop (TRUNC_MOD_EXPR, c, op1, 0))) + { + if (TYPE_OVERFLOW_UNDEFINED (ctype)) + *strict_overflow_p = true; + return fold_build2 (code, ctype, fold_convert (ctype, op0), + fold_convert (ctype, + const_binop (TRUNC_DIV_EXPR, + c, op1, 0))); + } + } + break; + + default: + break; + } + + return 0; +} + +/* Return a node which has the indicated constant VALUE (either 0 or + 1), and is of the indicated TYPE. */ + +tree +constant_boolean_node (int value, tree type) +{ + if (type == integer_type_node) + return value ? integer_one_node : integer_zero_node; + else if (type == boolean_type_node) + return value ? boolean_true_node : boolean_false_node; + else + return build_int_cst (type, value); +} + + +/* Return true if expr looks like an ARRAY_REF and set base and + offset to the appropriate trees. If there is no offset, + offset is set to NULL_TREE. Base will be canonicalized to + something you can get the element type from using + TREE_TYPE (TREE_TYPE (base)). Offset will be the offset + in bytes to the base. */ + +static bool +extract_array_ref (tree expr, tree *base, tree *offset) +{ + /* One canonical form is a PLUS_EXPR with the first + argument being an ADDR_EXPR with a possible NOP_EXPR + attached. */ + if (TREE_CODE (expr) == PLUS_EXPR) + { + tree op0 = TREE_OPERAND (expr, 0); + tree inner_base, dummy1; + /* Strip NOP_EXPRs here because the C frontends and/or + folders present us (int *)&x.a + 4B possibly. */ + STRIP_NOPS (op0); + if (extract_array_ref (op0, &inner_base, &dummy1)) + { + *base = inner_base; + if (dummy1 == NULL_TREE) + *offset = TREE_OPERAND (expr, 1); + else + *offset = fold_build2 (PLUS_EXPR, TREE_TYPE (expr), + dummy1, TREE_OPERAND (expr, 1)); + return true; + } + } + /* Other canonical form is an ADDR_EXPR of an ARRAY_REF, + which we transform into an ADDR_EXPR with appropriate + offset. For other arguments to the ADDR_EXPR we assume + zero offset and as such do not care about the ADDR_EXPR + type and strip possible nops from it. */ + else if (TREE_CODE (expr) == ADDR_EXPR) + { + tree op0 = TREE_OPERAND (expr, 0); + if (TREE_CODE (op0) == ARRAY_REF) + { + tree idx = TREE_OPERAND (op0, 1); + *base = TREE_OPERAND (op0, 0); + *offset = fold_build2 (MULT_EXPR, TREE_TYPE (idx), idx, + array_ref_element_size (op0)); + } + else + { + /* Handle array-to-pointer decay as &a. */ + if (TREE_CODE (TREE_TYPE (op0)) == ARRAY_TYPE) + *base = TREE_OPERAND (expr, 0); + else + *base = expr; + *offset = NULL_TREE; + } + return true; + } + /* The next canonical form is a VAR_DECL with POINTER_TYPE. */ + else if (SSA_VAR_P (expr) + && TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE) + { + *base = expr; + *offset = NULL_TREE; + return true; + } + + return false; +} + + +/* Transform `a + (b ? x : y)' into `b ? (a + x) : (a + y)'. + Transform, `a + (x < y)' into `(x < y) ? (a + 1) : (a + 0)'. Here + CODE corresponds to the `+', COND to the `(b ? x : y)' or `(x < y)' + expression, and ARG to `a'. If COND_FIRST_P is nonzero, then the + COND is the first argument to CODE; otherwise (as in the example + given here), it is the second argument. TYPE is the type of the + original expression. Return NULL_TREE if no simplification is + possible. */ + +static tree +fold_binary_op_with_conditional_arg (enum tree_code code, + tree type, tree op0, tree op1, + tree cond, tree arg, int cond_first_p) +{ + tree cond_type = cond_first_p ? TREE_TYPE (op0) : TREE_TYPE (op1); + tree arg_type = cond_first_p ? TREE_TYPE (op1) : TREE_TYPE (op0); + tree test, true_value, false_value; + tree lhs = NULL_TREE; + tree rhs = NULL_TREE; + + /* This transformation is only worthwhile if we don't have to wrap + arg in a SAVE_EXPR, and the operation can be simplified on at least + one of the branches once its pushed inside the COND_EXPR. */ + if (!TREE_CONSTANT (arg)) + return NULL_TREE; + + if (TREE_CODE (cond) == COND_EXPR) + { + test = TREE_OPERAND (cond, 0); + true_value = TREE_OPERAND (cond, 1); + false_value = TREE_OPERAND (cond, 2); + /* If this operand throws an expression, then it does not make + sense to try to perform a logical or arithmetic operation + involving it. */ + if (VOID_TYPE_P (TREE_TYPE (true_value))) + lhs = true_value; + if (VOID_TYPE_P (TREE_TYPE (false_value))) + rhs = false_value; + } + else + { + tree testtype = TREE_TYPE (cond); + test = cond; + true_value = constant_boolean_node (true, testtype); + false_value = constant_boolean_node (false, testtype); + } + + arg = fold_convert (arg_type, arg); + if (lhs == 0) + { + true_value = fold_convert (cond_type, true_value); + if (cond_first_p) + lhs = fold_build2 (code, type, true_value, arg); + else + lhs = fold_build2 (code, type, arg, true_value); + } + if (rhs == 0) + { + false_value = fold_convert (cond_type, false_value); + if (cond_first_p) + rhs = fold_build2 (code, type, false_value, arg); + else + rhs = fold_build2 (code, type, arg, false_value); + } + + test = fold_build3 (COND_EXPR, type, test, lhs, rhs); + return fold_convert (type, test); +} + + +/* Subroutine of fold() that checks for the addition of +/- 0.0. + + If !NEGATE, return true if ADDEND is +/-0.0 and, for all X of type + TYPE, X + ADDEND is the same as X. If NEGATE, return true if X - + ADDEND is the same as X. + + X + 0 and X - 0 both give X when X is NaN, infinite, or nonzero + and finite. The problematic cases are when X is zero, and its mode + has signed zeros. In the case of rounding towards -infinity, + X - 0 is not the same as X because 0 - 0 is -0. In other rounding + modes, X + 0 is not the same as X because -0 + 0 is 0. */ + +static bool +fold_real_zero_addition_p (tree type, tree addend, int negate) +{ + if (!real_zerop (addend)) + return false; + + /* Don't allow the fold with -fsignaling-nans. */ + if (HONOR_SNANS (TYPE_MODE (type))) + return false; + + /* Allow the fold if zeros aren't signed, or their sign isn't important. */ + if (!HONOR_SIGNED_ZEROS (TYPE_MODE (type))) + return true; + + /* Treat x + -0 as x - 0 and x - -0 as x + 0. */ + if (TREE_CODE (addend) == REAL_CST + && REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (addend))) + negate = !negate; + + /* The mode has signed zeros, and we have to honor their sign. + In this situation, there is only one case we can return true for. + X - 0 is the same as X unless rounding towards -infinity is + supported. */ + return negate && !HONOR_SIGN_DEPENDENT_ROUNDING (TYPE_MODE (type)); +} + +/* Subroutine of fold() that checks comparisons of built-in math + functions against real constants. + + FCODE is the DECL_FUNCTION_CODE of the built-in, CODE is the comparison + operator: EQ_EXPR, NE_EXPR, GT_EXPR, LT_EXPR, GE_EXPR or LE_EXPR. TYPE + is the type of the result and ARG0 and ARG1 are the operands of the + comparison. ARG1 must be a TREE_REAL_CST. + + The function returns the constant folded tree if a simplification + can be made, and NULL_TREE otherwise. */ + +static tree +fold_mathfn_compare (enum built_in_function fcode, enum tree_code code, + tree type, tree arg0, tree arg1) +{ + REAL_VALUE_TYPE c; + + if (BUILTIN_SQRT_P (fcode)) + { + tree arg = TREE_VALUE (TREE_OPERAND (arg0, 1)); + enum machine_mode mode = TYPE_MODE (TREE_TYPE (arg0)); + + c = TREE_REAL_CST (arg1); + if (REAL_VALUE_NEGATIVE (c)) + { + /* sqrt(x) < y is always false, if y is negative. */ + if (code == EQ_EXPR || code == LT_EXPR || code == LE_EXPR) + return omit_one_operand (type, integer_zero_node, arg); + + /* sqrt(x) > y is always true, if y is negative and we + don't care about NaNs, i.e. negative values of x. */ + if (code == NE_EXPR || !HONOR_NANS (mode)) + return omit_one_operand (type, integer_one_node, arg); + + /* sqrt(x) > y is the same as x >= 0, if y is negative. */ + return fold_build2 (GE_EXPR, type, arg, + build_real (TREE_TYPE (arg), dconst0)); + } + else if (code == GT_EXPR || code == GE_EXPR) + { + REAL_VALUE_TYPE c2; + + REAL_ARITHMETIC (c2, MULT_EXPR, c, c); + real_convert (&c2, mode, &c2); + + if (REAL_VALUE_ISINF (c2)) + { + /* sqrt(x) > y is x == +Inf, when y is very large. */ + if (HONOR_INFINITIES (mode)) + return fold_build2 (EQ_EXPR, type, arg, + build_real (TREE_TYPE (arg), c2)); + + /* sqrt(x) > y is always false, when y is very large + and we don't care about infinities. */ + return omit_one_operand (type, integer_zero_node, arg); + } + + /* sqrt(x) > c is the same as x > c*c. */ + return fold_build2 (code, type, arg, + build_real (TREE_TYPE (arg), c2)); + } + else if (code == LT_EXPR || code == LE_EXPR) + { + REAL_VALUE_TYPE c2; + + REAL_ARITHMETIC (c2, MULT_EXPR, c, c); + real_convert (&c2, mode, &c2); + + if (REAL_VALUE_ISINF (c2)) + { + /* sqrt(x) < y is always true, when y is a very large + value and we don't care about NaNs or Infinities. */ + if (! HONOR_NANS (mode) && ! HONOR_INFINITIES (mode)) + return omit_one_operand (type, integer_one_node, arg); + + /* sqrt(x) < y is x != +Inf when y is very large and we + don't care about NaNs. */ + if (! HONOR_NANS (mode)) + return fold_build2 (NE_EXPR, type, arg, + build_real (TREE_TYPE (arg), c2)); + + /* sqrt(x) < y is x >= 0 when y is very large and we + don't care about Infinities. */ + if (! HONOR_INFINITIES (mode)) + return fold_build2 (GE_EXPR, type, arg, + build_real (TREE_TYPE (arg), dconst0)); + + /* sqrt(x) < y is x >= 0 && x != +Inf, when y is large. */ + if (lang_hooks.decls.global_bindings_p () != 0 + || CONTAINS_PLACEHOLDER_P (arg)) + return NULL_TREE; + + arg = save_expr (arg); + return fold_build2 (TRUTH_ANDIF_EXPR, type, + fold_build2 (GE_EXPR, type, arg, + build_real (TREE_TYPE (arg), + dconst0)), + fold_build2 (NE_EXPR, type, arg, + build_real (TREE_TYPE (arg), + c2))); + } + + /* sqrt(x) < c is the same as x < c*c, if we ignore NaNs. */ + if (! HONOR_NANS (mode)) + return fold_build2 (code, type, arg, + build_real (TREE_TYPE (arg), c2)); + + /* sqrt(x) < c is the same as x >= 0 && x < c*c. */ + if (lang_hooks.decls.global_bindings_p () == 0 + && ! CONTAINS_PLACEHOLDER_P (arg)) + { + arg = save_expr (arg); + return fold_build2 (TRUTH_ANDIF_EXPR, type, + fold_build2 (GE_EXPR, type, arg, + build_real (TREE_TYPE (arg), + dconst0)), + fold_build2 (code, type, arg, + build_real (TREE_TYPE (arg), + c2))); + } + } + } + + return NULL_TREE; +} + +/* Subroutine of fold() that optimizes comparisons against Infinities, + either +Inf or -Inf. + + CODE is the comparison operator: EQ_EXPR, NE_EXPR, GT_EXPR, LT_EXPR, + GE_EXPR or LE_EXPR. TYPE is the type of the result and ARG0 and ARG1 + are the operands of the comparison. ARG1 must be a TREE_REAL_CST. + + The function returns the constant folded tree if a simplification + can be made, and NULL_TREE otherwise. */ + +static tree +fold_inf_compare (enum tree_code code, tree type, tree arg0, tree arg1) +{ + enum machine_mode mode; + REAL_VALUE_TYPE max; + tree temp; + bool neg; + + mode = TYPE_MODE (TREE_TYPE (arg0)); + + /* For negative infinity swap the sense of the comparison. */ + neg = REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg1)); + if (neg) + code = swap_tree_comparison (code); + + switch (code) + { + case GT_EXPR: + /* x > +Inf is always false, if with ignore sNANs. */ + if (HONOR_SNANS (mode)) + return NULL_TREE; + return omit_one_operand (type, integer_zero_node, arg0); + + case LE_EXPR: + /* x <= +Inf is always true, if we don't case about NaNs. */ + if (! HONOR_NANS (mode)) + return omit_one_operand (type, integer_one_node, arg0); + + /* x <= +Inf is the same as x == x, i.e. isfinite(x). */ + if (lang_hooks.decls.global_bindings_p () == 0 + && ! CONTAINS_PLACEHOLDER_P (arg0)) + { + arg0 = save_expr (arg0); + return fold_build2 (EQ_EXPR, type, arg0, arg0); + } + break; + + case EQ_EXPR: + case GE_EXPR: + /* x == +Inf and x >= +Inf are always equal to x > DBL_MAX. */ + real_maxval (&max, neg, mode); + return fold_build2 (neg ? LT_EXPR : GT_EXPR, type, + arg0, build_real (TREE_TYPE (arg0), max)); + + case LT_EXPR: + /* x < +Inf is always equal to x <= DBL_MAX. */ + real_maxval (&max, neg, mode); + return fold_build2 (neg ? GE_EXPR : LE_EXPR, type, + arg0, build_real (TREE_TYPE (arg0), max)); + + case NE_EXPR: + /* x != +Inf is always equal to !(x > DBL_MAX). */ + real_maxval (&max, neg, mode); + if (! HONOR_NANS (mode)) + return fold_build2 (neg ? GE_EXPR : LE_EXPR, type, + arg0, build_real (TREE_TYPE (arg0), max)); + + /* The transformation below creates non-gimple code and thus is + not appropriate if we are in gimple form. */ + if (in_gimple_form) + return NULL_TREE; + + temp = fold_build2 (neg ? LT_EXPR : GT_EXPR, type, + arg0, build_real (TREE_TYPE (arg0), max)); + return fold_build1 (TRUTH_NOT_EXPR, type, temp); + + default: + break; + } + + return NULL_TREE; +} + +/* Subroutine of fold() that optimizes comparisons of a division by + a nonzero integer constant against an integer constant, i.e. + X/C1 op C2. + + CODE is the comparison operator: EQ_EXPR, NE_EXPR, GT_EXPR, LT_EXPR, + GE_EXPR or LE_EXPR. TYPE is the type of the result and ARG0 and ARG1 + are the operands of the comparison. ARG1 must be a TREE_REAL_CST. + + The function returns the constant folded tree if a simplification + can be made, and NULL_TREE otherwise. */ + +static tree +fold_div_compare (enum tree_code code, tree type, tree arg0, tree arg1) +{ + tree prod, tmp, hi, lo; + tree arg00 = TREE_OPERAND (arg0, 0); + tree arg01 = TREE_OPERAND (arg0, 1); + unsigned HOST_WIDE_INT lpart; + HOST_WIDE_INT hpart; + bool unsigned_p = TYPE_UNSIGNED (TREE_TYPE (arg0)); + bool neg_overflow; + int overflow; + + /* We have to do this the hard way to detect unsigned overflow. + prod = int_const_binop (MULT_EXPR, arg01, arg1, 0); */ + overflow = mul_double_with_sign (TREE_INT_CST_LOW (arg01), + TREE_INT_CST_HIGH (arg01), + TREE_INT_CST_LOW (arg1), + TREE_INT_CST_HIGH (arg1), + &lpart, &hpart, unsigned_p); + prod = build_int_cst_wide (TREE_TYPE (arg00), lpart, hpart); + prod = force_fit_type (prod, -1, overflow, false); + neg_overflow = false; + + if (unsigned_p) + { + tmp = int_const_binop (MINUS_EXPR, arg01, integer_one_node, 0); + lo = prod; + + /* Likewise hi = int_const_binop (PLUS_EXPR, prod, tmp, 0). */ + overflow = add_double_with_sign (TREE_INT_CST_LOW (prod), + TREE_INT_CST_HIGH (prod), + TREE_INT_CST_LOW (tmp), + TREE_INT_CST_HIGH (tmp), + &lpart, &hpart, unsigned_p); + hi = build_int_cst_wide (TREE_TYPE (arg00), lpart, hpart); + hi = force_fit_type (hi, -1, overflow | TREE_OVERFLOW (prod), + TREE_CONSTANT_OVERFLOW (prod)); + } + else if (tree_int_cst_sgn (arg01) >= 0) + { + tmp = int_const_binop (MINUS_EXPR, arg01, integer_one_node, 0); + switch (tree_int_cst_sgn (arg1)) + { + case -1: + neg_overflow = true; + lo = int_const_binop (MINUS_EXPR, prod, tmp, 0); + hi = prod; + break; + + case 0: + lo = fold_negate_const (tmp, TREE_TYPE (arg0)); + hi = tmp; + break; + + case 1: + hi = int_const_binop (PLUS_EXPR, prod, tmp, 0); + lo = prod; + break; + + default: + gcc_unreachable (); + } + } + else + { + /* A negative divisor reverses the relational operators. */ + code = swap_tree_comparison (code); + + tmp = int_const_binop (PLUS_EXPR, arg01, integer_one_node, 0); + switch (tree_int_cst_sgn (arg1)) + { + case -1: + hi = int_const_binop (MINUS_EXPR, prod, tmp, 0); + lo = prod; + break; + + case 0: + hi = fold_negate_const (tmp, TREE_TYPE (arg0)); + lo = tmp; + break; + + case 1: + neg_overflow = true; + lo = int_const_binop (PLUS_EXPR, prod, tmp, 0); + hi = prod; + break; + + default: + gcc_unreachable (); + } + } + + switch (code) + { + case EQ_EXPR: + if (TREE_OVERFLOW (lo) && TREE_OVERFLOW (hi)) + return omit_one_operand (type, integer_zero_node, arg00); + if (TREE_OVERFLOW (hi)) + return fold_build2 (GE_EXPR, type, arg00, lo); + if (TREE_OVERFLOW (lo)) + return fold_build2 (LE_EXPR, type, arg00, hi); + return build_range_check (type, arg00, 1, lo, hi); + + case NE_EXPR: + if (TREE_OVERFLOW (lo) && TREE_OVERFLOW (hi)) + return omit_one_operand (type, integer_one_node, arg00); + if (TREE_OVERFLOW (hi)) + return fold_build2 (LT_EXPR, type, arg00, lo); + if (TREE_OVERFLOW (lo)) + return fold_build2 (GT_EXPR, type, arg00, hi); + return build_range_check (type, arg00, 0, lo, hi); + + case LT_EXPR: + if (TREE_OVERFLOW (lo)) + { + tmp = neg_overflow ? integer_zero_node : integer_one_node; + return omit_one_operand (type, tmp, arg00); + } + return fold_build2 (LT_EXPR, type, arg00, lo); + + case LE_EXPR: + if (TREE_OVERFLOW (hi)) + { + tmp = neg_overflow ? integer_zero_node : integer_one_node; + return omit_one_operand (type, tmp, arg00); + } + return fold_build2 (LE_EXPR, type, arg00, hi); + + case GT_EXPR: + if (TREE_OVERFLOW (hi)) + { + tmp = neg_overflow ? integer_one_node : integer_zero_node; + return omit_one_operand (type, tmp, arg00); + } + return fold_build2 (GT_EXPR, type, arg00, hi); + + case GE_EXPR: + if (TREE_OVERFLOW (lo)) + { + tmp = neg_overflow ? integer_one_node : integer_zero_node; + return omit_one_operand (type, tmp, arg00); + } + return fold_build2 (GE_EXPR, type, arg00, lo); + + default: + break; + } + + return NULL_TREE; +} + + +/* If CODE with arguments ARG0 and ARG1 represents a single bit + equality/inequality test, then return a simplified form of the test + using a sign testing. Otherwise return NULL. TYPE is the desired + result type. */ + +static tree +fold_single_bit_test_into_sign_test (enum tree_code code, tree arg0, tree arg1, + tree result_type) +{ + /* If this is testing a single bit, we can optimize the test. */ + if ((code == NE_EXPR || code == EQ_EXPR) + && TREE_CODE (arg0) == BIT_AND_EXPR && integer_zerop (arg1) + && integer_pow2p (TREE_OPERAND (arg0, 1))) + { + /* If we have (A & C) != 0 where C is the sign bit of A, convert + this into A < 0. Similarly for (A & C) == 0 into A >= 0. */ + tree arg00 = sign_bit_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg0, 1)); + + if (arg00 != NULL_TREE + /* This is only a win if casting to a signed type is cheap, + i.e. when arg00's type is not a partial mode. */ + && TYPE_PRECISION (TREE_TYPE (arg00)) + == GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (arg00)))) + { + tree stype = lang_hooks.types.signed_type (TREE_TYPE (arg00)); + return fold_build2 (code == EQ_EXPR ? GE_EXPR : LT_EXPR, + result_type, fold_convert (stype, arg00), + build_int_cst (stype, 0)); + } + } + + return NULL_TREE; +} + +/* If CODE with arguments ARG0 and ARG1 represents a single bit + equality/inequality test, then return a simplified form of + the test using shifts and logical operations. Otherwise return + NULL. TYPE is the desired result type. */ + +tree +fold_single_bit_test (enum tree_code code, tree arg0, tree arg1, + tree result_type) +{ + /* If this is testing a single bit, we can optimize the test. */ + if ((code == NE_EXPR || code == EQ_EXPR) + && TREE_CODE (arg0) == BIT_AND_EXPR && integer_zerop (arg1) + && integer_pow2p (TREE_OPERAND (arg0, 1))) + { + tree inner = TREE_OPERAND (arg0, 0); + tree type = TREE_TYPE (arg0); + int bitnum = tree_log2 (TREE_OPERAND (arg0, 1)); + enum machine_mode operand_mode = TYPE_MODE (type); + int ops_unsigned; + tree signed_type, unsigned_type, intermediate_type; + tree tem; + + /* First, see if we can fold the single bit test into a sign-bit + test. */ + tem = fold_single_bit_test_into_sign_test (code, arg0, arg1, + result_type); + if (tem) + return tem; + + /* Otherwise we have (A & C) != 0 where C is a single bit, + convert that into ((A >> C2) & 1). Where C2 = log2(C). + Similarly for (A & C) == 0. */ + + /* If INNER is a right shift of a constant and it plus BITNUM does + not overflow, adjust BITNUM and INNER. */ + if (TREE_CODE (inner) == RSHIFT_EXPR + && TREE_CODE (TREE_OPERAND (inner, 1)) == INTEGER_CST + && TREE_INT_CST_HIGH (TREE_OPERAND (inner, 1)) == 0 + && bitnum < TYPE_PRECISION (type) + && 0 > compare_tree_int (TREE_OPERAND (inner, 1), + bitnum - TYPE_PRECISION (type))) + { + bitnum += TREE_INT_CST_LOW (TREE_OPERAND (inner, 1)); + inner = TREE_OPERAND (inner, 0); + } + + /* If we are going to be able to omit the AND below, we must do our + operations as unsigned. If we must use the AND, we have a choice. + Normally unsigned is faster, but for some machines signed is. */ +#ifdef LOAD_EXTEND_OP + ops_unsigned = (LOAD_EXTEND_OP (operand_mode) == SIGN_EXTEND + && !flag_syntax_only) ? 0 : 1; +#else + ops_unsigned = 1; +#endif + + signed_type = lang_hooks.types.type_for_mode (operand_mode, 0); + unsigned_type = lang_hooks.types.type_for_mode (operand_mode, 1); + intermediate_type = ops_unsigned ? unsigned_type : signed_type; + inner = fold_convert (intermediate_type, inner); + + if (bitnum != 0) + inner = build2 (RSHIFT_EXPR, intermediate_type, + inner, size_int (bitnum)); + + if (code == EQ_EXPR) + inner = fold_build2 (BIT_XOR_EXPR, intermediate_type, + inner, integer_one_node); + + /* Put the AND last so it can combine with more things. */ + inner = build2 (BIT_AND_EXPR, intermediate_type, + inner, integer_one_node); + + /* Make sure to return the proper type. */ + inner = fold_convert (result_type, inner); + + return inner; + } + return NULL_TREE; +} + +/* Check whether we are allowed to reorder operands arg0 and arg1, + such that the evaluation of arg1 occurs before arg0. */ + +static bool +reorder_operands_p (tree arg0, tree arg1) +{ + if (! flag_evaluation_order) + return true; + if (TREE_CONSTANT (arg0) || TREE_CONSTANT (arg1)) + return true; + return ! TREE_SIDE_EFFECTS (arg0) + && ! TREE_SIDE_EFFECTS (arg1); +} + +/* Test whether it is preferable two swap two operands, ARG0 and + ARG1, for example because ARG0 is an integer constant and ARG1 + isn't. If REORDER is true, only recommend swapping if we can + evaluate the operands in reverse order. */ + +bool +tree_swap_operands_p (tree arg0, tree arg1, bool reorder) +{ + STRIP_SIGN_NOPS (arg0); + STRIP_SIGN_NOPS (arg1); + + if (TREE_CODE (arg1) == INTEGER_CST) + return 0; + if (TREE_CODE (arg0) == INTEGER_CST) + return 1; + + if (TREE_CODE (arg1) == REAL_CST) + return 0; + if (TREE_CODE (arg0) == REAL_CST) + return 1; + + if (TREE_CODE (arg1) == COMPLEX_CST) + return 0; + if (TREE_CODE (arg0) == COMPLEX_CST) + return 1; + + if (TREE_CONSTANT (arg1)) + return 0; + if (TREE_CONSTANT (arg0)) + return 1; + + if (optimize_size) + return 0; + + if (reorder && flag_evaluation_order + && (TREE_SIDE_EFFECTS (arg0) || TREE_SIDE_EFFECTS (arg1))) + return 0; + + if (DECL_P (arg1)) + return 0; + if (DECL_P (arg0)) + return 1; + + /* It is preferable to swap two SSA_NAME to ensure a canonical form + for commutative and comparison operators. Ensuring a canonical + form allows the optimizers to find additional redundancies without + having to explicitly check for both orderings. */ + if (TREE_CODE (arg0) == SSA_NAME + && TREE_CODE (arg1) == SSA_NAME + && SSA_NAME_VERSION (arg0) > SSA_NAME_VERSION (arg1)) + return 1; + + return 0; +} + +/* Fold comparison ARG0 CODE ARG1 (with result in TYPE), where + ARG0 is extended to a wider type. */ + +static tree +fold_widened_comparison (enum tree_code code, tree type, tree arg0, tree arg1) +{ + tree arg0_unw = get_unwidened (arg0, NULL_TREE); + tree arg1_unw; + tree shorter_type, outer_type; + tree min, max; + bool above, below; + + if (arg0_unw == arg0) + return NULL_TREE; + shorter_type = TREE_TYPE (arg0_unw); + +#ifdef HAVE_canonicalize_funcptr_for_compare + /* Disable this optimization if we're casting a function pointer + type on targets that require function pointer canonicalization. */ + if (HAVE_canonicalize_funcptr_for_compare + && TREE_CODE (shorter_type) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (shorter_type)) == FUNCTION_TYPE) + return NULL_TREE; +#endif + + if (TYPE_PRECISION (TREE_TYPE (arg0)) <= TYPE_PRECISION (shorter_type)) + return NULL_TREE; + + arg1_unw = get_unwidened (arg1, shorter_type); + + /* If possible, express the comparison in the shorter mode. */ + if ((code == EQ_EXPR || code == NE_EXPR + || TYPE_UNSIGNED (TREE_TYPE (arg0)) == TYPE_UNSIGNED (shorter_type)) + && (TREE_TYPE (arg1_unw) == shorter_type + || (TREE_CODE (arg1_unw) == INTEGER_CST + && (TREE_CODE (shorter_type) == INTEGER_TYPE + || TREE_CODE (shorter_type) == BOOLEAN_TYPE) + && int_fits_type_p (arg1_unw, shorter_type)))) + return fold_build2 (code, type, arg0_unw, + fold_convert (shorter_type, arg1_unw)); + + if (TREE_CODE (arg1_unw) != INTEGER_CST + || TREE_CODE (shorter_type) != INTEGER_TYPE + || !int_fits_type_p (arg1_unw, shorter_type)) + return NULL_TREE; + + /* If we are comparing with the integer that does not fit into the range + of the shorter type, the result is known. */ + outer_type = TREE_TYPE (arg1_unw); + min = lower_bound_in_type (outer_type, shorter_type); + max = upper_bound_in_type (outer_type, shorter_type); + + above = integer_nonzerop (fold_relational_const (LT_EXPR, type, + max, arg1_unw)); + below = integer_nonzerop (fold_relational_const (LT_EXPR, type, + arg1_unw, min)); + + switch (code) + { + case EQ_EXPR: + if (above || below) + return omit_one_operand (type, integer_zero_node, arg0); + break; + + case NE_EXPR: + if (above || below) + return omit_one_operand (type, integer_one_node, arg0); + break; + + case LT_EXPR: + case LE_EXPR: + if (above) + return omit_one_operand (type, integer_one_node, arg0); + else if (below) + return omit_one_operand (type, integer_zero_node, arg0); + + case GT_EXPR: + case GE_EXPR: + if (above) + return omit_one_operand (type, integer_zero_node, arg0); + else if (below) + return omit_one_operand (type, integer_one_node, arg0); + + default: + break; + } + + return NULL_TREE; +} + +/* Fold comparison ARG0 CODE ARG1 (with result in TYPE), where for + ARG0 just the signedness is changed. */ + +static tree +fold_sign_changed_comparison (enum tree_code code, tree type, + tree arg0, tree arg1) +{ + tree arg0_inner, tmp; + tree inner_type, outer_type; + + if (TREE_CODE (arg0) != NOP_EXPR + && TREE_CODE (arg0) != CONVERT_EXPR) + return NULL_TREE; + + outer_type = TREE_TYPE (arg0); + arg0_inner = TREE_OPERAND (arg0, 0); + inner_type = TREE_TYPE (arg0_inner); + +#ifdef HAVE_canonicalize_funcptr_for_compare + /* Disable this optimization if we're casting a function pointer + type on targets that require function pointer canonicalization. */ + if (HAVE_canonicalize_funcptr_for_compare + && TREE_CODE (inner_type) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (inner_type)) == FUNCTION_TYPE) + return NULL_TREE; +#endif + + if (TYPE_PRECISION (inner_type) != TYPE_PRECISION (outer_type)) + return NULL_TREE; + + if (TREE_CODE (arg1) != INTEGER_CST + && !((TREE_CODE (arg1) == NOP_EXPR + || TREE_CODE (arg1) == CONVERT_EXPR) + && TREE_TYPE (TREE_OPERAND (arg1, 0)) == inner_type)) + return NULL_TREE; + + if (TYPE_UNSIGNED (inner_type) != TYPE_UNSIGNED (outer_type) + && code != NE_EXPR + && code != EQ_EXPR) + return NULL_TREE; + + if (TREE_CODE (arg1) == INTEGER_CST) + { + tmp = build_int_cst_wide (inner_type, + TREE_INT_CST_LOW (arg1), + TREE_INT_CST_HIGH (arg1)); + arg1 = force_fit_type (tmp, 0, + TREE_OVERFLOW (arg1), + TREE_CONSTANT_OVERFLOW (arg1)); + } + else + arg1 = fold_convert (inner_type, arg1); + + return fold_build2 (code, type, arg0_inner, arg1); +} + +/* Tries to replace &a[idx] CODE s * delta with &a[idx CODE delta], if s is + step of the array. Reconstructs s and delta in the case of s * delta + being an integer constant (and thus already folded). + ADDR is the address. MULT is the multiplicative expression. + If the function succeeds, the new address expression is returned. Otherwise + NULL_TREE is returned. */ + +static tree +try_move_mult_to_index (enum tree_code code, tree addr, tree op1) +{ + tree s, delta, step; + tree ref = TREE_OPERAND (addr, 0), pref; + tree ret, pos; + tree itype; + + /* Canonicalize op1 into a possibly non-constant delta + and an INTEGER_CST s. */ + if (TREE_CODE (op1) == MULT_EXPR) + { + tree arg0 = TREE_OPERAND (op1, 0), arg1 = TREE_OPERAND (op1, 1); + + STRIP_NOPS (arg0); + STRIP_NOPS (arg1); + + if (TREE_CODE (arg0) == INTEGER_CST) + { + s = arg0; + delta = arg1; + } + else if (TREE_CODE (arg1) == INTEGER_CST) + { + s = arg1; + delta = arg0; + } + else + return NULL_TREE; + } + else if (TREE_CODE (op1) == INTEGER_CST) + { + delta = op1; + s = NULL_TREE; + } + else + { + /* Simulate we are delta * 1. */ + delta = op1; + s = integer_one_node; + } + + for (;; ref = TREE_OPERAND (ref, 0)) + { + if (TREE_CODE (ref) == ARRAY_REF) + { + itype = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (ref, 0))); + if (! itype) + continue; + + step = array_ref_element_size (ref); + if (TREE_CODE (step) != INTEGER_CST) + continue; + + if (s) + { + if (! tree_int_cst_equal (step, s)) + continue; + } + else + { + /* Try if delta is a multiple of step. */ + tree tmp = div_if_zero_remainder (EXACT_DIV_EXPR, delta, step); + if (! tmp) + continue; + delta = tmp; + } + + break; + } + + if (!handled_component_p (ref)) + return NULL_TREE; + } + + /* We found the suitable array reference. So copy everything up to it, + and replace the index. */ + + pref = TREE_OPERAND (addr, 0); + ret = copy_node (pref); + pos = ret; + + while (pref != ref) + { + pref = TREE_OPERAND (pref, 0); + TREE_OPERAND (pos, 0) = copy_node (pref); + pos = TREE_OPERAND (pos, 0); + } + + TREE_OPERAND (pos, 1) = fold_build2 (code, itype, + fold_convert (itype, + TREE_OPERAND (pos, 1)), + fold_convert (itype, delta)); + + return fold_build1 (ADDR_EXPR, TREE_TYPE (addr), ret); +} + + +/* Fold A < X && A + 1 > Y to A < X && A >= Y. Normally A + 1 > Y + means A >= Y && A != MAX, but in this case we know that + A < X <= MAX. INEQ is A + 1 > Y, BOUND is A < X. */ + +static tree +fold_to_nonsharp_ineq_using_bound (tree ineq, tree bound) +{ + tree a, typea, type = TREE_TYPE (ineq), a1, diff, y; + + if (TREE_CODE (bound) == LT_EXPR) + a = TREE_OPERAND (bound, 0); + else if (TREE_CODE (bound) == GT_EXPR) + a = TREE_OPERAND (bound, 1); + else + return NULL_TREE; + + typea = TREE_TYPE (a); + if (!INTEGRAL_TYPE_P (typea) + && !POINTER_TYPE_P (typea)) + return NULL_TREE; + + if (TREE_CODE (ineq) == LT_EXPR) + { + a1 = TREE_OPERAND (ineq, 1); + y = TREE_OPERAND (ineq, 0); + } + else if (TREE_CODE (ineq) == GT_EXPR) + { + a1 = TREE_OPERAND (ineq, 0); + y = TREE_OPERAND (ineq, 1); + } + else + return NULL_TREE; + + if (TREE_TYPE (a1) != typea) + return NULL_TREE; + + diff = fold_build2 (MINUS_EXPR, typea, a1, a); + if (!integer_onep (diff)) + return NULL_TREE; + + return fold_build2 (GE_EXPR, type, a, y); +} + +/* Fold a sum or difference of at least one multiplication. + Returns the folded tree or NULL if no simplification could be made. */ + +static tree +fold_plusminus_mult_expr (enum tree_code code, tree type, tree arg0, tree arg1) +{ + tree arg00, arg01, arg10, arg11; + tree alt0 = NULL_TREE, alt1 = NULL_TREE, same; + + /* (A * C) +- (B * C) -> (A+-B) * C. + (A * C) +- A -> A * (C+-1). + 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. */ + + if (TREE_CODE (arg0) == MULT_EXPR) + { + arg00 = TREE_OPERAND (arg0, 0); + arg01 = TREE_OPERAND (arg0, 1); + } + else + { + arg00 = arg0; + arg01 = build_one_cst (type); + } + if (TREE_CODE (arg1) == MULT_EXPR) + { + arg10 = TREE_OPERAND (arg1, 0); + arg11 = TREE_OPERAND (arg1, 1); + } + else + { + arg10 = arg1; + arg11 = build_one_cst (type); + } + 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; + + /* No identical multiplicands; see if we can find a common + power-of-two factor in non-power-of-two multiplies. This + can help in multi-dimensional array access. */ + else if (host_integerp (arg01, 0) + && host_integerp (arg11, 0)) + { + HOST_WIDE_INT int01, int11, tmp; + bool swap = false; + tree maybe_same; + int01 = TREE_INT_CST_LOW (arg01); + int11 = TREE_INT_CST_LOW (arg11); + + /* Move min of absolute values to int11. */ + if ((int01 >= 0 ? int01 : -int01) + < (int11 >= 0 ? int11 : -int11)) + { + tmp = int01, int01 = int11, int11 = tmp; + alt0 = arg00, arg00 = arg10, arg10 = alt0; + maybe_same = arg01; + swap = true; + } + else + maybe_same = arg11; + + if (exact_log2 (int11) > 0 && int01 % int11 == 0) + { + alt0 = fold_build2 (MULT_EXPR, TREE_TYPE (arg00), arg00, + build_int_cst (TREE_TYPE (arg00), + int01 / int11)); + alt1 = arg10; + same = maybe_same; + if (swap) + maybe_same = alt0, alt0 = alt1, alt1 = maybe_same; + } + } + + if (same) + return fold_build2 (MULT_EXPR, type, + fold_build2 (code, type, + fold_convert (type, alt0), + fold_convert (type, alt1)), + fold_convert (type, same)); + + return NULL_TREE; +} + +/* Subroutine of native_encode_expr. Encode the INTEGER_CST + specified by EXPR into the buffer PTR of length LEN bytes. + Return the number of bytes placed in the buffer, or zero + upon failure. */ + +static int +native_encode_int (tree expr, unsigned char *ptr, int len) +{ + tree type = TREE_TYPE (expr); + int total_bytes = GET_MODE_SIZE (TYPE_MODE (type)); + int byte, offset, word, words; + unsigned char value; + + if (total_bytes > len) + return 0; + words = total_bytes / UNITS_PER_WORD; + + for (byte = 0; byte < total_bytes; byte++) + { + int bitpos = byte * BITS_PER_UNIT; + if (bitpos < HOST_BITS_PER_WIDE_INT) + value = (unsigned char) (TREE_INT_CST_LOW (expr) >> bitpos); + else + value = (unsigned char) (TREE_INT_CST_HIGH (expr) + >> (bitpos - HOST_BITS_PER_WIDE_INT)); + + if (total_bytes > UNITS_PER_WORD) + { + word = byte / UNITS_PER_WORD; + if (WORDS_BIG_ENDIAN) + word = (words - 1) - word; + offset = word * UNITS_PER_WORD; + if (BYTES_BIG_ENDIAN) + offset += (UNITS_PER_WORD - 1) - (byte % UNITS_PER_WORD); + else + offset += byte % UNITS_PER_WORD; + } + else + offset = BYTES_BIG_ENDIAN ? (total_bytes - 1) - byte : byte; + ptr[offset] = value; + } + return total_bytes; +} + + +/* Subroutine of native_encode_expr. Encode the REAL_CST + specified by EXPR into the buffer PTR of length LEN bytes. + Return the number of bytes placed in the buffer, or zero + upon failure. */ + +static int +native_encode_real (tree expr, unsigned char *ptr, int len) +{ + tree type = TREE_TYPE (expr); + int total_bytes = GET_MODE_SIZE (TYPE_MODE (type)); + int byte, offset, word, words, bitpos; + unsigned char value; + + /* There are always 32 bits in each long, no matter the size of + the hosts long. We handle floating point representations with + up to 192 bits. */ + long tmp[6]; + + if (total_bytes > len) + return 0; + words = 32 / UNITS_PER_WORD; + + real_to_target (tmp, TREE_REAL_CST_PTR (expr), TYPE_MODE (type)); + + for (bitpos = 0; bitpos < total_bytes * BITS_PER_UNIT; + bitpos += BITS_PER_UNIT) + { + byte = (bitpos / BITS_PER_UNIT) & 3; + value = (unsigned char) (tmp[bitpos / 32] >> (bitpos & 31)); + + if (UNITS_PER_WORD < 4) + { + word = byte / UNITS_PER_WORD; + if (WORDS_BIG_ENDIAN) + word = (words - 1) - word; + offset = word * UNITS_PER_WORD; + if (BYTES_BIG_ENDIAN) + offset += (UNITS_PER_WORD - 1) - (byte % UNITS_PER_WORD); + else + offset += byte % UNITS_PER_WORD; + } + else + offset = BYTES_BIG_ENDIAN ? 3 - byte : byte; + ptr[offset + ((bitpos / BITS_PER_UNIT) & ~3)] = value; + } + return total_bytes; +} + +/* Subroutine of native_encode_expr. Encode the COMPLEX_CST + specified by EXPR into the buffer PTR of length LEN bytes. + Return the number of bytes placed in the buffer, or zero + upon failure. */ + +static int +native_encode_complex (tree expr, unsigned char *ptr, int len) +{ + int rsize, isize; + tree part; + + part = TREE_REALPART (expr); + rsize = native_encode_expr (part, ptr, len); + if (rsize == 0) + return 0; + part = TREE_IMAGPART (expr); + isize = native_encode_expr (part, ptr+rsize, len-rsize); + if (isize != rsize) + return 0; + return rsize + isize; +} + + +/* Subroutine of native_encode_expr. Encode the VECTOR_CST + specified by EXPR into the buffer PTR of length LEN bytes. + Return the number of bytes placed in the buffer, or zero + upon failure. */ + +static int +native_encode_vector (tree expr, unsigned char *ptr, int len) +{ + int i, size, offset, count; + tree itype, elem, elements; + + offset = 0; + elements = TREE_VECTOR_CST_ELTS (expr); + count = TYPE_VECTOR_SUBPARTS (TREE_TYPE (expr)); + itype = TREE_TYPE (TREE_TYPE (expr)); + size = GET_MODE_SIZE (TYPE_MODE (itype)); + for (i = 0; i < count; i++) + { + if (elements) + { + elem = TREE_VALUE (elements); + elements = TREE_CHAIN (elements); + } + else + elem = NULL_TREE; + + if (elem) + { + if (native_encode_expr (elem, ptr+offset, len-offset) != size) + return 0; + } + else + { + if (offset + size > len) + return 0; + memset (ptr+offset, 0, size); + } + offset += size; + } + return offset; +} + + +/* Subroutine of fold_view_convert_expr. Encode the INTEGER_CST, + REAL_CST, COMPLEX_CST or VECTOR_CST specified by EXPR into the + buffer PTR of length LEN bytes. Return the number of bytes + placed in the buffer, or zero upon failure. */ + +static int +native_encode_expr (tree expr, unsigned char *ptr, int len) +{ + switch (TREE_CODE (expr)) + { + case INTEGER_CST: + return native_encode_int (expr, ptr, len); + + case REAL_CST: + return native_encode_real (expr, ptr, len); + + case COMPLEX_CST: + return native_encode_complex (expr, ptr, len); + + case VECTOR_CST: + return native_encode_vector (expr, ptr, len); + + default: + return 0; + } +} + + +/* Subroutine of native_interpret_expr. Interpret the contents of + the buffer PTR of length LEN as an INTEGER_CST of type TYPE. + If the buffer cannot be interpreted, return NULL_TREE. */ + +static tree +native_interpret_int (tree type, unsigned char *ptr, int len) +{ + int total_bytes = GET_MODE_SIZE (TYPE_MODE (type)); + int byte, offset, word, words; + unsigned char value; + unsigned int HOST_WIDE_INT lo = 0; + HOST_WIDE_INT hi = 0; + + if (total_bytes > len) + return NULL_TREE; + if (total_bytes * BITS_PER_UNIT > 2 * HOST_BITS_PER_WIDE_INT) + return NULL_TREE; + words = total_bytes / UNITS_PER_WORD; + + for (byte = 0; byte < total_bytes; byte++) + { + int bitpos = byte * BITS_PER_UNIT; + if (total_bytes > UNITS_PER_WORD) + { + word = byte / UNITS_PER_WORD; + if (WORDS_BIG_ENDIAN) + word = (words - 1) - word; + offset = word * UNITS_PER_WORD; + if (BYTES_BIG_ENDIAN) + offset += (UNITS_PER_WORD - 1) - (byte % UNITS_PER_WORD); + else + offset += byte % UNITS_PER_WORD; + } + else + offset = BYTES_BIG_ENDIAN ? (total_bytes - 1) - byte : byte; + value = ptr[offset]; + + if (bitpos < HOST_BITS_PER_WIDE_INT) + lo |= (unsigned HOST_WIDE_INT) value << bitpos; + else + hi |= (unsigned HOST_WIDE_INT) value + << (bitpos - HOST_BITS_PER_WIDE_INT); + } + + return force_fit_type (build_int_cst_wide (type, lo, hi), + 0, false, false); +} + + +/* Subroutine of native_interpret_expr. Interpret the contents of + the buffer PTR of length LEN as a REAL_CST of type TYPE. + If the buffer cannot be interpreted, return NULL_TREE. */ + +static tree +native_interpret_real (tree type, unsigned char *ptr, int len) +{ + enum machine_mode mode = TYPE_MODE (type); + int total_bytes = GET_MODE_SIZE (mode); + int byte, offset, word, words, bitpos; + unsigned char value; + /* There are always 32 bits in each long, no matter the size of + the hosts long. We handle floating point representations with + up to 192 bits. */ + REAL_VALUE_TYPE r; + long tmp[6]; + + total_bytes = GET_MODE_SIZE (TYPE_MODE (type)); + if (total_bytes > len || total_bytes > 24) + return NULL_TREE; + words = 32 / UNITS_PER_WORD; + + memset (tmp, 0, sizeof (tmp)); + for (bitpos = 0; bitpos < total_bytes * BITS_PER_UNIT; + bitpos += BITS_PER_UNIT) + { + byte = (bitpos / BITS_PER_UNIT) & 3; + if (UNITS_PER_WORD < 4) + { + word = byte / UNITS_PER_WORD; + if (WORDS_BIG_ENDIAN) + word = (words - 1) - word; + offset = word * UNITS_PER_WORD; + if (BYTES_BIG_ENDIAN) + offset += (UNITS_PER_WORD - 1) - (byte % UNITS_PER_WORD); + else + offset += byte % UNITS_PER_WORD; + } + else + offset = BYTES_BIG_ENDIAN ? 3 - byte : byte; + value = ptr[offset + ((bitpos / BITS_PER_UNIT) & ~3)]; + + tmp[bitpos / 32] |= (unsigned long)value << (bitpos & 31); + } + + real_from_target (&r, tmp, mode); + return build_real (type, r); +} + + +/* Subroutine of native_interpret_expr. Interpret the contents of + the buffer PTR of length LEN as a COMPLEX_CST of type TYPE. + If the buffer cannot be interpreted, return NULL_TREE. */ + +static tree +native_interpret_complex (tree type, unsigned char *ptr, int len) +{ + tree etype, rpart, ipart; + int size; + + etype = TREE_TYPE (type); + size = GET_MODE_SIZE (TYPE_MODE (etype)); + if (size * 2 > len) + return NULL_TREE; + rpart = native_interpret_expr (etype, ptr, size); + if (!rpart) + return NULL_TREE; + ipart = native_interpret_expr (etype, ptr+size, size); + if (!ipart) + return NULL_TREE; + return build_complex (type, rpart, ipart); +} + + +/* Subroutine of native_interpret_expr. Interpret the contents of + the buffer PTR of length LEN as a VECTOR_CST of type TYPE. + If the buffer cannot be interpreted, return NULL_TREE. */ + +static tree +native_interpret_vector (tree type, unsigned char *ptr, int len) +{ + tree etype, elem, elements; + int i, size, count; + + etype = TREE_TYPE (type); + size = GET_MODE_SIZE (TYPE_MODE (etype)); + count = TYPE_VECTOR_SUBPARTS (type); + if (size * count > len) + return NULL_TREE; + + elements = NULL_TREE; + for (i = count - 1; i >= 0; i--) + { + elem = native_interpret_expr (etype, ptr+(i*size), size); + if (!elem) + return NULL_TREE; + elements = tree_cons (NULL_TREE, elem, elements); + } + return build_vector (type, elements); +} + + +/* Subroutine of fold_view_convert_expr. Interpret the contents of + the buffer PTR of length LEN as a constant of type TYPE. For + INTEGRAL_TYPE_P we return an INTEGER_CST, for SCALAR_FLOAT_TYPE_P + we return a REAL_CST, etc... If the buffer cannot be interpreted, + return NULL_TREE. */ + +static tree +native_interpret_expr (tree type, unsigned char *ptr, int len) +{ + switch (TREE_CODE (type)) + { + case INTEGER_TYPE: + case ENUMERAL_TYPE: + case BOOLEAN_TYPE: + return native_interpret_int (type, ptr, len); + + case REAL_TYPE: + return native_interpret_real (type, ptr, len); + + case COMPLEX_TYPE: + return native_interpret_complex (type, ptr, len); + + case VECTOR_TYPE: + return native_interpret_vector (type, ptr, len); + + default: + return NULL_TREE; + } +} + + +/* Fold a VIEW_CONVERT_EXPR of a constant expression EXPR to type + TYPE at compile-time. If we're unable to perform the conversion + return NULL_TREE. */ + +static tree +fold_view_convert_expr (tree type, tree expr) +{ + /* We support up to 512-bit values (for V8DFmode). */ + unsigned char buffer[64]; + int len; + + /* Check that the host and target are sane. */ + if (CHAR_BIT != 8 || BITS_PER_UNIT != 8) + return NULL_TREE; + + len = native_encode_expr (expr, buffer, sizeof (buffer)); + if (len == 0) + return NULL_TREE; + + return native_interpret_expr (type, buffer, len); +} + + +/* Fold a unary expression of code CODE and type TYPE with operand + OP0. Return the folded expression if folding is successful. + Otherwise, return NULL_TREE. */ + +tree +fold_unary (enum tree_code code, tree type, tree op0) +{ + tree tem; + tree arg0; + enum tree_code_class kind = TREE_CODE_CLASS (code); + + gcc_assert (IS_EXPR_CODE_CLASS (kind) + && TREE_CODE_LENGTH (code) == 1); + + arg0 = op0; + if (arg0) + { + if (code == NOP_EXPR || code == CONVERT_EXPR + || code == FLOAT_EXPR || code == ABS_EXPR) + { + /* Don't use STRIP_NOPS, because signedness of argument type + matters. */ + STRIP_SIGN_NOPS (arg0); + } + else + { + /* Strip any conversions that don't change the mode. This + is safe for every expression, except for a comparison + expression because its signedness is derived from its + operands. + + Note that this is done as an internal manipulation within + the constant folder, in order to find the simplest + representation of the arguments so that their form can be + studied. In any cases, the appropriate type conversions + should be put back in the tree that will get out of the + constant folder. */ + STRIP_NOPS (arg0); + } + } + + if (TREE_CODE_CLASS (code) == tcc_unary) + { + if (TREE_CODE (arg0) == COMPOUND_EXPR) + return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0), + fold_build1 (code, type, TREE_OPERAND (arg0, 1))); + else if (TREE_CODE (arg0) == COND_EXPR) + { + tree arg01 = TREE_OPERAND (arg0, 1); + tree arg02 = TREE_OPERAND (arg0, 2); + if (! VOID_TYPE_P (TREE_TYPE (arg01))) + arg01 = fold_build1 (code, type, arg01); + if (! VOID_TYPE_P (TREE_TYPE (arg02))) + arg02 = fold_build1 (code, type, arg02); + tem = fold_build3 (COND_EXPR, type, TREE_OPERAND (arg0, 0), + arg01, arg02); + + /* If this was a conversion, and all we did was to move into + inside the COND_EXPR, bring it back out. But leave it if + it is a conversion from integer to integer and the + result precision is no wider than a word since such a + conversion is cheap and may be optimized away by combine, + while it couldn't if it were outside the COND_EXPR. Then return + so we don't get into an infinite recursion loop taking the + conversion out and then back in. */ + + if ((code == NOP_EXPR || code == CONVERT_EXPR + || code == NON_LVALUE_EXPR) + && TREE_CODE (tem) == COND_EXPR + && TREE_CODE (TREE_OPERAND (tem, 1)) == code + && TREE_CODE (TREE_OPERAND (tem, 2)) == code + && ! VOID_TYPE_P (TREE_OPERAND (tem, 1)) + && ! VOID_TYPE_P (TREE_OPERAND (tem, 2)) + && (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (tem, 1), 0)) + == TREE_TYPE (TREE_OPERAND (TREE_OPERAND (tem, 2), 0))) + && (! (INTEGRAL_TYPE_P (TREE_TYPE (tem)) + && (INTEGRAL_TYPE_P + (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (tem, 1), 0)))) + && TYPE_PRECISION (TREE_TYPE (tem)) <= BITS_PER_WORD) + || flag_syntax_only)) + tem = build1 (code, type, + build3 (COND_EXPR, + TREE_TYPE (TREE_OPERAND + (TREE_OPERAND (tem, 1), 0)), + TREE_OPERAND (tem, 0), + TREE_OPERAND (TREE_OPERAND (tem, 1), 0), + TREE_OPERAND (TREE_OPERAND (tem, 2), 0))); + return tem; + } + else if (COMPARISON_CLASS_P (arg0)) + { + if (TREE_CODE (type) == BOOLEAN_TYPE) + { + arg0 = copy_node (arg0); + TREE_TYPE (arg0) = type; + return arg0; + } + else if (TREE_CODE (type) != INTEGER_TYPE) + return fold_build3 (COND_EXPR, type, arg0, + fold_build1 (code, type, + integer_one_node), + fold_build1 (code, type, + integer_zero_node)); + } + } + + switch (code) + { + case NOP_EXPR: + case FLOAT_EXPR: + case CONVERT_EXPR: + case FIX_TRUNC_EXPR: + case FIX_CEIL_EXPR: + case FIX_FLOOR_EXPR: + case FIX_ROUND_EXPR: + if (TREE_TYPE (op0) == type) + return op0; + + /* If we have (type) (a CMP b) and type is an integral type, return + new expression involving the new type. */ + if (COMPARISON_CLASS_P (op0) && INTEGRAL_TYPE_P (type)) + return fold_build2 (TREE_CODE (op0), type, TREE_OPERAND (op0, 0), + TREE_OPERAND (op0, 1)); + + /* Handle cases of two conversions in a row. */ + if (TREE_CODE (op0) == NOP_EXPR + || TREE_CODE (op0) == CONVERT_EXPR) + { + tree inside_type = TREE_TYPE (TREE_OPERAND (op0, 0)); + tree inter_type = TREE_TYPE (op0); + int inside_int = INTEGRAL_TYPE_P (inside_type); + int inside_ptr = POINTER_TYPE_P (inside_type); + int inside_float = FLOAT_TYPE_P (inside_type); + int inside_vec = TREE_CODE (inside_type) == VECTOR_TYPE; + unsigned int inside_prec = TYPE_PRECISION (inside_type); + int inside_unsignedp = TYPE_UNSIGNED (inside_type); + int inter_int = INTEGRAL_TYPE_P (inter_type); + int inter_ptr = POINTER_TYPE_P (inter_type); + int inter_float = FLOAT_TYPE_P (inter_type); + int inter_vec = TREE_CODE (inter_type) == VECTOR_TYPE; + unsigned int inter_prec = TYPE_PRECISION (inter_type); + int inter_unsignedp = TYPE_UNSIGNED (inter_type); + int final_int = INTEGRAL_TYPE_P (type); + int final_ptr = POINTER_TYPE_P (type); + int final_float = FLOAT_TYPE_P (type); + int final_vec = TREE_CODE (type) == VECTOR_TYPE; + unsigned int final_prec = TYPE_PRECISION (type); + int final_unsignedp = TYPE_UNSIGNED (type); + + /* In addition to the cases of two conversions in a row + handled below, if we are converting something to its own + type via an object of identical or wider precision, neither + conversion is needed. */ + if (TYPE_MAIN_VARIANT (inside_type) == TYPE_MAIN_VARIANT (type) + && (((inter_int || inter_ptr) && final_int) + || (inter_float && final_float)) + && inter_prec >= final_prec) + return fold_build1 (code, type, TREE_OPERAND (op0, 0)); + + /* Likewise, if the intermediate and final types are either both + float or both integer, we don't need the middle conversion if + it is wider than the final type and doesn't change the signedness + (for integers). Avoid this if the final type is a pointer + since then we sometimes need the inner conversion. Likewise if + the outer has a precision not equal to the size of its mode. */ + if ((((inter_int || inter_ptr) && (inside_int || inside_ptr)) + || (inter_float && inside_float) + || (inter_vec && inside_vec)) + && inter_prec >= inside_prec + && (inter_float || inter_vec + || inter_unsignedp == inside_unsignedp) + && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (type)) + && TYPE_MODE (type) == TYPE_MODE (inter_type)) + && ! final_ptr + && (! final_vec || inter_prec == inside_prec)) + return fold_build1 (code, type, TREE_OPERAND (op0, 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 fold_build1 (code, type, TREE_OPERAND (op0, 0)); + + /* Two conversions in a row are not needed unless: + - some conversion is floating-point (overstrict for now), or + - some conversion is a vector (overstrict for now), or + - the intermediate type is narrower than both initial and + final, or + - the intermediate type and innermost type differ in signedness, + and the outermost type is wider than the intermediate, or + - the initial type is a pointer type and the precisions of the + intermediate and final types differ, or + - the final type is a pointer type and the precisions of the + initial and intermediate types differ. + - the final type is a pointer type and the initial type not + - the initial type is a pointer to an array and the final type + not. */ + /* Java pointer type conversions generate checks in some + cases, so we explicitly disallow this optimization. */ + if (! inside_float && ! inter_float && ! final_float + && ! inside_vec && ! inter_vec && ! final_vec + && (inter_prec >= inside_prec || inter_prec >= final_prec) + && ! (inside_int && inter_int + && inter_unsignedp != inside_unsignedp + && inter_prec < final_prec) + && ((inter_unsignedp && inter_prec > inside_prec) + == (final_unsignedp && final_prec > inter_prec)) + && ! (inside_ptr && inter_prec != final_prec) + && ! (final_ptr && inside_prec != inter_prec) + && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (type)) + && TYPE_MODE (type) == TYPE_MODE (inter_type)) + && final_ptr == inside_ptr + && ! (inside_ptr + && TREE_CODE (TREE_TYPE (inside_type)) == ARRAY_TYPE + && TREE_CODE (TREE_TYPE (type)) != ARRAY_TYPE) + && ! ((strcmp (lang_hooks.name, "GNU Java") == 0) + && final_ptr)) + return fold_build1 (code, type, TREE_OPERAND (op0, 0)); + } + + /* Handle (T *)&A.B.C for A being of type T and B and C + living at offset zero. This occurs frequently in + C++ upcasting and then accessing the base. */ + if (TREE_CODE (op0) == ADDR_EXPR + && POINTER_TYPE_P (type) + && handled_component_p (TREE_OPERAND (op0, 0))) + { + HOST_WIDE_INT bitsize, bitpos; + tree offset; + enum machine_mode mode; + int unsignedp, volatilep; + tree base = TREE_OPERAND (op0, 0); + base = get_inner_reference (base, &bitsize, &bitpos, &offset, + &mode, &unsignedp, &volatilep, false); + /* If the reference was to a (constant) zero offset, we can use + the address of the base if it has the same base type + as the result type. */ + if (! offset && bitpos == 0 + && TYPE_MAIN_VARIANT (TREE_TYPE (type)) + == TYPE_MAIN_VARIANT (TREE_TYPE (base))) + return fold_convert (type, build_fold_addr_expr (base)); + } + + if (TREE_CODE (op0) == MODIFY_EXPR + && TREE_CONSTANT (TREE_OPERAND (op0, 1)) + /* Detect assigning a bitfield. */ + && !(TREE_CODE (TREE_OPERAND (op0, 0)) == COMPONENT_REF + && DECL_BIT_FIELD (TREE_OPERAND (TREE_OPERAND (op0, 0), 1)))) + { + /* Don't leave an assignment inside a conversion + unless assigning a bitfield. */ + tem = fold_build1 (code, type, TREE_OPERAND (op0, 1)); + /* First do the assignment, then return converted constant. */ + tem = build2 (COMPOUND_EXPR, TREE_TYPE (tem), op0, tem); + TREE_NO_WARNING (tem) = 1; + TREE_USED (tem) = 1; + return tem; + } + + /* Convert (T)(x & c) into (T)x & (T)c, if c is an integer + constants (if x has signed type, the sign bit cannot be set + in c). This folds extension into the BIT_AND_EXPR. */ + if (INTEGRAL_TYPE_P (type) + && TREE_CODE (type) != BOOLEAN_TYPE + && TREE_CODE (op0) == BIT_AND_EXPR + && TREE_CODE (TREE_OPERAND (op0, 1)) == INTEGER_CST) + { + tree and = op0; + tree and0 = TREE_OPERAND (and, 0), and1 = TREE_OPERAND (and, 1); + int change = 0; + + if (TYPE_UNSIGNED (TREE_TYPE (and)) + || (TYPE_PRECISION (type) + <= TYPE_PRECISION (TREE_TYPE (and)))) + change = 1; + else if (TYPE_PRECISION (TREE_TYPE (and1)) + <= HOST_BITS_PER_WIDE_INT + && host_integerp (and1, 1)) + { + unsigned HOST_WIDE_INT cst; + + cst = tree_low_cst (and1, 1); + cst &= (HOST_WIDE_INT) -1 + << (TYPE_PRECISION (TREE_TYPE (and1)) - 1); + change = (cst == 0); +#ifdef LOAD_EXTEND_OP + if (change + && !flag_syntax_only + && (LOAD_EXTEND_OP (TYPE_MODE (TREE_TYPE (and0))) + == ZERO_EXTEND)) + { + tree uns = lang_hooks.types.unsigned_type (TREE_TYPE (and0)); + and0 = fold_convert (uns, and0); + and1 = fold_convert (uns, and1); + } +#endif + } + if (change) + { + tem = build_int_cst_wide (type, TREE_INT_CST_LOW (and1), + TREE_INT_CST_HIGH (and1)); + tem = force_fit_type (tem, 0, TREE_OVERFLOW (and1), + TREE_CONSTANT_OVERFLOW (and1)); + return fold_build2 (BIT_AND_EXPR, type, + fold_convert (type, and0), tem); + } + } + + /* Convert (T1)((T2)X op Y) into (T1)X op Y, for pointer types T1 and + T2 being pointers to types of the same size. */ + if (POINTER_TYPE_P (type) + && BINARY_CLASS_P (arg0) + && TREE_CODE (TREE_OPERAND (arg0, 0)) == NOP_EXPR + && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (arg0, 0)))) + { + tree arg00 = TREE_OPERAND (arg0, 0); + tree t0 = type; + tree t1 = TREE_TYPE (arg00); + tree tt0 = TREE_TYPE (t0); + tree tt1 = TREE_TYPE (t1); + tree s0 = TYPE_SIZE (tt0); + tree s1 = TYPE_SIZE (tt1); + + if (s0 && s1 && operand_equal_p (s0, s1, OEP_ONLY_CONST)) + return build2 (TREE_CODE (arg0), t0, fold_convert (t0, arg00), + TREE_OPERAND (arg0, 1)); + } + + /* Convert (T1)(~(T2)X) into ~(T1)X if T1 and T2 are integral types + of the same precision, and X is a integer type not narrower than + types T1 or T2, i.e. the cast (T2)X isn't an extension. */ + if (INTEGRAL_TYPE_P (type) + && TREE_CODE (op0) == BIT_NOT_EXPR + && INTEGRAL_TYPE_P (TREE_TYPE (op0)) + && (TREE_CODE (TREE_OPERAND (op0, 0)) == NOP_EXPR + || TREE_CODE (TREE_OPERAND (op0, 0)) == CONVERT_EXPR) + && TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (op0))) + { + tem = TREE_OPERAND (TREE_OPERAND (op0, 0), 0); + if (INTEGRAL_TYPE_P (TREE_TYPE (tem)) + && TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (tem))) + return fold_build1 (BIT_NOT_EXPR, type, fold_convert (type, tem)); + } + + tem = fold_convert_const (code, type, op0); + return tem ? tem : NULL_TREE; + + case VIEW_CONVERT_EXPR: + if (TREE_CODE (op0) == VIEW_CONVERT_EXPR) + return fold_build1 (VIEW_CONVERT_EXPR, type, TREE_OPERAND (op0, 0)); + return fold_view_convert_expr (type, op0); + + case NEGATE_EXPR: + tem = fold_negate_expr (arg0); + if (tem) + return fold_convert (type, tem); + return NULL_TREE; + + case ABS_EXPR: + if (TREE_CODE (arg0) == INTEGER_CST || TREE_CODE (arg0) == REAL_CST) + return fold_abs_const (arg0, type); + else if (TREE_CODE (arg0) == NEGATE_EXPR) + return fold_build1 (ABS_EXPR, type, TREE_OPERAND (arg0, 0)); + /* Convert fabs((double)float) into (double)fabsf(float). */ + else if (TREE_CODE (arg0) == NOP_EXPR + && TREE_CODE (type) == REAL_TYPE) + { + tree targ0 = strip_float_extensions (arg0); + if (targ0 != arg0) + return fold_convert (type, fold_build1 (ABS_EXPR, + TREE_TYPE (targ0), + targ0)); + } + /* ABS_EXPR<ABS_EXPR<x>> = ABS_EXPR<x> even if flag_wrapv is on. */ + else if (TREE_CODE (arg0) == ABS_EXPR) + return arg0; + else if (tree_expr_nonnegative_p (arg0)) + return arg0; + + /* Strip sign ops from argument. */ + if (TREE_CODE (type) == REAL_TYPE) + { + tem = fold_strip_sign_ops (arg0); + if (tem) + return fold_build1 (ABS_EXPR, type, fold_convert (type, tem)); + } + return NULL_TREE; + + case CONJ_EXPR: + if (TREE_CODE (TREE_TYPE (arg0)) != COMPLEX_TYPE) + return fold_convert (type, arg0); + if (TREE_CODE (arg0) == COMPLEX_EXPR) + { + tree itype = TREE_TYPE (type); + tree rpart = fold_convert (itype, TREE_OPERAND (arg0, 0)); + tree ipart = fold_convert (itype, TREE_OPERAND (arg0, 1)); + return fold_build2 (COMPLEX_EXPR, type, rpart, negate_expr (ipart)); + } + if (TREE_CODE (arg0) == COMPLEX_CST) + { + tree itype = TREE_TYPE (type); + tree rpart = fold_convert (itype, TREE_REALPART (arg0)); + tree ipart = fold_convert (itype, TREE_IMAGPART (arg0)); + return build_complex (type, rpart, negate_expr (ipart)); + } + if (TREE_CODE (arg0) == CONJ_EXPR) + return fold_convert (type, TREE_OPERAND (arg0, 0)); + return NULL_TREE; + + case BIT_NOT_EXPR: + if (TREE_CODE (arg0) == INTEGER_CST) + return fold_not_const (arg0, type); + else if (TREE_CODE (arg0) == BIT_NOT_EXPR) + return TREE_OPERAND (arg0, 0); + /* Convert ~ (-A) to A - 1. */ + else if (INTEGRAL_TYPE_P (type) && TREE_CODE (arg0) == NEGATE_EXPR) + return fold_build2 (MINUS_EXPR, type, TREE_OPERAND (arg0, 0), + build_int_cst (type, 1)); + /* Convert ~ (A - 1) or ~ (A + -1) to -A. */ + else if (INTEGRAL_TYPE_P (type) + && ((TREE_CODE (arg0) == MINUS_EXPR + && integer_onep (TREE_OPERAND (arg0, 1))) + || (TREE_CODE (arg0) == PLUS_EXPR + && integer_all_onesp (TREE_OPERAND (arg0, 1))))) + return fold_build1 (NEGATE_EXPR, type, TREE_OPERAND (arg0, 0)); + /* Convert ~(X ^ Y) to ~X ^ Y or X ^ ~Y if ~X or ~Y simplify. */ + else if (TREE_CODE (arg0) == BIT_XOR_EXPR + && (tem = fold_unary (BIT_NOT_EXPR, type, + fold_convert (type, + TREE_OPERAND (arg0, 0))))) + return fold_build2 (BIT_XOR_EXPR, type, tem, + fold_convert (type, TREE_OPERAND (arg0, 1))); + else if (TREE_CODE (arg0) == BIT_XOR_EXPR + && (tem = fold_unary (BIT_NOT_EXPR, type, + fold_convert (type, + TREE_OPERAND (arg0, 1))))) + return fold_build2 (BIT_XOR_EXPR, type, + fold_convert (type, TREE_OPERAND (arg0, 0)), tem); + + return NULL_TREE; + + case TRUTH_NOT_EXPR: + /* The argument to invert_truthvalue must have Boolean type. */ + if (TREE_CODE (TREE_TYPE (arg0)) != BOOLEAN_TYPE) + arg0 = fold_convert (boolean_type_node, arg0); + + /* 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.) */ + tem = fold_truth_not_expr (arg0); + if (!tem) + return NULL_TREE; + return fold_convert (type, tem); + + case REALPART_EXPR: + if (TREE_CODE (TREE_TYPE (arg0)) != COMPLEX_TYPE) + return fold_convert (type, arg0); + if (TREE_CODE (arg0) == COMPLEX_EXPR) + return omit_one_operand (type, TREE_OPERAND (arg0, 0), + TREE_OPERAND (arg0, 1)); + if (TREE_CODE (arg0) == COMPLEX_CST) + return fold_convert (type, TREE_REALPART (arg0)); + if (TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR) + { + tree itype = TREE_TYPE (TREE_TYPE (arg0)); + tem = fold_build2 (TREE_CODE (arg0), itype, + fold_build1 (REALPART_EXPR, itype, + TREE_OPERAND (arg0, 0)), + fold_build1 (REALPART_EXPR, itype, + TREE_OPERAND (arg0, 1))); + return fold_convert (type, tem); + } + if (TREE_CODE (arg0) == CONJ_EXPR) + { + tree itype = TREE_TYPE (TREE_TYPE (arg0)); + tem = fold_build1 (REALPART_EXPR, itype, TREE_OPERAND (arg0, 0)); + return fold_convert (type, tem); + } + return NULL_TREE; + + case IMAGPART_EXPR: + if (TREE_CODE (TREE_TYPE (arg0)) != COMPLEX_TYPE) + return fold_convert (type, integer_zero_node); + if (TREE_CODE (arg0) == COMPLEX_EXPR) + return omit_one_operand (type, TREE_OPERAND (arg0, 1), + TREE_OPERAND (arg0, 0)); + if (TREE_CODE (arg0) == COMPLEX_CST) + return fold_convert (type, TREE_IMAGPART (arg0)); + if (TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR) + { + tree itype = TREE_TYPE (TREE_TYPE (arg0)); + tem = fold_build2 (TREE_CODE (arg0), itype, + fold_build1 (IMAGPART_EXPR, itype, + TREE_OPERAND (arg0, 0)), + fold_build1 (IMAGPART_EXPR, itype, + TREE_OPERAND (arg0, 1))); + return fold_convert (type, tem); + } + if (TREE_CODE (arg0) == CONJ_EXPR) + { + tree itype = TREE_TYPE (TREE_TYPE (arg0)); + tem = fold_build1 (IMAGPART_EXPR, itype, TREE_OPERAND (arg0, 0)); + return fold_convert (type, negate_expr (tem)); + } + return NULL_TREE; + + default: + return NULL_TREE; + } /* switch (code) */ +} + +/* Fold a binary expression of code CODE and type TYPE with operands + OP0 and OP1, containing either a MIN-MAX or a MAX-MIN combination. + Return the folded expression if folding is successful. Otherwise, + return NULL_TREE. */ + +static tree +fold_minmax (enum tree_code code, tree type, tree op0, tree op1) +{ + enum tree_code compl_code; + + if (code == MIN_EXPR) + compl_code = MAX_EXPR; + else if (code == MAX_EXPR) + compl_code = MIN_EXPR; + else + gcc_unreachable (); + + /* MIN (MAX (a, b), b) == b. */ + if (TREE_CODE (op0) == compl_code + && operand_equal_p (TREE_OPERAND (op0, 1), op1, 0)) + return omit_one_operand (type, op1, TREE_OPERAND (op0, 0)); + + /* MIN (MAX (b, a), b) == b. */ + if (TREE_CODE (op0) == compl_code + && operand_equal_p (TREE_OPERAND (op0, 0), op1, 0) + && reorder_operands_p (TREE_OPERAND (op0, 1), op1)) + return omit_one_operand (type, op1, TREE_OPERAND (op0, 1)); + + /* MIN (a, MAX (a, b)) == a. */ + if (TREE_CODE (op1) == compl_code + && operand_equal_p (op0, TREE_OPERAND (op1, 0), 0) + && reorder_operands_p (op0, TREE_OPERAND (op1, 1))) + return omit_one_operand (type, op0, TREE_OPERAND (op1, 1)); + + /* MIN (a, MAX (b, a)) == a. */ + if (TREE_CODE (op1) == compl_code + && operand_equal_p (op0, TREE_OPERAND (op1, 1), 0) + && reorder_operands_p (op0, TREE_OPERAND (op1, 0))) + return omit_one_operand (type, op0, TREE_OPERAND (op1, 0)); + + return NULL_TREE; +} + +/* Subroutine of fold_binary. This routine performs all of the + transformations that are common to the equality/inequality + operators (EQ_EXPR and NE_EXPR) and the ordering operators + (LT_EXPR, LE_EXPR, GE_EXPR and GT_EXPR). Callers other than + fold_binary should call fold_binary. Fold a comparison with + tree code CODE and type TYPE with operands OP0 and OP1. Return + the folded comparison or NULL_TREE. */ + +static tree +fold_comparison (enum tree_code code, tree type, tree op0, tree op1) +{ + tree arg0, arg1, tem; + + arg0 = op0; + arg1 = op1; + + STRIP_SIGN_NOPS (arg0); + STRIP_SIGN_NOPS (arg1); + + tem = fold_relational_const (code, type, arg0, arg1); + if (tem != NULL_TREE) + return tem; + + /* If one arg is a real or integer constant, put it last. */ + if (tree_swap_operands_p (arg0, arg1, true)) + return fold_build2 (swap_tree_comparison (code), type, op1, op0); + + /* Transform comparisons of the form X +- C1 CMP C2 to X CMP C2 +- C1. */ + if ((TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR) + && (TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST + && !TREE_OVERFLOW (TREE_OPERAND (arg0, 1)) + && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1))) + && (TREE_CODE (arg1) == INTEGER_CST + && !TREE_OVERFLOW (arg1))) + { + tree const1 = TREE_OPERAND (arg0, 1); + tree const2 = arg1; + tree variable = TREE_OPERAND (arg0, 0); + tree lhs; + int lhs_add; + lhs_add = TREE_CODE (arg0) != PLUS_EXPR; + + lhs = fold_build2 (lhs_add ? PLUS_EXPR : MINUS_EXPR, + TREE_TYPE (arg1), const2, const1); + if (TREE_CODE (lhs) == TREE_CODE (arg1) + && (TREE_CODE (lhs) != INTEGER_CST + || !TREE_OVERFLOW (lhs))) + { + fold_overflow_warning (("assuming signed overflow does not occur " + "when changing X +- C1 cmp C2 to " + "X cmp C1 +- C2"), + WARN_STRICT_OVERFLOW_COMPARISON); + return fold_build2 (code, type, variable, lhs); + } + } + + /* If this is a comparison of two exprs that look like an ARRAY_REF of the + same object, then we can fold this to a comparison of the two offsets in + signed size type. This is possible because pointer arithmetic is + restricted to retain within an object and overflow on pointer differences + is undefined as of 6.5.6/8 and /9 with respect to the signed ptrdiff_t. + + We check flag_wrapv directly because pointers types are unsigned, + and therefore TYPE_OVERFLOW_WRAPS returns true for them. That is + normally what we want to avoid certain odd overflow cases, but + not here. */ + if (POINTER_TYPE_P (TREE_TYPE (arg0)) + && !flag_wrapv + && !TYPE_OVERFLOW_TRAPS (TREE_TYPE (arg0))) + { + tree base0, offset0, base1, offset1; + + if (extract_array_ref (arg0, &base0, &offset0) + && extract_array_ref (arg1, &base1, &offset1) + && operand_equal_p (base0, base1, 0)) + { + tree signed_size_type_node; + signed_size_type_node = signed_type_for (size_type_node); + + /* By converting to signed size type we cover middle-end pointer + arithmetic which operates on unsigned pointer types of size + type size and ARRAY_REF offsets which are properly sign or + zero extended from their type in case it is narrower than + size type. */ + if (offset0 == NULL_TREE) + offset0 = build_int_cst (signed_size_type_node, 0); + else + offset0 = fold_convert (signed_size_type_node, offset0); + if (offset1 == NULL_TREE) + offset1 = build_int_cst (signed_size_type_node, 0); + else + offset1 = fold_convert (signed_size_type_node, offset1); + + return fold_build2 (code, type, offset0, offset1); + } + } + + if (FLOAT_TYPE_P (TREE_TYPE (arg0))) + { + tree targ0 = strip_float_extensions (arg0); + tree targ1 = strip_float_extensions (arg1); + tree newtype = TREE_TYPE (targ0); + + if (TYPE_PRECISION (TREE_TYPE (targ1)) > TYPE_PRECISION (newtype)) + newtype = TREE_TYPE (targ1); + + /* Fold (double)float1 CMP (double)float2 into float1 CMP float2. */ + if (TYPE_PRECISION (newtype) < TYPE_PRECISION (TREE_TYPE (arg0))) + return fold_build2 (code, type, fold_convert (newtype, targ0), + fold_convert (newtype, targ1)); + + /* (-a) CMP (-b) -> b CMP a */ + if (TREE_CODE (arg0) == NEGATE_EXPR + && TREE_CODE (arg1) == NEGATE_EXPR) + return fold_build2 (code, type, TREE_OPERAND (arg1, 0), + TREE_OPERAND (arg0, 0)); + + if (TREE_CODE (arg1) == REAL_CST) + { + REAL_VALUE_TYPE cst; + cst = TREE_REAL_CST (arg1); + + /* (-a) CMP CST -> a swap(CMP) (-CST) */ + if (TREE_CODE (arg0) == NEGATE_EXPR) + return fold_build2 (swap_tree_comparison (code), type, + TREE_OPERAND (arg0, 0), + build_real (TREE_TYPE (arg1), + REAL_VALUE_NEGATE (cst))); + + /* IEEE doesn't distinguish +0 and -0 in comparisons. */ + /* a CMP (-0) -> a CMP 0 */ + if (REAL_VALUE_MINUS_ZERO (cst)) + return fold_build2 (code, type, arg0, + build_real (TREE_TYPE (arg1), dconst0)); + + /* x != NaN is always true, other ops are always false. */ + if (REAL_VALUE_ISNAN (cst) + && ! HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg1)))) + { + tem = (code == NE_EXPR) ? integer_one_node : integer_zero_node; + return omit_one_operand (type, tem, arg0); + } + + /* Fold comparisons against infinity. */ + if (REAL_VALUE_ISINF (cst)) + { + tem = fold_inf_compare (code, type, arg0, arg1); + if (tem != NULL_TREE) + return tem; + } + } + + /* If this is a comparison of a real constant with a PLUS_EXPR + or a MINUS_EXPR of a real constant, we can convert it into a + comparison with a revised real constant as long as no overflow + occurs when unsafe_math_optimizations are enabled. */ + if (flag_unsafe_math_optimizations + && TREE_CODE (arg1) == REAL_CST + && (TREE_CODE (arg0) == PLUS_EXPR + || TREE_CODE (arg0) == MINUS_EXPR) + && TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST + && 0 != (tem = const_binop (TREE_CODE (arg0) == PLUS_EXPR + ? MINUS_EXPR : PLUS_EXPR, + arg1, TREE_OPERAND (arg0, 1), 0)) + && ! TREE_CONSTANT_OVERFLOW (tem)) + return fold_build2 (code, type, TREE_OPERAND (arg0, 0), tem); + + /* Likewise, we can simplify a comparison of a real constant with + a MINUS_EXPR whose first operand is also a real constant, i.e. + (c1 - x) < c2 becomes x > c1-c2. */ + if (flag_unsafe_math_optimizations + && TREE_CODE (arg1) == REAL_CST + && TREE_CODE (arg0) == MINUS_EXPR + && TREE_CODE (TREE_OPERAND (arg0, 0)) == REAL_CST + && 0 != (tem = const_binop (MINUS_EXPR, TREE_OPERAND (arg0, 0), + arg1, 0)) + && ! TREE_CONSTANT_OVERFLOW (tem)) + return fold_build2 (swap_tree_comparison (code), type, + TREE_OPERAND (arg0, 1), tem); + + /* Fold comparisons against built-in math functions. */ + if (TREE_CODE (arg1) == REAL_CST + && flag_unsafe_math_optimizations + && ! flag_errno_math) + { + enum built_in_function fcode = builtin_mathfn_code (arg0); + + if (fcode != END_BUILTINS) + { + tem = fold_mathfn_compare (fcode, code, type, arg0, arg1); + if (tem != NULL_TREE) + return tem; + } + } + } + + /* Convert foo++ == CONST into ++foo == CONST + INCR. */ + if (TREE_CONSTANT (arg1) + && (TREE_CODE (arg0) == POSTINCREMENT_EXPR + || TREE_CODE (arg0) == POSTDECREMENT_EXPR) + /* This optimization is invalid for ordered comparisons + 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. */ + && (POINTER_TYPE_P (TREE_TYPE (arg0)) + || (INTEGRAL_TYPE_P (TREE_TYPE (arg0)) + && (code == EQ_EXPR || code == NE_EXPR)))) + { + tree varop, newconst; + + if (TREE_CODE (arg0) == POSTINCREMENT_EXPR) + { + newconst = fold_build2 (PLUS_EXPR, TREE_TYPE (arg0), + arg1, TREE_OPERAND (arg0, 1)); + varop = build2 (PREINCREMENT_EXPR, TREE_TYPE (arg0), + TREE_OPERAND (arg0, 0), + TREE_OPERAND (arg0, 1)); + } + else + { + newconst = fold_build2 (MINUS_EXPR, TREE_TYPE (arg0), + arg1, TREE_OPERAND (arg0, 1)); + varop = build2 (PREDECREMENT_EXPR, TREE_TYPE (arg0), + TREE_OPERAND (arg0, 0), + TREE_OPERAND (arg0, 1)); + } + + + /* If VAROP is a reference to a bitfield, we must mask + the constant by the width of the field. */ + if (TREE_CODE (TREE_OPERAND (varop, 0)) == COMPONENT_REF + && DECL_BIT_FIELD (TREE_OPERAND (TREE_OPERAND (varop, 0), 1)) + && host_integerp (DECL_SIZE (TREE_OPERAND + (TREE_OPERAND (varop, 0), 1)), 1)) + { + tree fielddecl = TREE_OPERAND (TREE_OPERAND (varop, 0), 1); + HOST_WIDE_INT size = tree_low_cst (DECL_SIZE (fielddecl), 1); + tree folded_compare, shift; + + /* 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. */ + folded_compare = fold_build2 (code, type, + TREE_OPERAND (varop, 0), arg1); + if (TREE_CODE (folded_compare) == INTEGER_CST) + return omit_one_operand (type, folded_compare, varop); + + shift = build_int_cst (NULL_TREE, + TYPE_PRECISION (TREE_TYPE (varop)) - size); + shift = fold_convert (TREE_TYPE (varop), shift); + newconst = fold_build2 (LSHIFT_EXPR, TREE_TYPE (varop), + newconst, shift); + newconst = fold_build2 (RSHIFT_EXPR, TREE_TYPE (varop), + newconst, shift); + } + + return fold_build2 (code, type, varop, newconst); + } + + if (TREE_CODE (TREE_TYPE (arg0)) == INTEGER_TYPE + && (TREE_CODE (arg0) == NOP_EXPR + || TREE_CODE (arg0) == CONVERT_EXPR)) + { + /* If we are widening one operand of an integer comparison, + see if the other operand is similarly being widened. Perhaps we + can do the comparison in the narrower type. */ + tem = fold_widened_comparison (code, type, arg0, arg1); + if (tem) + return tem; + + /* Or if we are changing signedness. */ + tem = fold_sign_changed_comparison (code, type, arg0, arg1); + if (tem) + return tem; + } + + /* If this is comparing a constant with a MIN_EXPR or a MAX_EXPR of a + constant, we can simplify it. */ + if (TREE_CODE (arg1) == INTEGER_CST + && (TREE_CODE (arg0) == MIN_EXPR + || TREE_CODE (arg0) == MAX_EXPR) + && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST) + { + tem = optimize_minmax_comparison (code, type, op0, op1); + if (tem) + return tem; + } + + /* Simplify comparison of something with itself. (For IEEE + floating-point, we can only do some of these simplifications.) */ + if (operand_equal_p (arg0, arg1, 0)) + { + switch (code) + { + case EQ_EXPR: + if (! FLOAT_TYPE_P (TREE_TYPE (arg0)) + || ! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0)))) + return constant_boolean_node (1, type); + break; + + case GE_EXPR: + case LE_EXPR: + if (! FLOAT_TYPE_P (TREE_TYPE (arg0)) + || ! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0)))) + return constant_boolean_node (1, type); + return fold_build2 (EQ_EXPR, type, arg0, arg1); + + case NE_EXPR: + /* For NE, we can only do this simplification if integer + or we don't honor IEEE floating point NaNs. */ + if (FLOAT_TYPE_P (TREE_TYPE (arg0)) + && HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0)))) + break; + /* ... fall through ... */ + case GT_EXPR: + case LT_EXPR: + return constant_boolean_node (0, type); + default: + gcc_unreachable (); + } + } + + /* If we are comparing an expression that just has comparisons + of two integer values, arithmetic expressions of those comparisons, + and constants, we can simplify it. There are only three cases + to check: the two values can either be equal, the first can be + greater, or the second can be greater. Fold the expression for + those three values. Since each value must be 0 or 1, we have + eight possibilities, each of which corresponds to the constant 0 + or 1 or one of the six possible comparisons. + + This handles common cases like (a > b) == 0 but also handles + expressions like ((x > y) - (y > x)) > 0, which supposedly + occur in macroized code. */ + + if (TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg0) != INTEGER_CST) + { + tree cval1 = 0, cval2 = 0; + int save_p = 0; + + if (twoval_comparison_p (arg0, &cval1, &cval2, &save_p) + /* Don't handle degenerate cases here; they should already + have been handled anyway. */ + && cval1 != 0 && cval2 != 0 + && ! (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)) + { + tree maxval = TYPE_MAX_VALUE (TREE_TYPE (cval1)); + tree minval = TYPE_MIN_VALUE (TREE_TYPE (cval1)); + + /* We can't just pass T to eval_subst in case cval1 or cval2 + was the same as ARG1. */ + + tree high_result + = fold_build2 (code, type, + eval_subst (arg0, cval1, maxval, + cval2, minval), + arg1); + tree equal_result + = fold_build2 (code, type, + eval_subst (arg0, cval1, maxval, + cval2, maxval), + arg1); + tree low_result + = fold_build2 (code, type, + eval_subst (arg0, cval1, minval, + cval2, maxval), + arg1); + + /* All three of these results should be 0 or 1. Confirm they are. + Then use those values to select the proper code to use. */ + + if (TREE_CODE (high_result) == INTEGER_CST + && TREE_CODE (equal_result) == INTEGER_CST + && TREE_CODE (low_result) == INTEGER_CST) + { + /* Make a 3-bit mask with the high-order bit being the + value for `>', the next for '=', and the low for '<'. */ + switch ((integer_onep (high_result) * 4) + + (integer_onep (equal_result) * 2) + + integer_onep (low_result)) + { + case 0: + /* Always false. */ + return omit_one_operand (type, integer_zero_node, arg0); + case 1: + code = LT_EXPR; + break; + case 2: + code = EQ_EXPR; + break; + case 3: + code = LE_EXPR; + break; + case 4: + code = GT_EXPR; + break; + case 5: + code = NE_EXPR; + break; + case 6: + code = GE_EXPR; + break; + case 7: + /* Always true. */ + return omit_one_operand (type, integer_one_node, arg0); + } + + if (save_p) + return save_expr (build2 (code, type, cval1, cval2)); + return fold_build2 (code, type, cval1, cval2); + } + } + } + + /* Fold a comparison of the address of COMPONENT_REFs with the same + type and component to a comparison of the address of the base + object. In short, &x->a OP &y->a to x OP y and + &x->a OP &y.a to x OP &y */ + if (TREE_CODE (arg0) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (arg0, 0)) == COMPONENT_REF + && TREE_CODE (arg1) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (arg1, 0)) == COMPONENT_REF) + { + tree cref0 = TREE_OPERAND (arg0, 0); + tree cref1 = TREE_OPERAND (arg1, 0); + if (TREE_OPERAND (cref0, 1) == TREE_OPERAND (cref1, 1)) + { + tree op0 = TREE_OPERAND (cref0, 0); + tree op1 = TREE_OPERAND (cref1, 0); + return fold_build2 (code, type, + build_fold_addr_expr (op0), + build_fold_addr_expr (op1)); + } + } + + /* We can fold X/C1 op C2 where C1 and C2 are integer constants + into a single range test. */ + if ((TREE_CODE (arg0) == TRUNC_DIV_EXPR + || TREE_CODE (arg0) == EXACT_DIV_EXPR) + && TREE_CODE (arg1) == INTEGER_CST + && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST + && !integer_zerop (TREE_OPERAND (arg0, 1)) + && !TREE_OVERFLOW (TREE_OPERAND (arg0, 1)) + && !TREE_OVERFLOW (arg1)) + { + tem = fold_div_compare (code, type, arg0, arg1); + if (tem != NULL_TREE) + return tem; + } + + return NULL_TREE; +} + + +/* Subroutine of fold_binary. Optimize complex multiplications of the + form z * conj(z), as pow(realpart(z),2) + pow(imagpart(z),2). The + argument EXPR represents the expression "z" of type TYPE. */ + +static tree +fold_mult_zconjz (tree type, tree expr) +{ + tree itype = TREE_TYPE (type); + tree rpart, ipart, tem; + + if (TREE_CODE (expr) == COMPLEX_EXPR) + { + rpart = TREE_OPERAND (expr, 0); + ipart = TREE_OPERAND (expr, 1); + } + else if (TREE_CODE (expr) == COMPLEX_CST) + { + rpart = TREE_REALPART (expr); + ipart = TREE_IMAGPART (expr); + } + else + { + expr = save_expr (expr); + rpart = fold_build1 (REALPART_EXPR, itype, expr); + ipart = fold_build1 (IMAGPART_EXPR, itype, expr); + } + + rpart = save_expr (rpart); + ipart = save_expr (ipart); + tem = fold_build2 (PLUS_EXPR, itype, + fold_build2 (MULT_EXPR, itype, rpart, rpart), + fold_build2 (MULT_EXPR, itype, ipart, ipart)); + return fold_build2 (COMPLEX_EXPR, type, tem, + fold_convert (itype, integer_zero_node)); +} + + +/* Fold a binary expression of code CODE and type TYPE with operands + OP0 and OP1. Return the folded expression if folding is + successful. Otherwise, return NULL_TREE. */ + +tree +fold_binary (enum tree_code code, tree type, tree op0, tree op1) +{ + enum tree_code_class kind = TREE_CODE_CLASS (code); + tree arg0, arg1, tem; + tree t1 = NULL_TREE; + bool strict_overflow_p; + + gcc_assert (IS_EXPR_CODE_CLASS (kind) + && TREE_CODE_LENGTH (code) == 2 + && op0 != NULL_TREE + && op1 != NULL_TREE); + + arg0 = op0; + arg1 = op1; + + /* Strip any conversions that don't change the mode. This is + safe for every expression, except for a comparison expression + because its signedness is derived from its operands. So, in + the latter case, only strip conversions that don't change the + signedness. + + Note that this is done as an internal manipulation within the + constant folder, in order to find the simplest representation + of the arguments so that their form can be studied. In any + cases, the appropriate type conversions should be put back in + the tree that will get out of the constant folder. */ + + if (kind == tcc_comparison) + { + STRIP_SIGN_NOPS (arg0); + STRIP_SIGN_NOPS (arg1); + } + else + { + STRIP_NOPS (arg0); + STRIP_NOPS (arg1); + } + + /* Note that TREE_CONSTANT isn't enough: static var addresses are + constant but we can't do arithmetic on them. */ + if ((TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST) + || (TREE_CODE (arg0) == REAL_CST && TREE_CODE (arg1) == REAL_CST) + || (TREE_CODE (arg0) == COMPLEX_CST && TREE_CODE (arg1) == COMPLEX_CST) + || (TREE_CODE (arg0) == VECTOR_CST && TREE_CODE (arg1) == VECTOR_CST)) + { + if (kind == tcc_binary) + tem = const_binop (code, arg0, arg1, 0); + else if (kind == tcc_comparison) + tem = fold_relational_const (code, type, arg0, arg1); + else + tem = NULL_TREE; + + if (tem != NULL_TREE) + { + if (TREE_TYPE (tem) != type) + tem = fold_convert (type, tem); + return tem; + } + } + + /* If this is a commutative operation, and ARG0 is a constant, move it + to ARG1 to reduce the number of tests below. */ + if (commutative_tree_code (code) + && tree_swap_operands_p (arg0, arg1, true)) + return fold_build2 (code, type, op1, op0); + + /* ARG0 is the first operand of EXPR, and ARG1 is the second operand. + + First check for cases where an arithmetic operation is applied to a + compound, conditional, or comparison operation. Push the arithmetic + operation inside the compound or conditional to see if any folding + can then be done. Convert comparison to conditional for this purpose. + The also optimizes non-constant cases that used to be done in + expand_expr. + + Before we do that, see if this is a BIT_AND_EXPR or a BIT_IOR_EXPR, + one of the operands is a comparison and the other is a comparison, a + BIT_AND_EXPR with the constant 1, or a truth value. In that case, the + code below would make the expression more complex. Change it to a + TRUTH_{AND,OR}_EXPR. Likewise, convert a similar NE_EXPR to + TRUTH_XOR_EXPR and an EQ_EXPR to the inversion of a TRUTH_XOR_EXPR. */ + + if ((code == BIT_AND_EXPR || code == BIT_IOR_EXPR + || code == EQ_EXPR || code == NE_EXPR) + && ((truth_value_p (TREE_CODE (arg0)) + && (truth_value_p (TREE_CODE (arg1)) + || (TREE_CODE (arg1) == BIT_AND_EXPR + && integer_onep (TREE_OPERAND (arg1, 1))))) + || (truth_value_p (TREE_CODE (arg1)) + && (truth_value_p (TREE_CODE (arg0)) + || (TREE_CODE (arg0) == BIT_AND_EXPR + && integer_onep (TREE_OPERAND (arg0, 1))))))) + { + tem = fold_build2 (code == BIT_AND_EXPR ? TRUTH_AND_EXPR + : code == BIT_IOR_EXPR ? TRUTH_OR_EXPR + : TRUTH_XOR_EXPR, + boolean_type_node, + fold_convert (boolean_type_node, arg0), + fold_convert (boolean_type_node, arg1)); + + if (code == EQ_EXPR) + tem = invert_truthvalue (tem); + + return fold_convert (type, tem); + } + + if (TREE_CODE_CLASS (code) == tcc_binary + || TREE_CODE_CLASS (code) == tcc_comparison) + { + if (TREE_CODE (arg0) == COMPOUND_EXPR) + return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0), + fold_build2 (code, type, + TREE_OPERAND (arg0, 1), op1)); + if (TREE_CODE (arg1) == COMPOUND_EXPR + && reorder_operands_p (arg0, TREE_OPERAND (arg1, 0))) + return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg1, 0), + fold_build2 (code, type, + op0, TREE_OPERAND (arg1, 1))); + + if (TREE_CODE (arg0) == COND_EXPR || COMPARISON_CLASS_P (arg0)) + { + tem = fold_binary_op_with_conditional_arg (code, type, op0, op1, + arg0, arg1, + /*cond_first_p=*/1); + if (tem != NULL_TREE) + return tem; + } + + if (TREE_CODE (arg1) == COND_EXPR || COMPARISON_CLASS_P (arg1)) + { + tem = fold_binary_op_with_conditional_arg (code, type, op0, op1, + arg1, arg0, + /*cond_first_p=*/0); + if (tem != NULL_TREE) + return tem; + } + } + + switch (code) + { + case PLUS_EXPR: + /* A + (-B) -> A - B */ + if (TREE_CODE (arg1) == NEGATE_EXPR) + return fold_build2 (MINUS_EXPR, type, + fold_convert (type, arg0), + fold_convert (type, TREE_OPERAND (arg1, 0))); + /* (-A) + B -> B - A */ + if (TREE_CODE (arg0) == NEGATE_EXPR + && reorder_operands_p (TREE_OPERAND (arg0, 0), arg1)) + return fold_build2 (MINUS_EXPR, type, + fold_convert (type, arg1), + fold_convert (type, TREE_OPERAND (arg0, 0))); + /* Convert ~A + 1 to -A. */ + if (INTEGRAL_TYPE_P (type) + && TREE_CODE (arg0) == BIT_NOT_EXPR + && integer_onep (arg1)) + return fold_build1 (NEGATE_EXPR, type, TREE_OPERAND (arg0, 0)); + + /* Handle (A1 * C1) + (A2 * C2) with A1, A2 or C1, C2 being the + same or one. */ + if ((TREE_CODE (arg0) == MULT_EXPR + || TREE_CODE (arg1) == MULT_EXPR) + && (!FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations)) + { + tree tem = fold_plusminus_mult_expr (code, type, arg0, arg1); + if (tem) + return tem; + } + + if (! FLOAT_TYPE_P (type)) + { + if (integer_zerop (arg1)) + return non_lvalue (fold_convert (type, arg0)); + + /* If we are adding two BIT_AND_EXPR's, both of which are and'ing + with a constant, and the two constants have no bits in common, + we should treat this as a BIT_IOR_EXPR since this may produce more + simplifications. */ + if (TREE_CODE (arg0) == BIT_AND_EXPR + && TREE_CODE (arg1) == BIT_AND_EXPR + && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST + && TREE_CODE (TREE_OPERAND (arg1, 1)) == INTEGER_CST + && integer_zerop (const_binop (BIT_AND_EXPR, + TREE_OPERAND (arg0, 1), + TREE_OPERAND (arg1, 1), 0))) + { + code = BIT_IOR_EXPR; + goto bit_ior; + } + + /* Reassociate (plus (plus (mult) (foo)) (mult)) as + (plus (plus (mult) (mult)) (foo)) so that we can + take advantage of the factoring cases below. */ + if (((TREE_CODE (arg0) == PLUS_EXPR + || TREE_CODE (arg0) == MINUS_EXPR) + && TREE_CODE (arg1) == MULT_EXPR) + || ((TREE_CODE (arg1) == PLUS_EXPR + || TREE_CODE (arg1) == MINUS_EXPR) + && TREE_CODE (arg0) == MULT_EXPR)) + { + tree parg0, parg1, parg, marg; + enum tree_code pcode; + + if (TREE_CODE (arg1) == MULT_EXPR) + parg = arg0, marg = arg1; + else + parg = arg1, marg = arg0; + pcode = TREE_CODE (parg); + parg0 = TREE_OPERAND (parg, 0); + parg1 = TREE_OPERAND (parg, 1); + STRIP_NOPS (parg0); + STRIP_NOPS (parg1); + + if (TREE_CODE (parg0) == MULT_EXPR + && TREE_CODE (parg1) != MULT_EXPR) + return fold_build2 (pcode, type, + fold_build2 (PLUS_EXPR, type, + fold_convert (type, parg0), + fold_convert (type, marg)), + fold_convert (type, parg1)); + if (TREE_CODE (parg0) != MULT_EXPR + && TREE_CODE (parg1) == MULT_EXPR) + return fold_build2 (PLUS_EXPR, type, + fold_convert (type, parg0), + fold_build2 (pcode, type, + fold_convert (type, marg), + fold_convert (type, + parg1))); + } + + /* Try replacing &a[i1] + c * i2 with &a[i1 + i2], if c is step + of the array. Loop optimizer sometimes produce this type of + expressions. */ + if (TREE_CODE (arg0) == ADDR_EXPR) + { + tem = try_move_mult_to_index (PLUS_EXPR, arg0, arg1); + if (tem) + return fold_convert (type, tem); + } + else if (TREE_CODE (arg1) == ADDR_EXPR) + { + tem = try_move_mult_to_index (PLUS_EXPR, arg1, arg0); + if (tem) + return fold_convert (type, tem); + } + } + else + { + /* See if ARG1 is zero and X + ARG1 reduces to X. */ + if (fold_real_zero_addition_p (TREE_TYPE (arg0), arg1, 0)) + return non_lvalue (fold_convert (type, arg0)); + + /* Likewise if the operands are reversed. */ + if (fold_real_zero_addition_p (TREE_TYPE (arg1), arg0, 0)) + return non_lvalue (fold_convert (type, arg1)); + + /* Convert X + -C into X - C. */ + if (TREE_CODE (arg1) == REAL_CST + && REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg1))) + { + tem = fold_negate_const (arg1, type); + if (!TREE_OVERFLOW (arg1) || !flag_trapping_math) + return fold_build2 (MINUS_EXPR, type, + fold_convert (type, arg0), + fold_convert (type, tem)); + } + + if (flag_unsafe_math_optimizations + && (TREE_CODE (arg0) == RDIV_EXPR || TREE_CODE (arg0) == MULT_EXPR) + && (TREE_CODE (arg1) == RDIV_EXPR || TREE_CODE (arg1) == MULT_EXPR) + && (tem = distribute_real_division (code, type, arg0, arg1))) + return tem; + + /* Convert x+x into x*2.0. */ + if (operand_equal_p (arg0, arg1, 0) + && SCALAR_FLOAT_TYPE_P (type)) + return fold_build2 (MULT_EXPR, type, arg0, + build_real (type, dconst2)); + + /* Convert a + (b*c + d*e) into (a + b*c) + d*e. */ + if (flag_unsafe_math_optimizations + && TREE_CODE (arg1) == PLUS_EXPR + && TREE_CODE (arg0) != MULT_EXPR) + { + tree tree10 = TREE_OPERAND (arg1, 0); + tree tree11 = TREE_OPERAND (arg1, 1); + if (TREE_CODE (tree11) == MULT_EXPR + && TREE_CODE (tree10) == MULT_EXPR) + { + tree tree0; + tree0 = fold_build2 (PLUS_EXPR, type, arg0, tree10); + return fold_build2 (PLUS_EXPR, type, tree0, tree11); + } + } + /* Convert (b*c + d*e) + a into b*c + (d*e +a). */ + if (flag_unsafe_math_optimizations + && TREE_CODE (arg0) == PLUS_EXPR + && TREE_CODE (arg1) != MULT_EXPR) + { + tree tree00 = TREE_OPERAND (arg0, 0); + tree tree01 = TREE_OPERAND (arg0, 1); + if (TREE_CODE (tree01) == MULT_EXPR + && TREE_CODE (tree00) == MULT_EXPR) + { + tree tree0; + tree0 = fold_build2 (PLUS_EXPR, type, tree01, arg1); + return fold_build2 (PLUS_EXPR, type, tree00, tree0); + } + } + } + + bit_rotate: + /* (A << C1) + (A >> C2) if A is unsigned and C1+C2 is the size of A + is a rotate of A by C1 bits. */ + /* (A << B) + (A >> (Z - B)) if A is unsigned and Z is the size of A + is a rotate of A by B bits. */ + { + enum tree_code code0, code1; + code0 = TREE_CODE (arg0); + code1 = TREE_CODE (arg1); + if (((code0 == RSHIFT_EXPR && code1 == LSHIFT_EXPR) + || (code1 == RSHIFT_EXPR && code0 == LSHIFT_EXPR)) + && operand_equal_p (TREE_OPERAND (arg0, 0), + TREE_OPERAND (arg1, 0), 0) + && TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg0, 0)))) + { + tree tree01, tree11; + enum tree_code code01, code11; + + 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 + && code11 == INTEGER_CST + && TREE_INT_CST_HIGH (tree01) == 0 + && TREE_INT_CST_HIGH (tree11) == 0 + && ((TREE_INT_CST_LOW (tree01) + TREE_INT_CST_LOW (tree11)) + == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0))))) + return build2 (LROTATE_EXPR, type, TREE_OPERAND (arg0, 0), + code0 == LSHIFT_EXPR ? tree01 : 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 + && 0 == compare_tree_int (tree110, + TYPE_PRECISION + (TREE_TYPE (TREE_OPERAND + (arg0, 0)))) + && operand_equal_p (tree01, tree111, 0)) + return build2 ((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 + && 0 == compare_tree_int (tree010, + TYPE_PRECISION + (TREE_TYPE (TREE_OPERAND + (arg0, 0)))) + && operand_equal_p (tree11, tree011, 0)) + return build2 ((code0 != LSHIFT_EXPR + ? LROTATE_EXPR + : RROTATE_EXPR), + type, TREE_OPERAND (arg0, 0), tree11); + } + } + } + + 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, unless the user has specified + -funsafe-math-optimizations. */ + + if (! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations) + { + tree var0, con0, lit0, minus_lit0; + tree var1, con1, lit1, minus_lit1; + bool ok = true; + + /* Split both trees into variables, constants, and literals. Then + associate each group together, the constants with literals, + then the result with variables. This increases the chances of + literals being recombined later and of generating relocatable + expressions for the sum of a constant and literal. */ + var0 = split_tree (arg0, code, &con0, &lit0, &minus_lit0, 0); + var1 = split_tree (arg1, code, &con1, &lit1, &minus_lit1, + code == MINUS_EXPR); + + /* With undefined overflow we can only associate constants + with one variable. */ + if ((POINTER_TYPE_P (type) + || (INTEGRAL_TYPE_P (type) + && !(TYPE_UNSIGNED (type) || flag_wrapv))) + && var0 && var1) + { + tree tmp0 = var0; + tree tmp1 = var1; + + if (TREE_CODE (tmp0) == NEGATE_EXPR) + tmp0 = TREE_OPERAND (tmp0, 0); + if (TREE_CODE (tmp1) == NEGATE_EXPR) + tmp1 = TREE_OPERAND (tmp1, 0); + /* The only case we can still associate with two variables + is if they are the same, modulo negation. */ + if (!operand_equal_p (tmp0, tmp1, 0)) + ok = false; + } + + /* Only do something if we found more than two objects. Otherwise, + nothing has changed and we risk infinite recursion. */ + if (ok + && (2 < ((var0 != 0) + (var1 != 0) + + (con0 != 0) + (con1 != 0) + + (lit0 != 0) + (lit1 != 0) + + (minus_lit0 != 0) + (minus_lit1 != 0)))) + { + /* Recombine MINUS_EXPR operands by using PLUS_EXPR. */ + if (code == MINUS_EXPR) + code = PLUS_EXPR; + + var0 = associate_trees (var0, var1, code, type); + con0 = associate_trees (con0, con1, code, type); + lit0 = associate_trees (lit0, lit1, code, type); + minus_lit0 = associate_trees (minus_lit0, minus_lit1, code, type); + + /* Preserve the MINUS_EXPR if the negative part of the literal is + greater than the positive part. Otherwise, the multiplicative + folding code (i.e extract_muldiv) may be fooled in case + unsigned constants are subtracted, like in the following + example: ((X*2 + 4) - 8U)/2. */ + if (minus_lit0 && lit0) + { + if (TREE_CODE (lit0) == INTEGER_CST + && TREE_CODE (minus_lit0) == INTEGER_CST + && tree_int_cst_lt (lit0, minus_lit0)) + { + minus_lit0 = associate_trees (minus_lit0, lit0, + MINUS_EXPR, type); + lit0 = 0; + } + else + { + lit0 = associate_trees (lit0, minus_lit0, + MINUS_EXPR, type); + minus_lit0 = 0; + } + } + if (minus_lit0) + { + if (con0 == 0) + return fold_convert (type, + associate_trees (var0, minus_lit0, + MINUS_EXPR, type)); + else + { + con0 = associate_trees (con0, minus_lit0, + MINUS_EXPR, type); + return fold_convert (type, + associate_trees (var0, con0, + PLUS_EXPR, type)); + } + } + + con0 = associate_trees (con0, lit0, code, type); + return fold_convert (type, associate_trees (var0, con0, + code, type)); + } + } + + return NULL_TREE; + + case MINUS_EXPR: + /* A - (-B) -> A + B */ + if (TREE_CODE (arg1) == NEGATE_EXPR) + return fold_build2 (PLUS_EXPR, type, arg0, TREE_OPERAND (arg1, 0)); + /* (-A) - B -> (-B) - A where B is easily negated and we can swap. */ + if (TREE_CODE (arg0) == NEGATE_EXPR + && (FLOAT_TYPE_P (type) + || (INTEGRAL_TYPE_P (type) && flag_wrapv && !flag_trapv)) + && negate_expr_p (arg1) + && reorder_operands_p (arg0, arg1)) + return fold_build2 (MINUS_EXPR, type, negate_expr (arg1), + TREE_OPERAND (arg0, 0)); + /* Convert -A - 1 to ~A. */ + if (INTEGRAL_TYPE_P (type) + && TREE_CODE (arg0) == NEGATE_EXPR + && integer_onep (arg1)) + return fold_build1 (BIT_NOT_EXPR, type, + fold_convert (type, TREE_OPERAND (arg0, 0))); + + /* Convert -1 - A to ~A. */ + if (INTEGRAL_TYPE_P (type) + && integer_all_onesp (arg0)) + return fold_build1 (BIT_NOT_EXPR, type, arg1); + + if (! FLOAT_TYPE_P (type)) + { + if (integer_zerop (arg0)) + return negate_expr (fold_convert (type, arg1)); + if (integer_zerop (arg1)) + return non_lvalue (fold_convert (type, arg0)); + + /* Fold A - (A & B) into ~B & A. */ + if (!TREE_SIDE_EFFECTS (arg0) + && TREE_CODE (arg1) == BIT_AND_EXPR) + { + if (operand_equal_p (arg0, TREE_OPERAND (arg1, 1), 0)) + return fold_build2 (BIT_AND_EXPR, type, + fold_build1 (BIT_NOT_EXPR, type, + TREE_OPERAND (arg1, 0)), + arg0); + if (operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)) + return fold_build2 (BIT_AND_EXPR, type, + fold_build1 (BIT_NOT_EXPR, type, + TREE_OPERAND (arg1, 1)), + arg0); + } + + /* Fold (A & ~B) - (A & B) into (A ^ B) - B, where B is + any power of 2 minus 1. */ + if (TREE_CODE (arg0) == BIT_AND_EXPR + && TREE_CODE (arg1) == BIT_AND_EXPR + && operand_equal_p (TREE_OPERAND (arg0, 0), + TREE_OPERAND (arg1, 0), 0)) + { + tree mask0 = TREE_OPERAND (arg0, 1); + tree mask1 = TREE_OPERAND (arg1, 1); + tree tem = fold_build1 (BIT_NOT_EXPR, type, mask0); + + if (operand_equal_p (tem, mask1, 0)) + { + tem = fold_build2 (BIT_XOR_EXPR, type, + TREE_OPERAND (arg0, 0), mask1); + return fold_build2 (MINUS_EXPR, type, tem, mask1); + } + } + } + + /* See if ARG1 is zero and X - ARG1 reduces to X. */ + else if (fold_real_zero_addition_p (TREE_TYPE (arg0), arg1, 1)) + return non_lvalue (fold_convert (type, arg0)); + + /* (ARG0 - ARG1) is the same as (-ARG1 + ARG0). So check whether + ARG0 is zero and X + ARG0 reduces to X, since that would mean + (-ARG1 + ARG0) reduces to -ARG1. */ + else if (fold_real_zero_addition_p (TREE_TYPE (arg1), arg0, 0)) + return negate_expr (fold_convert (type, arg1)); + + /* Fold &x - &x. This can happen from &x.foo - &x. + This is unsafe for certain floats even in non-IEEE formats. + In IEEE, it is unsafe because it does wrong for NaNs. + Also note that operand_equal_p is always false if an operand + is volatile. */ + + if ((! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations) + && operand_equal_p (arg0, arg1, 0)) + return fold_convert (type, integer_zero_node); + + /* A - B -> A + (-B) if B is easily negatable. */ + if (negate_expr_p (arg1) + && ((FLOAT_TYPE_P (type) + /* Avoid this transformation if B is a positive REAL_CST. */ + && (TREE_CODE (arg1) != REAL_CST + || REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg1)))) + || (INTEGRAL_TYPE_P (type) && flag_wrapv && !flag_trapv))) + return fold_build2 (PLUS_EXPR, type, + fold_convert (type, arg0), + fold_convert (type, negate_expr (arg1))); + + /* Try folding difference of addresses. */ + { + HOST_WIDE_INT diff; + + if ((TREE_CODE (arg0) == ADDR_EXPR + || TREE_CODE (arg1) == ADDR_EXPR) + && ptr_difference_const (arg0, arg1, &diff)) + return build_int_cst_type (type, diff); + } + + /* Fold &a[i] - &a[j] to i-j. */ + if (TREE_CODE (arg0) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (arg0, 0)) == ARRAY_REF + && TREE_CODE (arg1) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (arg1, 0)) == ARRAY_REF) + { + tree aref0 = TREE_OPERAND (arg0, 0); + tree aref1 = TREE_OPERAND (arg1, 0); + if (operand_equal_p (TREE_OPERAND (aref0, 0), + TREE_OPERAND (aref1, 0), 0)) + { + tree op0 = fold_convert (type, TREE_OPERAND (aref0, 1)); + tree op1 = fold_convert (type, TREE_OPERAND (aref1, 1)); + tree esz = array_ref_element_size (aref0); + tree diff = build2 (MINUS_EXPR, type, op0, op1); + return fold_build2 (MULT_EXPR, type, diff, + fold_convert (type, esz)); + + } + } + + /* Try replacing &a[i1] - c * i2 with &a[i1 - i2], if c is step + of the array. Loop optimizer sometimes produce this type of + expressions. */ + if (TREE_CODE (arg0) == ADDR_EXPR) + { + tem = try_move_mult_to_index (MINUS_EXPR, arg0, arg1); + if (tem) + return fold_convert (type, tem); + } + + if (flag_unsafe_math_optimizations + && (TREE_CODE (arg0) == RDIV_EXPR || TREE_CODE (arg0) == MULT_EXPR) + && (TREE_CODE (arg1) == RDIV_EXPR || TREE_CODE (arg1) == MULT_EXPR) + && (tem = distribute_real_division (code, type, arg0, arg1))) + return tem; + + /* Handle (A1 * C1) - (A2 * C2) with A1, A2 or C1, C2 being the + same or one. */ + if ((TREE_CODE (arg0) == MULT_EXPR + || TREE_CODE (arg1) == MULT_EXPR) + && (!FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations)) + { + tree tem = fold_plusminus_mult_expr (code, type, arg0, arg1); + if (tem) + return tem; + } + + goto associate; + + case MULT_EXPR: + /* (-A) * (-B) -> A * B */ + if (TREE_CODE (arg0) == NEGATE_EXPR && negate_expr_p (arg1)) + return fold_build2 (MULT_EXPR, type, + fold_convert (type, TREE_OPERAND (arg0, 0)), + fold_convert (type, negate_expr (arg1))); + if (TREE_CODE (arg1) == NEGATE_EXPR && negate_expr_p (arg0)) + return fold_build2 (MULT_EXPR, type, + fold_convert (type, negate_expr (arg0)), + fold_convert (type, TREE_OPERAND (arg1, 0))); + + if (! FLOAT_TYPE_P (type)) + { + if (integer_zerop (arg1)) + return omit_one_operand (type, arg1, arg0); + if (integer_onep (arg1)) + return non_lvalue (fold_convert (type, arg0)); + /* Transform x * -1 into -x. */ + if (integer_all_onesp (arg1)) + return fold_convert (type, negate_expr (arg0)); + + /* (a * (1 << b)) is (a << b) */ + if (TREE_CODE (arg1) == LSHIFT_EXPR + && integer_onep (TREE_OPERAND (arg1, 0))) + return fold_build2 (LSHIFT_EXPR, type, arg0, + TREE_OPERAND (arg1, 1)); + if (TREE_CODE (arg0) == LSHIFT_EXPR + && integer_onep (TREE_OPERAND (arg0, 0))) + return fold_build2 (LSHIFT_EXPR, type, arg1, + TREE_OPERAND (arg0, 1)); + + strict_overflow_p = false; + if (TREE_CODE (arg1) == INTEGER_CST + && 0 != (tem = extract_muldiv (op0, + fold_convert (type, arg1), + code, NULL_TREE, + &strict_overflow_p))) + { + if (strict_overflow_p) + fold_overflow_warning (("assuming signed overflow does not " + "occur when simplifying " + "multiplication"), + WARN_STRICT_OVERFLOW_MISC); + return fold_convert (type, tem); + } + + /* Optimize z * conj(z) for integer complex numbers. */ + if (TREE_CODE (arg0) == CONJ_EXPR + && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)) + return fold_mult_zconjz (type, arg1); + if (TREE_CODE (arg1) == CONJ_EXPR + && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)) + return fold_mult_zconjz (type, arg0); + } + else + { + /* Maybe fold x * 0 to 0. The expressions aren't the same + when x is NaN, since x * 0 is also NaN. Nor are they the + same in modes with signed zeros, since multiplying a + negative value by 0 gives -0, not +0. */ + if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))) + && !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg0))) + && real_zerop (arg1)) + return omit_one_operand (type, arg1, arg0); + /* In IEEE floating point, x*1 is not equivalent to x for snans. */ + if (!HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0))) + && real_onep (arg1)) + return non_lvalue (fold_convert (type, arg0)); + + /* Transform x * -1.0 into -x. */ + if (!HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0))) + && real_minus_onep (arg1)) + return fold_convert (type, negate_expr (arg0)); + + /* Convert (C1/X)*C2 into (C1*C2)/X. */ + if (flag_unsafe_math_optimizations + && TREE_CODE (arg0) == RDIV_EXPR + && TREE_CODE (arg1) == REAL_CST + && TREE_CODE (TREE_OPERAND (arg0, 0)) == REAL_CST) + { + tree tem = const_binop (MULT_EXPR, TREE_OPERAND (arg0, 0), + arg1, 0); + if (tem) + return fold_build2 (RDIV_EXPR, type, tem, + TREE_OPERAND (arg0, 1)); + } + + /* Strip sign operations from X in X*X, i.e. -Y*-Y -> Y*Y. */ + if (operand_equal_p (arg0, arg1, 0)) + { + tree tem = fold_strip_sign_ops (arg0); + if (tem != NULL_TREE) + { + tem = fold_convert (type, tem); + return fold_build2 (MULT_EXPR, type, tem, tem); + } + } + + /* Optimize z * conj(z) for floating point complex numbers. + Guarded by flag_unsafe_math_optimizations as non-finite + imaginary components don't produce scalar results. */ + if (flag_unsafe_math_optimizations + && TREE_CODE (arg0) == CONJ_EXPR + && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)) + return fold_mult_zconjz (type, arg1); + if (flag_unsafe_math_optimizations + && TREE_CODE (arg1) == CONJ_EXPR + && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)) + return fold_mult_zconjz (type, arg0); + + if (flag_unsafe_math_optimizations) + { + enum built_in_function fcode0 = builtin_mathfn_code (arg0); + enum built_in_function fcode1 = builtin_mathfn_code (arg1); + + /* Optimizations of root(...)*root(...). */ + if (fcode0 == fcode1 && BUILTIN_ROOT_P (fcode0)) + { + tree rootfn, arg, arglist; + tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1)); + tree arg10 = TREE_VALUE (TREE_OPERAND (arg1, 1)); + + /* Optimize sqrt(x)*sqrt(x) as x. */ + if (BUILTIN_SQRT_P (fcode0) + && operand_equal_p (arg00, arg10, 0) + && ! HONOR_SNANS (TYPE_MODE (type))) + return arg00; + + /* Optimize root(x)*root(y) as root(x*y). */ + rootfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0); + arg = fold_build2 (MULT_EXPR, type, arg00, arg10); + arglist = build_tree_list (NULL_TREE, arg); + return build_function_call_expr (rootfn, arglist); + } + + /* Optimize expN(x)*expN(y) as expN(x+y). */ + if (fcode0 == fcode1 && BUILTIN_EXPONENT_P (fcode0)) + { + tree expfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0); + tree arg = fold_build2 (PLUS_EXPR, type, + TREE_VALUE (TREE_OPERAND (arg0, 1)), + TREE_VALUE (TREE_OPERAND (arg1, 1))); + tree arglist = build_tree_list (NULL_TREE, arg); + return build_function_call_expr (expfn, arglist); + } + + /* Optimizations of pow(...)*pow(...). */ + if ((fcode0 == BUILT_IN_POW && fcode1 == BUILT_IN_POW) + || (fcode0 == BUILT_IN_POWF && fcode1 == BUILT_IN_POWF) + || (fcode0 == BUILT_IN_POWL && fcode1 == BUILT_IN_POWL)) + { + tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1)); + tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg0, + 1))); + tree arg10 = TREE_VALUE (TREE_OPERAND (arg1, 1)); + tree arg11 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg1, + 1))); + + /* Optimize pow(x,y)*pow(z,y) as pow(x*z,y). */ + if (operand_equal_p (arg01, arg11, 0)) + { + tree powfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0); + tree arg = fold_build2 (MULT_EXPR, type, arg00, arg10); + tree arglist = tree_cons (NULL_TREE, arg, + build_tree_list (NULL_TREE, + arg01)); + return build_function_call_expr (powfn, arglist); + } + + /* Optimize pow(x,y)*pow(x,z) as pow(x,y+z). */ + if (operand_equal_p (arg00, arg10, 0)) + { + tree powfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0); + tree arg = fold_build2 (PLUS_EXPR, type, arg01, arg11); + tree arglist = tree_cons (NULL_TREE, arg00, + build_tree_list (NULL_TREE, + arg)); + return build_function_call_expr (powfn, arglist); + } + } + + /* Optimize tan(x)*cos(x) as sin(x). */ + if (((fcode0 == BUILT_IN_TAN && fcode1 == BUILT_IN_COS) + || (fcode0 == BUILT_IN_TANF && fcode1 == BUILT_IN_COSF) + || (fcode0 == BUILT_IN_TANL && fcode1 == BUILT_IN_COSL) + || (fcode0 == BUILT_IN_COS && fcode1 == BUILT_IN_TAN) + || (fcode0 == BUILT_IN_COSF && fcode1 == BUILT_IN_TANF) + || (fcode0 == BUILT_IN_COSL && fcode1 == BUILT_IN_TANL)) + && operand_equal_p (TREE_VALUE (TREE_OPERAND (arg0, 1)), + TREE_VALUE (TREE_OPERAND (arg1, 1)), 0)) + { + tree sinfn = mathfn_built_in (type, BUILT_IN_SIN); + + if (sinfn != NULL_TREE) + return build_function_call_expr (sinfn, + TREE_OPERAND (arg0, 1)); + } + + /* Optimize x*pow(x,c) as pow(x,c+1). */ + if (fcode1 == BUILT_IN_POW + || fcode1 == BUILT_IN_POWF + || fcode1 == BUILT_IN_POWL) + { + tree arg10 = TREE_VALUE (TREE_OPERAND (arg1, 1)); + tree arg11 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg1, + 1))); + if (TREE_CODE (arg11) == REAL_CST + && ! TREE_CONSTANT_OVERFLOW (arg11) + && operand_equal_p (arg0, arg10, 0)) + { + tree powfn = TREE_OPERAND (TREE_OPERAND (arg1, 0), 0); + REAL_VALUE_TYPE c; + tree arg, arglist; + + c = TREE_REAL_CST (arg11); + real_arithmetic (&c, PLUS_EXPR, &c, &dconst1); + arg = build_real (type, c); + arglist = build_tree_list (NULL_TREE, arg); + arglist = tree_cons (NULL_TREE, arg0, arglist); + return build_function_call_expr (powfn, arglist); + } + } + + /* Optimize pow(x,c)*x as pow(x,c+1). */ + if (fcode0 == BUILT_IN_POW + || fcode0 == BUILT_IN_POWF + || fcode0 == BUILT_IN_POWL) + { + tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1)); + tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg0, + 1))); + if (TREE_CODE (arg01) == REAL_CST + && ! TREE_CONSTANT_OVERFLOW (arg01) + && operand_equal_p (arg1, arg00, 0)) + { + tree powfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0); + REAL_VALUE_TYPE c; + tree arg, arglist; + + c = TREE_REAL_CST (arg01); + real_arithmetic (&c, PLUS_EXPR, &c, &dconst1); + arg = build_real (type, c); + arglist = build_tree_list (NULL_TREE, arg); + arglist = tree_cons (NULL_TREE, arg1, arglist); + return build_function_call_expr (powfn, arglist); + } + } + + /* Optimize x*x as pow(x,2.0), which is expanded as x*x. */ + if (! optimize_size + && operand_equal_p (arg0, arg1, 0)) + { + tree powfn = mathfn_built_in (type, BUILT_IN_POW); + + if (powfn) + { + tree arg = build_real (type, dconst2); + tree arglist = build_tree_list (NULL_TREE, arg); + arglist = tree_cons (NULL_TREE, arg0, arglist); + return build_function_call_expr (powfn, arglist); + } + } + } + } + goto associate; + + case BIT_IOR_EXPR: + bit_ior: + if (integer_all_onesp (arg1)) + return omit_one_operand (type, arg1, arg0); + if (integer_zerop (arg1)) + return non_lvalue (fold_convert (type, arg0)); + if (operand_equal_p (arg0, arg1, 0)) + return non_lvalue (fold_convert (type, arg0)); + + /* ~X | X is -1. */ + if (TREE_CODE (arg0) == BIT_NOT_EXPR + && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)) + { + t1 = build_int_cst (type, -1); + t1 = force_fit_type (t1, 0, false, false); + return omit_one_operand (type, t1, arg1); + } + + /* X | ~X is -1. */ + if (TREE_CODE (arg1) == BIT_NOT_EXPR + && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)) + { + t1 = build_int_cst (type, -1); + t1 = force_fit_type (t1, 0, false, false); + return omit_one_operand (type, t1, arg0); + } + + /* Canonicalize (X & C1) | C2. */ + if (TREE_CODE (arg0) == BIT_AND_EXPR + && TREE_CODE (arg1) == INTEGER_CST + && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST) + { + unsigned HOST_WIDE_INT hi1, lo1, hi2, lo2, mlo, mhi; + int width = TYPE_PRECISION (type); + hi1 = TREE_INT_CST_HIGH (TREE_OPERAND (arg0, 1)); + lo1 = TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1)); + hi2 = TREE_INT_CST_HIGH (arg1); + lo2 = TREE_INT_CST_LOW (arg1); + + /* If (C1&C2) == C1, then (X&C1)|C2 becomes (X,C2). */ + if ((hi1 & hi2) == hi1 && (lo1 & lo2) == lo1) + return omit_one_operand (type, arg1, TREE_OPERAND (arg0, 0)); + + if (width > HOST_BITS_PER_WIDE_INT) + { + mhi = (unsigned HOST_WIDE_INT) -1 + >> (2 * HOST_BITS_PER_WIDE_INT - width); + mlo = -1; + } + else + { + mhi = 0; + mlo = (unsigned HOST_WIDE_INT) -1 + >> (HOST_BITS_PER_WIDE_INT - width); + } + + /* If (C1|C2) == ~0 then (X&C1)|C2 becomes X|C2. */ + if ((~(hi1 | hi2) & mhi) == 0 && (~(lo1 | lo2) & mlo) == 0) + return fold_build2 (BIT_IOR_EXPR, type, + TREE_OPERAND (arg0, 0), arg1); + + /* Minimize the number of bits set in C1, i.e. C1 := C1 & ~C2. */ + hi1 &= mhi; + lo1 &= mlo; + if ((hi1 & ~hi2) != hi1 || (lo1 & ~lo2) != lo1) + return fold_build2 (BIT_IOR_EXPR, type, + fold_build2 (BIT_AND_EXPR, type, + TREE_OPERAND (arg0, 0), + build_int_cst_wide (type, + lo1 & ~lo2, + hi1 & ~hi2)), + arg1); + } + + /* (X & Y) | Y is (X, Y). */ + if (TREE_CODE (arg0) == BIT_AND_EXPR + && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0)) + return omit_one_operand (type, arg1, TREE_OPERAND (arg0, 0)); + /* (X & Y) | X is (Y, X). */ + if (TREE_CODE (arg0) == BIT_AND_EXPR + && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0) + && reorder_operands_p (TREE_OPERAND (arg0, 1), arg1)) + return omit_one_operand (type, arg1, TREE_OPERAND (arg0, 1)); + /* X | (X & Y) is (Y, X). */ + if (TREE_CODE (arg1) == BIT_AND_EXPR + && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0) + && reorder_operands_p (arg0, TREE_OPERAND (arg1, 1))) + return omit_one_operand (type, arg0, TREE_OPERAND (arg1, 1)); + /* X | (Y & X) is (Y, X). */ + if (TREE_CODE (arg1) == BIT_AND_EXPR + && operand_equal_p (arg0, TREE_OPERAND (arg1, 1), 0) + && reorder_operands_p (arg0, TREE_OPERAND (arg1, 0))) + return omit_one_operand (type, arg0, TREE_OPERAND (arg1, 0)); + + t1 = distribute_bit_expr (code, type, arg0, arg1); + if (t1 != NULL_TREE) + return t1; + + /* Convert (or (not arg0) (not arg1)) to (not (and (arg0) (arg1))). + + This results in more efficient code for machines without a NAND + instruction. Combine will canonicalize to the first form + which will allow use of NAND instructions provided by the + backend if they exist. */ + if (TREE_CODE (arg0) == BIT_NOT_EXPR + && TREE_CODE (arg1) == BIT_NOT_EXPR) + { + return fold_build1 (BIT_NOT_EXPR, type, + build2 (BIT_AND_EXPR, type, + TREE_OPERAND (arg0, 0), + TREE_OPERAND (arg1, 0))); + } + + /* See if this can be simplified into a rotate first. If that + is unsuccessful continue in the association code. */ + goto bit_rotate; + + case BIT_XOR_EXPR: + if (integer_zerop (arg1)) + return non_lvalue (fold_convert (type, arg0)); + if (integer_all_onesp (arg1)) + return fold_build1 (BIT_NOT_EXPR, type, arg0); + if (operand_equal_p (arg0, arg1, 0)) + return omit_one_operand (type, integer_zero_node, arg0); + + /* ~X ^ X is -1. */ + if (TREE_CODE (arg0) == BIT_NOT_EXPR + && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)) + { + t1 = build_int_cst (type, -1); + t1 = force_fit_type (t1, 0, false, false); + return omit_one_operand (type, t1, arg1); + } + + /* X ^ ~X is -1. */ + if (TREE_CODE (arg1) == BIT_NOT_EXPR + && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)) + { + t1 = build_int_cst (type, -1); + t1 = force_fit_type (t1, 0, false, false); + return omit_one_operand (type, t1, arg0); + } + + /* If we are XORing two BIT_AND_EXPR's, both of which are and'ing + with a constant, and the two constants have no bits in common, + we should treat this as a BIT_IOR_EXPR since this may produce more + simplifications. */ + if (TREE_CODE (arg0) == BIT_AND_EXPR + && TREE_CODE (arg1) == BIT_AND_EXPR + && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST + && TREE_CODE (TREE_OPERAND (arg1, 1)) == INTEGER_CST + && integer_zerop (const_binop (BIT_AND_EXPR, + TREE_OPERAND (arg0, 1), + TREE_OPERAND (arg1, 1), 0))) + { + code = BIT_IOR_EXPR; + goto bit_ior; + } + + /* (X | Y) ^ X -> Y & ~ X*/ + if (TREE_CODE (arg0) == BIT_IOR_EXPR + && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)) + { + tree t2 = TREE_OPERAND (arg0, 1); + t1 = fold_build1 (BIT_NOT_EXPR, TREE_TYPE (arg1), + arg1); + t1 = fold_build2 (BIT_AND_EXPR, type, fold_convert (type, t2), + fold_convert (type, t1)); + return t1; + } + + /* (Y | X) ^ X -> Y & ~ X*/ + if (TREE_CODE (arg0) == BIT_IOR_EXPR + && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0)) + { + tree t2 = TREE_OPERAND (arg0, 0); + t1 = fold_build1 (BIT_NOT_EXPR, TREE_TYPE (arg1), + arg1); + t1 = fold_build2 (BIT_AND_EXPR, type, fold_convert (type, t2), + fold_convert (type, t1)); + return t1; + } + + /* X ^ (X | Y) -> Y & ~ X*/ + if (TREE_CODE (arg1) == BIT_IOR_EXPR + && operand_equal_p (TREE_OPERAND (arg1, 0), arg0, 0)) + { + tree t2 = TREE_OPERAND (arg1, 1); + t1 = fold_build1 (BIT_NOT_EXPR, TREE_TYPE (arg0), + arg0); + t1 = fold_build2 (BIT_AND_EXPR, type, fold_convert (type, t2), + fold_convert (type, t1)); + return t1; + } + + /* X ^ (Y | X) -> Y & ~ X*/ + if (TREE_CODE (arg1) == BIT_IOR_EXPR + && operand_equal_p (TREE_OPERAND (arg1, 1), arg0, 0)) + { + tree t2 = TREE_OPERAND (arg1, 0); + t1 = fold_build1 (BIT_NOT_EXPR, TREE_TYPE (arg0), + arg0); + t1 = fold_build2 (BIT_AND_EXPR, type, fold_convert (type, t2), + fold_convert (type, t1)); + return t1; + } + + /* Convert ~X ^ ~Y to X ^ Y. */ + if (TREE_CODE (arg0) == BIT_NOT_EXPR + && TREE_CODE (arg1) == BIT_NOT_EXPR) + return fold_build2 (code, type, + fold_convert (type, TREE_OPERAND (arg0, 0)), + fold_convert (type, TREE_OPERAND (arg1, 0))); + + /* Fold (X & 1) ^ 1 as (X & 1) == 0. */ + if (TREE_CODE (arg0) == BIT_AND_EXPR + && integer_onep (TREE_OPERAND (arg0, 1)) + && integer_onep (arg1)) + return fold_build2 (EQ_EXPR, type, arg0, + build_int_cst (TREE_TYPE (arg0), 0)); + + /* Fold (X & Y) ^ Y as ~X & Y. */ + if (TREE_CODE (arg0) == BIT_AND_EXPR + && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0)) + { + tem = fold_convert (type, TREE_OPERAND (arg0, 0)); + return fold_build2 (BIT_AND_EXPR, type, + fold_build1 (BIT_NOT_EXPR, type, tem), + fold_convert (type, arg1)); + } + /* Fold (X & Y) ^ X as ~Y & X. */ + if (TREE_CODE (arg0) == BIT_AND_EXPR + && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0) + && reorder_operands_p (TREE_OPERAND (arg0, 1), arg1)) + { + tem = fold_convert (type, TREE_OPERAND (arg0, 1)); + return fold_build2 (BIT_AND_EXPR, type, + fold_build1 (BIT_NOT_EXPR, type, tem), + fold_convert (type, arg1)); + } + /* Fold X ^ (X & Y) as X & ~Y. */ + if (TREE_CODE (arg1) == BIT_AND_EXPR + && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)) + { + tem = fold_convert (type, TREE_OPERAND (arg1, 1)); + return fold_build2 (BIT_AND_EXPR, type, + fold_convert (type, arg0), + fold_build1 (BIT_NOT_EXPR, type, tem)); + } + /* Fold X ^ (Y & X) as ~Y & X. */ + if (TREE_CODE (arg1) == BIT_AND_EXPR + && operand_equal_p (arg0, TREE_OPERAND (arg1, 1), 0) + && reorder_operands_p (arg0, TREE_OPERAND (arg1, 0))) + { + tem = fold_convert (type, TREE_OPERAND (arg1, 0)); + return fold_build2 (BIT_AND_EXPR, type, + fold_build1 (BIT_NOT_EXPR, type, tem), + fold_convert (type, arg0)); + } + + /* See if this can be simplified into a rotate first. If that + is unsuccessful continue in the association code. */ + goto bit_rotate; + + case BIT_AND_EXPR: + if (integer_all_onesp (arg1)) + return non_lvalue (fold_convert (type, arg0)); + if (integer_zerop (arg1)) + return omit_one_operand (type, arg1, arg0); + if (operand_equal_p (arg0, arg1, 0)) + return non_lvalue (fold_convert (type, arg0)); + + /* ~X & X is always zero. */ + if (TREE_CODE (arg0) == BIT_NOT_EXPR + && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)) + return omit_one_operand (type, integer_zero_node, arg1); + + /* X & ~X is always zero. */ + if (TREE_CODE (arg1) == BIT_NOT_EXPR + && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)) + return omit_one_operand (type, integer_zero_node, arg0); + + /* Canonicalize (X | C1) & C2 as (X & C2) | (C1 & C2). */ + if (TREE_CODE (arg0) == BIT_IOR_EXPR + && TREE_CODE (arg1) == INTEGER_CST + && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST) + return fold_build2 (BIT_IOR_EXPR, type, + fold_build2 (BIT_AND_EXPR, type, + TREE_OPERAND (arg0, 0), arg1), + fold_build2 (BIT_AND_EXPR, type, + TREE_OPERAND (arg0, 1), arg1)); + + /* (X | Y) & Y is (X, Y). */ + if (TREE_CODE (arg0) == BIT_IOR_EXPR + && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0)) + return omit_one_operand (type, arg1, TREE_OPERAND (arg0, 0)); + /* (X | Y) & X is (Y, X). */ + if (TREE_CODE (arg0) == BIT_IOR_EXPR + && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0) + && reorder_operands_p (TREE_OPERAND (arg0, 1), arg1)) + return omit_one_operand (type, arg1, TREE_OPERAND (arg0, 1)); + /* X & (X | Y) is (Y, X). */ + if (TREE_CODE (arg1) == BIT_IOR_EXPR + && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0) + && reorder_operands_p (arg0, TREE_OPERAND (arg1, 1))) + return omit_one_operand (type, arg0, TREE_OPERAND (arg1, 1)); + /* X & (Y | X) is (Y, X). */ + if (TREE_CODE (arg1) == BIT_IOR_EXPR + && operand_equal_p (arg0, TREE_OPERAND (arg1, 1), 0) + && reorder_operands_p (arg0, TREE_OPERAND (arg1, 0))) + return omit_one_operand (type, arg0, TREE_OPERAND (arg1, 0)); + + /* Fold (X ^ 1) & 1 as (X & 1) == 0. */ + if (TREE_CODE (arg0) == BIT_XOR_EXPR + && integer_onep (TREE_OPERAND (arg0, 1)) + && integer_onep (arg1)) + { + tem = TREE_OPERAND (arg0, 0); + return fold_build2 (EQ_EXPR, type, + fold_build2 (BIT_AND_EXPR, TREE_TYPE (tem), tem, + build_int_cst (TREE_TYPE (tem), 1)), + build_int_cst (TREE_TYPE (tem), 0)); + } + /* Fold ~X & 1 as (X & 1) == 0. */ + if (TREE_CODE (arg0) == BIT_NOT_EXPR + && integer_onep (arg1)) + { + tem = TREE_OPERAND (arg0, 0); + return fold_build2 (EQ_EXPR, type, + fold_build2 (BIT_AND_EXPR, TREE_TYPE (tem), tem, + build_int_cst (TREE_TYPE (tem), 1)), + build_int_cst (TREE_TYPE (tem), 0)); + } + + /* Fold (X ^ Y) & Y as ~X & Y. */ + if (TREE_CODE (arg0) == BIT_XOR_EXPR + && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0)) + { + tem = fold_convert (type, TREE_OPERAND (arg0, 0)); + return fold_build2 (BIT_AND_EXPR, type, + fold_build1 (BIT_NOT_EXPR, type, tem), + fold_convert (type, arg1)); + } + /* Fold (X ^ Y) & X as ~Y & X. */ + if (TREE_CODE (arg0) == BIT_XOR_EXPR + && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0) + && reorder_operands_p (TREE_OPERAND (arg0, 1), arg1)) + { + tem = fold_convert (type, TREE_OPERAND (arg0, 1)); + return fold_build2 (BIT_AND_EXPR, type, + fold_build1 (BIT_NOT_EXPR, type, tem), + fold_convert (type, arg1)); + } + /* Fold X & (X ^ Y) as X & ~Y. */ + if (TREE_CODE (arg1) == BIT_XOR_EXPR + && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)) + { + tem = fold_convert (type, TREE_OPERAND (arg1, 1)); + return fold_build2 (BIT_AND_EXPR, type, + fold_convert (type, arg0), + fold_build1 (BIT_NOT_EXPR, type, tem)); + } + /* Fold X & (Y ^ X) as ~Y & X. */ + if (TREE_CODE (arg1) == BIT_XOR_EXPR + && operand_equal_p (arg0, TREE_OPERAND (arg1, 1), 0) + && reorder_operands_p (arg0, TREE_OPERAND (arg1, 0))) + { + tem = fold_convert (type, TREE_OPERAND (arg1, 0)); + return fold_build2 (BIT_AND_EXPR, type, + fold_build1 (BIT_NOT_EXPR, type, tem), + fold_convert (type, arg0)); + } + + t1 = distribute_bit_expr (code, type, arg0, arg1); + if (t1 != NULL_TREE) + return t1; + /* Simplify ((int)c & 0377) into (int)c, if c is unsigned char. */ + if (TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg0) == NOP_EXPR + && TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg0, 0)))) + { + unsigned int prec + = TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0))); + + if (prec < BITS_PER_WORD && prec < HOST_BITS_PER_WIDE_INT + && (~TREE_INT_CST_LOW (arg1) + & (((HOST_WIDE_INT) 1 << prec) - 1)) == 0) + return fold_convert (type, TREE_OPERAND (arg0, 0)); + } + + /* Convert (and (not arg0) (not arg1)) to (not (or (arg0) (arg1))). + + This results in more efficient code for machines without a NOR + instruction. Combine will canonicalize to the first form + which will allow use of NOR instructions provided by the + backend if they exist. */ + if (TREE_CODE (arg0) == BIT_NOT_EXPR + && TREE_CODE (arg1) == BIT_NOT_EXPR) + { + return fold_build1 (BIT_NOT_EXPR, type, + build2 (BIT_IOR_EXPR, type, + TREE_OPERAND (arg0, 0), + TREE_OPERAND (arg1, 0))); + } + + goto associate; + + case RDIV_EXPR: + /* Don't touch a floating-point divide by zero unless the mode + of the constant can represent infinity. */ + if (TREE_CODE (arg1) == REAL_CST + && !MODE_HAS_INFINITIES (TYPE_MODE (TREE_TYPE (arg1))) + && real_zerop (arg1)) + return NULL_TREE; + + /* Optimize A / A to 1.0 if we don't care about + NaNs or Infinities. Skip the transformation + for non-real operands. */ + if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (arg0)) + && ! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))) + && ! HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (arg0))) + && operand_equal_p (arg0, arg1, 0)) + { + tree r = build_real (TREE_TYPE (arg0), dconst1); + + return omit_two_operands (type, r, arg0, arg1); + } + + /* The complex version of the above A / A optimization. */ + if (COMPLEX_FLOAT_TYPE_P (TREE_TYPE (arg0)) + && operand_equal_p (arg0, arg1, 0)) + { + tree elem_type = TREE_TYPE (TREE_TYPE (arg0)); + if (! HONOR_NANS (TYPE_MODE (elem_type)) + && ! HONOR_INFINITIES (TYPE_MODE (elem_type))) + { + tree r = build_real (elem_type, dconst1); + /* omit_two_operands will call fold_convert for us. */ + return omit_two_operands (type, r, arg0, arg1); + } + } + + /* (-A) / (-B) -> A / B */ + if (TREE_CODE (arg0) == NEGATE_EXPR && negate_expr_p (arg1)) + return fold_build2 (RDIV_EXPR, type, + TREE_OPERAND (arg0, 0), + negate_expr (arg1)); + if (TREE_CODE (arg1) == NEGATE_EXPR && negate_expr_p (arg0)) + return fold_build2 (RDIV_EXPR, type, + negate_expr (arg0), + TREE_OPERAND (arg1, 0)); + + /* In IEEE floating point, x/1 is not equivalent to x for snans. */ + if (!HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0))) + && real_onep (arg1)) + return non_lvalue (fold_convert (type, arg0)); + + /* In IEEE floating point, x/-1 is not equivalent to -x for snans. */ + if (!HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0))) + && real_minus_onep (arg1)) + return non_lvalue (fold_convert (type, negate_expr (arg0))); + + /* If ARG1 is a constant, we can convert this to a multiply by the + reciprocal. This does not have the same rounding properties, + so only do this if -funsafe-math-optimizations. We can actually + always safely do it if ARG1 is a power of two, but it's hard to + tell if it is or not in a portable manner. */ + if (TREE_CODE (arg1) == REAL_CST) + { + if (flag_unsafe_math_optimizations + && 0 != (tem = const_binop (code, build_real (type, dconst1), + arg1, 0))) + return fold_build2 (MULT_EXPR, type, arg0, tem); + /* Find the reciprocal if optimizing and the result is exact. */ + if (optimize) + { + REAL_VALUE_TYPE r; + r = TREE_REAL_CST (arg1); + if (exact_real_inverse (TYPE_MODE(TREE_TYPE(arg0)), &r)) + { + tem = build_real (type, r); + return fold_build2 (MULT_EXPR, type, + fold_convert (type, arg0), tem); + } + } + } + /* Convert A/B/C to A/(B*C). */ + if (flag_unsafe_math_optimizations + && TREE_CODE (arg0) == RDIV_EXPR) + return fold_build2 (RDIV_EXPR, type, TREE_OPERAND (arg0, 0), + fold_build2 (MULT_EXPR, type, + TREE_OPERAND (arg0, 1), arg1)); + + /* Convert A/(B/C) to (A/B)*C. */ + if (flag_unsafe_math_optimizations + && TREE_CODE (arg1) == RDIV_EXPR) + return fold_build2 (MULT_EXPR, type, + fold_build2 (RDIV_EXPR, type, arg0, + TREE_OPERAND (arg1, 0)), + TREE_OPERAND (arg1, 1)); + + /* Convert C1/(X*C2) into (C1/C2)/X. */ + if (flag_unsafe_math_optimizations + && TREE_CODE (arg1) == MULT_EXPR + && TREE_CODE (arg0) == REAL_CST + && TREE_CODE (TREE_OPERAND (arg1, 1)) == REAL_CST) + { + tree tem = const_binop (RDIV_EXPR, arg0, + TREE_OPERAND (arg1, 1), 0); + if (tem) + return fold_build2 (RDIV_EXPR, type, tem, + TREE_OPERAND (arg1, 0)); + } + + if (flag_unsafe_math_optimizations) + { + enum built_in_function fcode0 = builtin_mathfn_code (arg0); + enum built_in_function fcode1 = builtin_mathfn_code (arg1); + + /* Optimize sin(x)/cos(x) as tan(x). */ + if (((fcode0 == BUILT_IN_SIN && fcode1 == BUILT_IN_COS) + || (fcode0 == BUILT_IN_SINF && fcode1 == BUILT_IN_COSF) + || (fcode0 == BUILT_IN_SINL && fcode1 == BUILT_IN_COSL)) + && operand_equal_p (TREE_VALUE (TREE_OPERAND (arg0, 1)), + TREE_VALUE (TREE_OPERAND (arg1, 1)), 0)) + { + tree tanfn = mathfn_built_in (type, BUILT_IN_TAN); + + if (tanfn != NULL_TREE) + return build_function_call_expr (tanfn, + TREE_OPERAND (arg0, 1)); + } + + /* Optimize cos(x)/sin(x) as 1.0/tan(x). */ + if (((fcode0 == BUILT_IN_COS && fcode1 == BUILT_IN_SIN) + || (fcode0 == BUILT_IN_COSF && fcode1 == BUILT_IN_SINF) + || (fcode0 == BUILT_IN_COSL && fcode1 == BUILT_IN_SINL)) + && operand_equal_p (TREE_VALUE (TREE_OPERAND (arg0, 1)), + TREE_VALUE (TREE_OPERAND (arg1, 1)), 0)) + { + tree tanfn = mathfn_built_in (type, BUILT_IN_TAN); + + if (tanfn != NULL_TREE) + { + tree tmp = TREE_OPERAND (arg0, 1); + tmp = build_function_call_expr (tanfn, tmp); + return fold_build2 (RDIV_EXPR, type, + build_real (type, dconst1), tmp); + } + } + + /* Optimize sin(x)/tan(x) as cos(x) if we don't care about + NaNs or Infinities. */ + if (((fcode0 == BUILT_IN_SIN && fcode1 == BUILT_IN_TAN) + || (fcode0 == BUILT_IN_SINF && fcode1 == BUILT_IN_TANF) + || (fcode0 == BUILT_IN_SINL && fcode1 == BUILT_IN_TANL))) + { + tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1)); + tree arg01 = TREE_VALUE (TREE_OPERAND (arg1, 1)); + + if (! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg00))) + && ! HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (arg00))) + && operand_equal_p (arg00, arg01, 0)) + { + tree cosfn = mathfn_built_in (type, BUILT_IN_COS); + + if (cosfn != NULL_TREE) + return build_function_call_expr (cosfn, + TREE_OPERAND (arg0, 1)); + } + } + + /* Optimize tan(x)/sin(x) as 1.0/cos(x) if we don't care about + NaNs or Infinities. */ + if (((fcode0 == BUILT_IN_TAN && fcode1 == BUILT_IN_SIN) + || (fcode0 == BUILT_IN_TANF && fcode1 == BUILT_IN_SINF) + || (fcode0 == BUILT_IN_TANL && fcode1 == BUILT_IN_SINL))) + { + tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1)); + tree arg01 = TREE_VALUE (TREE_OPERAND (arg1, 1)); + + if (! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg00))) + && ! HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (arg00))) + && operand_equal_p (arg00, arg01, 0)) + { + tree cosfn = mathfn_built_in (type, BUILT_IN_COS); + + if (cosfn != NULL_TREE) + { + tree tmp = TREE_OPERAND (arg0, 1); + tmp = build_function_call_expr (cosfn, tmp); + return fold_build2 (RDIV_EXPR, type, + build_real (type, dconst1), + tmp); + } + } + } + + /* Optimize pow(x,c)/x as pow(x,c-1). */ + if (fcode0 == BUILT_IN_POW + || fcode0 == BUILT_IN_POWF + || fcode0 == BUILT_IN_POWL) + { + tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1)); + tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg0, 1))); + if (TREE_CODE (arg01) == REAL_CST + && ! TREE_CONSTANT_OVERFLOW (arg01) + && operand_equal_p (arg1, arg00, 0)) + { + tree powfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0); + REAL_VALUE_TYPE c; + tree arg, arglist; + + c = TREE_REAL_CST (arg01); + real_arithmetic (&c, MINUS_EXPR, &c, &dconst1); + arg = build_real (type, c); + arglist = build_tree_list (NULL_TREE, arg); + arglist = tree_cons (NULL_TREE, arg1, arglist); + return build_function_call_expr (powfn, arglist); + } + } + + /* Optimize x/expN(y) into x*expN(-y). */ + if (BUILTIN_EXPONENT_P (fcode1)) + { + tree expfn = TREE_OPERAND (TREE_OPERAND (arg1, 0), 0); + tree arg = negate_expr (TREE_VALUE (TREE_OPERAND (arg1, 1))); + tree arglist = build_tree_list (NULL_TREE, + fold_convert (type, arg)); + arg1 = build_function_call_expr (expfn, arglist); + return fold_build2 (MULT_EXPR, type, arg0, arg1); + } + + /* Optimize x/pow(y,z) into x*pow(y,-z). */ + if (fcode1 == BUILT_IN_POW + || fcode1 == BUILT_IN_POWF + || fcode1 == BUILT_IN_POWL) + { + tree powfn = TREE_OPERAND (TREE_OPERAND (arg1, 0), 0); + tree arg10 = TREE_VALUE (TREE_OPERAND (arg1, 1)); + tree arg11 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg1, 1))); + tree neg11 = fold_convert (type, negate_expr (arg11)); + tree arglist = tree_cons(NULL_TREE, arg10, + build_tree_list (NULL_TREE, neg11)); + arg1 = build_function_call_expr (powfn, arglist); + return fold_build2 (MULT_EXPR, type, arg0, arg1); + } + } + return NULL_TREE; + + case TRUNC_DIV_EXPR: + case FLOOR_DIV_EXPR: + /* Simplify A / (B << N) where A and B are positive and B is + a power of 2, to A >> (N + log2(B)). */ + strict_overflow_p = false; + if (TREE_CODE (arg1) == LSHIFT_EXPR + && (TYPE_UNSIGNED (type) + || tree_expr_nonnegative_warnv_p (arg0, &strict_overflow_p))) + { + tree sval = TREE_OPERAND (arg1, 0); + if (integer_pow2p (sval) && tree_int_cst_sgn (sval) > 0) + { + tree sh_cnt = TREE_OPERAND (arg1, 1); + unsigned long pow2 = exact_log2 (TREE_INT_CST_LOW (sval)); + + if (strict_overflow_p) + fold_overflow_warning (("assuming signed overflow does not " + "occur when simplifying A / (B << N)"), + WARN_STRICT_OVERFLOW_MISC); + + sh_cnt = fold_build2 (PLUS_EXPR, TREE_TYPE (sh_cnt), + sh_cnt, build_int_cst (NULL_TREE, pow2)); + return fold_build2 (RSHIFT_EXPR, type, + fold_convert (type, arg0), sh_cnt); + } + } + /* Fall thru */ + + case ROUND_DIV_EXPR: + case CEIL_DIV_EXPR: + case EXACT_DIV_EXPR: + if (integer_onep (arg1)) + return non_lvalue (fold_convert (type, arg0)); + if (integer_zerop (arg1)) + return NULL_TREE; + /* X / -1 is -X. */ + if (!TYPE_UNSIGNED (type) + && TREE_CODE (arg1) == INTEGER_CST + && TREE_INT_CST_LOW (arg1) == (unsigned HOST_WIDE_INT) -1 + && TREE_INT_CST_HIGH (arg1) == -1) + return fold_convert (type, negate_expr (arg0)); + + /* Convert -A / -B to A / B when the type is signed and overflow is + undefined. */ + if ((!INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_UNDEFINED (type)) + && TREE_CODE (arg0) == NEGATE_EXPR + && negate_expr_p (arg1)) + { + if (INTEGRAL_TYPE_P (type)) + fold_overflow_warning (("assuming signed overflow does not occur " + "when distributing negation across " + "division"), + WARN_STRICT_OVERFLOW_MISC); + return fold_build2 (code, type, TREE_OPERAND (arg0, 0), + negate_expr (arg1)); + } + if ((!INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_UNDEFINED (type)) + && TREE_CODE (arg1) == NEGATE_EXPR + && negate_expr_p (arg0)) + { + if (INTEGRAL_TYPE_P (type)) + fold_overflow_warning (("assuming signed overflow does not occur " + "when distributing negation across " + "division"), + WARN_STRICT_OVERFLOW_MISC); + return fold_build2 (code, type, negate_expr (arg0), + TREE_OPERAND (arg1, 0)); + } + + /* If arg0 is a multiple of arg1, then rewrite to the fastest div + operation, EXACT_DIV_EXPR. + + Note that only CEIL_DIV_EXPR and FLOOR_DIV_EXPR are rewritten now. + At one time others generated faster code, it's not clear if they do + after the last round to changes to the DIV code in expmed.c. */ + if ((code == CEIL_DIV_EXPR || code == FLOOR_DIV_EXPR) + && multiple_of_p (type, arg0, arg1)) + return fold_build2 (EXACT_DIV_EXPR, type, arg0, arg1); + + strict_overflow_p = false; + if (TREE_CODE (arg1) == INTEGER_CST + && 0 != (tem = extract_muldiv (op0, arg1, code, NULL_TREE, + &strict_overflow_p))) + { + if (strict_overflow_p) + fold_overflow_warning (("assuming signed overflow does not occur " + "when simplifying division"), + WARN_STRICT_OVERFLOW_MISC); + return fold_convert (type, tem); + } + + return NULL_TREE; + + case CEIL_MOD_EXPR: + case FLOOR_MOD_EXPR: + case ROUND_MOD_EXPR: + case TRUNC_MOD_EXPR: + /* X % 1 is always zero, but be sure to preserve any side + effects in X. */ + if (integer_onep (arg1)) + return omit_one_operand (type, integer_zero_node, arg0); + + /* X % 0, return X % 0 unchanged so that we can get the + proper warnings and errors. */ + if (integer_zerop (arg1)) + return NULL_TREE; + + /* 0 % X is always zero, but be sure to preserve any side + effects in X. Place this after checking for X == 0. */ + if (integer_zerop (arg0)) + return omit_one_operand (type, integer_zero_node, arg1); + + /* X % -1 is zero. */ + if (!TYPE_UNSIGNED (type) + && TREE_CODE (arg1) == INTEGER_CST + && TREE_INT_CST_LOW (arg1) == (unsigned HOST_WIDE_INT) -1 + && TREE_INT_CST_HIGH (arg1) == -1) + return omit_one_operand (type, integer_zero_node, arg0); + + /* Optimize TRUNC_MOD_EXPR by a power of two into a BIT_AND_EXPR, + i.e. "X % C" into "X & (C - 1)", if X and C are positive. */ + strict_overflow_p = false; + if ((code == TRUNC_MOD_EXPR || code == FLOOR_MOD_EXPR) + && (TYPE_UNSIGNED (type) + || tree_expr_nonnegative_warnv_p (arg0, &strict_overflow_p))) + { + tree c = arg1; + /* Also optimize A % (C << N) where C is a power of 2, + to A & ((C << N) - 1). */ + if (TREE_CODE (arg1) == LSHIFT_EXPR) + c = TREE_OPERAND (arg1, 0); + + if (integer_pow2p (c) && tree_int_cst_sgn (c) > 0) + { + tree mask = fold_build2 (MINUS_EXPR, TREE_TYPE (arg1), + arg1, integer_one_node); + if (strict_overflow_p) + fold_overflow_warning (("assuming signed overflow does not " + "occur when simplifying " + "X % (power of two)"), + WARN_STRICT_OVERFLOW_MISC); + return fold_build2 (BIT_AND_EXPR, type, + fold_convert (type, arg0), + fold_convert (type, mask)); + } + } + + /* X % -C is the same as X % C. */ + if (code == TRUNC_MOD_EXPR + && !TYPE_UNSIGNED (type) + && TREE_CODE (arg1) == INTEGER_CST + && !TREE_CONSTANT_OVERFLOW (arg1) + && TREE_INT_CST_HIGH (arg1) < 0 + && !TYPE_OVERFLOW_TRAPS (type) + /* Avoid this transformation if C is INT_MIN, i.e. C == -C. */ + && !sign_bit_p (arg1, arg1)) + return fold_build2 (code, type, fold_convert (type, arg0), + fold_convert (type, negate_expr (arg1))); + + /* X % -Y is the same as X % Y. */ + if (code == TRUNC_MOD_EXPR + && !TYPE_UNSIGNED (type) + && TREE_CODE (arg1) == NEGATE_EXPR + && !TYPE_OVERFLOW_TRAPS (type)) + return fold_build2 (code, type, fold_convert (type, arg0), + fold_convert (type, TREE_OPERAND (arg1, 0))); + + if (TREE_CODE (arg1) == INTEGER_CST + && 0 != (tem = extract_muldiv (op0, arg1, code, NULL_TREE, + &strict_overflow_p))) + { + if (strict_overflow_p) + fold_overflow_warning (("assuming signed overflow does not occur " + "when simplifying modulos"), + WARN_STRICT_OVERFLOW_MISC); + return fold_convert (type, tem); + } + + return NULL_TREE; + + case LROTATE_EXPR: + case RROTATE_EXPR: + if (integer_all_onesp (arg0)) + return omit_one_operand (type, arg0, arg1); + goto shift; + + case RSHIFT_EXPR: + /* Optimize -1 >> x for arithmetic right shifts. */ + if (integer_all_onesp (arg0) && !TYPE_UNSIGNED (type)) + return omit_one_operand (type, arg0, arg1); + /* ... fall through ... */ + + case LSHIFT_EXPR: + shift: + if (integer_zerop (arg1)) + return non_lvalue (fold_convert (type, arg0)); + if (integer_zerop (arg0)) + return omit_one_operand (type, arg0, arg1); + + /* Since negative shift count is not well-defined, + don't try to compute it in the compiler. */ + if (TREE_CODE (arg1) == INTEGER_CST && tree_int_cst_sgn (arg1) < 0) + return NULL_TREE; + + /* Turn (a OP c1) OP c2 into a OP (c1+c2). */ + if (TREE_CODE (op0) == code && host_integerp (arg1, false) + && TREE_INT_CST_LOW (arg1) < TYPE_PRECISION (type) + && host_integerp (TREE_OPERAND (arg0, 1), false) + && TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1)) < TYPE_PRECISION (type)) + { + HOST_WIDE_INT low = (TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1)) + + TREE_INT_CST_LOW (arg1)); + + /* Deal with a OP (c1 + c2) being undefined but (a OP c1) OP c2 + being well defined. */ + if (low >= TYPE_PRECISION (type)) + { + if (code == LROTATE_EXPR || code == RROTATE_EXPR) + low = low % TYPE_PRECISION (type); + else if (TYPE_UNSIGNED (type) || code == LSHIFT_EXPR) + return build_int_cst (type, 0); + else + low = TYPE_PRECISION (type) - 1; + } + + return fold_build2 (code, type, TREE_OPERAND (arg0, 0), + build_int_cst (type, low)); + } + + /* Transform (x >> c) << c into x & (-1<<c), or transform (x << c) >> c + into x & ((unsigned)-1 >> c) for unsigned types. */ + if (((code == LSHIFT_EXPR && TREE_CODE (arg0) == RSHIFT_EXPR) + || (TYPE_UNSIGNED (type) + && code == RSHIFT_EXPR && TREE_CODE (arg0) == LSHIFT_EXPR)) + && host_integerp (arg1, false) + && TREE_INT_CST_LOW (arg1) < TYPE_PRECISION (type) + && host_integerp (TREE_OPERAND (arg0, 1), false) + && TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1)) < TYPE_PRECISION (type)) + { + HOST_WIDE_INT low0 = TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1)); + HOST_WIDE_INT low1 = TREE_INT_CST_LOW (arg1); + tree lshift; + tree arg00; + + if (low0 == low1) + { + arg00 = fold_convert (type, TREE_OPERAND (arg0, 0)); + + lshift = build_int_cst (type, -1); + lshift = int_const_binop (code, lshift, arg1, 0); + + return fold_build2 (BIT_AND_EXPR, type, arg00, lshift); + } + } + + /* Rewrite an LROTATE_EXPR by a constant into an + RROTATE_EXPR by a new constant. */ + if (code == LROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST) + { + tree tem = build_int_cst (NULL_TREE, + GET_MODE_BITSIZE (TYPE_MODE (type))); + tem = fold_convert (TREE_TYPE (arg1), tem); + tem = const_binop (MINUS_EXPR, tem, arg1, 0); + return fold_build2 (RROTATE_EXPR, type, arg0, tem); + } + + /* If we have a rotate of a bit operation with the rotate count and + the second operand of the bit operation both constant, + permute the two operations. */ + if (code == RROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST + && (TREE_CODE (arg0) == BIT_AND_EXPR + || TREE_CODE (arg0) == BIT_IOR_EXPR + || TREE_CODE (arg0) == BIT_XOR_EXPR) + && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST) + return fold_build2 (TREE_CODE (arg0), type, + fold_build2 (code, type, + TREE_OPERAND (arg0, 0), arg1), + fold_build2 (code, type, + TREE_OPERAND (arg0, 1), arg1)); + + /* Two consecutive rotates adding up to the width of the mode can + be ignored. */ + if (code == RROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST + && TREE_CODE (arg0) == RROTATE_EXPR + && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST + && TREE_INT_CST_HIGH (arg1) == 0 + && TREE_INT_CST_HIGH (TREE_OPERAND (arg0, 1)) == 0 + && ((TREE_INT_CST_LOW (arg1) + + TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1))) + == (unsigned int) GET_MODE_BITSIZE (TYPE_MODE (type)))) + return TREE_OPERAND (arg0, 0); + + return NULL_TREE; + + case MIN_EXPR: + if (operand_equal_p (arg0, arg1, 0)) + return omit_one_operand (type, arg0, arg1); + if (INTEGRAL_TYPE_P (type) + && operand_equal_p (arg1, TYPE_MIN_VALUE (type), OEP_ONLY_CONST)) + return omit_one_operand (type, arg1, arg0); + tem = fold_minmax (MIN_EXPR, type, arg0, arg1); + if (tem) + return tem; + goto associate; + + case MAX_EXPR: + if (operand_equal_p (arg0, arg1, 0)) + return omit_one_operand (type, arg0, arg1); + if (INTEGRAL_TYPE_P (type) + && TYPE_MAX_VALUE (type) + && operand_equal_p (arg1, TYPE_MAX_VALUE (type), OEP_ONLY_CONST)) + return omit_one_operand (type, arg1, arg0); + tem = fold_minmax (MAX_EXPR, type, arg0, arg1); + if (tem) + return tem; + goto associate; + + 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 (integer_zerop (arg0)) + return fold_convert (type, arg0); + case TRUTH_AND_EXPR: + /* If either arg is constant true, drop it. */ + if (TREE_CODE (arg0) == INTEGER_CST && ! integer_zerop (arg0)) + return non_lvalue (fold_convert (type, arg1)); + if (TREE_CODE (arg1) == INTEGER_CST && ! integer_zerop (arg1) + /* Preserve sequence points. */ + && (code != TRUTH_ANDIF_EXPR || ! TREE_SIDE_EFFECTS (arg0))) + return non_lvalue (fold_convert (type, arg0)); + /* If second arg is constant zero, result is zero, but first arg + must be evaluated. */ + if (integer_zerop (arg1)) + return omit_one_operand (type, arg1, arg0); + /* Likewise for first arg, but note that only the TRUTH_AND_EXPR + case will be handled here. */ + if (integer_zerop (arg0)) + return omit_one_operand (type, arg0, arg1); + + /* !X && X is always false. */ + if (TREE_CODE (arg0) == TRUTH_NOT_EXPR + && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)) + return omit_one_operand (type, integer_zero_node, arg1); + /* X && !X is always false. */ + if (TREE_CODE (arg1) == TRUTH_NOT_EXPR + && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)) + return omit_one_operand (type, integer_zero_node, arg0); + + /* A < X && A + 1 > Y ==> A < X && A >= Y. Normally A + 1 > Y + means A >= Y && A != MAX, but in this case we know that + A < X <= MAX. */ + + if (!TREE_SIDE_EFFECTS (arg0) + && !TREE_SIDE_EFFECTS (arg1)) + { + tem = fold_to_nonsharp_ineq_using_bound (arg0, arg1); + if (tem && !operand_equal_p (tem, arg0, 0)) + return fold_build2 (code, type, tem, arg1); + + tem = fold_to_nonsharp_ineq_using_bound (arg1, arg0); + if (tem && !operand_equal_p (tem, arg1, 0)) + return fold_build2 (code, type, arg0, tem); + } + + truth_andor: + /* We only do these simplifications if we are optimizing. */ + if (!optimize) + return NULL_TREE; + + /* Check for things like (A || B) && (A || C). We can convert this + to A || (B && C). Note that either operator can be any of the four + truth and/or operations and the transformation will still be + valid. Also note that we only care about order for the + ANDIF and ORIF operators. If B contains side effects, this + might change the truth-value of A. */ + if (TREE_CODE (arg0) == TREE_CODE (arg1) + && (TREE_CODE (arg0) == TRUTH_ANDIF_EXPR + || TREE_CODE (arg0) == TRUTH_ORIF_EXPR + || TREE_CODE (arg0) == TRUTH_AND_EXPR + || TREE_CODE (arg0) == TRUTH_OR_EXPR) + && ! TREE_SIDE_EFFECTS (TREE_OPERAND (arg0, 1))) + { + tree a00 = TREE_OPERAND (arg0, 0); + tree a01 = TREE_OPERAND (arg0, 1); + tree a10 = TREE_OPERAND (arg1, 0); + tree a11 = TREE_OPERAND (arg1, 1); + int commutative = ((TREE_CODE (arg0) == TRUTH_OR_EXPR + || TREE_CODE (arg0) == TRUTH_AND_EXPR) + && (code == TRUTH_AND_EXPR + || code == TRUTH_OR_EXPR)); + + if (operand_equal_p (a00, a10, 0)) + return fold_build2 (TREE_CODE (arg0), type, a00, + fold_build2 (code, type, a01, a11)); + else if (commutative && operand_equal_p (a00, a11, 0)) + return fold_build2 (TREE_CODE (arg0), type, a00, + fold_build2 (code, type, a01, a10)); + else if (commutative && operand_equal_p (a01, a10, 0)) + return fold_build2 (TREE_CODE (arg0), type, a01, + fold_build2 (code, type, a00, a11)); + + /* This case if tricky because we must either have commutative + operators or else A10 must not have side-effects. */ + + else if ((commutative || ! TREE_SIDE_EFFECTS (a10)) + && operand_equal_p (a01, a11, 0)) + return fold_build2 (TREE_CODE (arg0), type, + fold_build2 (code, type, a00, a10), + a01); + } + + /* See if we can build a range comparison. */ + if (0 != (tem = fold_range_test (code, type, op0, op1))) + return tem; + + /* Check for the possibility of merging component references. If our + lhs is another similar operation, try to merge its rhs with our + rhs. Then try to merge our lhs and rhs. */ + if (TREE_CODE (arg0) == code + && 0 != (tem = fold_truthop (code, type, + TREE_OPERAND (arg0, 1), arg1))) + return fold_build2 (code, type, TREE_OPERAND (arg0, 0), tem); + + if ((tem = fold_truthop (code, type, arg0, arg1)) != 0) + return tem; + + return NULL_TREE; + + 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 fold_convert (type, arg0); + case TRUTH_OR_EXPR: + /* If either arg is constant zero, drop it. */ + if (TREE_CODE (arg0) == INTEGER_CST && integer_zerop (arg0)) + return non_lvalue (fold_convert (type, arg1)); + if (TREE_CODE (arg1) == INTEGER_CST && integer_zerop (arg1) + /* Preserve sequence points. */ + && (code != TRUTH_ORIF_EXPR || ! TREE_SIDE_EFFECTS (arg0))) + return non_lvalue (fold_convert (type, arg0)); + /* If second arg is constant true, result is true, but we must + evaluate first arg. */ + if (TREE_CODE (arg1) == INTEGER_CST && ! integer_zerop (arg1)) + return omit_one_operand (type, arg1, arg0); + /* Likewise for first arg, but note this only occurs here for + TRUTH_OR_EXPR. */ + if (TREE_CODE (arg0) == INTEGER_CST && ! integer_zerop (arg0)) + return omit_one_operand (type, arg0, arg1); + + /* !X || X is always true. */ + if (TREE_CODE (arg0) == TRUTH_NOT_EXPR + && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)) + return omit_one_operand (type, integer_one_node, arg1); + /* X || !X is always true. */ + if (TREE_CODE (arg1) == TRUTH_NOT_EXPR + && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)) + return omit_one_operand (type, integer_one_node, arg0); + + goto truth_andor; + + case TRUTH_XOR_EXPR: + /* If the second arg is constant zero, drop it. */ + if (integer_zerop (arg1)) + return non_lvalue (fold_convert (type, arg0)); + /* If the second arg is constant true, this is a logical inversion. */ + if (integer_onep (arg1)) + { + /* Only call invert_truthvalue if operand is a truth value. */ + if (TREE_CODE (TREE_TYPE (arg0)) != BOOLEAN_TYPE) + tem = fold_build1 (TRUTH_NOT_EXPR, TREE_TYPE (arg0), arg0); + else + tem = invert_truthvalue (arg0); + return non_lvalue (fold_convert (type, tem)); + } + /* Identical arguments cancel to zero. */ + if (operand_equal_p (arg0, arg1, 0)) + return omit_one_operand (type, integer_zero_node, arg0); + + /* !X ^ X is always true. */ + if (TREE_CODE (arg0) == TRUTH_NOT_EXPR + && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)) + return omit_one_operand (type, integer_one_node, arg1); + + /* X ^ !X is always true. */ + if (TREE_CODE (arg1) == TRUTH_NOT_EXPR + && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)) + return omit_one_operand (type, integer_one_node, arg0); + + return NULL_TREE; + + case EQ_EXPR: + case NE_EXPR: + tem = fold_comparison (code, type, op0, op1); + if (tem != NULL_TREE) + return tem; + + /* bool_var != 0 becomes bool_var. */ + if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE && integer_zerop (arg1) + && code == NE_EXPR) + return non_lvalue (fold_convert (type, arg0)); + + /* bool_var == 1 becomes bool_var. */ + if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE && integer_onep (arg1) + && code == EQ_EXPR) + return non_lvalue (fold_convert (type, arg0)); + + /* bool_var != 1 becomes !bool_var. */ + if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE && integer_onep (arg1) + && code == NE_EXPR) + return fold_build1 (TRUTH_NOT_EXPR, type, arg0); + + /* bool_var == 0 becomes !bool_var. */ + if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE && integer_zerop (arg1) + && code == EQ_EXPR) + return fold_build1 (TRUTH_NOT_EXPR, type, arg0); + + /* ~a != C becomes a != ~C where C is a constant. Likewise for ==. */ + if (TREE_CODE (arg0) == BIT_NOT_EXPR + && TREE_CODE (arg1) == INTEGER_CST) + { + tree cmp_type = TREE_TYPE (TREE_OPERAND (arg0, 0)); + return fold_build2 (code, type, TREE_OPERAND (arg0, 0), + fold_build1 (BIT_NOT_EXPR, cmp_type, + fold_convert (cmp_type, arg1))); + } + + /* If this is an equality comparison of the address of a non-weak + object against zero, then we know the result. */ + if (TREE_CODE (arg0) == ADDR_EXPR + && VAR_OR_FUNCTION_DECL_P (TREE_OPERAND (arg0, 0)) + && ! DECL_WEAK (TREE_OPERAND (arg0, 0)) + && integer_zerop (arg1)) + return constant_boolean_node (code != EQ_EXPR, type); + + /* If this is an equality comparison of the address of two non-weak, + unaliased symbols neither of which are extern (since we do not + have access to attributes for externs), then we know the result. */ + if (TREE_CODE (arg0) == ADDR_EXPR + && VAR_OR_FUNCTION_DECL_P (TREE_OPERAND (arg0, 0)) + && ! DECL_WEAK (TREE_OPERAND (arg0, 0)) + && ! lookup_attribute ("alias", + DECL_ATTRIBUTES (TREE_OPERAND (arg0, 0))) + && ! DECL_EXTERNAL (TREE_OPERAND (arg0, 0)) + && TREE_CODE (arg1) == ADDR_EXPR + && VAR_OR_FUNCTION_DECL_P (TREE_OPERAND (arg1, 0)) + && ! DECL_WEAK (TREE_OPERAND (arg1, 0)) + && ! lookup_attribute ("alias", + DECL_ATTRIBUTES (TREE_OPERAND (arg1, 0))) + && ! DECL_EXTERNAL (TREE_OPERAND (arg1, 0))) + { + /* We know that we're looking at the address of two + non-weak, unaliased, static _DECL nodes. + + It is both wasteful and incorrect to call operand_equal_p + to compare the two ADDR_EXPR nodes. It is wasteful in that + all we need to do is test pointer equality for the arguments + to the two ADDR_EXPR nodes. It is incorrect to use + operand_equal_p as that function is NOT equivalent to a + C equality test. It can in fact return false for two + objects which would test as equal using the C equality + operator. */ + bool equal = TREE_OPERAND (arg0, 0) == TREE_OPERAND (arg1, 0); + return constant_boolean_node (equal + ? code == EQ_EXPR : code != EQ_EXPR, + type); + } + + /* If this is an EQ or NE comparison of a constant with a PLUS_EXPR or + a MINUS_EXPR of a constant, we can convert it into a comparison with + a revised constant as long as no overflow occurs. */ + if (TREE_CODE (arg1) == INTEGER_CST + && (TREE_CODE (arg0) == PLUS_EXPR + || TREE_CODE (arg0) == MINUS_EXPR) + && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST + && 0 != (tem = const_binop (TREE_CODE (arg0) == PLUS_EXPR + ? MINUS_EXPR : PLUS_EXPR, + fold_convert (TREE_TYPE (arg0), arg1), + TREE_OPERAND (arg0, 1), 0)) + && ! TREE_CONSTANT_OVERFLOW (tem)) + return fold_build2 (code, type, TREE_OPERAND (arg0, 0), tem); + + /* Similarly for a NEGATE_EXPR. */ + if (TREE_CODE (arg0) == NEGATE_EXPR + && TREE_CODE (arg1) == INTEGER_CST + && 0 != (tem = negate_expr (arg1)) + && TREE_CODE (tem) == INTEGER_CST + && ! TREE_CONSTANT_OVERFLOW (tem)) + return fold_build2 (code, type, TREE_OPERAND (arg0, 0), tem); + + /* If we have X - Y == 0, we can convert that to X == Y and similarly + for !=. Don't do this for ordered comparisons due to overflow. */ + if (TREE_CODE (arg0) == MINUS_EXPR + && integer_zerop (arg1)) + return fold_build2 (code, type, + TREE_OPERAND (arg0, 0), TREE_OPERAND (arg0, 1)); + + /* Convert ABS_EXPR<x> == 0 or ABS_EXPR<x> != 0 to x == 0 or x != 0. */ + if (TREE_CODE (arg0) == ABS_EXPR + && (integer_zerop (arg1) || real_zerop (arg1))) + return fold_build2 (code, type, TREE_OPERAND (arg0, 0), arg1); + + /* If this is an EQ or NE comparison with zero and ARG0 is + (1 << foo) & bar, convert it to (bar >> foo) & 1. Both require + two operations, but the latter can be done in one less insn + on machines that have only two-operand insns or on which a + constant cannot be the first operand. */ + if (TREE_CODE (arg0) == BIT_AND_EXPR + && integer_zerop (arg1)) + { + tree arg00 = TREE_OPERAND (arg0, 0); + tree arg01 = TREE_OPERAND (arg0, 1); + if (TREE_CODE (arg00) == LSHIFT_EXPR + && integer_onep (TREE_OPERAND (arg00, 0))) + return + fold_build2 (code, type, + build2 (BIT_AND_EXPR, TREE_TYPE (arg0), + build2 (RSHIFT_EXPR, TREE_TYPE (arg00), + arg01, TREE_OPERAND (arg00, 1)), + fold_convert (TREE_TYPE (arg0), + integer_one_node)), + arg1); + else if (TREE_CODE (TREE_OPERAND (arg0, 1)) == LSHIFT_EXPR + && integer_onep (TREE_OPERAND (TREE_OPERAND (arg0, 1), 0))) + return + fold_build2 (code, type, + build2 (BIT_AND_EXPR, TREE_TYPE (arg0), + build2 (RSHIFT_EXPR, TREE_TYPE (arg01), + arg00, TREE_OPERAND (arg01, 1)), + fold_convert (TREE_TYPE (arg0), + integer_one_node)), + arg1); + } + + /* If this is an NE or EQ comparison of zero against the result of a + signed MOD operation whose second operand is a power of 2, make + the MOD operation unsigned since it is simpler and equivalent. */ + if (integer_zerop (arg1) + && !TYPE_UNSIGNED (TREE_TYPE (arg0)) + && (TREE_CODE (arg0) == TRUNC_MOD_EXPR + || TREE_CODE (arg0) == CEIL_MOD_EXPR + || TREE_CODE (arg0) == FLOOR_MOD_EXPR + || TREE_CODE (arg0) == ROUND_MOD_EXPR) + && integer_pow2p (TREE_OPERAND (arg0, 1))) + { + tree newtype = lang_hooks.types.unsigned_type (TREE_TYPE (arg0)); + tree newmod = fold_build2 (TREE_CODE (arg0), newtype, + fold_convert (newtype, + TREE_OPERAND (arg0, 0)), + fold_convert (newtype, + TREE_OPERAND (arg0, 1))); + + return fold_build2 (code, type, newmod, + fold_convert (newtype, arg1)); + } + + /* Fold ((X >> C1) & C2) == 0 and ((X >> C1) & C2) != 0 where + C1 is a valid shift constant, and C2 is a power of two, i.e. + a single bit. */ + if (TREE_CODE (arg0) == BIT_AND_EXPR + && TREE_CODE (TREE_OPERAND (arg0, 0)) == RSHIFT_EXPR + && TREE_CODE (TREE_OPERAND (TREE_OPERAND (arg0, 0), 1)) + == INTEGER_CST + && integer_pow2p (TREE_OPERAND (arg0, 1)) + && integer_zerop (arg1)) + { + tree itype = TREE_TYPE (arg0); + unsigned HOST_WIDE_INT prec = TYPE_PRECISION (itype); + tree arg001 = TREE_OPERAND (TREE_OPERAND (arg0, 0), 1); + + /* Check for a valid shift count. */ + if (TREE_INT_CST_HIGH (arg001) == 0 + && TREE_INT_CST_LOW (arg001) < prec) + { + tree arg01 = TREE_OPERAND (arg0, 1); + tree arg000 = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0); + unsigned HOST_WIDE_INT log2 = tree_log2 (arg01); + /* If (C2 << C1) doesn't overflow, then ((X >> C1) & C2) != 0 + can be rewritten as (X & (C2 << C1)) != 0. */ + if ((log2 + TREE_INT_CST_LOW (arg001)) < prec) + { + tem = fold_build2 (LSHIFT_EXPR, itype, arg01, arg001); + tem = fold_build2 (BIT_AND_EXPR, itype, arg000, tem); + return fold_build2 (code, type, tem, arg1); + } + /* Otherwise, for signed (arithmetic) shifts, + ((X >> C1) & C2) != 0 is rewritten as X < 0, and + ((X >> C1) & C2) == 0 is rewritten as X >= 0. */ + else if (!TYPE_UNSIGNED (itype)) + return fold_build2 (code == EQ_EXPR ? GE_EXPR : LT_EXPR, type, + arg000, build_int_cst (itype, 0)); + /* Otherwise, of unsigned (logical) shifts, + ((X >> C1) & C2) != 0 is rewritten as (X,false), and + ((X >> C1) & C2) == 0 is rewritten as (X,true). */ + else + return omit_one_operand (type, + code == EQ_EXPR ? integer_one_node + : integer_zero_node, + arg000); + } + } + + /* If this is an NE comparison of zero with an AND of one, remove the + comparison since the AND will give the correct value. */ + if (code == NE_EXPR + && integer_zerop (arg1) + && TREE_CODE (arg0) == BIT_AND_EXPR + && integer_onep (TREE_OPERAND (arg0, 1))) + return fold_convert (type, arg0); + + /* If we have (A & C) == C where C is a power of 2, convert this into + (A & C) != 0. Similarly for NE_EXPR. */ + if (TREE_CODE (arg0) == BIT_AND_EXPR + && integer_pow2p (TREE_OPERAND (arg0, 1)) + && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0)) + return fold_build2 (code == EQ_EXPR ? NE_EXPR : EQ_EXPR, type, + arg0, fold_convert (TREE_TYPE (arg0), + integer_zero_node)); + + /* If we have (A & C) != 0 or (A & C) == 0 and C is the sign + bit, then fold the expression into A < 0 or A >= 0. */ + tem = fold_single_bit_test_into_sign_test (code, arg0, arg1, type); + if (tem) + return tem; + + /* If we have (A & C) == D where D & ~C != 0, convert this into 0. + Similarly for NE_EXPR. */ + if (TREE_CODE (arg0) == BIT_AND_EXPR + && TREE_CODE (arg1) == INTEGER_CST + && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST) + { + tree notc = fold_build1 (BIT_NOT_EXPR, + TREE_TYPE (TREE_OPERAND (arg0, 1)), + TREE_OPERAND (arg0, 1)); + tree dandnotc = fold_build2 (BIT_AND_EXPR, TREE_TYPE (arg0), + arg1, notc); + tree rslt = code == EQ_EXPR ? integer_zero_node : integer_one_node; + if (integer_nonzerop (dandnotc)) + return omit_one_operand (type, rslt, arg0); + } + + /* If we have (A | C) == D where C & ~D != 0, convert this into 0. + Similarly for NE_EXPR. */ + if (TREE_CODE (arg0) == BIT_IOR_EXPR + && TREE_CODE (arg1) == INTEGER_CST + && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST) + { + tree notd = fold_build1 (BIT_NOT_EXPR, TREE_TYPE (arg1), arg1); + tree candnotd = fold_build2 (BIT_AND_EXPR, TREE_TYPE (arg0), + TREE_OPERAND (arg0, 1), notd); + tree rslt = code == EQ_EXPR ? integer_zero_node : integer_one_node; + if (integer_nonzerop (candnotd)) + return omit_one_operand (type, rslt, arg0); + } + + /* If this is a comparison of a field, we may be able to simplify it. */ + if (((TREE_CODE (arg0) == COMPONENT_REF + && lang_hooks.can_use_bit_fields_p ()) + || TREE_CODE (arg0) == BIT_FIELD_REF) + /* Handle the constant case even without -O + to make sure the warnings are given. */ + && (optimize || TREE_CODE (arg1) == INTEGER_CST)) + { + t1 = optimize_bit_field_compare (code, type, arg0, arg1); + if (t1) + return t1; + } + + /* Optimize comparisons of strlen vs zero to a compare of the + first character of the string vs zero. To wit, + strlen(ptr) == 0 => *ptr == 0 + strlen(ptr) != 0 => *ptr != 0 + Other cases should reduce to one of these two (or a constant) + due to the return value of strlen being unsigned. */ + if (TREE_CODE (arg0) == CALL_EXPR + && integer_zerop (arg1)) + { + tree fndecl = get_callee_fndecl (arg0); + tree arglist; + + if (fndecl + && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL + && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STRLEN + && (arglist = TREE_OPERAND (arg0, 1)) + && TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) == POINTER_TYPE + && ! TREE_CHAIN (arglist)) + { + tree iref = build_fold_indirect_ref (TREE_VALUE (arglist)); + return fold_build2 (code, type, iref, + build_int_cst (TREE_TYPE (iref), 0)); + } + } + + /* Fold (X >> C) != 0 into X < 0 if C is one less than the width + of X. Similarly fold (X >> C) == 0 into X >= 0. */ + if (TREE_CODE (arg0) == RSHIFT_EXPR + && integer_zerop (arg1) + && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST) + { + tree arg00 = TREE_OPERAND (arg0, 0); + tree arg01 = TREE_OPERAND (arg0, 1); + tree itype = TREE_TYPE (arg00); + if (TREE_INT_CST_HIGH (arg01) == 0 + && TREE_INT_CST_LOW (arg01) + == (unsigned HOST_WIDE_INT) (TYPE_PRECISION (itype) - 1)) + { + if (TYPE_UNSIGNED (itype)) + { + itype = lang_hooks.types.signed_type (itype); + arg00 = fold_convert (itype, arg00); + } + return fold_build2 (code == EQ_EXPR ? GE_EXPR : LT_EXPR, + type, arg00, build_int_cst (itype, 0)); + } + } + + /* (X ^ Y) == 0 becomes X == Y, and (X ^ Y) != 0 becomes X != Y. */ + if (integer_zerop (arg1) + && TREE_CODE (arg0) == BIT_XOR_EXPR) + return fold_build2 (code, type, TREE_OPERAND (arg0, 0), + TREE_OPERAND (arg0, 1)); + + /* (X ^ Y) == Y becomes X == 0. We know that Y has no side-effects. */ + if (TREE_CODE (arg0) == BIT_XOR_EXPR + && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0)) + return fold_build2 (code, type, TREE_OPERAND (arg0, 0), + build_int_cst (TREE_TYPE (arg1), 0)); + /* Likewise (X ^ Y) == X becomes Y == 0. X has no side-effects. */ + if (TREE_CODE (arg0) == BIT_XOR_EXPR + && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0) + && reorder_operands_p (TREE_OPERAND (arg0, 1), arg1)) + return fold_build2 (code, type, TREE_OPERAND (arg0, 1), + build_int_cst (TREE_TYPE (arg1), 0)); + + /* (X ^ C1) op C2 can be rewritten as X op (C1 ^ C2). */ + if (TREE_CODE (arg0) == BIT_XOR_EXPR + && TREE_CODE (arg1) == INTEGER_CST + && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST) + return fold_build2 (code, type, TREE_OPERAND (arg0, 0), + fold_build2 (BIT_XOR_EXPR, TREE_TYPE (arg1), + TREE_OPERAND (arg0, 1), arg1)); + + /* Fold (~X & C) == 0 into (X & C) != 0 and (~X & C) != 0 into + (X & C) == 0 when C is a single bit. */ + if (TREE_CODE (arg0) == BIT_AND_EXPR + && TREE_CODE (TREE_OPERAND (arg0, 0)) == BIT_NOT_EXPR + && integer_zerop (arg1) + && integer_pow2p (TREE_OPERAND (arg0, 1))) + { + tem = fold_build2 (BIT_AND_EXPR, TREE_TYPE (arg0), + TREE_OPERAND (TREE_OPERAND (arg0, 0), 0), + TREE_OPERAND (arg0, 1)); + return fold_build2 (code == EQ_EXPR ? NE_EXPR : EQ_EXPR, + type, tem, arg1); + } + + /* Fold ((X & C) ^ C) eq/ne 0 into (X & C) ne/eq 0, when the + constant C is a power of two, i.e. a single bit. */ + if (TREE_CODE (arg0) == BIT_XOR_EXPR + && TREE_CODE (TREE_OPERAND (arg0, 0)) == BIT_AND_EXPR + && integer_zerop (arg1) + && integer_pow2p (TREE_OPERAND (arg0, 1)) + && operand_equal_p (TREE_OPERAND (TREE_OPERAND (arg0, 0), 1), + TREE_OPERAND (arg0, 1), OEP_ONLY_CONST)) + { + tree arg00 = TREE_OPERAND (arg0, 0); + return fold_build2 (code == EQ_EXPR ? NE_EXPR : EQ_EXPR, type, + arg00, build_int_cst (TREE_TYPE (arg00), 0)); + } + + /* Likewise, fold ((X ^ C) & C) eq/ne 0 into (X & C) ne/eq 0, + when is C is a power of two, i.e. a single bit. */ + if (TREE_CODE (arg0) == BIT_AND_EXPR + && TREE_CODE (TREE_OPERAND (arg0, 0)) == BIT_XOR_EXPR + && integer_zerop (arg1) + && integer_pow2p (TREE_OPERAND (arg0, 1)) + && operand_equal_p (TREE_OPERAND (TREE_OPERAND (arg0, 0), 1), + TREE_OPERAND (arg0, 1), OEP_ONLY_CONST)) + { + tree arg000 = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0); + tem = fold_build2 (BIT_AND_EXPR, TREE_TYPE (arg000), + arg000, TREE_OPERAND (arg0, 1)); + return fold_build2 (code == EQ_EXPR ? NE_EXPR : EQ_EXPR, type, + tem, build_int_cst (TREE_TYPE (tem), 0)); + } + + if (integer_zerop (arg1) + && tree_expr_nonzero_p (arg0)) + { + tree res = constant_boolean_node (code==NE_EXPR, type); + return omit_one_operand (type, res, arg0); + } + return NULL_TREE; + + case LT_EXPR: + case GT_EXPR: + case LE_EXPR: + case GE_EXPR: + tem = fold_comparison (code, type, op0, op1); + if (tem != NULL_TREE) + return tem; + + /* Transform comparisons of the form X +- C CMP X. */ + if ((TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR) + && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0) + && ((TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST + && !HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0)))) + || (TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST + && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1))))) + { + tree arg01 = TREE_OPERAND (arg0, 1); + enum tree_code code0 = TREE_CODE (arg0); + int is_positive; + + if (TREE_CODE (arg01) == REAL_CST) + is_positive = REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg01)) ? -1 : 1; + else + is_positive = tree_int_cst_sgn (arg01); + + /* (X - c) > X becomes false. */ + if (code == GT_EXPR + && ((code0 == MINUS_EXPR && is_positive >= 0) + || (code0 == PLUS_EXPR && is_positive <= 0))) + { + if (TREE_CODE (arg01) == INTEGER_CST + && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1))) + fold_overflow_warning (("assuming signed overflow does not " + "occur when assuming that (X - c) > X " + "is always false"), + WARN_STRICT_OVERFLOW_ALL); + return constant_boolean_node (0, type); + } + + /* Likewise (X + c) < X becomes false. */ + if (code == LT_EXPR + && ((code0 == PLUS_EXPR && is_positive >= 0) + || (code0 == MINUS_EXPR && is_positive <= 0))) + { + if (TREE_CODE (arg01) == INTEGER_CST + && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1))) + fold_overflow_warning (("assuming signed overflow does not " + "occur when assuming that " + "(X + c) < X is always false"), + WARN_STRICT_OVERFLOW_ALL); + return constant_boolean_node (0, type); + } + + /* Convert (X - c) <= X to true. */ + if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg1))) + && code == LE_EXPR + && ((code0 == MINUS_EXPR && is_positive >= 0) + || (code0 == PLUS_EXPR && is_positive <= 0))) + { + if (TREE_CODE (arg01) == INTEGER_CST + && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1))) + fold_overflow_warning (("assuming signed overflow does not " + "occur when assuming that " + "(X - c) <= X is always true"), + WARN_STRICT_OVERFLOW_ALL); + return constant_boolean_node (1, type); + } + + /* Convert (X + c) >= X to true. */ + if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg1))) + && code == GE_EXPR + && ((code0 == PLUS_EXPR && is_positive >= 0) + || (code0 == MINUS_EXPR && is_positive <= 0))) + { + if (TREE_CODE (arg01) == INTEGER_CST + && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1))) + fold_overflow_warning (("assuming signed overflow does not " + "occur when assuming that " + "(X + c) >= X is always true"), + WARN_STRICT_OVERFLOW_ALL); + return constant_boolean_node (1, type); + } + + if (TREE_CODE (arg01) == INTEGER_CST) + { + /* Convert X + c > X and X - c < X to true for integers. */ + if (code == GT_EXPR + && ((code0 == PLUS_EXPR && is_positive > 0) + || (code0 == MINUS_EXPR && is_positive < 0))) + { + if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1))) + fold_overflow_warning (("assuming signed overflow does " + "not occur when assuming that " + "(X + c) > X is always true"), + WARN_STRICT_OVERFLOW_ALL); + return constant_boolean_node (1, type); + } + + if (code == LT_EXPR + && ((code0 == MINUS_EXPR && is_positive > 0) + || (code0 == PLUS_EXPR && is_positive < 0))) + { + if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1))) + fold_overflow_warning (("assuming signed overflow does " + "not occur when assuming that " + "(X - c) < X is always true"), + WARN_STRICT_OVERFLOW_ALL); + return constant_boolean_node (1, type); + } + + /* Convert X + c <= X and X - c >= X to false for integers. */ + if (code == LE_EXPR + && ((code0 == PLUS_EXPR && is_positive > 0) + || (code0 == MINUS_EXPR && is_positive < 0))) + { + if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1))) + fold_overflow_warning (("assuming signed overflow does " + "not occur when assuming that " + "(X + c) <= X is always false"), + WARN_STRICT_OVERFLOW_ALL); + return constant_boolean_node (0, type); + } + + if (code == GE_EXPR + && ((code0 == MINUS_EXPR && is_positive > 0) + || (code0 == PLUS_EXPR && is_positive < 0))) + { + if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1))) + fold_overflow_warning (("assuming signed overflow does " + "not occur when assuming that " + "(X - c) >= X is always true"), + WARN_STRICT_OVERFLOW_ALL); + return constant_boolean_node (0, type); + } + } + } + + /* Change X >= C to X > (C - 1) and X < C to X <= (C - 1) if C > 0. + This transformation affects the cases which are handled in later + optimizations involving comparisons with non-negative constants. */ + if (TREE_CODE (arg1) == INTEGER_CST + && TREE_CODE (arg0) != INTEGER_CST + && tree_int_cst_sgn (arg1) > 0) + { + if (code == GE_EXPR) + { + arg1 = const_binop (MINUS_EXPR, arg1, + build_int_cst (TREE_TYPE (arg1), 1), 0); + return fold_build2 (GT_EXPR, type, arg0, + fold_convert (TREE_TYPE (arg0), arg1)); + } + if (code == LT_EXPR) + { + arg1 = const_binop (MINUS_EXPR, arg1, + build_int_cst (TREE_TYPE (arg1), 1), 0); + return fold_build2 (LE_EXPR, type, arg0, + fold_convert (TREE_TYPE (arg0), arg1)); + } + } + + /* Comparisons with the highest or lowest possible integer of + the specified size will have known values. */ + { + int width = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (arg1))); + + if (TREE_CODE (arg1) == INTEGER_CST + && ! TREE_CONSTANT_OVERFLOW (arg1) + && width <= 2 * HOST_BITS_PER_WIDE_INT + && (INTEGRAL_TYPE_P (TREE_TYPE (arg1)) + || POINTER_TYPE_P (TREE_TYPE (arg1)))) + { + HOST_WIDE_INT signed_max_hi; + unsigned HOST_WIDE_INT signed_max_lo; + unsigned HOST_WIDE_INT max_hi, max_lo, min_hi, min_lo; + + if (width <= HOST_BITS_PER_WIDE_INT) + { + signed_max_lo = ((unsigned HOST_WIDE_INT) 1 << (width - 1)) + - 1; + signed_max_hi = 0; + max_hi = 0; + + if (TYPE_UNSIGNED (TREE_TYPE (arg1))) + { + max_lo = ((unsigned HOST_WIDE_INT) 2 << (width - 1)) - 1; + min_lo = 0; + min_hi = 0; + } + else + { + max_lo = signed_max_lo; + min_lo = ((unsigned HOST_WIDE_INT) -1 << (width - 1)); + min_hi = -1; + } + } + else + { + width -= HOST_BITS_PER_WIDE_INT; + signed_max_lo = -1; + signed_max_hi = ((unsigned HOST_WIDE_INT) 1 << (width - 1)) + - 1; + max_lo = -1; + min_lo = 0; + + if (TYPE_UNSIGNED (TREE_TYPE (arg1))) + { + max_hi = ((unsigned HOST_WIDE_INT) 2 << (width - 1)) - 1; + min_hi = 0; + } + else + { + max_hi = signed_max_hi; + min_hi = ((unsigned HOST_WIDE_INT) -1 << (width - 1)); + } + } + + if ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (arg1) == max_hi + && TREE_INT_CST_LOW (arg1) == max_lo) + switch (code) + { + case GT_EXPR: + return omit_one_operand (type, integer_zero_node, arg0); + + case GE_EXPR: + return fold_build2 (EQ_EXPR, type, op0, op1); + + case LE_EXPR: + return omit_one_operand (type, integer_one_node, arg0); + + case LT_EXPR: + return fold_build2 (NE_EXPR, type, op0, op1); + + /* The GE_EXPR and LT_EXPR cases above are not normally + reached because of previous transformations. */ + + default: + break; + } + else if ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (arg1) + == max_hi + && TREE_INT_CST_LOW (arg1) == max_lo - 1) + switch (code) + { + case GT_EXPR: + arg1 = const_binop (PLUS_EXPR, arg1, integer_one_node, 0); + return fold_build2 (EQ_EXPR, type, + fold_convert (TREE_TYPE (arg1), arg0), + arg1); + case LE_EXPR: + arg1 = const_binop (PLUS_EXPR, arg1, integer_one_node, 0); + return fold_build2 (NE_EXPR, type, + fold_convert (TREE_TYPE (arg1), arg0), + arg1); + default: + break; + } + else if ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (arg1) + == min_hi + && TREE_INT_CST_LOW (arg1) == min_lo) + switch (code) + { + case LT_EXPR: + return omit_one_operand (type, integer_zero_node, arg0); + + case LE_EXPR: + return fold_build2 (EQ_EXPR, type, op0, op1); + + case GE_EXPR: + return omit_one_operand (type, integer_one_node, arg0); + + case GT_EXPR: + return fold_build2 (NE_EXPR, type, op0, op1); + + default: + break; + } + else if ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (arg1) + == min_hi + && TREE_INT_CST_LOW (arg1) == min_lo + 1) + switch (code) + { + case GE_EXPR: + arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node, 0); + return fold_build2 (NE_EXPR, type, + fold_convert (TREE_TYPE (arg1), arg0), + arg1); + case LT_EXPR: + arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node, 0); + return fold_build2 (EQ_EXPR, type, + fold_convert (TREE_TYPE (arg1), arg0), + arg1); + default: + break; + } + + else if (!in_gimple_form + && TREE_INT_CST_HIGH (arg1) == signed_max_hi + && TREE_INT_CST_LOW (arg1) == signed_max_lo + && TYPE_UNSIGNED (TREE_TYPE (arg1)) + /* signed_type does not work on pointer types. */ + && INTEGRAL_TYPE_P (TREE_TYPE (arg1))) + { + /* The following case also applies to X < signed_max+1 + and X >= signed_max+1 because previous transformations. */ + if (code == LE_EXPR || code == GT_EXPR) + { + tree st; + st = lang_hooks.types.signed_type (TREE_TYPE (arg1)); + return fold_build2 (code == LE_EXPR ? GE_EXPR : LT_EXPR, + type, fold_convert (st, arg0), + build_int_cst (st, 0)); + } + } + } + } + + /* If we are comparing an ABS_EXPR with a constant, we can + convert all the cases into explicit comparisons, but they may + well not be faster than doing the ABS and one comparison. + But ABS (X) <= C is a range comparison, which becomes a subtraction + and a comparison, and is probably faster. */ + if (code == LE_EXPR + && TREE_CODE (arg1) == INTEGER_CST + && TREE_CODE (arg0) == ABS_EXPR + && ! TREE_SIDE_EFFECTS (arg0) + && (0 != (tem = negate_expr (arg1))) + && TREE_CODE (tem) == INTEGER_CST + && ! TREE_CONSTANT_OVERFLOW (tem)) + return fold_build2 (TRUTH_ANDIF_EXPR, type, + build2 (GE_EXPR, type, + TREE_OPERAND (arg0, 0), tem), + build2 (LE_EXPR, type, + TREE_OPERAND (arg0, 0), arg1)); + + /* Convert ABS_EXPR<x> >= 0 to true. */ + strict_overflow_p = false; + if (code == GE_EXPR + && (integer_zerop (arg1) + || (! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))) + && real_zerop (arg1))) + && tree_expr_nonnegative_warnv_p (arg0, &strict_overflow_p)) + { + if (strict_overflow_p) + fold_overflow_warning (("assuming signed overflow does not occur " + "when simplifying comparison of " + "absolute value and zero"), + WARN_STRICT_OVERFLOW_CONDITIONAL); + return omit_one_operand (type, integer_one_node, arg0); + } + + /* Convert ABS_EXPR<x> < 0 to false. */ + strict_overflow_p = false; + if (code == LT_EXPR + && (integer_zerop (arg1) || real_zerop (arg1)) + && tree_expr_nonnegative_warnv_p (arg0, &strict_overflow_p)) + { + if (strict_overflow_p) + fold_overflow_warning (("assuming signed overflow does not occur " + "when simplifying comparison of " + "absolute value and zero"), + WARN_STRICT_OVERFLOW_CONDITIONAL); + return omit_one_operand (type, integer_zero_node, arg0); + } + + /* If X is unsigned, convert X < (1 << Y) into X >> Y == 0 + and similarly for >= into !=. */ + if ((code == LT_EXPR || code == GE_EXPR) + && TYPE_UNSIGNED (TREE_TYPE (arg0)) + && TREE_CODE (arg1) == LSHIFT_EXPR + && integer_onep (TREE_OPERAND (arg1, 0))) + return build2 (code == LT_EXPR ? EQ_EXPR : NE_EXPR, type, + build2 (RSHIFT_EXPR, TREE_TYPE (arg0), arg0, + TREE_OPERAND (arg1, 1)), + build_int_cst (TREE_TYPE (arg0), 0)); + + if ((code == LT_EXPR || code == GE_EXPR) + && TYPE_UNSIGNED (TREE_TYPE (arg0)) + && (TREE_CODE (arg1) == NOP_EXPR + || TREE_CODE (arg1) == CONVERT_EXPR) + && TREE_CODE (TREE_OPERAND (arg1, 0)) == LSHIFT_EXPR + && integer_onep (TREE_OPERAND (TREE_OPERAND (arg1, 0), 0))) + return + build2 (code == LT_EXPR ? EQ_EXPR : NE_EXPR, type, + fold_convert (TREE_TYPE (arg0), + build2 (RSHIFT_EXPR, TREE_TYPE (arg0), arg0, + TREE_OPERAND (TREE_OPERAND (arg1, 0), + 1))), + build_int_cst (TREE_TYPE (arg0), 0)); + + return NULL_TREE; + + case UNORDERED_EXPR: + case ORDERED_EXPR: + case UNLT_EXPR: + case UNLE_EXPR: + case UNGT_EXPR: + case UNGE_EXPR: + case UNEQ_EXPR: + case LTGT_EXPR: + if (TREE_CODE (arg0) == REAL_CST && TREE_CODE (arg1) == REAL_CST) + { + t1 = fold_relational_const (code, type, arg0, arg1); + if (t1 != NULL_TREE) + return t1; + } + + /* If the first operand is NaN, the result is constant. */ + if (TREE_CODE (arg0) == REAL_CST + && REAL_VALUE_ISNAN (TREE_REAL_CST (arg0)) + && (code != LTGT_EXPR || ! flag_trapping_math)) + { + t1 = (code == ORDERED_EXPR || code == LTGT_EXPR) + ? integer_zero_node + : integer_one_node; + return omit_one_operand (type, t1, arg1); + } + + /* If the second operand is NaN, the result is constant. */ + if (TREE_CODE (arg1) == REAL_CST + && REAL_VALUE_ISNAN (TREE_REAL_CST (arg1)) + && (code != LTGT_EXPR || ! flag_trapping_math)) + { + t1 = (code == ORDERED_EXPR || code == LTGT_EXPR) + ? integer_zero_node + : integer_one_node; + return omit_one_operand (type, t1, arg0); + } + + /* Simplify unordered comparison of something with itself. */ + if ((code == UNLE_EXPR || code == UNGE_EXPR || code == UNEQ_EXPR) + && operand_equal_p (arg0, arg1, 0)) + return constant_boolean_node (1, type); + + if (code == LTGT_EXPR + && !flag_trapping_math + && operand_equal_p (arg0, arg1, 0)) + return constant_boolean_node (0, type); + + /* Fold (double)float1 CMP (double)float2 into float1 CMP float2. */ + { + tree targ0 = strip_float_extensions (arg0); + tree targ1 = strip_float_extensions (arg1); + tree newtype = TREE_TYPE (targ0); + + if (TYPE_PRECISION (TREE_TYPE (targ1)) > TYPE_PRECISION (newtype)) + newtype = TREE_TYPE (targ1); + + if (TYPE_PRECISION (newtype) < TYPE_PRECISION (TREE_TYPE (arg0))) + return fold_build2 (code, type, fold_convert (newtype, targ0), + fold_convert (newtype, targ1)); + } + + return NULL_TREE; + + case COMPOUND_EXPR: + /* When pedantic, a compound expression can be neither an lvalue + nor an integer constant expression. */ + if (TREE_SIDE_EFFECTS (arg0) || TREE_CONSTANT (arg1)) + return NULL_TREE; + /* Don't let (0, 0) be null pointer constant. */ + tem = integer_zerop (arg1) ? build1 (NOP_EXPR, type, arg1) + : fold_convert (type, arg1); + return pedantic_non_lvalue (tem); + + case COMPLEX_EXPR: + if ((TREE_CODE (arg0) == REAL_CST + && TREE_CODE (arg1) == REAL_CST) + || (TREE_CODE (arg0) == INTEGER_CST + && TREE_CODE (arg1) == INTEGER_CST)) + return build_complex (type, arg0, arg1); + return NULL_TREE; + + case ASSERT_EXPR: + /* An ASSERT_EXPR should never be passed to fold_binary. */ + gcc_unreachable (); + + default: + return NULL_TREE; + } /* switch (code) */ +} + +/* Callback for walk_tree, looking for LABEL_EXPR. + Returns tree TP if it is LABEL_EXPR. Otherwise it returns NULL_TREE. + Do not check the sub-tree of GOTO_EXPR. */ + +static tree +contains_label_1 (tree *tp, + int *walk_subtrees, + void *data ATTRIBUTE_UNUSED) +{ + switch (TREE_CODE (*tp)) + { + case LABEL_EXPR: + return *tp; + case GOTO_EXPR: + *walk_subtrees = 0; + /* no break */ + default: + return NULL_TREE; + } +} + +/* Checks whether the sub-tree ST contains a label LABEL_EXPR which is + accessible from outside the sub-tree. Returns NULL_TREE if no + addressable label is found. */ + +static bool +contains_label_p (tree st) +{ + return (walk_tree (&st, contains_label_1 , NULL, NULL) != NULL_TREE); +} + +/* Fold a ternary expression of code CODE and type TYPE with operands + OP0, OP1, and OP2. Return the folded expression if folding is + successful. Otherwise, return NULL_TREE. */ + +tree +fold_ternary (enum tree_code code, tree type, tree op0, tree op1, tree op2) +{ + tree tem; + tree arg0 = NULL_TREE, arg1 = NULL_TREE; + enum tree_code_class kind = TREE_CODE_CLASS (code); + + gcc_assert (IS_EXPR_CODE_CLASS (kind) + && TREE_CODE_LENGTH (code) == 3); + + /* Strip any conversions that don't change the mode. This is safe + for every expression, except for a comparison expression because + its signedness is derived from its operands. So, in the latter + case, only strip conversions that don't change the signedness. + + Note that this is done as an internal manipulation within the + constant folder, in order to find the simplest representation of + the arguments so that their form can be studied. In any cases, + the appropriate type conversions should be put back in the tree + that will get out of the constant folder. */ + if (op0) + { + arg0 = op0; + STRIP_NOPS (arg0); + } + + if (op1) + { + arg1 = op1; + STRIP_NOPS (arg1); + } + + switch (code) + { + case COMPONENT_REF: + if (TREE_CODE (arg0) == CONSTRUCTOR + && ! type_contains_placeholder_p (TREE_TYPE (arg0))) + { + unsigned HOST_WIDE_INT idx; + tree field, value; + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (arg0), idx, field, value) + if (field == arg1) + return value; + } + return NULL_TREE; + + case COND_EXPR: + /* Pedantic ANSI C says that a conditional expression is never an lvalue, + so all simple results must be passed through pedantic_non_lvalue. */ + if (TREE_CODE (arg0) == INTEGER_CST) + { + tree unused_op = integer_zerop (arg0) ? op1 : op2; + tem = integer_zerop (arg0) ? op2 : op1; + /* Only optimize constant conditions when the selected branch + has the same type as the COND_EXPR. This avoids optimizing + away "c ? x : throw", where the throw has a void type. + Avoid throwing away that operand which contains label. */ + if ((!TREE_SIDE_EFFECTS (unused_op) + || !contains_label_p (unused_op)) + && (! VOID_TYPE_P (TREE_TYPE (tem)) + || VOID_TYPE_P (type))) + return pedantic_non_lvalue (tem); + return NULL_TREE; + } + if (operand_equal_p (arg1, op2, 0)) + return pedantic_omit_one_operand (type, arg1, arg0); + + /* If we have A op B ? A : C, we may be able to convert this to a + simpler expression, depending on the operation and the values + of B and C. Signed zeros prevent all of these transformations, + for reasons given above each one. + + Also try swapping the arguments and inverting the conditional. */ + if (COMPARISON_CLASS_P (arg0) + && operand_equal_for_comparison_p (TREE_OPERAND (arg0, 0), + arg1, TREE_OPERAND (arg0, 1)) + && !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg1)))) + { + tem = fold_cond_expr_with_comparison (type, arg0, op1, op2); + if (tem) + return tem; + } + + if (COMPARISON_CLASS_P (arg0) + && operand_equal_for_comparison_p (TREE_OPERAND (arg0, 0), + op2, + TREE_OPERAND (arg0, 1)) + && !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (op2)))) + { + tem = fold_truth_not_expr (arg0); + if (tem && COMPARISON_CLASS_P (tem)) + { + tem = fold_cond_expr_with_comparison (type, tem, op2, op1); + if (tem) + return tem; + } + } + + /* If the second operand is simpler than the third, swap them + since that produces better jump optimization results. */ + if (truth_value_p (TREE_CODE (arg0)) + && tree_swap_operands_p (op1, op2, false)) + { + /* See if this can be inverted. If it can't, possibly because + it was a floating-point inequality comparison, don't do + anything. */ + tem = fold_truth_not_expr (arg0); + if (tem) + return fold_build3 (code, type, tem, op2, op1); + } + + /* Convert A ? 1 : 0 to simply A. */ + if (integer_onep (op1) + && integer_zerop (op2) + /* If we try to convert OP0 to our type, the + call to fold will try to move the conversion inside + a COND, which will recurse. In that case, the COND_EXPR + is probably the best choice, so leave it alone. */ + && type == TREE_TYPE (arg0)) + return pedantic_non_lvalue (arg0); + + /* Convert A ? 0 : 1 to !A. This prefers the use of NOT_EXPR + over COND_EXPR in cases such as floating point comparisons. */ + if (integer_zerop (op1) + && integer_onep (op2) + && truth_value_p (TREE_CODE (arg0))) + return pedantic_non_lvalue (fold_convert (type, + invert_truthvalue (arg0))); + + /* A < 0 ? <sign bit of A> : 0 is simply (A & <sign bit of A>). */ + if (TREE_CODE (arg0) == LT_EXPR + && integer_zerop (TREE_OPERAND (arg0, 1)) + && integer_zerop (op2) + && (tem = sign_bit_p (TREE_OPERAND (arg0, 0), arg1))) + { + /* sign_bit_p only checks ARG1 bits within A's precision. + If <sign bit of A> has wider type than A, bits outside + of A's precision in <sign bit of A> need to be checked. + If they are all 0, this optimization needs to be done + in unsigned A's type, if they are all 1 in signed A's type, + otherwise this can't be done. */ + if (TYPE_PRECISION (TREE_TYPE (tem)) + < TYPE_PRECISION (TREE_TYPE (arg1)) + && TYPE_PRECISION (TREE_TYPE (tem)) + < TYPE_PRECISION (type)) + { + unsigned HOST_WIDE_INT mask_lo; + HOST_WIDE_INT mask_hi; + int inner_width, outer_width; + tree tem_type; + + inner_width = TYPE_PRECISION (TREE_TYPE (tem)); + outer_width = TYPE_PRECISION (TREE_TYPE (arg1)); + if (outer_width > TYPE_PRECISION (type)) + outer_width = TYPE_PRECISION (type); + + if (outer_width > HOST_BITS_PER_WIDE_INT) + { + mask_hi = ((unsigned HOST_WIDE_INT) -1 + >> (2 * HOST_BITS_PER_WIDE_INT - outer_width)); + mask_lo = -1; + } + else + { + mask_hi = 0; + mask_lo = ((unsigned HOST_WIDE_INT) -1 + >> (HOST_BITS_PER_WIDE_INT - outer_width)); + } + if (inner_width > HOST_BITS_PER_WIDE_INT) + { + mask_hi &= ~((unsigned HOST_WIDE_INT) -1 + >> (HOST_BITS_PER_WIDE_INT - inner_width)); + mask_lo = 0; + } + else + mask_lo &= ~((unsigned HOST_WIDE_INT) -1 + >> (HOST_BITS_PER_WIDE_INT - inner_width)); + + if ((TREE_INT_CST_HIGH (arg1) & mask_hi) == mask_hi + && (TREE_INT_CST_LOW (arg1) & mask_lo) == mask_lo) + { + tem_type = lang_hooks.types.signed_type (TREE_TYPE (tem)); + tem = fold_convert (tem_type, tem); + } + else if ((TREE_INT_CST_HIGH (arg1) & mask_hi) == 0 + && (TREE_INT_CST_LOW (arg1) & mask_lo) == 0) + { + tem_type = lang_hooks.types.unsigned_type (TREE_TYPE (tem)); + tem = fold_convert (tem_type, tem); + } + else + tem = NULL; + } + + if (tem) + return fold_convert (type, + fold_build2 (BIT_AND_EXPR, + TREE_TYPE (tem), tem, + fold_convert (TREE_TYPE (tem), + arg1))); + } + + /* (A >> N) & 1 ? (1 << N) : 0 is simply A & (1 << N). A & 1 was + already handled above. */ + if (TREE_CODE (arg0) == BIT_AND_EXPR + && integer_onep (TREE_OPERAND (arg0, 1)) + && integer_zerop (op2) + && integer_pow2p (arg1)) + { + tree tem = TREE_OPERAND (arg0, 0); + STRIP_NOPS (tem); + if (TREE_CODE (tem) == RSHIFT_EXPR + && TREE_CODE (TREE_OPERAND (tem, 1)) == INTEGER_CST + && (unsigned HOST_WIDE_INT) tree_log2 (arg1) == + TREE_INT_CST_LOW (TREE_OPERAND (tem, 1))) + return fold_build2 (BIT_AND_EXPR, type, + TREE_OPERAND (tem, 0), arg1); + } + + /* A & N ? N : 0 is simply A & N if N is a power of two. This + is probably obsolete because the first operand should be a + truth value (that's why we have the two cases above), but let's + leave it in until we can confirm this for all front-ends. */ + if (integer_zerop (op2) + && TREE_CODE (arg0) == NE_EXPR + && integer_zerop (TREE_OPERAND (arg0, 1)) + && integer_pow2p (arg1) + && TREE_CODE (TREE_OPERAND (arg0, 0)) == BIT_AND_EXPR + && operand_equal_p (TREE_OPERAND (TREE_OPERAND (arg0, 0), 1), + arg1, OEP_ONLY_CONST)) + return pedantic_non_lvalue (fold_convert (type, + TREE_OPERAND (arg0, 0))); + + /* Convert A ? B : 0 into A && B if A and B are truth values. */ + if (integer_zerop (op2) + && truth_value_p (TREE_CODE (arg0)) + && truth_value_p (TREE_CODE (arg1))) + return fold_build2 (TRUTH_ANDIF_EXPR, type, + fold_convert (type, arg0), + arg1); + + /* Convert A ? B : 1 into !A || B if A and B are truth values. */ + if (integer_onep (op2) + && truth_value_p (TREE_CODE (arg0)) + && truth_value_p (TREE_CODE (arg1))) + { + /* Only perform transformation if ARG0 is easily inverted. */ + tem = fold_truth_not_expr (arg0); + if (tem) + return fold_build2 (TRUTH_ORIF_EXPR, type, + fold_convert (type, tem), + arg1); + } + + /* Convert A ? 0 : B into !A && B if A and B are truth values. */ + if (integer_zerop (arg1) + && truth_value_p (TREE_CODE (arg0)) + && truth_value_p (TREE_CODE (op2))) + { + /* Only perform transformation if ARG0 is easily inverted. */ + tem = fold_truth_not_expr (arg0); + if (tem) + return fold_build2 (TRUTH_ANDIF_EXPR, type, + fold_convert (type, tem), + op2); + } + + /* Convert A ? 1 : B into A || B if A and B are truth values. */ + if (integer_onep (arg1) + && truth_value_p (TREE_CODE (arg0)) + && truth_value_p (TREE_CODE (op2))) + return fold_build2 (TRUTH_ORIF_EXPR, type, + fold_convert (type, arg0), + op2); + + return NULL_TREE; + + case CALL_EXPR: + /* Check for a built-in function. */ + if (TREE_CODE (op0) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (op0, 0)) == FUNCTION_DECL + && DECL_BUILT_IN (TREE_OPERAND (op0, 0))) + return fold_builtin (TREE_OPERAND (op0, 0), op1, false); + return NULL_TREE; + + case BIT_FIELD_REF: + if (TREE_CODE (arg0) == VECTOR_CST + && type == TREE_TYPE (TREE_TYPE (arg0)) + && host_integerp (arg1, 1) + && host_integerp (op2, 1)) + { + unsigned HOST_WIDE_INT width = tree_low_cst (arg1, 1); + unsigned HOST_WIDE_INT idx = tree_low_cst (op2, 1); + + if (width != 0 + && simple_cst_equal (arg1, TYPE_SIZE (type)) == 1 + && (idx % width) == 0 + && (idx = idx / width) + < TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0))) + { + tree elements = TREE_VECTOR_CST_ELTS (arg0); + while (idx-- > 0 && elements) + elements = TREE_CHAIN (elements); + if (elements) + return TREE_VALUE (elements); + else + return fold_convert (type, integer_zero_node); + } + } + return NULL_TREE; + + default: + return NULL_TREE; + } /* switch (code) */ +} + +/* 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 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. */ + +#ifdef ENABLE_FOLD_CHECKING +# define fold(x) fold_1 (x) +static tree fold_1 (tree); +static +#endif +tree +fold (tree expr) +{ + const tree t = expr; + enum tree_code code = TREE_CODE (t); + enum tree_code_class kind = TREE_CODE_CLASS (code); + tree tem; + + /* Return right away if a constant. */ + if (kind == tcc_constant) + return t; + + if (IS_EXPR_CODE_CLASS (kind)) + { + tree type = TREE_TYPE (t); + tree op0, op1, op2; + + switch (TREE_CODE_LENGTH (code)) + { + case 1: + op0 = TREE_OPERAND (t, 0); + tem = fold_unary (code, type, op0); + return tem ? tem : expr; + case 2: + op0 = TREE_OPERAND (t, 0); + op1 = TREE_OPERAND (t, 1); + tem = fold_binary (code, type, op0, op1); + return tem ? tem : expr; + case 3: + op0 = TREE_OPERAND (t, 0); + op1 = TREE_OPERAND (t, 1); + op2 = TREE_OPERAND (t, 2); + tem = fold_ternary (code, type, op0, op1, op2); + return tem ? tem : expr; + default: + break; + } + } + + switch (code) + { + case CONST_DECL: + return fold (DECL_INITIAL (t)); + + default: + return t; + } /* switch (code) */ +} + +#ifdef ENABLE_FOLD_CHECKING +#undef fold + +static void fold_checksum_tree (tree, struct md5_ctx *, htab_t); +static void fold_check_failed (tree, tree); +void print_fold_checksum (tree); + +/* When --enable-checking=fold, compute a digest of expr before + and after actual fold call to see if fold did not accidentally + change original expr. */ + +tree +fold (tree expr) +{ + tree ret; + struct md5_ctx ctx; + unsigned char checksum_before[16], checksum_after[16]; + htab_t ht; + + ht = htab_create (32, htab_hash_pointer, htab_eq_pointer, NULL); + md5_init_ctx (&ctx); + fold_checksum_tree (expr, &ctx, ht); + md5_finish_ctx (&ctx, checksum_before); + htab_empty (ht); + + ret = fold_1 (expr); + + md5_init_ctx (&ctx); + fold_checksum_tree (expr, &ctx, ht); + md5_finish_ctx (&ctx, checksum_after); + htab_delete (ht); + + if (memcmp (checksum_before, checksum_after, 16)) + fold_check_failed (expr, ret); + + return ret; +} + +void +print_fold_checksum (tree expr) +{ + struct md5_ctx ctx; + unsigned char checksum[16], cnt; + htab_t ht; + + ht = htab_create (32, htab_hash_pointer, htab_eq_pointer, NULL); + md5_init_ctx (&ctx); + fold_checksum_tree (expr, &ctx, ht); + md5_finish_ctx (&ctx, checksum); + htab_delete (ht); + for (cnt = 0; cnt < 16; ++cnt) + fprintf (stderr, "%02x", checksum[cnt]); + putc ('\n', stderr); +} + +static void +fold_check_failed (tree expr ATTRIBUTE_UNUSED, tree ret ATTRIBUTE_UNUSED) +{ + internal_error ("fold check: original tree changed by fold"); +} + +static void +fold_checksum_tree (tree expr, struct md5_ctx *ctx, htab_t ht) +{ + void **slot; + enum tree_code code; + struct tree_function_decl buf; + int i, len; + +recursive_label: + + gcc_assert ((sizeof (struct tree_exp) + 5 * sizeof (tree) + <= sizeof (struct tree_function_decl)) + && sizeof (struct tree_type) <= sizeof (struct tree_function_decl)); + if (expr == NULL) + return; + slot = htab_find_slot (ht, expr, INSERT); + if (*slot != NULL) + return; + *slot = expr; + code = TREE_CODE (expr); + if (TREE_CODE_CLASS (code) == tcc_declaration + && DECL_ASSEMBLER_NAME_SET_P (expr)) + { + /* Allow DECL_ASSEMBLER_NAME to be modified. */ + memcpy ((char *) &buf, expr, tree_size (expr)); + expr = (tree) &buf; + SET_DECL_ASSEMBLER_NAME (expr, NULL); + } + else if (TREE_CODE_CLASS (code) == tcc_type + && (TYPE_POINTER_TO (expr) || TYPE_REFERENCE_TO (expr) + || TYPE_CACHED_VALUES_P (expr) + || TYPE_CONTAINS_PLACEHOLDER_INTERNAL (expr))) + { + /* Allow these fields to be modified. */ + memcpy ((char *) &buf, expr, tree_size (expr)); + expr = (tree) &buf; + TYPE_CONTAINS_PLACEHOLDER_INTERNAL (expr) = 0; + TYPE_POINTER_TO (expr) = NULL; + TYPE_REFERENCE_TO (expr) = NULL; + if (TYPE_CACHED_VALUES_P (expr)) + { + TYPE_CACHED_VALUES_P (expr) = 0; + TYPE_CACHED_VALUES (expr) = NULL; + } + } + md5_process_bytes (expr, tree_size (expr), ctx); + fold_checksum_tree (TREE_TYPE (expr), ctx, ht); + if (TREE_CODE_CLASS (code) != tcc_type + && TREE_CODE_CLASS (code) != tcc_declaration + && code != TREE_LIST) + fold_checksum_tree (TREE_CHAIN (expr), ctx, ht); + switch (TREE_CODE_CLASS (code)) + { + case tcc_constant: + switch (code) + { + case STRING_CST: + md5_process_bytes (TREE_STRING_POINTER (expr), + TREE_STRING_LENGTH (expr), ctx); + break; + case COMPLEX_CST: + fold_checksum_tree (TREE_REALPART (expr), ctx, ht); + fold_checksum_tree (TREE_IMAGPART (expr), ctx, ht); + break; + case VECTOR_CST: + fold_checksum_tree (TREE_VECTOR_CST_ELTS (expr), ctx, ht); + break; + default: + break; + } + break; + case tcc_exceptional: + switch (code) + { + case TREE_LIST: + fold_checksum_tree (TREE_PURPOSE (expr), ctx, ht); + fold_checksum_tree (TREE_VALUE (expr), ctx, ht); + expr = TREE_CHAIN (expr); + goto recursive_label; + break; + case TREE_VEC: + for (i = 0; i < TREE_VEC_LENGTH (expr); ++i) + fold_checksum_tree (TREE_VEC_ELT (expr, i), ctx, ht); + break; + default: + break; + } + break; + case tcc_expression: + case tcc_reference: + case tcc_comparison: + case tcc_unary: + case tcc_binary: + case tcc_statement: + len = TREE_CODE_LENGTH (code); + for (i = 0; i < len; ++i) + fold_checksum_tree (TREE_OPERAND (expr, i), ctx, ht); + break; + case tcc_declaration: + fold_checksum_tree (DECL_NAME (expr), ctx, ht); + fold_checksum_tree (DECL_CONTEXT (expr), ctx, ht); + if (CODE_CONTAINS_STRUCT (TREE_CODE (expr), TS_DECL_COMMON)) + { + fold_checksum_tree (DECL_SIZE (expr), ctx, ht); + fold_checksum_tree (DECL_SIZE_UNIT (expr), ctx, ht); + fold_checksum_tree (DECL_INITIAL (expr), ctx, ht); + fold_checksum_tree (DECL_ABSTRACT_ORIGIN (expr), ctx, ht); + fold_checksum_tree (DECL_ATTRIBUTES (expr), ctx, ht); + } + if (CODE_CONTAINS_STRUCT (TREE_CODE (expr), TS_DECL_WITH_VIS)) + fold_checksum_tree (DECL_SECTION_NAME (expr), ctx, ht); + + if (CODE_CONTAINS_STRUCT (TREE_CODE (expr), TS_DECL_NON_COMMON)) + { + fold_checksum_tree (DECL_VINDEX (expr), ctx, ht); + fold_checksum_tree (DECL_RESULT_FLD (expr), ctx, ht); + fold_checksum_tree (DECL_ARGUMENT_FLD (expr), ctx, ht); + } + break; + case tcc_type: + if (TREE_CODE (expr) == ENUMERAL_TYPE) + fold_checksum_tree (TYPE_VALUES (expr), ctx, ht); + fold_checksum_tree (TYPE_SIZE (expr), ctx, ht); + fold_checksum_tree (TYPE_SIZE_UNIT (expr), ctx, ht); + fold_checksum_tree (TYPE_ATTRIBUTES (expr), ctx, ht); + fold_checksum_tree (TYPE_NAME (expr), ctx, ht); + if (INTEGRAL_TYPE_P (expr) + || SCALAR_FLOAT_TYPE_P (expr)) + { + fold_checksum_tree (TYPE_MIN_VALUE (expr), ctx, ht); + fold_checksum_tree (TYPE_MAX_VALUE (expr), ctx, ht); + } + fold_checksum_tree (TYPE_MAIN_VARIANT (expr), ctx, ht); + if (TREE_CODE (expr) == RECORD_TYPE + || TREE_CODE (expr) == UNION_TYPE + || TREE_CODE (expr) == QUAL_UNION_TYPE) + fold_checksum_tree (TYPE_BINFO (expr), ctx, ht); + fold_checksum_tree (TYPE_CONTEXT (expr), ctx, ht); + break; + default: + break; + } +} + +#endif + +/* Fold a unary tree expression with code CODE of type TYPE with an + operand OP0. Return a folded expression if successful. Otherwise, + return a tree expression with code CODE of type TYPE with an + operand OP0. */ + +tree +fold_build1_stat (enum tree_code code, tree type, tree op0 MEM_STAT_DECL) +{ + tree tem; +#ifdef ENABLE_FOLD_CHECKING + unsigned char checksum_before[16], checksum_after[16]; + struct md5_ctx ctx; + htab_t ht; + + ht = htab_create (32, htab_hash_pointer, htab_eq_pointer, NULL); + md5_init_ctx (&ctx); + fold_checksum_tree (op0, &ctx, ht); + md5_finish_ctx (&ctx, checksum_before); + htab_empty (ht); +#endif + + tem = fold_unary (code, type, op0); + if (!tem) + tem = build1_stat (code, type, op0 PASS_MEM_STAT); + +#ifdef ENABLE_FOLD_CHECKING + md5_init_ctx (&ctx); + fold_checksum_tree (op0, &ctx, ht); + md5_finish_ctx (&ctx, checksum_after); + htab_delete (ht); + + if (memcmp (checksum_before, checksum_after, 16)) + fold_check_failed (op0, tem); +#endif + return tem; +} + +/* Fold a binary tree expression with code CODE of type TYPE with + operands OP0 and OP1. Return a folded expression if successful. + Otherwise, return a tree expression with code CODE of type TYPE + with operands OP0 and OP1. */ + +tree +fold_build2_stat (enum tree_code code, tree type, tree op0, tree op1 + MEM_STAT_DECL) +{ + tree tem; +#ifdef ENABLE_FOLD_CHECKING + unsigned char checksum_before_op0[16], + checksum_before_op1[16], + checksum_after_op0[16], + checksum_after_op1[16]; + struct md5_ctx ctx; + htab_t ht; + + ht = htab_create (32, htab_hash_pointer, htab_eq_pointer, NULL); + md5_init_ctx (&ctx); + fold_checksum_tree (op0, &ctx, ht); + md5_finish_ctx (&ctx, checksum_before_op0); + htab_empty (ht); + + md5_init_ctx (&ctx); + fold_checksum_tree (op1, &ctx, ht); + md5_finish_ctx (&ctx, checksum_before_op1); + htab_empty (ht); +#endif + + tem = fold_binary (code, type, op0, op1); + if (!tem) + tem = build2_stat (code, type, op0, op1 PASS_MEM_STAT); + +#ifdef ENABLE_FOLD_CHECKING + md5_init_ctx (&ctx); + fold_checksum_tree (op0, &ctx, ht); + md5_finish_ctx (&ctx, checksum_after_op0); + htab_empty (ht); + + if (memcmp (checksum_before_op0, checksum_after_op0, 16)) + fold_check_failed (op0, tem); + + md5_init_ctx (&ctx); + fold_checksum_tree (op1, &ctx, ht); + md5_finish_ctx (&ctx, checksum_after_op1); + htab_delete (ht); + + if (memcmp (checksum_before_op1, checksum_after_op1, 16)) + fold_check_failed (op1, tem); +#endif + return tem; +} + +/* Fold a ternary tree expression with code CODE of type TYPE with + operands OP0, OP1, and OP2. Return a folded expression if + successful. Otherwise, return a tree expression with code CODE of + type TYPE with operands OP0, OP1, and OP2. */ + +tree +fold_build3_stat (enum tree_code code, tree type, tree op0, tree op1, tree op2 + MEM_STAT_DECL) +{ + tree tem; +#ifdef ENABLE_FOLD_CHECKING + unsigned char checksum_before_op0[16], + checksum_before_op1[16], + checksum_before_op2[16], + checksum_after_op0[16], + checksum_after_op1[16], + checksum_after_op2[16]; + struct md5_ctx ctx; + htab_t ht; + + ht = htab_create (32, htab_hash_pointer, htab_eq_pointer, NULL); + md5_init_ctx (&ctx); + fold_checksum_tree (op0, &ctx, ht); + md5_finish_ctx (&ctx, checksum_before_op0); + htab_empty (ht); + + md5_init_ctx (&ctx); + fold_checksum_tree (op1, &ctx, ht); + md5_finish_ctx (&ctx, checksum_before_op1); + htab_empty (ht); + + md5_init_ctx (&ctx); + fold_checksum_tree (op2, &ctx, ht); + md5_finish_ctx (&ctx, checksum_before_op2); + htab_empty (ht); +#endif + + tem = fold_ternary (code, type, op0, op1, op2); + if (!tem) + tem = build3_stat (code, type, op0, op1, op2 PASS_MEM_STAT); + +#ifdef ENABLE_FOLD_CHECKING + md5_init_ctx (&ctx); + fold_checksum_tree (op0, &ctx, ht); + md5_finish_ctx (&ctx, checksum_after_op0); + htab_empty (ht); + + if (memcmp (checksum_before_op0, checksum_after_op0, 16)) + fold_check_failed (op0, tem); + + md5_init_ctx (&ctx); + fold_checksum_tree (op1, &ctx, ht); + md5_finish_ctx (&ctx, checksum_after_op1); + htab_empty (ht); + + if (memcmp (checksum_before_op1, checksum_after_op1, 16)) + fold_check_failed (op1, tem); + + md5_init_ctx (&ctx); + fold_checksum_tree (op2, &ctx, ht); + md5_finish_ctx (&ctx, checksum_after_op2); + htab_delete (ht); + + if (memcmp (checksum_before_op2, checksum_after_op2, 16)) + fold_check_failed (op2, tem); +#endif + return tem; +} + +/* Perform constant folding and related simplification of initializer + expression EXPR. These behave identically to "fold_buildN" but ignore + potential run-time traps and exceptions that fold must preserve. */ + +#define START_FOLD_INIT \ + int saved_signaling_nans = flag_signaling_nans;\ + int saved_trapping_math = flag_trapping_math;\ + int saved_rounding_math = flag_rounding_math;\ + int saved_trapv = flag_trapv;\ + int saved_folding_initializer = folding_initializer;\ + flag_signaling_nans = 0;\ + flag_trapping_math = 0;\ + flag_rounding_math = 0;\ + flag_trapv = 0;\ + folding_initializer = 1; + +#define END_FOLD_INIT \ + flag_signaling_nans = saved_signaling_nans;\ + flag_trapping_math = saved_trapping_math;\ + flag_rounding_math = saved_rounding_math;\ + flag_trapv = saved_trapv;\ + folding_initializer = saved_folding_initializer; + +tree +fold_build1_initializer (enum tree_code code, tree type, tree op) +{ + tree result; + START_FOLD_INIT; + + result = fold_build1 (code, type, op); + + END_FOLD_INIT; + return result; +} + +tree +fold_build2_initializer (enum tree_code code, tree type, tree op0, tree op1) +{ + tree result; + START_FOLD_INIT; + + result = fold_build2 (code, type, op0, op1); + + END_FOLD_INIT; + return result; +} + +tree +fold_build3_initializer (enum tree_code code, tree type, tree op0, tree op1, + tree op2) +{ + tree result; + START_FOLD_INIT; + + result = fold_build3 (code, type, op0, op1, op2); + + END_FOLD_INIT; + return result; +} + +#undef START_FOLD_INIT +#undef END_FOLD_INIT + +/* Determine if first argument is a multiple of second argument. Return 0 if + it is not, or we cannot easily determined it to be. + + An example of the sort of thing we care about (at this point; this routine + could surely be made more general, and expanded to do what the *_DIV_EXPR's + fold cases do now) is discovering that + + SAVE_EXPR (I) * SAVE_EXPR (J * 8) + + is a multiple of + + SAVE_EXPR (J * 8) + + when we know that the two SAVE_EXPR (J * 8) nodes are the same node. + + This code also handles discovering that + + SAVE_EXPR (I) * SAVE_EXPR (J * 8) + + is a multiple of 8 so we don't have to worry about dealing with a + possible remainder. + + Note that we *look* inside a SAVE_EXPR only to determine how it was + calculated; it is not safe for fold to do much of anything else with the + internals of a SAVE_EXPR, since it cannot know when it will be evaluated + at run time. For example, the latter example above *cannot* be implemented + as SAVE_EXPR (I) * J or any variant thereof, since the value of J at + evaluation time of the original SAVE_EXPR is not necessarily the same at + the time the new expression is evaluated. The only optimization of this + sort that would be valid is changing + + SAVE_EXPR (I) * SAVE_EXPR (SAVE_EXPR (J) * 8) + + divided by 8 to + + SAVE_EXPR (I) * SAVE_EXPR (J) + + (where the same SAVE_EXPR (J) is used in the original and the + transformed version). */ + +static int +multiple_of_p (tree type, tree top, tree bottom) +{ + if (operand_equal_p (top, bottom, 0)) + return 1; + + if (TREE_CODE (type) != INTEGER_TYPE) + return 0; + + switch (TREE_CODE (top)) + { + case BIT_AND_EXPR: + /* Bitwise and provides a power of two multiple. If the mask is + a multiple of BOTTOM then TOP is a multiple of BOTTOM. */ + if (!integer_pow2p (bottom)) + return 0; + /* FALLTHRU */ + + case MULT_EXPR: + return (multiple_of_p (type, TREE_OPERAND (top, 0), bottom) + || multiple_of_p (type, TREE_OPERAND (top, 1), bottom)); + + case PLUS_EXPR: + case MINUS_EXPR: + return (multiple_of_p (type, TREE_OPERAND (top, 0), bottom) + && multiple_of_p (type, TREE_OPERAND (top, 1), bottom)); + + case LSHIFT_EXPR: + if (TREE_CODE (TREE_OPERAND (top, 1)) == INTEGER_CST) + { + tree op1, t1; + + op1 = TREE_OPERAND (top, 1); + /* const_binop may not detect overflow correctly, + so check for it explicitly here. */ + if (TYPE_PRECISION (TREE_TYPE (size_one_node)) + > TREE_INT_CST_LOW (op1) + && TREE_INT_CST_HIGH (op1) == 0 + && 0 != (t1 = fold_convert (type, + const_binop (LSHIFT_EXPR, + size_one_node, + op1, 0))) + && ! TREE_OVERFLOW (t1)) + return multiple_of_p (type, t1, bottom); + } + return 0; + + case NOP_EXPR: + /* Can't handle conversions from non-integral or wider integral type. */ + if ((TREE_CODE (TREE_TYPE (TREE_OPERAND (top, 0))) != INTEGER_TYPE) + || (TYPE_PRECISION (type) + < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (top, 0))))) + return 0; + + /* .. fall through ... */ + + case SAVE_EXPR: + return multiple_of_p (type, TREE_OPERAND (top, 0), bottom); + + case INTEGER_CST: + if (TREE_CODE (bottom) != INTEGER_CST + || (TYPE_UNSIGNED (type) + && (tree_int_cst_sgn (top) < 0 + || tree_int_cst_sgn (bottom) < 0))) + return 0; + return integer_zerop (const_binop (TRUNC_MOD_EXPR, + top, bottom, 0)); + + default: + return 0; + } +} + +/* Return true if `t' is known to be non-negative. If the return + value is based on the assumption that signed overflow is undefined, + set *STRICT_OVERFLOW_P to true; otherwise, don't change + *STRICT_OVERFLOW_P. */ + +int +tree_expr_nonnegative_warnv_p (tree t, bool *strict_overflow_p) +{ + if (t == error_mark_node) + return 0; + + if (TYPE_UNSIGNED (TREE_TYPE (t))) + return 1; + + switch (TREE_CODE (t)) + { + case SSA_NAME: + /* Query VRP to see if it has recorded any information about + the range of this object. */ + return ssa_name_nonnegative_p (t); + + case ABS_EXPR: + /* We can't return 1 if flag_wrapv is set because + ABS_EXPR<INT_MIN> = INT_MIN. */ + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + return 1; + if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (t))) + { + *strict_overflow_p = true; + return 1; + } + break; + + case INTEGER_CST: + return tree_int_cst_sgn (t) >= 0; + + case REAL_CST: + return ! REAL_VALUE_NEGATIVE (TREE_REAL_CST (t)); + + case PLUS_EXPR: + if (FLOAT_TYPE_P (TREE_TYPE (t))) + return (tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p) + && tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1), + strict_overflow_p)); + + /* zero_extend(x) + zero_extend(y) is non-negative if x and y are + both unsigned and at least 2 bits shorter than the result. */ + if (TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE + && TREE_CODE (TREE_OPERAND (t, 0)) == NOP_EXPR + && TREE_CODE (TREE_OPERAND (t, 1)) == NOP_EXPR) + { + tree inner1 = TREE_TYPE (TREE_OPERAND (TREE_OPERAND (t, 0), 0)); + tree inner2 = TREE_TYPE (TREE_OPERAND (TREE_OPERAND (t, 1), 0)); + if (TREE_CODE (inner1) == INTEGER_TYPE && TYPE_UNSIGNED (inner1) + && TREE_CODE (inner2) == INTEGER_TYPE && TYPE_UNSIGNED (inner2)) + { + unsigned int prec = MAX (TYPE_PRECISION (inner1), + TYPE_PRECISION (inner2)) + 1; + return prec < TYPE_PRECISION (TREE_TYPE (t)); + } + } + break; + + case MULT_EXPR: + if (FLOAT_TYPE_P (TREE_TYPE (t))) + { + /* x * x for floating point x is always non-negative. */ + if (operand_equal_p (TREE_OPERAND (t, 0), TREE_OPERAND (t, 1), 0)) + return 1; + return (tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p) + && tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1), + strict_overflow_p)); + } + + /* zero_extend(x) * zero_extend(y) is non-negative if x and y are + both unsigned and their total bits is shorter than the result. */ + if (TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE + && TREE_CODE (TREE_OPERAND (t, 0)) == NOP_EXPR + && TREE_CODE (TREE_OPERAND (t, 1)) == NOP_EXPR) + { + tree inner1 = TREE_TYPE (TREE_OPERAND (TREE_OPERAND (t, 0), 0)); + tree inner2 = TREE_TYPE (TREE_OPERAND (TREE_OPERAND (t, 1), 0)); + if (TREE_CODE (inner1) == INTEGER_TYPE && TYPE_UNSIGNED (inner1) + && TREE_CODE (inner2) == INTEGER_TYPE && TYPE_UNSIGNED (inner2)) + return TYPE_PRECISION (inner1) + TYPE_PRECISION (inner2) + < TYPE_PRECISION (TREE_TYPE (t)); + } + return 0; + + case BIT_AND_EXPR: + case MAX_EXPR: + return (tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p) + || tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1), + strict_overflow_p)); + + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + case MIN_EXPR: + case RDIV_EXPR: + case TRUNC_DIV_EXPR: + case CEIL_DIV_EXPR: + case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: + return (tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p) + && tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1), + strict_overflow_p)); + + case TRUNC_MOD_EXPR: + case CEIL_MOD_EXPR: + case FLOOR_MOD_EXPR: + case ROUND_MOD_EXPR: + case SAVE_EXPR: + case NON_LVALUE_EXPR: + case FLOAT_EXPR: + case FIX_TRUNC_EXPR: + return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p); + + case COMPOUND_EXPR: + case MODIFY_EXPR: + return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1), + strict_overflow_p); + + case BIND_EXPR: + return tree_expr_nonnegative_warnv_p (expr_last (TREE_OPERAND (t, 1)), + strict_overflow_p); + + case COND_EXPR: + return (tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1), + strict_overflow_p) + && tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 2), + strict_overflow_p)); + + case NOP_EXPR: + { + tree inner_type = TREE_TYPE (TREE_OPERAND (t, 0)); + tree outer_type = TREE_TYPE (t); + + if (TREE_CODE (outer_type) == REAL_TYPE) + { + if (TREE_CODE (inner_type) == REAL_TYPE) + return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p); + if (TREE_CODE (inner_type) == INTEGER_TYPE) + { + if (TYPE_UNSIGNED (inner_type)) + return 1; + return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p); + } + } + else if (TREE_CODE (outer_type) == INTEGER_TYPE) + { + if (TREE_CODE (inner_type) == REAL_TYPE) + return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t,0), + strict_overflow_p); + if (TREE_CODE (inner_type) == INTEGER_TYPE) + return TYPE_PRECISION (inner_type) < TYPE_PRECISION (outer_type) + && TYPE_UNSIGNED (inner_type); + } + } + break; + + case TARGET_EXPR: + { + tree temp = TARGET_EXPR_SLOT (t); + t = TARGET_EXPR_INITIAL (t); + + /* If the initializer is non-void, then it's a normal expression + that will be assigned to the slot. */ + if (!VOID_TYPE_P (t)) + return tree_expr_nonnegative_warnv_p (t, strict_overflow_p); + + /* Otherwise, the initializer sets the slot in some way. One common + way is an assignment statement at the end of the initializer. */ + while (1) + { + if (TREE_CODE (t) == BIND_EXPR) + t = expr_last (BIND_EXPR_BODY (t)); + else if (TREE_CODE (t) == TRY_FINALLY_EXPR + || TREE_CODE (t) == TRY_CATCH_EXPR) + t = expr_last (TREE_OPERAND (t, 0)); + else if (TREE_CODE (t) == STATEMENT_LIST) + t = expr_last (t); + else + break; + } + if (TREE_CODE (t) == MODIFY_EXPR + && TREE_OPERAND (t, 0) == temp) + return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1), + strict_overflow_p); + + return 0; + } + + case CALL_EXPR: + { + tree fndecl = get_callee_fndecl (t); + tree arglist = TREE_OPERAND (t, 1); + if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL) + switch (DECL_FUNCTION_CODE (fndecl)) + { + CASE_FLT_FN (BUILT_IN_ACOS): + CASE_FLT_FN (BUILT_IN_ACOSH): + CASE_FLT_FN (BUILT_IN_CABS): + CASE_FLT_FN (BUILT_IN_COSH): + CASE_FLT_FN (BUILT_IN_ERFC): + CASE_FLT_FN (BUILT_IN_EXP): + CASE_FLT_FN (BUILT_IN_EXP10): + CASE_FLT_FN (BUILT_IN_EXP2): + CASE_FLT_FN (BUILT_IN_FABS): + CASE_FLT_FN (BUILT_IN_FDIM): + CASE_FLT_FN (BUILT_IN_HYPOT): + CASE_FLT_FN (BUILT_IN_POW10): + CASE_INT_FN (BUILT_IN_FFS): + CASE_INT_FN (BUILT_IN_PARITY): + CASE_INT_FN (BUILT_IN_POPCOUNT): + /* Always true. */ + return 1; + + CASE_FLT_FN (BUILT_IN_SQRT): + /* sqrt(-0.0) is -0.0. */ + if (!HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (t)))) + return 1; + return tree_expr_nonnegative_warnv_p (TREE_VALUE (arglist), + strict_overflow_p); + + CASE_FLT_FN (BUILT_IN_ASINH): + CASE_FLT_FN (BUILT_IN_ATAN): + CASE_FLT_FN (BUILT_IN_ATANH): + CASE_FLT_FN (BUILT_IN_CBRT): + CASE_FLT_FN (BUILT_IN_CEIL): + CASE_FLT_FN (BUILT_IN_ERF): + CASE_FLT_FN (BUILT_IN_EXPM1): + CASE_FLT_FN (BUILT_IN_FLOOR): + CASE_FLT_FN (BUILT_IN_FMOD): + CASE_FLT_FN (BUILT_IN_FREXP): + CASE_FLT_FN (BUILT_IN_LCEIL): + CASE_FLT_FN (BUILT_IN_LDEXP): + CASE_FLT_FN (BUILT_IN_LFLOOR): + CASE_FLT_FN (BUILT_IN_LLCEIL): + CASE_FLT_FN (BUILT_IN_LLFLOOR): + CASE_FLT_FN (BUILT_IN_LLRINT): + CASE_FLT_FN (BUILT_IN_LLROUND): + CASE_FLT_FN (BUILT_IN_LRINT): + CASE_FLT_FN (BUILT_IN_LROUND): + CASE_FLT_FN (BUILT_IN_MODF): + CASE_FLT_FN (BUILT_IN_NEARBYINT): + CASE_FLT_FN (BUILT_IN_POW): + CASE_FLT_FN (BUILT_IN_RINT): + CASE_FLT_FN (BUILT_IN_ROUND): + CASE_FLT_FN (BUILT_IN_SIGNBIT): + CASE_FLT_FN (BUILT_IN_SINH): + CASE_FLT_FN (BUILT_IN_TANH): + CASE_FLT_FN (BUILT_IN_TRUNC): + /* True if the 1st argument is nonnegative. */ + return tree_expr_nonnegative_warnv_p (TREE_VALUE (arglist), + strict_overflow_p); + + CASE_FLT_FN (BUILT_IN_FMAX): + /* True if the 1st OR 2nd arguments are nonnegative. */ + return (tree_expr_nonnegative_warnv_p (TREE_VALUE (arglist), + strict_overflow_p) + || (tree_expr_nonnegative_warnv_p + (TREE_VALUE (TREE_CHAIN (arglist)), + strict_overflow_p))); + + CASE_FLT_FN (BUILT_IN_FMIN): + /* True if the 1st AND 2nd arguments are nonnegative. */ + return (tree_expr_nonnegative_warnv_p (TREE_VALUE (arglist), + strict_overflow_p) + && (tree_expr_nonnegative_warnv_p + (TREE_VALUE (TREE_CHAIN (arglist)), + strict_overflow_p))); + + CASE_FLT_FN (BUILT_IN_COPYSIGN): + /* True if the 2nd argument is nonnegative. */ + return (tree_expr_nonnegative_warnv_p + (TREE_VALUE (TREE_CHAIN (arglist)), + strict_overflow_p)); + + default: + break; + } + } + + /* ... fall through ... */ + + default: + { + tree type = TREE_TYPE (t); + if ((TYPE_PRECISION (type) != 1 || TYPE_UNSIGNED (type)) + && truth_value_p (TREE_CODE (t))) + /* Truth values evaluate to 0 or 1, which is nonnegative unless we + have a signed:1 type (where the value is -1 and 0). */ + return true; + } + } + + /* We don't know sign of `t', so be conservative and return false. */ + return 0; +} + +/* Return true if `t' is known to be non-negative. Handle warnings + about undefined signed overflow. */ + +int +tree_expr_nonnegative_p (tree t) +{ + int ret; + bool strict_overflow_p; + + strict_overflow_p = false; + ret = tree_expr_nonnegative_warnv_p (t, &strict_overflow_p); + if (strict_overflow_p) + fold_overflow_warning (("assuming signed overflow does not occur when " + "determining that expression is always " + "non-negative"), + WARN_STRICT_OVERFLOW_MISC); + return ret; +} + +/* Return true when T is an address and is known to be nonzero. + For floating point we further ensure that T is not denormal. + Similar logic is present in nonzero_address in rtlanal.h. + + If the return value is based on the assumption that signed overflow + is undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't + change *STRICT_OVERFLOW_P. */ + +bool +tree_expr_nonzero_warnv_p (tree t, bool *strict_overflow_p) +{ + tree type = TREE_TYPE (t); + bool sub_strict_overflow_p; + + /* Doing something useful for floating point would need more work. */ + if (!INTEGRAL_TYPE_P (type) && !POINTER_TYPE_P (type)) + return false; + + switch (TREE_CODE (t)) + { + case SSA_NAME: + /* Query VRP to see if it has recorded any information about + the range of this object. */ + return ssa_name_nonzero_p (t); + + case ABS_EXPR: + return tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p); + + case INTEGER_CST: + /* We used to test for !integer_zerop here. This does not work correctly + if TREE_CONSTANT_OVERFLOW (t). */ + return (TREE_INT_CST_LOW (t) != 0 + || TREE_INT_CST_HIGH (t) != 0); + + case PLUS_EXPR: + if (TYPE_OVERFLOW_UNDEFINED (type)) + { + /* With the presence of negative values it is hard + to say something. */ + sub_strict_overflow_p = false; + if (!tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0), + &sub_strict_overflow_p) + || !tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1), + &sub_strict_overflow_p)) + return false; + /* One of operands must be positive and the other non-negative. */ + /* We don't set *STRICT_OVERFLOW_P here: even if this value + overflows, on a twos-complement machine the sum of two + nonnegative numbers can never be zero. */ + return (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p) + || tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1), + strict_overflow_p)); + } + break; + + case MULT_EXPR: + if (TYPE_OVERFLOW_UNDEFINED (type)) + { + if (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p) + && tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1), + strict_overflow_p)) + { + *strict_overflow_p = true; + return true; + } + } + break; + + case NOP_EXPR: + { + tree inner_type = TREE_TYPE (TREE_OPERAND (t, 0)); + tree outer_type = TREE_TYPE (t); + + return (TYPE_PRECISION (outer_type) >= TYPE_PRECISION (inner_type) + && tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p)); + } + break; + + case ADDR_EXPR: + { + tree base = get_base_address (TREE_OPERAND (t, 0)); + + if (!base) + return false; + + /* Weak declarations may link to NULL. */ + if (VAR_OR_FUNCTION_DECL_P (base)) + return !DECL_WEAK (base); + + /* Constants are never weak. */ + if (CONSTANT_CLASS_P (base)) + return true; + + return false; + } + + case COND_EXPR: + sub_strict_overflow_p = false; + if (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1), + &sub_strict_overflow_p) + && tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 2), + &sub_strict_overflow_p)) + { + if (sub_strict_overflow_p) + *strict_overflow_p = true; + return true; + } + break; + + case MIN_EXPR: + sub_strict_overflow_p = false; + if (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0), + &sub_strict_overflow_p) + && tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1), + &sub_strict_overflow_p)) + { + if (sub_strict_overflow_p) + *strict_overflow_p = true; + } + break; + + case MAX_EXPR: + sub_strict_overflow_p = false; + if (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0), + &sub_strict_overflow_p)) + { + if (sub_strict_overflow_p) + *strict_overflow_p = true; + + /* When both operands are nonzero, then MAX must be too. */ + if (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1), + strict_overflow_p)) + return true; + + /* MAX where operand 0 is positive is positive. */ + return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p); + } + /* MAX where operand 1 is positive is positive. */ + else if (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1), + &sub_strict_overflow_p) + && tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1), + &sub_strict_overflow_p)) + { + if (sub_strict_overflow_p) + *strict_overflow_p = true; + return true; + } + break; + + case COMPOUND_EXPR: + case MODIFY_EXPR: + case BIND_EXPR: + return tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1), + strict_overflow_p); + + case SAVE_EXPR: + case NON_LVALUE_EXPR: + return tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p); + + case BIT_IOR_EXPR: + return (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1), + strict_overflow_p) + || tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p)); + + case CALL_EXPR: + return alloca_call_p (t); + + default: + break; + } + return false; +} + +/* Return true when T is an address and is known to be nonzero. + Handle warnings about undefined signed overflow. */ + +bool +tree_expr_nonzero_p (tree t) +{ + bool ret, strict_overflow_p; + + strict_overflow_p = false; + ret = tree_expr_nonzero_warnv_p (t, &strict_overflow_p); + if (strict_overflow_p) + fold_overflow_warning (("assuming signed overflow does not occur when " + "determining that expression is always " + "non-zero"), + WARN_STRICT_OVERFLOW_MISC); + return ret; +} + +/* Given the components of a binary expression CODE, TYPE, OP0 and OP1, + attempt to fold the expression to a constant without modifying TYPE, + OP0 or OP1. + + If the expression could be simplified to a constant, then return + the constant. If the expression would not be simplified to a + constant, then return NULL_TREE. */ + +tree +fold_binary_to_constant (enum tree_code code, tree type, tree op0, tree op1) +{ + tree tem = fold_binary (code, type, op0, op1); + return (tem && TREE_CONSTANT (tem)) ? tem : NULL_TREE; +} + +/* Given the components of a unary expression CODE, TYPE and OP0, + attempt to fold the expression to a constant without modifying + TYPE or OP0. + + If the expression could be simplified to a constant, then return + the constant. If the expression would not be simplified to a + constant, then return NULL_TREE. */ + +tree +fold_unary_to_constant (enum tree_code code, tree type, tree op0) +{ + tree tem = fold_unary (code, type, op0); + return (tem && TREE_CONSTANT (tem)) ? tem : NULL_TREE; +} + +/* If EXP represents referencing an element in a constant string + (either via pointer arithmetic or array indexing), return the + tree representing the value accessed, otherwise return NULL. */ + +tree +fold_read_from_constant_string (tree exp) +{ + if ((TREE_CODE (exp) == INDIRECT_REF + || TREE_CODE (exp) == ARRAY_REF) + && TREE_CODE (TREE_TYPE (exp)) == INTEGER_TYPE) + { + tree exp1 = TREE_OPERAND (exp, 0); + tree index; + tree string; + + if (TREE_CODE (exp) == INDIRECT_REF) + string = string_constant (exp1, &index); + else + { + tree low_bound = array_ref_low_bound (exp); + index = fold_convert (sizetype, TREE_OPERAND (exp, 1)); + + /* Optimize the special-case of a zero lower bound. + + We convert the low_bound to sizetype to avoid some problems + with constant folding. (E.g. suppose the lower bound is 1, + and its mode is QI. Without the conversion,l (ARRAY + +(INDEX-(unsigned char)1)) becomes ((ARRAY+(-(unsigned char)1)) + +INDEX), which becomes (ARRAY+255+INDEX). Opps!) */ + if (! integer_zerop (low_bound)) + index = size_diffop (index, fold_convert (sizetype, low_bound)); + + string = exp1; + } + + if (string + && TYPE_MODE (TREE_TYPE (exp)) == TYPE_MODE (TREE_TYPE (TREE_TYPE (string))) + && TREE_CODE (string) == STRING_CST + && TREE_CODE (index) == INTEGER_CST + && compare_tree_int (index, TREE_STRING_LENGTH (string)) < 0 + && (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_TYPE (string)))) + == MODE_INT) + && (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (string)))) == 1)) + return fold_convert (TREE_TYPE (exp), + build_int_cst (NULL_TREE, + (TREE_STRING_POINTER (string) + [TREE_INT_CST_LOW (index)]))); + } + return NULL; +} + +/* Return the tree for neg (ARG0) when ARG0 is known to be either + an integer constant or real constant. + + TYPE is the type of the result. */ + +static tree +fold_negate_const (tree arg0, tree type) +{ + tree t = NULL_TREE; + + switch (TREE_CODE (arg0)) + { + case INTEGER_CST: + { + unsigned HOST_WIDE_INT low; + HOST_WIDE_INT high; + int overflow = neg_double (TREE_INT_CST_LOW (arg0), + TREE_INT_CST_HIGH (arg0), + &low, &high); + t = build_int_cst_wide (type, low, high); + t = force_fit_type (t, 1, + (overflow | TREE_OVERFLOW (arg0)) + && !TYPE_UNSIGNED (type), + TREE_CONSTANT_OVERFLOW (arg0)); + break; + } + + case REAL_CST: + t = build_real (type, REAL_VALUE_NEGATE (TREE_REAL_CST (arg0))); + break; + + default: + gcc_unreachable (); + } + + return t; +} + +/* Return the tree for abs (ARG0) when ARG0 is known to be either + an integer constant or real constant. + + TYPE is the type of the result. */ + +tree +fold_abs_const (tree arg0, tree type) +{ + tree t = NULL_TREE; + + switch (TREE_CODE (arg0)) + { + case INTEGER_CST: + /* If the value is unsigned, then the absolute value is + the same as the ordinary value. */ + if (TYPE_UNSIGNED (type)) + t = arg0; + /* Similarly, if the value is non-negative. */ + else if (INT_CST_LT (integer_minus_one_node, arg0)) + t = arg0; + /* If the value is negative, then the absolute value is + its negation. */ + else + { + unsigned HOST_WIDE_INT low; + HOST_WIDE_INT high; + int overflow = neg_double (TREE_INT_CST_LOW (arg0), + TREE_INT_CST_HIGH (arg0), + &low, &high); + t = build_int_cst_wide (type, low, high); + t = force_fit_type (t, -1, overflow | TREE_OVERFLOW (arg0), + TREE_CONSTANT_OVERFLOW (arg0)); + } + break; + + case REAL_CST: + if (REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg0))) + t = build_real (type, REAL_VALUE_NEGATE (TREE_REAL_CST (arg0))); + else + t = arg0; + break; + + default: + gcc_unreachable (); + } + + return t; +} + +/* Return the tree for not (ARG0) when ARG0 is known to be an integer + constant. TYPE is the type of the result. */ + +static tree +fold_not_const (tree arg0, tree type) +{ + tree t = NULL_TREE; + + gcc_assert (TREE_CODE (arg0) == INTEGER_CST); + + t = build_int_cst_wide (type, + ~ TREE_INT_CST_LOW (arg0), + ~ TREE_INT_CST_HIGH (arg0)); + t = force_fit_type (t, 0, TREE_OVERFLOW (arg0), + TREE_CONSTANT_OVERFLOW (arg0)); + + return t; +} + +/* Given CODE, a relational operator, the target type, TYPE and two + constant operands OP0 and OP1, return the result of the + relational operation. If the result is not a compile time + constant, then return NULL_TREE. */ + +static tree +fold_relational_const (enum tree_code code, tree type, tree op0, tree op1) +{ + int result, invert; + + /* From here on, the only cases we handle are when the result is + known to be a constant. */ + + if (TREE_CODE (op0) == REAL_CST && TREE_CODE (op1) == REAL_CST) + { + const REAL_VALUE_TYPE *c0 = TREE_REAL_CST_PTR (op0); + const REAL_VALUE_TYPE *c1 = TREE_REAL_CST_PTR (op1); + + /* Handle the cases where either operand is a NaN. */ + if (real_isnan (c0) || real_isnan (c1)) + { + switch (code) + { + case EQ_EXPR: + case ORDERED_EXPR: + result = 0; + break; + + case NE_EXPR: + case UNORDERED_EXPR: + case UNLT_EXPR: + case UNLE_EXPR: + case UNGT_EXPR: + case UNGE_EXPR: + case UNEQ_EXPR: + result = 1; + break; + + case LT_EXPR: + case LE_EXPR: + case GT_EXPR: + case GE_EXPR: + case LTGT_EXPR: + if (flag_trapping_math) + return NULL_TREE; + result = 0; + break; + + default: + gcc_unreachable (); + } + + return constant_boolean_node (result, type); + } + + return constant_boolean_node (real_compare (code, c0, c1), type); + } + + /* Handle equality/inequality of complex constants. */ + if (TREE_CODE (op0) == COMPLEX_CST && TREE_CODE (op1) == COMPLEX_CST) + { + tree rcond = fold_relational_const (code, type, + TREE_REALPART (op0), + TREE_REALPART (op1)); + tree icond = fold_relational_const (code, type, + TREE_IMAGPART (op0), + TREE_IMAGPART (op1)); + if (code == EQ_EXPR) + return fold_build2 (TRUTH_ANDIF_EXPR, type, rcond, icond); + else if (code == NE_EXPR) + return fold_build2 (TRUTH_ORIF_EXPR, type, rcond, icond); + else + return NULL_TREE; + } + + /* From here on we only handle LT, LE, GT, GE, EQ and NE. + + 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. + + Therefore, the code below must handle only EQ and LT. */ + + if (code == LE_EXPR || code == GT_EXPR) + { + tree tem = op0; + op0 = op1; + op1 = tem; + code = swap_tree_comparison (code); + } + + /* Note that it is safe to invert for real values here because we + have already handled the one case that it matters. */ + + invert = 0; + if (code == NE_EXPR || code == GE_EXPR) + { + invert = 1; + code = invert_tree_comparison (code, false); + } + + /* Compute a result for LT or EQ if args permit; + Otherwise return T. */ + if (TREE_CODE (op0) == INTEGER_CST && TREE_CODE (op1) == INTEGER_CST) + { + if (code == EQ_EXPR) + result = tree_int_cst_equal (op0, op1); + else if (TYPE_UNSIGNED (TREE_TYPE (op0))) + result = INT_CST_LT_UNSIGNED (op0, op1); + else + result = INT_CST_LT (op0, op1); + } + else + return NULL_TREE; + + if (invert) + result ^= 1; + return constant_boolean_node (result, type); +} + +/* Build an expression for the a clean point containing EXPR with type TYPE. + Don't build a cleanup point expression for EXPR which don't have side + effects. */ + +tree +fold_build_cleanup_point_expr (tree type, tree expr) +{ + /* If the expression does not have side effects then we don't have to wrap + it with a cleanup point expression. */ + if (!TREE_SIDE_EFFECTS (expr)) + return expr; + + /* If the expression is a return, check to see if the expression inside the + return has no side effects or the right hand side of the modify expression + inside the return. If either don't have side effects set we don't need to + wrap the expression in a cleanup point expression. Note we don't check the + left hand side of the modify because it should always be a return decl. */ + if (TREE_CODE (expr) == RETURN_EXPR) + { + tree op = TREE_OPERAND (expr, 0); + if (!op || !TREE_SIDE_EFFECTS (op)) + return expr; + op = TREE_OPERAND (op, 1); + if (!TREE_SIDE_EFFECTS (op)) + return expr; + } + + return build1 (CLEANUP_POINT_EXPR, type, expr); +} + +/* Build an expression for the address of T. Folds away INDIRECT_REF to + avoid confusing the gimplify process. */ + +tree +build_fold_addr_expr_with_type (tree t, tree ptrtype) +{ + /* The size of the object is not relevant when talking about its address. */ + if (TREE_CODE (t) == WITH_SIZE_EXPR) + t = TREE_OPERAND (t, 0); + + /* Note: doesn't apply to ALIGN_INDIRECT_REF */ + if (TREE_CODE (t) == INDIRECT_REF + || TREE_CODE (t) == MISALIGNED_INDIRECT_REF) + { + t = TREE_OPERAND (t, 0); + if (TREE_TYPE (t) != ptrtype) + t = build1 (NOP_EXPR, ptrtype, t); + } + else + { + tree base = t; + + while (handled_component_p (base)) + base = TREE_OPERAND (base, 0); + if (DECL_P (base)) + TREE_ADDRESSABLE (base) = 1; + + t = build1 (ADDR_EXPR, ptrtype, t); + } + + return t; +} + +tree +build_fold_addr_expr (tree t) +{ + return build_fold_addr_expr_with_type (t, build_pointer_type (TREE_TYPE (t))); +} + +/* Given a pointer value OP0 and a type TYPE, return a simplified version + of an indirection through OP0, or NULL_TREE if no simplification is + possible. */ + +tree +fold_indirect_ref_1 (tree type, tree op0) +{ + tree sub = op0; + tree subtype; + + STRIP_NOPS (sub); + subtype = TREE_TYPE (sub); + if (!POINTER_TYPE_P (subtype)) + return NULL_TREE; + + if (TREE_CODE (sub) == ADDR_EXPR) + { + tree op = TREE_OPERAND (sub, 0); + tree optype = TREE_TYPE (op); + /* *&CONST_DECL -> to the value of the const decl. */ + if (TREE_CODE (op) == CONST_DECL) + return DECL_INITIAL (op); + /* *&p => p; make sure to handle *&"str"[cst] here. */ + if (type == optype) + { + tree fop = fold_read_from_constant_string (op); + if (fop) + return fop; + else + return op; + } + /* *(foo *)&fooarray => fooarray[0] */ + else if (TREE_CODE (optype) == ARRAY_TYPE + && type == TREE_TYPE (optype)) + { + tree type_domain = TYPE_DOMAIN (optype); + tree min_val = size_zero_node; + if (type_domain && TYPE_MIN_VALUE (type_domain)) + min_val = TYPE_MIN_VALUE (type_domain); + return build4 (ARRAY_REF, type, op, min_val, NULL_TREE, NULL_TREE); + } + /* *(foo *)&complexfoo => __real__ complexfoo */ + else if (TREE_CODE (optype) == COMPLEX_TYPE + && type == TREE_TYPE (optype)) + return fold_build1 (REALPART_EXPR, type, op); + } + + /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */ + if (TREE_CODE (sub) == PLUS_EXPR + && TREE_CODE (TREE_OPERAND (sub, 1)) == INTEGER_CST) + { + tree op00 = TREE_OPERAND (sub, 0); + tree op01 = TREE_OPERAND (sub, 1); + tree op00type; + + STRIP_NOPS (op00); + op00type = TREE_TYPE (op00); + if (TREE_CODE (op00) == ADDR_EXPR + && TREE_CODE (TREE_TYPE (op00type)) == COMPLEX_TYPE + && type == TREE_TYPE (TREE_TYPE (op00type))) + { + tree size = TYPE_SIZE_UNIT (type); + if (tree_int_cst_equal (size, op01)) + return fold_build1 (IMAGPART_EXPR, type, TREE_OPERAND (op00, 0)); + } + } + + /* *(foo *)fooarrptr => (*fooarrptr)[0] */ + if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE + && type == TREE_TYPE (TREE_TYPE (subtype))) + { + tree type_domain; + tree min_val = size_zero_node; + sub = build_fold_indirect_ref (sub); + type_domain = TYPE_DOMAIN (TREE_TYPE (sub)); + if (type_domain && TYPE_MIN_VALUE (type_domain)) + min_val = TYPE_MIN_VALUE (type_domain); + return build4 (ARRAY_REF, type, sub, min_val, NULL_TREE, NULL_TREE); + } + + return NULL_TREE; +} + +/* Builds an expression for an indirection through T, simplifying some + cases. */ + +tree +build_fold_indirect_ref (tree t) +{ + tree type = TREE_TYPE (TREE_TYPE (t)); + tree sub = fold_indirect_ref_1 (type, t); + + if (sub) + return sub; + else + return build1 (INDIRECT_REF, type, t); +} + +/* Given an INDIRECT_REF T, return either T or a simplified version. */ + +tree +fold_indirect_ref (tree t) +{ + tree sub = fold_indirect_ref_1 (TREE_TYPE (t), TREE_OPERAND (t, 0)); + + if (sub) + return sub; + else + return t; +} + +/* Strip non-trapping, non-side-effecting tree nodes from an expression + whose result is ignored. The type of the returned tree need not be + the same as the original expression. */ + +tree +fold_ignored_result (tree t) +{ + if (!TREE_SIDE_EFFECTS (t)) + return integer_zero_node; + + for (;;) + switch (TREE_CODE_CLASS (TREE_CODE (t))) + { + case tcc_unary: + t = TREE_OPERAND (t, 0); + break; + + case tcc_binary: + case tcc_comparison: + if (!TREE_SIDE_EFFECTS (TREE_OPERAND (t, 1))) + t = TREE_OPERAND (t, 0); + else if (!TREE_SIDE_EFFECTS (TREE_OPERAND (t, 0))) + t = TREE_OPERAND (t, 1); + else + return t; + break; + + case tcc_expression: + switch (TREE_CODE (t)) + { + case COMPOUND_EXPR: + if (TREE_SIDE_EFFECTS (TREE_OPERAND (t, 1))) + return t; + t = TREE_OPERAND (t, 0); + break; + + case COND_EXPR: + if (TREE_SIDE_EFFECTS (TREE_OPERAND (t, 1)) + || TREE_SIDE_EFFECTS (TREE_OPERAND (t, 2))) + return t; + t = TREE_OPERAND (t, 0); + break; + + default: + return t; + } + break; + + default: + return t; + } +} + +/* Return the value of VALUE, rounded up to a multiple of DIVISOR. + This can only be applied to objects of a sizetype. */ + +tree +round_up (tree value, int divisor) +{ + tree div = NULL_TREE; + + gcc_assert (divisor > 0); + if (divisor == 1) + return value; + + /* See if VALUE is already a multiple of DIVISOR. If so, we don't + have to do anything. Only do this when we are not given a const, + because in that case, this check is more expensive than just + doing it. */ + if (TREE_CODE (value) != INTEGER_CST) + { + div = build_int_cst (TREE_TYPE (value), divisor); + + if (multiple_of_p (TREE_TYPE (value), value, div)) + return value; + } + + /* If divisor is a power of two, simplify this to bit manipulation. */ + if (divisor == (divisor & -divisor)) + { + tree t; + + t = build_int_cst (TREE_TYPE (value), divisor - 1); + value = size_binop (PLUS_EXPR, value, t); + t = build_int_cst (TREE_TYPE (value), -divisor); + value = size_binop (BIT_AND_EXPR, value, t); + } + else + { + if (!div) + div = build_int_cst (TREE_TYPE (value), divisor); + value = size_binop (CEIL_DIV_EXPR, value, div); + value = size_binop (MULT_EXPR, value, div); + } + + return value; +} + +/* Likewise, but round down. */ + +tree +round_down (tree value, int divisor) +{ + tree div = NULL_TREE; + + gcc_assert (divisor > 0); + if (divisor == 1) + return value; + + /* See if VALUE is already a multiple of DIVISOR. If so, we don't + have to do anything. Only do this when we are not given a const, + because in that case, this check is more expensive than just + doing it. */ + if (TREE_CODE (value) != INTEGER_CST) + { + div = build_int_cst (TREE_TYPE (value), divisor); + + if (multiple_of_p (TREE_TYPE (value), value, div)) + return value; + } + + /* If divisor is a power of two, simplify this to bit manipulation. */ + if (divisor == (divisor & -divisor)) + { + tree t; + + t = build_int_cst (TREE_TYPE (value), -divisor); + value = size_binop (BIT_AND_EXPR, value, t); + } + else + { + if (!div) + div = build_int_cst (TREE_TYPE (value), divisor); + value = size_binop (FLOOR_DIV_EXPR, value, div); + value = size_binop (MULT_EXPR, value, div); + } + + return value; +} + +/* Returns the pointer to the base of the object addressed by EXP and + extracts the information about the offset of the access, storing it + to PBITPOS and POFFSET. */ + +static tree +split_address_to_core_and_offset (tree exp, + HOST_WIDE_INT *pbitpos, tree *poffset) +{ + tree core; + enum machine_mode mode; + int unsignedp, volatilep; + HOST_WIDE_INT bitsize; + + if (TREE_CODE (exp) == ADDR_EXPR) + { + core = get_inner_reference (TREE_OPERAND (exp, 0), &bitsize, pbitpos, + poffset, &mode, &unsignedp, &volatilep, + false); + core = build_fold_addr_expr (core); + } + else + { + core = exp; + *pbitpos = 0; + *poffset = NULL_TREE; + } + + return core; +} + +/* Returns true if addresses of E1 and E2 differ by a constant, false + otherwise. If they do, E1 - E2 is stored in *DIFF. */ + +bool +ptr_difference_const (tree e1, tree e2, HOST_WIDE_INT *diff) +{ + tree core1, core2; + HOST_WIDE_INT bitpos1, bitpos2; + tree toffset1, toffset2, tdiff, type; + + core1 = split_address_to_core_and_offset (e1, &bitpos1, &toffset1); + core2 = split_address_to_core_and_offset (e2, &bitpos2, &toffset2); + + if (bitpos1 % BITS_PER_UNIT != 0 + || bitpos2 % BITS_PER_UNIT != 0 + || !operand_equal_p (core1, core2, 0)) + return false; + + if (toffset1 && toffset2) + { + type = TREE_TYPE (toffset1); + if (type != TREE_TYPE (toffset2)) + toffset2 = fold_convert (type, toffset2); + + tdiff = fold_build2 (MINUS_EXPR, type, toffset1, toffset2); + if (!cst_and_fits_in_hwi (tdiff)) + return false; + + *diff = int_cst_value (tdiff); + } + else if (toffset1 || toffset2) + { + /* If only one of the offsets is non-constant, the difference cannot + be a constant. */ + return false; + } + else + *diff = 0; + + *diff += (bitpos1 - bitpos2) / BITS_PER_UNIT; + return true; +} + +/* Simplify the floating point expression EXP when the sign of the + result is not significant. Return NULL_TREE if no simplification + is possible. */ + +tree +fold_strip_sign_ops (tree exp) +{ + tree arg0, arg1; + + switch (TREE_CODE (exp)) + { + case ABS_EXPR: + case NEGATE_EXPR: + arg0 = fold_strip_sign_ops (TREE_OPERAND (exp, 0)); + return arg0 ? arg0 : TREE_OPERAND (exp, 0); + + case MULT_EXPR: + case RDIV_EXPR: + if (HONOR_SIGN_DEPENDENT_ROUNDING (TYPE_MODE (TREE_TYPE (exp)))) + return NULL_TREE; + arg0 = fold_strip_sign_ops (TREE_OPERAND (exp, 0)); + arg1 = fold_strip_sign_ops (TREE_OPERAND (exp, 1)); + if (arg0 != NULL_TREE || arg1 != NULL_TREE) + return fold_build2 (TREE_CODE (exp), TREE_TYPE (exp), + arg0 ? arg0 : TREE_OPERAND (exp, 0), + arg1 ? arg1 : TREE_OPERAND (exp, 1)); + break; + + default: + break; + } + return NULL_TREE; +} + |