mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-21 00:21:03 +08:00
dojump.c (do_jump): Move below.
2008-09-11 Paolo Bonzini <bonzini@gnu.org> * dojump.c (do_jump) [BIT_AND_EXPR]: Move below. Fall through to TRUTH_AND_EXPR for boolean (1-bit precision) expressions. (do_jump) [BIT_IOR_EXPR]: Compile as TRUTH_OR_EXPR. * tree-flow.h (simplify_stmt_using_ranges): Accept a GSI, return a bool. * tree-ssa-propagate.c (substitute_and_fold): Pass a GSI to VRP's simplify_stmt_using_ranges. Do simplify_stmt_using_ranges before finalizing the changes. * tree-vrp.c (extract_range_from_binary_expr): Add limited support for BIT_IOR_EXPR. (simplify_truth_ops_using_ranges): New. (simplify_div_or_mod_using_ranges, simplify_abs_using_ranges, simplify_cond_using_ranges, simplify_switch_using_ranges): Return whether a simplification was made. (simplify_stmt_using_ranges): Ditto, and accept a GSI. For GS_ASSIGN, use a switch statement and also call simplify_truth_ops_using_ranges. testsuite: 2008-09-11 Paolo Bonzini <bonzini@gnu.org> * gcc.dg/tree-ssa/vrp47.c: New. * gcc.target/i386/andor-2.c: New. From-SVN: r140288
This commit is contained in:
parent
cf9757477e
commit
3082165492
@ -1,3 +1,22 @@
|
||||
2008-09-11 Paolo Bonzini <bonzini@gnu.org>
|
||||
|
||||
* dojump.c (do_jump) [BIT_AND_EXPR]: Move below. Fall through to
|
||||
TRUTH_AND_EXPR for boolean (1-bit precision) expressions.
|
||||
(do_jump) [BIT_IOR_EXPR]: Compile as TRUTH_OR_EXPR.
|
||||
|
||||
* tree-flow.h (simplify_stmt_using_ranges): Accept a GSI, return a bool.
|
||||
* tree-ssa-propagate.c (substitute_and_fold): Pass a GSI to
|
||||
VRP's simplify_stmt_using_ranges. Do simplify_stmt_using_ranges
|
||||
before finalizing the changes.
|
||||
* tree-vrp.c (extract_range_from_binary_expr): Add limited support
|
||||
for BIT_IOR_EXPR.
|
||||
(simplify_truth_ops_using_ranges): New.
|
||||
(simplify_div_or_mod_using_ranges, simplify_abs_using_ranges,
|
||||
simplify_cond_using_ranges, simplify_switch_using_ranges): Return
|
||||
whether a simplification was made.
|
||||
(simplify_stmt_using_ranges): Ditto, and accept a GSI. For GS_ASSIGN,
|
||||
use a switch statement and also call simplify_truth_ops_using_ranges.
|
||||
|
||||
2008-09-11 Jan Hubicka <jh@suse.cz>
|
||||
|
||||
* ggc-common.c (loc_array): Make static.
|
||||
|
154
gcc/dojump.c
154
gcc/dojump.c
@ -208,79 +208,6 @@ do_jump (tree exp, rtx if_false_label, rtx if_true_label)
|
||||
do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
|
||||
break;
|
||||
|
||||
case BIT_AND_EXPR:
|
||||
/* fold_single_bit_test() converts (X & (1 << C)) into (X >> C) & 1.
|
||||
See if the former is preferred for jump tests and restore it
|
||||
if so. */
|
||||
if (integer_onep (TREE_OPERAND (exp, 1)))
|
||||
{
|
||||
tree exp0 = TREE_OPERAND (exp, 0);
|
||||
rtx set_label, clr_label;
|
||||
|
||||
/* Strip narrowing integral type conversions. */
|
||||
while (CONVERT_EXPR_P (exp0)
|
||||
&& TREE_OPERAND (exp0, 0) != error_mark_node
|
||||
&& TYPE_PRECISION (TREE_TYPE (exp0))
|
||||
<= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp0, 0))))
|
||||
exp0 = TREE_OPERAND (exp0, 0);
|
||||
|
||||
/* "exp0 ^ 1" inverts the sense of the single bit test. */
|
||||
if (TREE_CODE (exp0) == BIT_XOR_EXPR
|
||||
&& integer_onep (TREE_OPERAND (exp0, 1)))
|
||||
{
|
||||
exp0 = TREE_OPERAND (exp0, 0);
|
||||
clr_label = if_true_label;
|
||||
set_label = if_false_label;
|
||||
}
|
||||
else
|
||||
{
|
||||
clr_label = if_false_label;
|
||||
set_label = if_true_label;
|
||||
}
|
||||
|
||||
if (TREE_CODE (exp0) == RSHIFT_EXPR)
|
||||
{
|
||||
tree arg = TREE_OPERAND (exp0, 0);
|
||||
tree shift = TREE_OPERAND (exp0, 1);
|
||||
tree argtype = TREE_TYPE (arg);
|
||||
if (TREE_CODE (shift) == INTEGER_CST
|
||||
&& compare_tree_int (shift, 0) >= 0
|
||||
&& compare_tree_int (shift, HOST_BITS_PER_WIDE_INT) < 0
|
||||
&& prefer_and_bit_test (TYPE_MODE (argtype),
|
||||
TREE_INT_CST_LOW (shift)))
|
||||
{
|
||||
HOST_WIDE_INT mask = (HOST_WIDE_INT) 1
|
||||
<< TREE_INT_CST_LOW (shift);
|
||||
do_jump (build2 (BIT_AND_EXPR, argtype, arg,
|
||||
build_int_cst_type (argtype, mask)),
|
||||
clr_label, set_label);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If we are AND'ing with a small constant, do this comparison in the
|
||||
smallest type that fits. If the machine doesn't have comparisons
|
||||
that small, it will be converted back to the wider comparison.
|
||||
This helps if we are testing the sign bit of a narrower object.
|
||||
combine can't do this for us because it can't know whether a
|
||||
ZERO_EXTRACT or a compare in a smaller mode exists, but we do. */
|
||||
|
||||
if (! SLOW_BYTE_ACCESS
|
||||
&& TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
|
||||
&& TYPE_PRECISION (TREE_TYPE (exp)) <= HOST_BITS_PER_WIDE_INT
|
||||
&& (i = tree_floor_log2 (TREE_OPERAND (exp, 1))) >= 0
|
||||
&& (mode = mode_for_size (i + 1, MODE_INT, 0)) != BLKmode
|
||||
&& (type = lang_hooks.types.type_for_mode (mode, 1)) != 0
|
||||
&& TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (exp))
|
||||
&& (optab_handler (cmp_optab, TYPE_MODE (type))->insn_code
|
||||
!= CODE_FOR_nothing))
|
||||
{
|
||||
do_jump (fold_convert (type, exp), if_false_label, if_true_label);
|
||||
break;
|
||||
}
|
||||
goto normal;
|
||||
|
||||
case TRUTH_NOT_EXPR:
|
||||
do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label);
|
||||
break;
|
||||
@ -504,8 +431,86 @@ do_jump (tree exp, rtx if_false_label, rtx if_true_label)
|
||||
do_jump (cmp0, 0, if_true_label);
|
||||
do_jump (cmp1, if_false_label, if_true_label);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BIT_AND_EXPR:
|
||||
/* fold_single_bit_test() converts (X & (1 << C)) into (X >> C) & 1.
|
||||
See if the former is preferred for jump tests and restore it
|
||||
if so. */
|
||||
if (integer_onep (TREE_OPERAND (exp, 1)))
|
||||
{
|
||||
tree exp0 = TREE_OPERAND (exp, 0);
|
||||
rtx set_label, clr_label;
|
||||
|
||||
/* Strip narrowing integral type conversions. */
|
||||
while (CONVERT_EXPR_P (exp0)
|
||||
&& TREE_OPERAND (exp0, 0) != error_mark_node
|
||||
&& TYPE_PRECISION (TREE_TYPE (exp0))
|
||||
<= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp0, 0))))
|
||||
exp0 = TREE_OPERAND (exp0, 0);
|
||||
|
||||
/* "exp0 ^ 1" inverts the sense of the single bit test. */
|
||||
if (TREE_CODE (exp0) == BIT_XOR_EXPR
|
||||
&& integer_onep (TREE_OPERAND (exp0, 1)))
|
||||
{
|
||||
exp0 = TREE_OPERAND (exp0, 0);
|
||||
clr_label = if_true_label;
|
||||
set_label = if_false_label;
|
||||
}
|
||||
else
|
||||
{
|
||||
clr_label = if_false_label;
|
||||
set_label = if_true_label;
|
||||
}
|
||||
|
||||
if (TREE_CODE (exp0) == RSHIFT_EXPR)
|
||||
{
|
||||
tree arg = TREE_OPERAND (exp0, 0);
|
||||
tree shift = TREE_OPERAND (exp0, 1);
|
||||
tree argtype = TREE_TYPE (arg);
|
||||
if (TREE_CODE (shift) == INTEGER_CST
|
||||
&& compare_tree_int (shift, 0) >= 0
|
||||
&& compare_tree_int (shift, HOST_BITS_PER_WIDE_INT) < 0
|
||||
&& prefer_and_bit_test (TYPE_MODE (argtype),
|
||||
TREE_INT_CST_LOW (shift)))
|
||||
{
|
||||
HOST_WIDE_INT mask = (HOST_WIDE_INT) 1
|
||||
<< TREE_INT_CST_LOW (shift);
|
||||
do_jump (build2 (BIT_AND_EXPR, argtype, arg,
|
||||
build_int_cst_type (argtype, mask)),
|
||||
clr_label, set_label);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If we are AND'ing with a small constant, do this comparison in the
|
||||
smallest type that fits. If the machine doesn't have comparisons
|
||||
that small, it will be converted back to the wider comparison.
|
||||
This helps if we are testing the sign bit of a narrower object.
|
||||
combine can't do this for us because it can't know whether a
|
||||
ZERO_EXTRACT or a compare in a smaller mode exists, but we do. */
|
||||
|
||||
if (! SLOW_BYTE_ACCESS
|
||||
&& TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
|
||||
&& TYPE_PRECISION (TREE_TYPE (exp)) <= HOST_BITS_PER_WIDE_INT
|
||||
&& (i = tree_floor_log2 (TREE_OPERAND (exp, 1))) >= 0
|
||||
&& (mode = mode_for_size (i + 1, MODE_INT, 0)) != BLKmode
|
||||
&& (type = lang_hooks.types.type_for_mode (mode, 1)) != 0
|
||||
&& TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (exp))
|
||||
&& (optab_handler (cmp_optab, TYPE_MODE (type))->insn_code
|
||||
!= CODE_FOR_nothing))
|
||||
{
|
||||
do_jump (fold_convert (type, exp), if_false_label, if_true_label);
|
||||
break;
|
||||
}
|
||||
|
||||
if (TYPE_PRECISION (TREE_TYPE (exp)) > 1
|
||||
|| TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
|
||||
goto normal;
|
||||
|
||||
/* Boolean comparisons can be compiled as TRUTH_AND_EXPR. */
|
||||
|
||||
case TRUTH_AND_EXPR:
|
||||
/* High branch cost, expand as the bitwise AND of the conditions.
|
||||
@ -530,6 +535,7 @@ do_jump (tree exp, rtx if_false_label, rtx if_true_label)
|
||||
}
|
||||
break;
|
||||
|
||||
case BIT_IOR_EXPR:
|
||||
case TRUTH_OR_EXPR:
|
||||
/* High branch cost, expand as the bitwise OR of the conditions.
|
||||
Do the same if the RHS has side effects, because we're effectively
|
||||
|
@ -1,3 +1,8 @@
|
||||
2008-09-11 Paolo Bonzini <bonzini@gnu.org>
|
||||
|
||||
* gcc.dg/tree-ssa/vrp47.c: New.
|
||||
* gcc.target/i386/andor-2.c: New.
|
||||
|
||||
2008-09-11 Ira Rosen <irar@il.ibm.com>
|
||||
|
||||
PR tree-optimization/37474
|
||||
|
42
gcc/testsuite/gcc.dg/tree-ssa/vrp47.c
Normal file
42
gcc/testsuite/gcc.dg/tree-ssa/vrp47.c
Normal file
@ -0,0 +1,42 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-vrp -fdump-tree-dom" } */
|
||||
|
||||
int h(int x, int y)
|
||||
{
|
||||
if ((x >= 0 && x <= 1) && (y >= 0 && y <= 1))
|
||||
return x && y;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
int g(int x, int y)
|
||||
{
|
||||
if ((x >= 0 && x <= 1) && (y >= 0 && y <= 1))
|
||||
return x || y;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
int f(int x)
|
||||
{
|
||||
if (x != 0 && x != 1)
|
||||
return -2;
|
||||
|
||||
else
|
||||
return !x;
|
||||
}
|
||||
|
||||
/* Test that x and y are never compared to 0 -- they're always known to be
|
||||
0 or 1. */
|
||||
/* { dg-final { scan-tree-dump-times "\[xy\]\[^ \]* !=" 0 "vrp1" } } */
|
||||
|
||||
/* This one needs more copy propagation that only happens in dom1. */
|
||||
/* { dg-final { scan-tree-dump-times "x\[^ \]* & y" 1 "dom1" } } */
|
||||
/* { dg-final { scan-tree-dump-times "x\[^ \]* & y" 1 "vrp1" { xfail *-*-* } } } */
|
||||
|
||||
/* These two are fully simplified by VRP. */
|
||||
/* { dg-final { scan-tree-dump-times "x\[^ \]* \[|\] y" 1 "vrp1" } } */
|
||||
/* { dg-final { scan-tree-dump-times "x\[^ \]* \\^ 1" 1 "vrp1" } } */
|
||||
|
||||
/* { dg-final { cleanup-tree-dump "vrp\[0-9\]" } } */
|
||||
/* { dg-final { cleanup-tree-dump "dom\[0-9\]" } } */
|
30
gcc/testsuite/gcc.target/i386/andor-2.c
Normal file
30
gcc/testsuite/gcc.target/i386/andor-2.c
Normal file
@ -0,0 +1,30 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -mtune=i686" } */
|
||||
|
||||
int h(int x, int y)
|
||||
{
|
||||
if ((x >= 0 && x <= 1) && (y >= 0 && y <= 1))
|
||||
return x && y;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
int g(int x, int y)
|
||||
{
|
||||
if ((x >= 0 && x <= 1) && (y >= 0 && y <= 1))
|
||||
return x || y;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
int f(int x, int y)
|
||||
{
|
||||
if (x != 0 && x != 1)
|
||||
return -2;
|
||||
|
||||
else
|
||||
return !x;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-assembler-not "setne" } } */
|
||||
/* { dg-final { scan-assembler-not "sete" } } */
|
@ -913,7 +913,7 @@ tree fold_const_aggregate_ref (tree);
|
||||
|
||||
/* In tree-vrp.c */
|
||||
tree vrp_evaluate_conditional (enum tree_code, tree, tree, gimple);
|
||||
void simplify_stmt_using_ranges (gimple);
|
||||
bool simplify_stmt_using_ranges (gimple_stmt_iterator *);
|
||||
|
||||
/* In tree-ssa-dom.c */
|
||||
extern void dump_dominator_optimization_stats (FILE *);
|
||||
|
@ -1098,6 +1098,7 @@ substitute_and_fold (prop_value_t *prop_value, bool use_ranges_p)
|
||||
{
|
||||
bool did_replace;
|
||||
gimple stmt = gsi_stmt (i);
|
||||
gimple old_stmt;
|
||||
enum gimple_code code = gimple_code (stmt);
|
||||
|
||||
/* Ignore ASSERT_EXPRs. They are used by VRP to generate
|
||||
@ -1162,12 +1163,24 @@ substitute_and_fold (prop_value_t *prop_value, bool use_ranges_p)
|
||||
&& !did_replace)
|
||||
did_replace |= replace_uses_in (stmt, prop_value);
|
||||
|
||||
/* If we made a replacement, fold and cleanup the statement. */
|
||||
/* If we made a replacement, fold the statement. */
|
||||
|
||||
old_stmt = stmt;
|
||||
if (did_replace)
|
||||
fold_stmt (&i);
|
||||
|
||||
/* Some statements may be simplified using ranges. For
|
||||
example, division may be replaced by shifts, modulo
|
||||
replaced with bitwise and, etc. Do this after
|
||||
substituting constants, folding, etc so that we're
|
||||
presented with a fully propagated, canonicalized
|
||||
statement. */
|
||||
if (use_ranges_p)
|
||||
did_replace |= simplify_stmt_using_ranges (&i);
|
||||
|
||||
/* Now cleanup. */
|
||||
if (did_replace)
|
||||
{
|
||||
gimple old_stmt = stmt;
|
||||
|
||||
fold_stmt (&i);
|
||||
stmt = gsi_stmt (i);
|
||||
|
||||
/* If we cleaned up EH information from the statement,
|
||||
@ -1207,15 +1220,6 @@ substitute_and_fold (prop_value_t *prop_value, bool use_ranges_p)
|
||||
fprintf (dump_file, "Not folded\n");
|
||||
}
|
||||
|
||||
/* Some statements may be simplified using ranges. For
|
||||
example, division may be replaced by shifts, modulo
|
||||
replaced with bitwise and, etc. Do this after
|
||||
substituting constants, folding, etc so that we're
|
||||
presented with a fully propagated, canonicalized
|
||||
statement. */
|
||||
if (use_ranges_p)
|
||||
simplify_stmt_using_ranges (stmt);
|
||||
|
||||
gsi_prev (&i);
|
||||
}
|
||||
}
|
||||
|
243
gcc/tree-vrp.c
243
gcc/tree-vrp.c
@ -2055,6 +2055,7 @@ extract_range_from_binary_expr (value_range_t *vr,
|
||||
&& code != MIN_EXPR
|
||||
&& code != MAX_EXPR
|
||||
&& code != BIT_AND_EXPR
|
||||
&& code != BIT_IOR_EXPR
|
||||
&& code != TRUTH_AND_EXPR
|
||||
&& code != TRUTH_OR_EXPR)
|
||||
{
|
||||
@ -2415,6 +2416,45 @@ extract_range_from_binary_expr (value_range_t *vr,
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (code == BIT_IOR_EXPR)
|
||||
{
|
||||
if (vr0.type == VR_RANGE
|
||||
&& vr1.type == VR_RANGE
|
||||
&& TREE_CODE (vr0.min) == INTEGER_CST
|
||||
&& TREE_CODE (vr1.min) == INTEGER_CST
|
||||
&& TREE_CODE (vr0.max) == INTEGER_CST
|
||||
&& TREE_CODE (vr1.max) == INTEGER_CST
|
||||
&& tree_int_cst_sgn (vr0.min) >= 0
|
||||
&& tree_int_cst_sgn (vr1.min) >= 0)
|
||||
{
|
||||
double_int vr0_max = tree_to_double_int (vr0.max);
|
||||
double_int vr1_max = tree_to_double_int (vr1.max);
|
||||
double_int ior_max;
|
||||
|
||||
/* Set all bits to the right of the most significant one to 1.
|
||||
For example, [0, 4] | [4, 4] = [4, 7]. */
|
||||
ior_max.low = vr0_max.low | vr1_max.low;
|
||||
ior_max.high = vr0_max.high | vr1_max.high;
|
||||
if (ior_max.high != 0)
|
||||
{
|
||||
ior_max.low = ~0u;
|
||||
ior_max.high |= ((HOST_WIDE_INT) 1
|
||||
<< floor_log2 (ior_max.high)) - 1;
|
||||
}
|
||||
else
|
||||
ior_max.low |= ((unsigned HOST_WIDE_INT) 1u
|
||||
<< floor_log2 (ior_max.low)) - 1;
|
||||
|
||||
/* Both of these endpoints are conservative. */
|
||||
min = vrp_int_const_binop (MAX_EXPR, vr0.min, vr1.min);
|
||||
max = double_int_to_tree (expr_type, ior_max);
|
||||
}
|
||||
else
|
||||
{
|
||||
set_value_range_to_varying (vr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
gcc_unreachable ();
|
||||
|
||||
@ -6251,11 +6291,137 @@ varying:
|
||||
return SSA_PROP_VARYING;
|
||||
}
|
||||
|
||||
/* Simplify boolean operations if the source is known
|
||||
to be already a boolean. */
|
||||
static bool
|
||||
simplify_truth_ops_using_ranges (gimple_stmt_iterator *gsi, gimple stmt)
|
||||
{
|
||||
enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
|
||||
tree val = NULL;
|
||||
tree op0, op1;
|
||||
value_range_t *vr;
|
||||
bool sop = false;
|
||||
bool need_conversion;
|
||||
|
||||
op0 = gimple_assign_rhs1 (stmt);
|
||||
vr = get_value_range (op0);
|
||||
if (TYPE_PRECISION (TREE_TYPE (op0)) != 1)
|
||||
{
|
||||
val = compare_range_with_value (GE_EXPR, vr, integer_zero_node, &sop);
|
||||
if (!val || !integer_onep (val))
|
||||
return false;
|
||||
|
||||
val = compare_range_with_value (LE_EXPR, vr, integer_one_node, &sop);
|
||||
if (!val || !integer_onep (val))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rhs_code == TRUTH_NOT_EXPR)
|
||||
{
|
||||
rhs_code = NE_EXPR;
|
||||
op1 = integer_one_node;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
op1 = gimple_assign_rhs2 (stmt);
|
||||
|
||||
/* Reduce number of cases to handle. */
|
||||
if (is_gimple_min_invariant (op1))
|
||||
{
|
||||
/* Exclude anything that should have been already folded. */
|
||||
gcc_assert (rhs_code == EQ_EXPR || rhs_code == NE_EXPR
|
||||
|| rhs_code == TRUTH_XOR_EXPR);
|
||||
gcc_assert (integer_zerop (op1) || integer_onep (op1));
|
||||
|
||||
/* Limit the number of cases we have to consider. */
|
||||
if (rhs_code == EQ_EXPR)
|
||||
{
|
||||
rhs_code = NE_EXPR;
|
||||
op1 = fold_unary (TRUTH_NOT_EXPR, TREE_TYPE (op1), op1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Punt on A == B as there is no BIT_XNOR_EXPR. */
|
||||
if (rhs_code == EQ_EXPR)
|
||||
return false;
|
||||
|
||||
if (TYPE_PRECISION (TREE_TYPE (op1)) != 1)
|
||||
{
|
||||
vr = get_value_range (op1);
|
||||
val = compare_range_with_value (GE_EXPR, vr, integer_zero_node, &sop);
|
||||
if (!val || !integer_onep (val))
|
||||
return false;
|
||||
|
||||
val = compare_range_with_value (LE_EXPR, vr, integer_one_node, &sop);
|
||||
if (!val || !integer_onep (val))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sop && issue_strict_overflow_warning (WARN_STRICT_OVERFLOW_MISC))
|
||||
{
|
||||
location_t location;
|
||||
|
||||
if (!gimple_has_location (stmt))
|
||||
location = input_location;
|
||||
else
|
||||
location = gimple_location (stmt);
|
||||
|
||||
if (rhs_code == TRUTH_AND_EXPR || rhs_code == TRUTH_OR_EXPR)
|
||||
warning_at (location, OPT_Wstrict_overflow,
|
||||
_("assuming signed overflow does not occur when "
|
||||
"simplifying && or || to & or |"));
|
||||
else
|
||||
warning_at (location, OPT_Wstrict_overflow,
|
||||
_("assuming signed overflow does not occur when "
|
||||
"simplifying ==, != or ! to identity or ^"));
|
||||
}
|
||||
|
||||
need_conversion =
|
||||
!useless_type_conversion_p (TREE_TYPE (gimple_assign_lhs (stmt)),
|
||||
TREE_TYPE (op0));
|
||||
|
||||
switch (rhs_code)
|
||||
{
|
||||
case TRUTH_AND_EXPR:
|
||||
rhs_code = BIT_AND_EXPR;
|
||||
break;
|
||||
case TRUTH_OR_EXPR:
|
||||
rhs_code = BIT_IOR_EXPR;
|
||||
break;
|
||||
case TRUTH_XOR_EXPR:
|
||||
case NE_EXPR:
|
||||
if (integer_zerop (op1))
|
||||
{
|
||||
gimple_assign_set_rhs_with_ops (gsi,
|
||||
need_conversion ? NOP_EXPR : SSA_NAME,
|
||||
op0, NULL);
|
||||
update_stmt (gsi_stmt (*gsi));
|
||||
return true;
|
||||
}
|
||||
|
||||
rhs_code = BIT_XOR_EXPR;
|
||||
break;
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
if (need_conversion)
|
||||
return false;
|
||||
|
||||
gimple_assign_set_rhs_with_ops (gsi, rhs_code, op0, op1);
|
||||
update_stmt (gsi_stmt (*gsi));
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Simplify a division or modulo operator to a right shift or
|
||||
bitwise and if the first operand is unsigned or is greater
|
||||
than zero and the second operand is an exact power of two. */
|
||||
|
||||
static void
|
||||
static bool
|
||||
simplify_div_or_mod_using_ranges (gimple stmt)
|
||||
{
|
||||
enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
|
||||
@ -6315,14 +6481,17 @@ simplify_div_or_mod_using_ranges (gimple stmt)
|
||||
}
|
||||
|
||||
update_stmt (stmt);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* If the operand to an ABS_EXPR is >= 0, then eliminate the
|
||||
ABS_EXPR. If the operand is <= 0, then simplify the
|
||||
ABS_EXPR into a NEGATE_EXPR. */
|
||||
|
||||
static void
|
||||
static bool
|
||||
simplify_abs_using_ranges (gimple stmt)
|
||||
{
|
||||
tree val = NULL;
|
||||
@ -6377,8 +6546,11 @@ simplify_abs_using_ranges (gimple stmt)
|
||||
else
|
||||
gimple_assign_set_rhs_code (stmt, SSA_NAME);
|
||||
update_stmt (stmt);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* We are comparing trees OP0 and OP1 using COND_CODE. OP0 has
|
||||
@ -6453,7 +6625,7 @@ test_for_singularity (enum tree_code cond_code, tree op0,
|
||||
test if the range information indicates only one value can satisfy
|
||||
the original conditional. */
|
||||
|
||||
static void
|
||||
static bool
|
||||
simplify_cond_using_ranges (gimple stmt)
|
||||
{
|
||||
tree op0 = gimple_cond_lhs (stmt);
|
||||
@ -6494,8 +6666,8 @@ simplify_cond_using_ranges (gimple stmt)
|
||||
print_gimple_stmt (dump_file, stmt, 0, 0);
|
||||
fprintf (dump_file, "\n");
|
||||
}
|
||||
return;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Try again after inverting the condition. We only deal
|
||||
@ -6524,17 +6696,19 @@ simplify_cond_using_ranges (gimple stmt)
|
||||
print_gimple_stmt (dump_file, stmt, 0, 0);
|
||||
fprintf (dump_file, "\n");
|
||||
}
|
||||
return;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Simplify a switch statement using the value range of the switch
|
||||
argument. */
|
||||
|
||||
static void
|
||||
static bool
|
||||
simplify_switch_using_ranges (gimple stmt)
|
||||
{
|
||||
tree op = gimple_switch_index (stmt);
|
||||
@ -6547,14 +6721,14 @@ simplify_switch_using_ranges (gimple stmt)
|
||||
switch_update su;
|
||||
|
||||
if (TREE_CODE (op) != SSA_NAME)
|
||||
return;
|
||||
return false;
|
||||
|
||||
vr = get_value_range (op);
|
||||
|
||||
/* We can only handle integer ranges. */
|
||||
if (vr->type != VR_RANGE
|
||||
|| symbolic_range_p (vr))
|
||||
return;
|
||||
return false;
|
||||
|
||||
/* Find case label for min/max of the value range. */
|
||||
n = gimple_switch_num_labels (stmt);
|
||||
@ -6564,7 +6738,7 @@ simplify_switch_using_ranges (gimple stmt)
|
||||
if (i == 1
|
||||
&& j == n - 1
|
||||
&& take_default)
|
||||
return;
|
||||
return false;
|
||||
|
||||
/* Build a new vector of taken case labels. */
|
||||
vec2 = make_tree_vec (j - i + 1 + (int)take_default);
|
||||
@ -6605,35 +6779,62 @@ simplify_switch_using_ranges (gimple stmt)
|
||||
su.stmt = stmt;
|
||||
su.vec = vec2;
|
||||
VEC_safe_push (switch_update, heap, to_update_switch_stmts, &su);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Simplify STMT using ranges if possible. */
|
||||
|
||||
void
|
||||
simplify_stmt_using_ranges (gimple stmt)
|
||||
bool
|
||||
simplify_stmt_using_ranges (gimple_stmt_iterator *gsi)
|
||||
{
|
||||
gimple stmt = gsi_stmt (*gsi);
|
||||
if (is_gimple_assign (stmt))
|
||||
{
|
||||
enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
|
||||
|
||||
switch (rhs_code)
|
||||
{
|
||||
case EQ_EXPR:
|
||||
case NE_EXPR:
|
||||
case TRUTH_NOT_EXPR:
|
||||
case TRUTH_AND_EXPR:
|
||||
case TRUTH_OR_EXPR:
|
||||
case TRUTH_XOR_EXPR:
|
||||
/* Transform EQ_EXPR, NE_EXPR, TRUTH_NOT_EXPR into BIT_XOR_EXPR
|
||||
or identity if the RHS is zero or one, and the LHS are known
|
||||
to be boolean values. Transform all TRUTH_*_EXPR into
|
||||
BIT_*_EXPR if both arguments are known to be boolean values. */
|
||||
if (INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt))))
|
||||
return simplify_truth_ops_using_ranges (gsi, stmt);
|
||||
break;
|
||||
|
||||
/* Transform TRUNC_DIV_EXPR and TRUNC_MOD_EXPR into RSHIFT_EXPR
|
||||
and BIT_AND_EXPR respectively if the first operand is greater
|
||||
than zero and the second operand is an exact power of two. */
|
||||
if ((rhs_code == TRUNC_DIV_EXPR || rhs_code == TRUNC_MOD_EXPR)
|
||||
&& INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt)))
|
||||
&& integer_pow2p (gimple_assign_rhs2 (stmt)))
|
||||
simplify_div_or_mod_using_ranges (stmt);
|
||||
case TRUNC_DIV_EXPR:
|
||||
case TRUNC_MOD_EXPR:
|
||||
if (INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt)))
|
||||
&& integer_pow2p (gimple_assign_rhs2 (stmt)))
|
||||
return simplify_div_or_mod_using_ranges (stmt);
|
||||
break;
|
||||
|
||||
/* Transform ABS (X) into X or -X as appropriate. */
|
||||
if (rhs_code == ABS_EXPR
|
||||
&& TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME
|
||||
&& INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt))))
|
||||
simplify_abs_using_ranges (stmt);
|
||||
case ABS_EXPR:
|
||||
if (TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME
|
||||
&& INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt))))
|
||||
return simplify_abs_using_ranges (stmt);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (gimple_code (stmt) == GIMPLE_COND)
|
||||
simplify_cond_using_ranges (stmt);
|
||||
return simplify_cond_using_ranges (stmt);
|
||||
else if (gimple_code (stmt) == GIMPLE_SWITCH)
|
||||
simplify_switch_using_ranges (stmt);
|
||||
return simplify_switch_using_ranges (stmt);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Stack of dest,src equivalency pairs that need to be restored after
|
||||
|
Loading…
x
Reference in New Issue
Block a user