#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"
int folding_initializer = 0;
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);
#define OVERFLOW_SUM_SIGN(a, b, sum) ((~((a) ^ (b)) & ((a) ^ (sum))) < 0)
#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)
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);
}
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;
}
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));
sign_extended_type = (!TYPE_UNSIGNED (TREE_TYPE (t))
|| (TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE
&& TYPE_IS_SIZETYPE (TREE_TYPE (t))));
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)
;
else if (prec >= 2 * HOST_BITS_PER_WIDE_INT)
;
else if (prec > HOST_BITS_PER_WIDE_INT)
{
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
{
if (low & ((unsigned HOST_WIDE_INT)1 << (prec - 1)))
{
high = -1;
low |= (HOST_WIDE_INT)(-1) << prec;
}
}
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;
}
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);
}
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;
}
}
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;
carry += arg1[i] * arg2[j];
carry += prod[k];
prod[k] = LOWPART (carry);
carry = HIGHPART (carry);
}
prod[i + 4] = carry;
}
decode (prod, lv, hv);
decode (prod + 4, &toplow, &tophigh);
if (unsigned_p)
return (toplow | tophigh) != 0;
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;
}
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)
{
*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;
}
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;
}
}
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)
{
*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));
}
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);
}
}
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;
}
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;
}
int
div_and_round_double (enum tree_code code, int uns,
unsigned HOST_WIDE_INT lnum_orig,
HOST_WIDE_INT hnum_orig,
unsigned HOST_WIDE_INT lden_orig,
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];
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;
if (!uns)
{
if (hnum < 0)
{
quo_neg = ~ quo_neg;
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)
{
*hquo = *hrem = 0;
*lquo = lnum / lden;
goto finish_up;
}
if (hnum == 0)
{
*hquo = *lquo = 0;
*hrem = hnum;
*lrem = lnum;
goto finish_up;
}
memset (quo, 0, sizeof quo);
memset (num, 0, sizeof num);
memset (den, 0, sizeof den);
encode (num, lnum, hnum);
encode (den, lden, hden);
if (hden == 0 && lden < (unsigned HOST_WIDE_INT) BASE)
{
for (i = 4 - 1; i >= 0; i--)
{
work = num[i] + carry * BASE;
quo[i] = work / lden;
carry = work % lden;
}
}
else
{
int num_hi_sig, den_hi_sig;
unsigned HOST_WIDE_INT quo_est, scale;
for (i = 4 - 1;; i--)
if (den[i] != 0)
{
den_hi_sig = i;
break;
}
scale = BASE / (den[den_hi_sig] + 1);
if (scale > 1)
{
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;
for (i = num_hi_sig - den_hi_sig - 1; i >= 0; i--)
{
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;
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--;
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 (num[num_hi_sig] < (HOST_WIDE_INT) carry)
{
quo_est--;
carry = 0;
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;
}
quo[i] = quo_est;
}
}
decode (quo, lquo, hquo);
finish_up:
if (quo_neg)
neg_double (*lquo, *hquo, lquo, hquo);
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:
case EXACT_DIV_EXPR:
return overflow;
case FLOOR_DIV_EXPR:
case FLOOR_MOD_EXPR:
if (quo_neg && (*lrem != 0 || *hrem != 0))
{
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:
if (!quo_neg && (*lrem != 0 || *hrem != 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:
{
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;
if (*hrem < 0)
neg_double (*lrem, *hrem, &labs_rem, &habs_rem);
if (hden < 0)
neg_double (lden, hden, &labs_den, &habs_den);
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)
add_double (*lquo, *hquo,
(HOST_WIDE_INT) -1, (HOST_WIDE_INT) -1, lquo, hquo);
else
add_double (*lquo, *hquo, (HOST_WIDE_INT) 1, (HOST_WIDE_INT) 0,
lquo, hquo);
}
else
return overflow;
}
break;
default:
gcc_unreachable ();
}
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;
}
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);
}
static int fold_deferring_overflow_warnings;
static const char* fold_deferred_overflow_warning;
static enum warn_strict_overflow_code fold_deferred_overflow_code;
void
fold_defer_overflow_warnings (void)
{
++fold_deferring_overflow_warnings;
}
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;
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);
}
void
fold_undefer_and_ignore_overflow_warnings (void)
{
fold_undefer_overflow_warnings (false, NULL_TREE, 0);
}
bool
fold_deferring_overflow_warnings_p (void)
{
return fold_deferring_overflow_warnings > 0;
}
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, "%s", gmsgid);
}
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;
}
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));
}
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;
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;
if (negate_expr_p (TREE_OPERAND (t, 1))
&& reorder_operands_p (TREE_OPERAND (t, 0),
TREE_OPERAND (t, 1)))
return true;
return negate_expr_p (TREE_OPERAND (t, 0));
case MINUS_EXPR:
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;
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:
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:
if (TREE_CODE (type) == REAL_TYPE)
{
tree tem = strip_float_extensions (t);
if (tem != t)
return negate_expr_p (tem);
}
break;
case CALL_EXPR:
if (negate_mathfn_p (builtin_mathfn_code (t)))
return negate_expr_p (TREE_VALUE (TREE_OPERAND (t, 1)));
break;
case RSHIFT_EXPR:
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;
}
static tree
fold_negate_expr (tree t)
{
tree type = TREE_TYPE (t);
tree tem;
switch (TREE_CODE (t))
{
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);
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)
{
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));
}
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:
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;
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:
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:
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:
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:
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;
}
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);
}
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_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))
&& ((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;
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 (op0 != 0 && op1 != 0)
var = in;
else if (op0 != 0)
var = op0;
else
var = op1, neg_var_p = neg1_p;
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;
}
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 (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));
}
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:
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:
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;
}
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:
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;
}
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)
{
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;
}
static tree
const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
{
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;
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);
if (HONOR_SNANS (mode)
&& (REAL_VALUE_ISNAN (d1) || REAL_VALUE_ISNAN (d2)))
return NULL_TREE;
if (code == RDIV_EXPR
&& REAL_VALUES_EQUAL (d2, dconst0)
&& (flag_trapping_math || ! MODE_HAS_INFINITIES (mode)))
return NULL_TREE;
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);
if (flag_trapping_math
&& MODE_HAS_INFINITIES (mode)
&& REAL_VALUE_ISINF (result)
&& !REAL_VALUE_ISINF (d1)
&& !REAL_VALUE_ISINF (d2))
return NULL_TREE;
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;
}
tree
size_int_kind (HOST_WIDE_INT number, enum size_type_kind kind)
{
return build_int_cst (sizetype_tab[(int) kind], number);
}
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));
if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)
{
#ifdef ENABLE_LLVM
if (code == PLUS_EXPR)
{
if (integer_zerop (arg0) && !TREE_OVERFLOW (arg0))
return arg1;
if (integer_zerop (arg1) && !TREE_OVERFLOW (arg1))
return arg0;
}
else if (code == MINUS_EXPR)
{
if (integer_zerop (arg1) && !TREE_OVERFLOW (arg1))
return arg0;
}
else if (code == MULT_EXPR)
{
if (integer_onep (arg0) && !TREE_OVERFLOW (arg0))
return arg1;
}
#else
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;
#endif
return int_const_binop (code, arg0, arg1, 0);
}
return fold_build2 (code, type, arg0, arg1);
}
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 (!TYPE_UNSIGNED (type))
return size_binop (MINUS_EXPR, arg0, arg1);
ctype = type == bitsizetype ? sbitsizetype : ssizetype;
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 (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)));
}
static tree
fold_convert_const_int_from_int (tree type, tree arg1)
{
tree t;
t = build_int_cst_wide (type, TREE_INT_CST_LOW (arg1),
TREE_INT_CST_HIGH (arg1));
t = force_fit_type (t,
!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;
}
static tree
fold_convert_const_int_from_real (enum tree_code code, tree type, tree arg1)
{
int overflow = 0;
tree t;
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 (REAL_VALUE_ISNAN (r))
{
overflow = 1;
high = 0;
low = 0;
}
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;
}
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;
}
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;
}
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);
}
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 BLOCK_POINTER_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 ();
}
}
static bool
maybe_lvalue_p (tree x)
{
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:
if ((int)TREE_CODE (x) >= NUM_TREE_CODES)
break;
return false;
}
return true;
}
tree
non_lvalue (tree x)
{
if (in_gimple_form)
return x;
if (! maybe_lvalue_p (x))
return x;
return build1 (NON_LVALUE_EXPR, TREE_TYPE (x), x);
}
int pedantic_lvalues;
static tree
pedantic_non_lvalue (tree x)
{
if (pedantic_lvalues)
return non_lvalue (x);
else
return x;
}
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 ();
}
}
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 ();
}
}
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 ();
}
}
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 ();
}
}
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)
{
compcode &= ~COMPCODE_UNORD;
if (compcode == COMPCODE_LTGT)
compcode = COMPCODE_NE;
else if (compcode == COMPCODE_ORD)
compcode = COMPCODE_TRUE;
}
else if (flag_trapping_math)
{
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);
if ((code == TRUTH_ORIF_EXPR && (lcompcode & COMPCODE_UNORD))
|| (code == TRUTH_ANDIF_EXPR && !(lcompcode & COMPCODE_UNORD)))
rtrap = false;
if (rtrap && !ltrap
&& (code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR))
return NULL_TREE;
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);
}
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);
}
int
operand_equal_p (tree arg0, tree arg1, unsigned int flags)
{
if (TREE_CODE (arg0) == ERROR_MARK || TREE_CODE (arg1) == ERROR_MARK)
return 0;
if (TYPE_UNSIGNED (TREE_TYPE (arg0)) != TYPE_UNSIGNED (TREE_TYPE (arg1)))
return 0;
if (TYPE_PRECISION (TREE_TYPE (arg0)) != TYPE_PRECISION (TREE_TYPE (arg1)))
return 0;
STRIP_NOPS (arg0);
STRIP_NOPS (arg1);
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)
|| 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 == arg1 && ! (flags & OEP_ONLY_CONST)
&& (TREE_CODE (arg0) == SAVE_EXPR
|| (! TREE_SIDE_EFFECTS (arg0) && ! TREE_SIDE_EFFECTS (arg1))))
return 1;
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 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:
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;
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 (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:
return (OP_SAME (0)
&& OP_SAME (1)
&& OP_SAME_WITH_NULL (2)
&& OP_SAME_WITH_NULL (3));
case COMPONENT_REF:
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;
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 (!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;
}
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);
}
return ! (arg0 || arg1);
default:
return 0;
}
case tcc_declaration:
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
}
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;
primarg0 = arg0, primarg1 = arg1;
STRIP_NOPS (primarg0);
STRIP_NOPS (primarg1);
if (operand_equal_p (primarg0, primarg1, 0))
return 1;
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);
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;
}
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);
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 (*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:
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;
}
}
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);
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;
}
case tcc_comparison:
{
tree arg0 = TREE_OPERAND (arg, 0);
tree arg1 = TREE_OPERAND (arg, 1);
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;
}
}
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);
}
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);
}
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;
}
tree
fold_truth_not_expr (tree arg)
{
tree type = TREE_TYPE (arg);
enum tree_code code = TREE_CODE (arg);
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:
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);
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;
}
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;
}
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));
}
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;
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));
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;
}
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;
}
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;
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)
{
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;
}
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;
signed_type = lang_hooks.types.type_for_mode (nmode, 0);
unsigned_type = lang_hooks.types.type_for_mode (nmode, 1);
nbitsize = GET_MODE_BITSIZE (nmode);
nbitpos = lbitpos & ~ (nbitsize - 1);
lbitpos -= nbitpos;
if (nbitsize == lbitsize)
return 0;
if (BYTES_BIG_ENDIAN)
lbitpos = nbitsize - lbitsize - lbitpos;
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)
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));
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);
}
}
if (lbitsize == 1 && ! integer_zerop (rhs))
{
code = code == EQ_EXPR ? NE_EXPR : EQ_EXPR;
rhs = build_int_cst (type, 0);
}
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);
}
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;
if (! INTEGRAL_TYPE_P (TREE_TYPE (exp)))
return 0;
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 (outer_type && *pbitsize == TYPE_PRECISION (outer_type))
*punsignedp = TYPE_UNSIGNED (outer_type);
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);
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;
}
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));
}
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;
t = TREE_TYPE (exp);
if (! INTEGRAL_TYPE_P (t))
return NULL_TREE;
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));
}
if ((TREE_INT_CST_HIGH (val) & mask_hi) == hi
&& (TREE_INT_CST_LOW (val) & mask_lo) == lo)
return exp;
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;
}
static int
simple_operand_p (tree exp)
{
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)
&& ! TREE_PUBLIC (exp)
&& ! DECL_EXTERNAL (exp)
&& (! TREE_STATIC (exp) || DECL_REGISTER (exp))));
}
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 (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;
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);
}
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;
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:
if (low == 0 || high == 0
|| ! integer_zerop (low) || ! integer_zerop (high)
|| TREE_CODE (arg1) != INTEGER_CST)
break;
switch (code)
{
case NE_EXPR:
low = high = arg1;
break;
case EQ_EXPR:
in_p = ! in_p, low = high = arg1;
break;
case GT_EXPR:
low = 0, high = arg1;
break;
case GE_EXPR:
in_p = ! in_p, low = arg1, high = 0;
break;
case LT_EXPR:
low = arg1, high = 0;
break;
case LE_EXPR:
in_p = ! in_p, low = 0, high = arg1;
break;
default:
gcc_unreachable ();
}
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 (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:
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:
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 (!TYPE_UNSIGNED (arg0_type)
&& !TYPE_OVERFLOW_UNDEFINED (arg0_type))
break;
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;
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 (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 (!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);
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 (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
{
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 (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;
}
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
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);
}
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));
}
}
switch (TREE_CODE (etype))
{
case INTEGER_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 (TREE_CODE (etype) == INTEGER_TYPE
&& !TYPE_OVERFLOW_WRAPS (etype))
{
tree utype, minv, maxv;
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;
}
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);
}
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);
}
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)));
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;
}
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));
if (in0_p && in1_p)
{
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 (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)
{
return 0;
}
}
else if (! subset || highequal)
{
low = low0;
high = range_predecessor (low1);
in_p = 1;
if (high == 0)
{
return 0;
}
}
else
return 0;
}
else if (! in0_p && in1_p)
{
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)
{
return 0;
}
}
}
else
{
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
{
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;
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;
}
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;
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;
}
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;
}
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 ((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))
|| (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;
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;
}
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);
}
if (operand_equal_for_comparison_p (arg01, arg2, arg00)
&& (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);
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:
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 (INTEGRAL_TYPE_P (type)
&& TREE_CODE (arg01) == INTEGER_CST
&& TREE_CODE (arg2) == INTEGER_CST)
switch (comp_code)
{
case EQ_EXPR:
arg1 = fold_convert (type, arg01);
return fold_build3 (COND_EXPR, type, arg0, arg1, arg2);
case LT_EXPR:
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 (! 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 (! 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 (! 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
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 (or_op)
in0_p = ! in0_p, in1_p = ! in1_p;
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;
}
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_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;
}
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;
temp = const_binop (RSHIFT_EXPR, c, size_int (p - 1), 0);
temp = const_binop (BIT_AND_EXPR, temp, size_int (1), 0);
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 (TYPE_UNSIGNED (type))
temp = fold_convert (type, temp);
return fold_convert (type, const_binop (BIT_XOR_EXPR, c, temp, 0));
}
static tree
fold_truthop (enum tree_code code, tree truth_type, tree lhs, tree rhs)
{
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;
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);
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 (BRANCH_COST >= 2
&& ! FLOAT_TYPE_P (TREE_TYPE (rl_arg))
&& simple_operand_p (rl_arg)
&& simple_operand_p (rr_arg))
{
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));
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;
}
}
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);
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;
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))
{
ll_unsignedp = 1;
l_const = ll_mask;
}
else
return 0;
}
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;
}
#ifdef ENABLE_LLVM
return 0;
#endif
if (! lang_hooks.can_use_bit_fields_p ())
return 0;
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 (l_const == 0)
{
if (ll_bitsize != lr_bitsize || rl_bitsize != rr_bitsize
|| ll_unsignedp != lr_unsignedp || rl_unsignedp != rr_unsignedp
|| 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);
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);
}
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);
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;
}
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);
}
}
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));
}
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 ((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;
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)
return fold_build2 (LE_EXPR, type, inner, comp_const);
else if (op_code == MAX_EXPR && consts_lt)
return fold_build2 (EQ_EXPR, type, inner, comp_const);
else if (op_code == MAX_EXPR)
return omit_one_operand (type, integer_zero_node, inner);
else if (consts_equal)
return fold_build2 (GE_EXPR, type, inner, comp_const);
else if (consts_lt)
return omit_one_operand (type, integer_zero_node, inner);
else
return fold_build2 (EQ_EXPR, type, inner, comp_const);
case GT_EXPR:
if (op_code == MAX_EXPR && (consts_equal || consts_lt))
return fold_build2 (GT_EXPR, type, inner, comp_const);
else if (op_code == MAX_EXPR)
return omit_one_operand (type, integer_one_node, inner);
else if (op_code == MIN_EXPR && (consts_equal || consts_lt))
return omit_one_operand (type, integer_zero_node, inner);
else
return fold_build2 (GT_EXPR, type, inner, comp_const);
default:
return NULL_TREE;
}
}
static tree
extract_muldiv (tree t, tree c, enum tree_code code, tree wide_type,
bool *strict_overflow_p)
{
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;
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);
switch (tcode)
{
case INTEGER_CST:
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 ((COMPARISON_CLASS_P (op0)
|| UNARY_CLASS_P (op0)
|| BINARY_CLASS_P (op0)
|| EXPRESSION_CLASS_P (op0))
&& ((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)))))
|| (GET_MODE_SIZE (TYPE_MODE (type))
< GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0))))
|| (code != MULT_EXPR
&& (TYPE_UNSIGNED (ctype)
!= TYPE_UNSIGNED (TREE_TYPE (op0))))))
break;
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 (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;
}
else if (!TYPE_UNSIGNED (ctype)
&& !TYPE_UNSIGNED (type)
&& TREE_CODE (c) == INTEGER_CST
&& TREE_INT_CST_HIGH (c) < 0)
break;
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 (TYPE_UNSIGNED (ctype) != TYPE_UNSIGNED (type))
break;
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 (TREE_CODE (op1) == INTEGER_CST
&& (tcode == RSHIFT_EXPR || TYPE_UNSIGNED (TREE_TYPE (op0)))
&& 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:
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
|| (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 (tcode == MINUS_EXPR)
tcode = PLUS_EXPR, op1 = negate_expr (op1);
if (TREE_CODE (op1) != INTEGER_CST)
break;
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 (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);
if (op1 == 0
|| (TREE_OVERFLOW (op1) && !TYPE_OVERFLOW_WRAPS (ctype)))
break;
}
else
break;
if (TYPE_UNSIGNED (ctype)
&& ! (TREE_CODE (ctype) == INTEGER_TYPE && TYPE_IS_SIZETYPE (ctype))
&& ctype != type)
break;
if (t1 != 0 && (TREE_CODE (t1) != code || code == MULT_EXPR))
return fold_build2 (tcode, ctype, fold_convert (ctype, t1), op1);
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:
if ((code == TRUNC_MOD_EXPR || code == CEIL_MOD_EXPR
|| code == FLOOR_MOD_EXPR || code == ROUND_MOD_EXPR)
&& (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (t))
|| (TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE
&& TYPE_IS_SIZETYPE (TREE_TYPE (t))))
&& 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);
case TRUNC_DIV_EXPR: case CEIL_DIV_EXPR: case FLOOR_DIV_EXPR:
case ROUND_DIV_EXPR: case EXACT_DIV_EXPR:
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 (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 ((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;
}
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);
}
static bool
extract_array_ref (tree expr, tree *base, tree *offset)
{
if (TREE_CODE (expr) == PLUS_EXPR)
{
tree op0 = TREE_OPERAND (expr, 0);
tree inner_base, dummy1;
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;
}
}
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
{
if (TREE_CODE (TREE_TYPE (op0)) == ARRAY_TYPE)
*base = TREE_OPERAND (expr, 0);
else
*base = expr;
*offset = NULL_TREE;
}
return true;
}
else if (SSA_VAR_P (expr)
&& TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE)
{
*base = expr;
*offset = NULL_TREE;
return true;
}
return false;
}
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;
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 (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);
}
static bool
fold_real_zero_addition_p (tree type, tree addend, int negate)
{
if (!real_zerop (addend))
return false;
if (HONOR_SNANS (TYPE_MODE (type)))
return false;
if (!HONOR_SIGNED_ZEROS (TYPE_MODE (type)))
return true;
if (TREE_CODE (addend) == REAL_CST
&& REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (addend)))
negate = !negate;
return negate && !HONOR_SIGN_DEPENDENT_ROUNDING (TYPE_MODE (type));
}
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))
{
if (code == EQ_EXPR || code == LT_EXPR || code == LE_EXPR)
return omit_one_operand (type, integer_zero_node, arg);
if (code == NE_EXPR || !HONOR_NANS (mode))
return omit_one_operand (type, integer_one_node, arg);
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))
{
if (HONOR_INFINITIES (mode))
return fold_build2 (EQ_EXPR, type, arg,
build_real (TREE_TYPE (arg), c2));
return omit_one_operand (type, integer_zero_node, arg);
}
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))
{
if (! HONOR_NANS (mode) && ! HONOR_INFINITIES (mode))
return omit_one_operand (type, integer_one_node, arg);
if (! HONOR_NANS (mode))
return fold_build2 (NE_EXPR, type, arg,
build_real (TREE_TYPE (arg), c2));
if (! HONOR_INFINITIES (mode))
return fold_build2 (GE_EXPR, type, arg,
build_real (TREE_TYPE (arg), dconst0));
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)));
}
if (! HONOR_NANS (mode))
return fold_build2 (code, type, arg,
build_real (TREE_TYPE (arg), c2));
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;
}
static tree
fold_inf_compare (enum tree_code code, tree type, tree arg0, tree arg1)
{
enum machine_mode mode;
REAL_VALUE_TYPE max;
bool neg;
mode = TYPE_MODE (TREE_TYPE (arg0));
neg = REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg1));
if (neg)
code = swap_tree_comparison (code);
switch (code)
{
case GT_EXPR:
if (HONOR_SNANS (mode))
return NULL_TREE;
return omit_one_operand (type, integer_zero_node, arg0);
case LE_EXPR:
if (! HONOR_NANS (mode))
return omit_one_operand (type, integer_one_node, arg0);
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 LT_EXPR:
real_maxval (&max, neg, mode);
return fold_build2 (neg ? GE_EXPR : LE_EXPR, type,
arg0, build_real (TREE_TYPE (arg0), max));
default:
break;
}
return NULL_TREE;
}
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;
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;
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
{
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;
}
static tree
fold_single_bit_test_into_sign_test (enum tree_code code, tree arg0, tree arg1,
tree result_type)
{
if ((code == NE_EXPR || code == EQ_EXPR)
&& TREE_CODE (arg0) == BIT_AND_EXPR && integer_zerop (arg1)
&& integer_pow2p (TREE_OPERAND (arg0, 1)))
{
tree arg00 = sign_bit_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg0, 1));
if (arg00 != NULL_TREE
&& 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;
}
tree
fold_single_bit_test (enum tree_code code, tree arg0, tree arg1,
tree result_type)
{
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;
tem = fold_single_bit_test_into_sign_test (code, arg0, arg1,
result_type);
if (tem)
return tem;
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);
}
#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);
inner = build2 (BIT_AND_EXPR, intermediate_type,
inner, integer_one_node);
inner = fold_convert (result_type, inner);
return inner;
}
return NULL_TREE;
}
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);
}
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;
if (TREE_CODE (arg0) == SSA_NAME
&& TREE_CODE (arg1) == SSA_NAME
&& SSA_NAME_VERSION (arg0) > SSA_NAME_VERSION (arg1))
return 1;
return 0;
}
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
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 ((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;
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;
}
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
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);
}
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;
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
{
delta = op1;
s = integer_one_node;
}
for (;; ref = TREE_OPERAND (ref, 0))
{
if (TREE_CODE (ref) == ARRAY_REF
#ifdef ENABLE_LLVM
&& (TREE_CODE (TREE_TYPE (TREE_OPERAND (ref, 0))) == ARRAY_TYPE)
#endif
)
{
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
{
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;
}
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);
}
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);
}
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;
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;
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);
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;
}
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;
}
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;
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;
}
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;
}
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;
}
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;
}
}
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);
}
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;
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);
}
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);
}
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);
}
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;
}
}
static tree
fold_view_convert_expr (tree type, tree expr)
{
unsigned char buffer[64];
int len;
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);
}
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)
{
STRIP_SIGN_NOPS (arg0);
}
else
{
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 ((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 (COMPARISON_CLASS_P (op0) && INTEGRAL_TYPE_P (type))
return fold_build2 (TREE_CODE (op0), type, TREE_OPERAND (op0, 0),
TREE_OPERAND (op0, 1));
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);
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));
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 (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));
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));
}
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 (! 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))
&& !(TREE_CODE (TREE_OPERAND (op0, 0)) == COMPONENT_REF
&& DECL_BIT_FIELD (TREE_OPERAND (TREE_OPERAND (op0, 0), 1))))
{
tem = fold_build1 (code, type, TREE_OPERAND (op0, 1));
tem = build2 (COMPOUND_EXPR, TREE_TYPE (tem), op0, tem);
TREE_NO_WARNING (tem) = 1;
TREE_USED (tem) = 1;
return tem;
}
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);
}
}
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));
}
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));
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));
}
else if (TREE_CODE (arg0) == ABS_EXPR)
return arg0;
else if (tree_expr_nonnegative_p (arg0))
return arg0;
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);
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));
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));
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:
if (TREE_CODE (TREE_TYPE (arg0)) != BOOLEAN_TYPE)
arg0 = fold_convert (boolean_type_node, arg0);
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;
}
}
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 ();
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));
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));
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));
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;
}
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 (tree_swap_operands_p (arg0, arg1, true))
return fold_build2 (swap_tree_comparison (code), type, op1, op0);
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 (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);
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);
if (TYPE_PRECISION (newtype) < TYPE_PRECISION (TREE_TYPE (arg0)))
return fold_build2 (code, type, fold_convert (newtype, targ0),
fold_convert (newtype, targ1));
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);
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)));
if (REAL_VALUE_MINUS_ZERO (cst))
return fold_build2 (code, type, arg0,
build_real (TREE_TYPE (arg1), dconst0));
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);
}
if (REAL_VALUE_ISINF (cst))
{
tem = fold_inf_compare (code, type, arg0, arg1);
if (tem != NULL_TREE)
return tem;
}
}
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);
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);
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;
}
}
}
if (TREE_CONSTANT (arg1)
&& (TREE_CODE (arg0) == POSTINCREMENT_EXPR
|| TREE_CODE (arg0) == POSTDECREMENT_EXPR)
&& (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 (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;
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))
{
tem = fold_widened_comparison (code, type, arg0, arg1);
if (tem)
return tem;
tem = fold_sign_changed_comparison (code, type, arg0, arg1);
if (tem)
return tem;
}
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;
}
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:
if (FLOAT_TYPE_P (TREE_TYPE (arg0))
&& HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))))
break;
case GT_EXPR:
case LT_EXPR:
return constant_boolean_node (0, type);
default:
gcc_unreachable ();
}
}
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)
&& 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));
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);
if (TREE_CODE (high_result) == INTEGER_CST
&& TREE_CODE (equal_result) == INTEGER_CST
&& TREE_CODE (low_result) == INTEGER_CST)
{
switch ((integer_onep (high_result) * 4)
+ (integer_onep (equal_result) * 2)
+ integer_onep (low_result))
{
case 0:
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:
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);
}
}
}
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));
}
}
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;
}
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));
}
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;
if (kind == tcc_comparison)
{
STRIP_SIGN_NOPS (arg0);
STRIP_SIGN_NOPS (arg1);
}
else
{
STRIP_NOPS (arg0);
STRIP_NOPS (arg1);
}
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 (commutative_tree_code (code)
&& tree_swap_operands_p (arg0, arg1, true))
return fold_build2 (code, type, op1, op0);
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,
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,
0);
if (tem != NULL_TREE)
return tem;
}
}
switch (code)
{
case PLUS_EXPR:
if (TREE_CODE (arg1) == NEGATE_EXPR)
return fold_build2 (MINUS_EXPR, type,
fold_convert (type, arg0),
fold_convert (type, TREE_OPERAND (arg1, 0)));
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)));
if (INTEGRAL_TYPE_P (type)
&& TREE_CODE (arg0) == BIT_NOT_EXPR
&& integer_onep (arg1))
return fold_build1 (NEGATE_EXPR, type, TREE_OPERAND (arg0, 0));
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 (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;
}
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)));
}
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
{
if (fold_real_zero_addition_p (TREE_TYPE (arg0), arg1, 0))
return non_lvalue (fold_convert (type, arg0));
if (fold_real_zero_addition_p (TREE_TYPE (arg1), arg0, 0))
return non_lvalue (fold_convert (type, arg1));
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;
if (operand_equal_p (arg0, arg1, 0)
&& SCALAR_FLOAT_TYPE_P (type))
return fold_build2 (MULT_EXPR, type, arg0,
build_real (type, dconst2));
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);
}
}
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:
{
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:
if (! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations)
{
tree var0, con0, lit0, minus_lit0;
tree var1, con1, lit1, minus_lit1;
bool ok = true;
var0 = split_tree (arg0, code, &con0, &lit0, &minus_lit0, 0);
var1 = split_tree (arg1, code, &con1, &lit1, &minus_lit1,
code == MINUS_EXPR);
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);
if (!operand_equal_p (tmp0, tmp1, 0))
ok = false;
}
if (ok
&& (2 < ((var0 != 0) + (var1 != 0)
+ (con0 != 0) + (con1 != 0)
+ (lit0 != 0) + (lit1 != 0)
+ (minus_lit0 != 0) + (minus_lit1 != 0))))
{
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);
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:
if (TREE_CODE (arg1) == NEGATE_EXPR)
return fold_build2 (PLUS_EXPR, type, arg0, TREE_OPERAND (arg1, 0));
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));
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)));
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));
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);
}
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);
}
}
}
else if (fold_real_zero_addition_p (TREE_TYPE (arg0), arg1, 1))
return non_lvalue (fold_convert (type, arg0));
else if (fold_real_zero_addition_p (TREE_TYPE (arg1), arg0, 0))
return negate_expr (fold_convert (type, arg1));
if ((! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations)
&& operand_equal_p (arg0, arg1, 0))
return fold_convert (type, integer_zero_node);
if (negate_expr_p (arg1)
&& ((FLOAT_TYPE_P (type)
&& (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)));
{
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);
}
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));
}
}
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;
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:
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));
if (integer_all_onesp (arg1))
return fold_convert (type, negate_expr (arg0));
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);
}
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
{
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);
if (!HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0)))
&& real_onep (arg1))
return non_lvalue (fold_convert (type, arg0));
if (!HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0)))
&& real_minus_onep (arg1))
return fold_convert (type, negate_expr (arg0));
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));
}
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);
}
}
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);
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));
if (BUILTIN_SQRT_P (fcode0)
&& operand_equal_p (arg00, arg10, 0)
&& ! HONOR_SNANS (TYPE_MODE (type)))
return arg00;
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);
}
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);
}
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)));
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);
}
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);
}
}
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));
}
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);
}
}
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);
}
}
#ifndef ENABLE_LLVM
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);
}
}
#endif
}
}
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));
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);
}
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 (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 ((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 ((~(hi1 | hi2) & mhi) == 0 && (~(lo1 | lo2) & mlo) == 0)
return fold_build2 (BIT_IOR_EXPR, type,
TREE_OPERAND (arg0, 0), arg1);
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);
}
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));
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));
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));
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;
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)));
}
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);
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);
}
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 (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;
}
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;
}
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;
}
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;
}
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;
}
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)));
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));
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));
}
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));
}
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));
}
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));
}
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));
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);
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);
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));
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));
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));
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));
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));
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));
}
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));
}
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));
}
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));
}
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));
}
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;
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));
}
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:
if (TREE_CODE (arg1) == REAL_CST
&& !MODE_HAS_INFINITIES (TYPE_MODE (TREE_TYPE (arg1)))
&& real_zerop (arg1))
return NULL_TREE;
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);
}
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);
return omit_two_operands (type, r, arg0, arg1);
}
}
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));
if (!HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0)))
&& real_onep (arg1))
return non_lvalue (fold_convert (type, arg0));
if (!HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0)))
&& real_minus_onep (arg1))
return non_lvalue (fold_convert (type, negate_expr (arg0)));
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);
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);
}
}
}
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));
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));
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);
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));
}
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);
}
}
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));
}
}
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);
}
}
}
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);
}
}
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);
}
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:
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);
}
}
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;
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));
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 ((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:
if (integer_onep (arg1))
return omit_one_operand (type, integer_zero_node, arg0);
if (integer_zerop (arg1))
return NULL_TREE;
if (integer_zerop (arg0))
return omit_one_operand (type, integer_zero_node, arg1);
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);
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;
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));
}
}
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)
&& !sign_bit_p (arg1, arg1))
return fold_build2 (code, type, fold_convert (type, arg0),
fold_convert (type, negate_expr (arg1)));
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:
if (integer_all_onesp (arg0) && !TYPE_UNSIGNED (type))
return omit_one_operand (type, arg0, arg1);
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);
if (TREE_CODE (arg1) == INTEGER_CST && tree_int_cst_sgn (arg1) < 0)
return NULL_TREE;
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));
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));
}
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);
}
}
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 (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));
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:
if (integer_zerop (arg0))
return fold_convert (type, arg0);
case TRUTH_AND_EXPR:
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)
&& (code != TRUTH_ANDIF_EXPR || ! TREE_SIDE_EFFECTS (arg0)))
return non_lvalue (fold_convert (type, arg0));
if (integer_zerop (arg1))
return omit_one_operand (type, arg1, arg0);
if (integer_zerop (arg0))
return omit_one_operand (type, arg0, arg1);
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);
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);
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:
if (!optimize)
return NULL_TREE;
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));
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);
}
if (0 != (tem = fold_range_test (code, type, op0, op1)))
return tem;
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:
if (TREE_CODE (arg0) == INTEGER_CST && ! integer_zerop (arg0))
return fold_convert (type, arg0);
case TRUTH_OR_EXPR:
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)
&& (code != TRUTH_ORIF_EXPR || ! TREE_SIDE_EFFECTS (arg0)))
return non_lvalue (fold_convert (type, arg0));
if (TREE_CODE (arg1) == INTEGER_CST && ! integer_zerop (arg1))
return omit_one_operand (type, arg1, arg0);
if (TREE_CODE (arg0) == INTEGER_CST && ! integer_zerop (arg0))
return omit_one_operand (type, arg0, arg1);
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);
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 (integer_zerop (arg1))
return non_lvalue (fold_convert (type, arg0));
if (integer_onep (arg1))
{
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));
}
if (operand_equal_p (arg0, arg1, 0))
return omit_one_operand (type, integer_zero_node, arg0);
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);
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;
if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE && integer_zerop (arg1)
&& code == NE_EXPR)
return non_lvalue (fold_convert (type, arg0));
if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE && integer_onep (arg1)
&& code == EQ_EXPR)
return non_lvalue (fold_convert (type, arg0));
if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE && integer_onep (arg1)
&& code == NE_EXPR)
return fold_build1 (TRUTH_NOT_EXPR, type, fold_convert (type, arg0));
if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE && integer_zerop (arg1)
&& code == EQ_EXPR)
return fold_build1 (TRUTH_NOT_EXPR, type, fold_convert (type, arg0));
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 (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 (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))
&& ! (TREE_CODE (TREE_OPERAND (arg0, 0)) == VAR_DECL
&& DECL_HAS_VALUE_EXPR_P (TREE_OPERAND (arg0, 0))
&& TREE_CODE (TREE_OPERAND (arg0, 0)) == VAR_DECL
&& DECL_HAS_VALUE_EXPR_P (TREE_OPERAND (arg0, 0))))
{
bool equal = TREE_OPERAND (arg0, 0) == TREE_OPERAND (arg1, 0);
return constant_boolean_node (equal
? code == EQ_EXPR : code != EQ_EXPR,
type);
}
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);
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 (TREE_CODE (arg0) == MINUS_EXPR
&& integer_zerop (arg1))
return fold_build2 (code, type,
TREE_OPERAND (arg0, 0), TREE_OPERAND (arg0, 1));
if (TREE_CODE (arg0) == ABS_EXPR
&& (integer_zerop (arg1) || real_zerop (arg1)))
return fold_build2 (code, type, TREE_OPERAND (arg0, 0), arg1);
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 (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));
}
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);
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 ((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);
}
else if (!TYPE_UNSIGNED (itype))
return fold_build2 (code == EQ_EXPR ? GE_EXPR : LT_EXPR, type,
arg000, build_int_cst (itype, 0));
else
return omit_one_operand (type,
code == EQ_EXPR ? integer_one_node
: integer_zero_node,
arg000);
}
}
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 (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));
tem = fold_single_bit_test_into_sign_test (code, arg0, arg1, type);
if (tem)
return tem;
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 (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 (((TREE_CODE (arg0) == COMPONENT_REF
#ifdef ENABLE_LLVM
&& 0
#endif
&& lang_hooks.can_use_bit_fields_p ())
|| TREE_CODE (arg0) == BIT_FIELD_REF)
&& (optimize || TREE_CODE (arg1) == INTEGER_CST))
{
t1 = optimize_bit_field_compare (code, type, arg0, arg1);
if (t1)
return t1;
}
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));
}
}
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));
}
}
if (integer_zerop (arg1)
&& TREE_CODE (arg0) == BIT_XOR_EXPR)
return fold_build2 (code, type, TREE_OPERAND (arg0, 0),
TREE_OPERAND (arg0, 1));
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));
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));
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));
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);
}
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));
}
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;
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);
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);
}
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);
}
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);
}
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)
{
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);
}
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);
}
}
}
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));
}
}
{
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);
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))
&& INTEGRAL_TYPE_P (TREE_TYPE (arg1)))
{
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 (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));
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);
}
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 ((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 (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 (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);
}
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);
{
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:
if (TREE_SIDE_EFFECTS (arg0) || TREE_CONSTANT (arg1))
return NULL_TREE;
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:
gcc_unreachable ();
default:
return NULL_TREE;
}
}
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;
default:
return NULL_TREE;
}
}
static bool
contains_label_p (tree st)
{
return (walk_tree (&st, contains_label_1 , NULL, NULL) != 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);
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:
if (TREE_CODE (arg0) == INTEGER_CST)
{
tree unused_op = integer_zerop (arg0) ? op1 : op2;
tem = integer_zerop (arg0) ? op2 : op1;
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 (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 (truth_value_p (TREE_CODE (arg0))
&& tree_swap_operands_p (op1, op2, false))
{
tem = fold_truth_not_expr (arg0);
if (tem)
return fold_build3 (code, type, tem, op2, op1);
}
if (integer_onep (op1)
&& integer_zerop (op2)
&& type == TREE_TYPE (arg0))
return pedantic_non_lvalue (arg0);
if (integer_zerop (op1)
&& integer_onep (op2)
&& truth_value_p (TREE_CODE (arg0)))
return pedantic_non_lvalue (fold_convert (type,
invert_truthvalue (arg0)));
if (TREE_CODE (arg0) == LT_EXPR
&& integer_zerop (TREE_OPERAND (arg0, 1))
&& integer_zerop (op2)
&& (tem = sign_bit_p (TREE_OPERAND (arg0, 0), arg1)))
{
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)));
}
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);
}
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)));
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);
if (integer_onep (op2)
&& truth_value_p (TREE_CODE (arg0))
&& truth_value_p (TREE_CODE (arg1)))
{
tem = fold_truth_not_expr (arg0);
if (tem)
return fold_build2 (TRUTH_ORIF_EXPR, type,
fold_convert (type, tem),
arg1);
}
if (integer_zerop (arg1)
&& truth_value_p (TREE_CODE (arg0))
&& truth_value_p (TREE_CODE (op2)))
{
tem = fold_truth_not_expr (arg0);
if (tem)
return fold_build2 (TRUTH_ANDIF_EXPR, type,
fold_convert (type, tem),
op2);
}
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:
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;
}
}
#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;
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;
}
}
#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);
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))
{
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)))
{
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
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;
}
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;
}
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;
}
#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
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:
if (!integer_pow2p (bottom))
return 0;
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);
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:
if ((TREE_CODE (TREE_TYPE (TREE_OPERAND (top, 0))) != INTEGER_TYPE)
|| (TYPE_PRECISION (type)
< TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (top, 0)))))
return 0;
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;
}
}
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:
return ssa_name_nonnegative_p (t);
case ABS_EXPR:
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));
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)))
{
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));
}
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 (!VOID_TYPE_P (t))
return tree_expr_nonnegative_warnv_p (t, strict_overflow_p);
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):
case BUILT_IN_BSWAP32:
case BUILT_IN_BSWAP64:
return 1;
CASE_FLT_FN (BUILT_IN_SQRT):
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):
return tree_expr_nonnegative_warnv_p (TREE_VALUE (arglist),
strict_overflow_p);
CASE_FLT_FN (BUILT_IN_FMAX):
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):
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):
return (tree_expr_nonnegative_warnv_p
(TREE_VALUE (TREE_CHAIN (arglist)),
strict_overflow_p));
default:
break;
}
}
default:
{
tree type = TREE_TYPE (t);
if ((TYPE_PRECISION (type) != 1 || TYPE_UNSIGNED (type))
&& truth_value_p (TREE_CODE (t)))
return true;
}
}
return 0;
}
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;
}
bool
tree_expr_nonzero_warnv_p (tree t, bool *strict_overflow_p)
{
tree type = TREE_TYPE (t);
bool sub_strict_overflow_p;
if (!INTEGRAL_TYPE_P (type) && !POINTER_TYPE_P (type))
return false;
switch (TREE_CODE (t))
{
case SSA_NAME:
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:
return (TREE_INT_CST_LOW (t) != 0
|| TREE_INT_CST_HIGH (t) != 0);
case PLUS_EXPR:
if (TYPE_OVERFLOW_UNDEFINED (type))
{
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;
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;
if (VAR_OR_FUNCTION_DECL_P (base))
return !DECL_WEAK (base);
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;
if (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1),
strict_overflow_p))
return true;
return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0),
strict_overflow_p);
}
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;
}
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;
}
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;
}
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;
}
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
#if ENABLE_LLVM
&& (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == ARRAY_TYPE)
#endif
)
{
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));
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;
}
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;
}
tree
fold_abs_const (tree arg0, tree type)
{
tree t = NULL_TREE;
switch (TREE_CODE (arg0))
{
case INTEGER_CST:
if (TYPE_UNSIGNED (type))
t = arg0;
else if (INT_CST_LT (integer_minus_one_node, arg0))
t = arg0;
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;
}
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;
}
static tree
fold_relational_const (enum tree_code code, tree type, tree op0, tree op1)
{
int result, invert;
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);
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);
}
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;
}
if (code == LE_EXPR || code == GT_EXPR)
{
tree tem = op0;
op0 = op1;
op1 = tem;
code = swap_tree_comparison (code);
}
invert = 0;
if (code == NE_EXPR || code == GE_EXPR)
{
invert = 1;
code = invert_tree_comparison (code, false);
}
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);
}
tree
fold_build_cleanup_point_expr (tree type, tree expr)
{
if (!TREE_SIDE_EFFECTS (expr))
return expr;
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);
}
tree
build_fold_addr_expr_with_type (tree t, tree ptrtype)
{
if (TREE_CODE (t) == WITH_SIZE_EXPR)
t = TREE_OPERAND (t, 0);
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)));
}
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);
if (TREE_CODE (op) == CONST_DECL)
return DECL_INITIAL (op);
if (type == optype)
{
tree fop = fold_read_from_constant_string (op);
if (fop)
return fop;
else
return op;
}
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);
}
else if (TREE_CODE (optype) == COMPLEX_TYPE
&& type == TREE_TYPE (optype))
return fold_build1 (REALPART_EXPR, type, op);
}
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));
}
}
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;
}
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);
}
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;
}
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;
}
}
tree
round_up (tree value, int divisor)
{
tree div = NULL_TREE;
gcc_assert (divisor > 0);
if (divisor == 1)
return value;
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 == (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;
}
tree
round_down (tree value, int divisor)
{
tree div = NULL_TREE;
gcc_assert (divisor > 0);
if (divisor == 1)
return value;
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 == (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;
}
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;
}
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)
{
return false;
}
else
*diff = 0;
*diff += (bitpos1 - bitpos2) / BITS_PER_UNIT;
return true;
}
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;
}