From: Paolo Bonzini Date: Thu, 11 Sep 2008 14:45:05 +0000 (+0000) Subject: dojump.c (do_jump): Move below. X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=308216549297c41fb602dced560fa1ed8af0f8f6;p=platform%2Fupstream%2Fgcc.git dojump.c (do_jump): Move below. 2008-09-11 Paolo Bonzini * 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 * gcc.dg/tree-ssa/vrp47.c: New. * gcc.target/i386/andor-2.c: New. From-SVN: r140288 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 67d1649..2f4e784 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,22 @@ +2008-09-11 Paolo Bonzini + + * 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 * ggc-common.c (loc_array): Make static. diff --git a/gcc/dojump.c b/gcc/dojump.c index 0ff5395..849f69f 100644 --- a/gcc/dojump.c +++ b/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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 85bb2a5..84ba775 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2008-09-11 Paolo Bonzini + + * gcc.dg/tree-ssa/vrp47.c: New. + * gcc.target/i386/andor-2.c: New. + 2008-09-11 Ira Rosen PR tree-optimization/37474 diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp47.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp47.c new file mode 100644 index 0000000..a1ee927 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp47.c @@ -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\]" } } */ diff --git a/gcc/testsuite/gcc.target/i386/andor-2.c b/gcc/testsuite/gcc.target/i386/andor-2.c new file mode 100644 index 0000000..88118aa --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/andor-2.c @@ -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" } } */ diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h index 99b993d..7f3c0dd 100644 --- a/gcc/tree-flow.h +++ b/gcc/tree-flow.h @@ -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 *); diff --git a/gcc/tree-ssa-propagate.c b/gcc/tree-ssa-propagate.c index 4c246e6..86bc238 100644 --- a/gcc/tree-ssa-propagate.c +++ b/gcc/tree-ssa-propagate.c @@ -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) - { - gimple old_stmt = stmt; + 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); - fold_stmt (&i); + /* Now cleanup. */ + if (did_replace) + { 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); } } diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index 46aa69d..fffa224 100644 --- a/gcc/tree-vrp.c +++ b/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