diff options
Diffstat (limited to 'meta-oe/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99306.patch')
-rw-r--r-- | meta-oe/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99306.patch | 1401 |
1 files changed, 1401 insertions, 0 deletions
diff --git a/meta-oe/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99306.patch b/meta-oe/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99306.patch new file mode 100644 index 0000000..423cd56 --- /dev/null +++ b/meta-oe/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99306.patch @@ -0,0 +1,1401 @@ +2010-07-10 Sandra Loosemore <sandra@codesourcery.com> + + Backport from mainline: + + 2010-05-08 Sandra Loosemore <sandra@codesourcery.com> + + PR middle-end/28685 + + gcc/ + * tree-ssa-reassoc.c (eliminate_redundant_comparison): New function. + (optimize_ops_list): Call it. + + gcc/testsuite/ + * gcc.dg/pr28685-1.c: New file. + + 2010-06-08 Sandra Loosemore <sandra@codesourcery.com> + + PR tree-optimization/39874 + PR middle-end/28685 + + gcc/ + * gimple.h (maybe_fold_and_comparisons, maybe_fold_or_comparisons): + Declare. + * gimple-fold.c (canonicalize_bool, same_bool_comparison_p, + same_bool_result_p): New. + (and_var_with_comparison, and_var_with_comparison_1, + and_comparisons_1, and_comparisons, maybe_fold_and_comparisons): New. + (or_var_with_comparison, or_var_with_comparison_1, + or_comparisons_1, or_comparisons, maybe_fold_or_comparisons): New. + * tree-ssa-reassoc.c (eliminate_redundant_comparison): Use + maybe_fold_and_comparisons or maybe_fold_or_comparisons instead + of combine_comparisons. + * tree-ssa-ifcombine.c (ifcombine_ifandif, ifcombine_iforif): Likewise. + + gcc/testsuite/ + * gcc.dg/pr39874.c: New file. + + 2010-07-10 Yao Qi <yao@codesourcery.com> + + Merge from Sourcery G++ 4.4: + +=== modified file 'gcc/gimple.h' +--- old/gcc/gimple.h 2010-04-02 18:54:46 +0000 ++++ new/gcc/gimple.h 2010-07-30 13:21:51 +0000 +@@ -4743,4 +4743,9 @@ + + extern void dump_gimple_statistics (void); + ++extern tree maybe_fold_and_comparisons (enum tree_code, tree, tree, ++ enum tree_code, tree, tree); ++extern tree maybe_fold_or_comparisons (enum tree_code, tree, tree, ++ enum tree_code, tree, tree); ++ + #endif /* GCC_GIMPLE_H */ + +=== added file 'gcc/testsuite/gcc.dg/pr28685-1.c' +--- old/gcc/testsuite/gcc.dg/pr28685-1.c 1970-01-01 00:00:00 +0000 ++++ new/gcc/testsuite/gcc.dg/pr28685-1.c 2010-07-30 13:21:51 +0000 +@@ -0,0 +1,50 @@ ++/* { dg-do compile } */ ++/* { dg-options "-O2 -fdump-tree-optimized" } */ ++ ++/* Should produce <=. */ ++int test1 (int a, int b) ++{ ++ return (a < b || a == b); ++} ++ ++/* Should produce <=. */ ++int test2 (int a, int b) ++{ ++ int lt = a < b; ++ int eq = a == b; ++ ++ return (lt || eq); ++} ++ ++/* Should produce <= (just deleting redundant test). */ ++int test3 (int a, int b) ++{ ++ int lt = a <= b; ++ int eq = a == b; ++ ++ return (lt || eq); ++} ++ ++/* Should produce <= (operands reversed to test the swap logic). */ ++int test4 (int a, int b) ++{ ++ int lt = a < b; ++ int eq = b == a; ++ ++ return (lt || eq); ++} ++ ++/* Should produce constant 0. */ ++int test5 (int a, int b) ++{ ++ int lt = a < b; ++ int eq = a == b; ++ ++ return (lt && eq); ++} ++ ++/* { dg-final { scan-tree-dump-times " <= " 4 "optimized" } } */ ++/* { dg-final { scan-tree-dump-times "return 0" 1 "optimized" } } */ ++/* { dg-final { scan-tree-dump-not " < " "optimized" } } */ ++/* { dg-final { scan-tree-dump-not " == " "optimized" } } */ ++/* { dg-final { cleanup-tree-dump "optimized" } } */ + +=== added file 'gcc/testsuite/gcc.dg/pr39874.c' +--- old/gcc/testsuite/gcc.dg/pr39874.c 1970-01-01 00:00:00 +0000 ++++ new/gcc/testsuite/gcc.dg/pr39874.c 2010-07-30 13:21:51 +0000 +@@ -0,0 +1,29 @@ ++/* { dg-do compile } */ ++/* { dg-options "-O2 -fdump-tree-optimized" } */ ++ ++extern void func(); ++ ++void test1(char *signature) ++{ ++ char ch = signature[0]; ++ if (ch == 15 || ch == 3) ++ { ++ if (ch == 15) func(); ++ } ++} ++ ++ ++void test2(char *signature) ++{ ++ char ch = signature[0]; ++ if (ch == 15 || ch == 3) ++ { ++ if (ch > 14) func(); ++ } ++} ++ ++/* { dg-final { scan-tree-dump-times " == 15" 2 "optimized" } } */ ++/* { dg-final { scan-tree-dump-not " == 3" "optimized" } } */ ++/* { dg-final { cleanup-tree-dump "optimized" } } */ ++ ++ + +=== modified file 'gcc/tree-ssa-ccp.c' +--- old/gcc/tree-ssa-ccp.c 2010-04-02 15:50:04 +0000 ++++ new/gcc/tree-ssa-ccp.c 2010-07-30 13:21:51 +0000 +@@ -3176,6 +3176,1056 @@ + return changed; + } + ++/* Canonicalize and possibly invert the boolean EXPR; return NULL_TREE ++ if EXPR is null or we don't know how. ++ If non-null, the result always has boolean type. */ ++ ++static tree ++canonicalize_bool (tree expr, bool invert) ++{ ++ if (!expr) ++ return NULL_TREE; ++ else if (invert) ++ { ++ if (integer_nonzerop (expr)) ++ return boolean_false_node; ++ else if (integer_zerop (expr)) ++ return boolean_true_node; ++ else if (TREE_CODE (expr) == SSA_NAME) ++ return fold_build2 (EQ_EXPR, boolean_type_node, expr, ++ build_int_cst (TREE_TYPE (expr), 0)); ++ else if (TREE_CODE_CLASS (TREE_CODE (expr)) == tcc_comparison) ++ return fold_build2 (invert_tree_comparison (TREE_CODE (expr), false), ++ boolean_type_node, ++ TREE_OPERAND (expr, 0), ++ TREE_OPERAND (expr, 1)); ++ else ++ return NULL_TREE; ++ } ++ else ++ { ++ if (TREE_CODE (TREE_TYPE (expr)) == BOOLEAN_TYPE) ++ return expr; ++ if (integer_nonzerop (expr)) ++ return boolean_true_node; ++ else if (integer_zerop (expr)) ++ return boolean_false_node; ++ else if (TREE_CODE (expr) == SSA_NAME) ++ return fold_build2 (NE_EXPR, boolean_type_node, expr, ++ build_int_cst (TREE_TYPE (expr), 0)); ++ else if (TREE_CODE_CLASS (TREE_CODE (expr)) == tcc_comparison) ++ return fold_build2 (TREE_CODE (expr), ++ boolean_type_node, ++ TREE_OPERAND (expr, 0), ++ TREE_OPERAND (expr, 1)); ++ else ++ return NULL_TREE; ++ } ++} ++ ++/* Check to see if a boolean expression EXPR is logically equivalent to the ++ comparison (OP1 CODE OP2). Check for various identities involving ++ SSA_NAMEs. */ ++ ++static bool ++same_bool_comparison_p (const_tree expr, enum tree_code code, ++ const_tree op1, const_tree op2) ++{ ++ gimple s; ++ ++ /* The obvious case. */ ++ if (TREE_CODE (expr) == code ++ && operand_equal_p (TREE_OPERAND (expr, 0), op1, 0) ++ && operand_equal_p (TREE_OPERAND (expr, 1), op2, 0)) ++ return true; ++ ++ /* Check for comparing (name, name != 0) and the case where expr ++ is an SSA_NAME with a definition matching the comparison. */ ++ if (TREE_CODE (expr) == SSA_NAME ++ && TREE_CODE (TREE_TYPE (expr)) == BOOLEAN_TYPE) ++ { ++ if (operand_equal_p (expr, op1, 0)) ++ return ((code == NE_EXPR && integer_zerop (op2)) ++ || (code == EQ_EXPR && integer_nonzerop (op2))); ++ s = SSA_NAME_DEF_STMT (expr); ++ if (is_gimple_assign (s) ++ && gimple_assign_rhs_code (s) == code ++ && operand_equal_p (gimple_assign_rhs1 (s), op1, 0) ++ && operand_equal_p (gimple_assign_rhs2 (s), op2, 0)) ++ return true; ++ } ++ ++ /* If op1 is of the form (name != 0) or (name == 0), and the definition ++ of name is a comparison, recurse. */ ++ if (TREE_CODE (op1) == SSA_NAME ++ && TREE_CODE (TREE_TYPE (op1)) == BOOLEAN_TYPE) ++ { ++ s = SSA_NAME_DEF_STMT (op1); ++ if (is_gimple_assign (s) ++ && TREE_CODE_CLASS (gimple_assign_rhs_code (s)) == tcc_comparison) ++ { ++ enum tree_code c = gimple_assign_rhs_code (s); ++ if ((c == NE_EXPR && integer_zerop (op2)) ++ || (c == EQ_EXPR && integer_nonzerop (op2))) ++ return same_bool_comparison_p (expr, c, ++ gimple_assign_rhs1 (s), ++ gimple_assign_rhs2 (s)); ++ if ((c == EQ_EXPR && integer_zerop (op2)) ++ || (c == NE_EXPR && integer_nonzerop (op2))) ++ return same_bool_comparison_p (expr, ++ invert_tree_comparison (c, false), ++ gimple_assign_rhs1 (s), ++ gimple_assign_rhs2 (s)); ++ } ++ } ++ return false; ++} ++ ++/* Check to see if two boolean expressions OP1 and OP2 are logically ++ equivalent. */ ++ ++static bool ++same_bool_result_p (const_tree op1, const_tree op2) ++{ ++ /* Simple cases first. */ ++ if (operand_equal_p (op1, op2, 0)) ++ return true; ++ ++ /* Check the cases where at least one of the operands is a comparison. ++ These are a bit smarter than operand_equal_p in that they apply some ++ identifies on SSA_NAMEs. */ ++ if (TREE_CODE_CLASS (TREE_CODE (op2)) == tcc_comparison ++ && same_bool_comparison_p (op1, TREE_CODE (op2), ++ TREE_OPERAND (op2, 0), ++ TREE_OPERAND (op2, 1))) ++ return true; ++ if (TREE_CODE_CLASS (TREE_CODE (op1)) == tcc_comparison ++ && same_bool_comparison_p (op2, TREE_CODE (op1), ++ TREE_OPERAND (op1, 0), ++ TREE_OPERAND (op1, 1))) ++ return true; ++ ++ /* Default case. */ ++ return false; ++} ++ ++/* Forward declarations for some mutually recursive functions. */ ++ ++static tree ++and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b, ++ enum tree_code code2, tree op2a, tree op2b); ++static tree ++and_var_with_comparison (tree var, bool invert, ++ enum tree_code code2, tree op2a, tree op2b); ++static tree ++and_var_with_comparison_1 (gimple stmt, ++ enum tree_code code2, tree op2a, tree op2b); ++static tree ++or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b, ++ enum tree_code code2, tree op2a, tree op2b); ++static tree ++or_var_with_comparison (tree var, bool invert, ++ enum tree_code code2, tree op2a, tree op2b); ++static tree ++or_var_with_comparison_1 (gimple stmt, ++ enum tree_code code2, tree op2a, tree op2b); ++ ++/* Helper function for and_comparisons_1: try to simplify the AND of the ++ ssa variable VAR with the comparison specified by (OP2A CODE2 OP2B). ++ If INVERT is true, invert the value of the VAR before doing the AND. ++ Return NULL_EXPR if we can't simplify this to a single expression. */ ++ ++static tree ++and_var_with_comparison (tree var, bool invert, ++ enum tree_code code2, tree op2a, tree op2b) ++{ ++ tree t; ++ gimple stmt = SSA_NAME_DEF_STMT (var); ++ ++ /* We can only deal with variables whose definitions are assignments. */ ++ if (!is_gimple_assign (stmt)) ++ return NULL_TREE; ++ ++ /* If we have an inverted comparison, apply DeMorgan's law and rewrite ++ !var AND (op2a code2 op2b) => !(var OR !(op2a code2 op2b)) ++ Then we only have to consider the simpler non-inverted cases. */ ++ if (invert) ++ t = or_var_with_comparison_1 (stmt, ++ invert_tree_comparison (code2, false), ++ op2a, op2b); ++ else ++ t = and_var_with_comparison_1 (stmt, code2, op2a, op2b); ++ return canonicalize_bool (t, invert); ++} ++ ++/* Try to simplify the AND of the ssa variable defined by the assignment ++ STMT with the comparison specified by (OP2A CODE2 OP2B). ++ Return NULL_EXPR if we can't simplify this to a single expression. */ ++ ++static tree ++and_var_with_comparison_1 (gimple stmt, ++ enum tree_code code2, tree op2a, tree op2b) ++{ ++ tree var = gimple_assign_lhs (stmt); ++ tree true_test_var = NULL_TREE; ++ tree false_test_var = NULL_TREE; ++ enum tree_code innercode = gimple_assign_rhs_code (stmt); ++ ++ /* Check for identities like (var AND (var == 0)) => false. */ ++ if (TREE_CODE (op2a) == SSA_NAME ++ && TREE_CODE (TREE_TYPE (var)) == BOOLEAN_TYPE) ++ { ++ if ((code2 == NE_EXPR && integer_zerop (op2b)) ++ || (code2 == EQ_EXPR && integer_nonzerop (op2b))) ++ { ++ true_test_var = op2a; ++ if (var == true_test_var) ++ return var; ++ } ++ else if ((code2 == EQ_EXPR && integer_zerop (op2b)) ++ || (code2 == NE_EXPR && integer_nonzerop (op2b))) ++ { ++ false_test_var = op2a; ++ if (var == false_test_var) ++ return boolean_false_node; ++ } ++ } ++ ++ /* If the definition is a comparison, recurse on it. */ ++ if (TREE_CODE_CLASS (innercode) == tcc_comparison) ++ { ++ tree t = and_comparisons_1 (innercode, ++ gimple_assign_rhs1 (stmt), ++ gimple_assign_rhs2 (stmt), ++ code2, ++ op2a, ++ op2b); ++ if (t) ++ return t; ++ } ++ ++ /* If the definition is an AND or OR expression, we may be able to ++ simplify by reassociating. */ ++ if (innercode == TRUTH_AND_EXPR ++ || innercode == TRUTH_OR_EXPR ++ || (TREE_CODE (TREE_TYPE (var)) == BOOLEAN_TYPE ++ && (innercode == BIT_AND_EXPR || innercode == BIT_IOR_EXPR))) ++ { ++ tree inner1 = gimple_assign_rhs1 (stmt); ++ tree inner2 = gimple_assign_rhs2 (stmt); ++ gimple s; ++ tree t; ++ tree partial = NULL_TREE; ++ bool is_and = (innercode == TRUTH_AND_EXPR || innercode == BIT_AND_EXPR); ++ ++ /* Check for boolean identities that don't require recursive examination ++ of inner1/inner2: ++ inner1 AND (inner1 AND inner2) => inner1 AND inner2 => var ++ inner1 AND (inner1 OR inner2) => inner1 ++ !inner1 AND (inner1 AND inner2) => false ++ !inner1 AND (inner1 OR inner2) => !inner1 AND inner2 ++ Likewise for similar cases involving inner2. */ ++ if (inner1 == true_test_var) ++ return (is_and ? var : inner1); ++ else if (inner2 == true_test_var) ++ return (is_and ? var : inner2); ++ else if (inner1 == false_test_var) ++ return (is_and ++ ? boolean_false_node ++ : and_var_with_comparison (inner2, false, code2, op2a, op2b)); ++ else if (inner2 == false_test_var) ++ return (is_and ++ ? boolean_false_node ++ : and_var_with_comparison (inner1, false, code2, op2a, op2b)); ++ ++ /* Next, redistribute/reassociate the AND across the inner tests. ++ Compute the first partial result, (inner1 AND (op2a code op2b)) */ ++ if (TREE_CODE (inner1) == SSA_NAME ++ && is_gimple_assign (s = SSA_NAME_DEF_STMT (inner1)) ++ && TREE_CODE_CLASS (gimple_assign_rhs_code (s)) == tcc_comparison ++ && (t = maybe_fold_and_comparisons (gimple_assign_rhs_code (s), ++ gimple_assign_rhs1 (s), ++ gimple_assign_rhs2 (s), ++ code2, op2a, op2b))) ++ { ++ /* Handle the AND case, where we are reassociating: ++ (inner1 AND inner2) AND (op2a code2 op2b) ++ => (t AND inner2) ++ If the partial result t is a constant, we win. Otherwise ++ continue on to try reassociating with the other inner test. */ ++ if (is_and) ++ { ++ if (integer_onep (t)) ++ return inner2; ++ else if (integer_zerop (t)) ++ return boolean_false_node; ++ } ++ ++ /* Handle the OR case, where we are redistributing: ++ (inner1 OR inner2) AND (op2a code2 op2b) ++ => (t OR (inner2 AND (op2a code2 op2b))) */ ++ else ++ { ++ if (integer_onep (t)) ++ return boolean_true_node; ++ else ++ /* Save partial result for later. */ ++ partial = t; ++ } ++ } ++ ++ /* Compute the second partial result, (inner2 AND (op2a code op2b)) */ ++ if (TREE_CODE (inner2) == SSA_NAME ++ && is_gimple_assign (s = SSA_NAME_DEF_STMT (inner2)) ++ && TREE_CODE_CLASS (gimple_assign_rhs_code (s)) == tcc_comparison ++ && (t = maybe_fold_and_comparisons (gimple_assign_rhs_code (s), ++ gimple_assign_rhs1 (s), ++ gimple_assign_rhs2 (s), ++ code2, op2a, op2b))) ++ { ++ /* Handle the AND case, where we are reassociating: ++ (inner1 AND inner2) AND (op2a code2 op2b) ++ => (inner1 AND t) */ ++ if (is_and) ++ { ++ if (integer_onep (t)) ++ return inner1; ++ else if (integer_zerop (t)) ++ return boolean_false_node; ++ } ++ ++ /* Handle the OR case. where we are redistributing: ++ (inner1 OR inner2) AND (op2a code2 op2b) ++ => (t OR (inner1 AND (op2a code2 op2b))) ++ => (t OR partial) */ ++ else ++ { ++ if (integer_onep (t)) ++ return boolean_true_node; ++ else if (partial) ++ { ++ /* We already got a simplification for the other ++ operand to the redistributed OR expression. The ++ interesting case is when at least one is false. ++ Or, if both are the same, we can apply the identity ++ (x OR x) == x. */ ++ if (integer_zerop (partial)) ++ return t; ++ else if (integer_zerop (t)) ++ return partial; ++ else if (same_bool_result_p (t, partial)) ++ return t; ++ } ++ } ++ } ++ } ++ return NULL_TREE; ++} ++ ++/* Try to simplify the AND of two comparisons defined by ++ (OP1A CODE1 OP1B) and (OP2A CODE2 OP2B), respectively. ++ If this can be done without constructing an intermediate value, ++ return the resulting tree; otherwise NULL_TREE is returned. ++ This function is deliberately asymmetric as it recurses on SSA_DEFs ++ in the first comparison but not the second. */ ++ ++static tree ++and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b, ++ enum tree_code code2, tree op2a, tree op2b) ++{ ++ /* First check for ((x CODE1 y) AND (x CODE2 y)). */ ++ if (operand_equal_p (op1a, op2a, 0) ++ && operand_equal_p (op1b, op2b, 0)) ++ { ++ tree t = combine_comparisons (UNKNOWN_LOCATION, ++ TRUTH_ANDIF_EXPR, code1, code2, ++ boolean_type_node, op1a, op1b); ++ if (t) ++ return t; ++ } ++ ++ /* Likewise the swapped case of the above. */ ++ if (operand_equal_p (op1a, op2b, 0) ++ && operand_equal_p (op1b, op2a, 0)) ++ { ++ tree t = combine_comparisons (UNKNOWN_LOCATION, ++ TRUTH_ANDIF_EXPR, code1, ++ swap_tree_comparison (code2), ++ boolean_type_node, op1a, op1b); ++ if (t) ++ return t; ++ } ++ ++ /* If both comparisons are of the same value against constants, we might ++ be able to merge them. */ ++ if (operand_equal_p (op1a, op2a, 0) ++ && TREE_CODE (op1b) == INTEGER_CST ++ && TREE_CODE (op2b) == INTEGER_CST) ++ { ++ int cmp = tree_int_cst_compare (op1b, op2b); ++ ++ /* If we have (op1a == op1b), we should either be able to ++ return that or FALSE, depending on whether the constant op1b ++ also satisfies the other comparison against op2b. */ ++ if (code1 == EQ_EXPR) ++ { ++ bool done = true; ++ bool val; ++ switch (code2) ++ { ++ case EQ_EXPR: val = (cmp == 0); break; ++ case NE_EXPR: val = (cmp != 0); break; ++ case LT_EXPR: val = (cmp < 0); break; ++ case GT_EXPR: val = (cmp > 0); break; ++ case LE_EXPR: val = (cmp <= 0); break; ++ case GE_EXPR: val = (cmp >= 0); break; ++ default: done = false; ++ } ++ if (done) ++ { ++ if (val) ++ return fold_build2 (code1, boolean_type_node, op1a, op1b); ++ else ++ return boolean_false_node; ++ } ++ } ++ /* Likewise if the second comparison is an == comparison. */ ++ else if (code2 == EQ_EXPR) ++ { ++ bool done = true; ++ bool val; ++ switch (code1) ++ { ++ case EQ_EXPR: val = (cmp == 0); break; ++ case NE_EXPR: val = (cmp != 0); break; ++ case LT_EXPR: val = (cmp > 0); break; ++ case GT_EXPR: val = (cmp < 0); break; ++ case LE_EXPR: val = (cmp >= 0); break; ++ case GE_EXPR: val = (cmp <= 0); break; ++ default: done = false; ++ } ++ if (done) ++ { ++ if (val) ++ return fold_build2 (code2, boolean_type_node, op2a, op2b); ++ else ++ return boolean_false_node; ++ } ++ } ++ ++ /* Same business with inequality tests. */ ++ else if (code1 == NE_EXPR) ++ { ++ bool val; ++ switch (code2) ++ { ++ case EQ_EXPR: val = (cmp != 0); break; ++ case NE_EXPR: val = (cmp == 0); break; ++ case LT_EXPR: val = (cmp >= 0); break; ++ case GT_EXPR: val = (cmp <= 0); break; ++ case LE_EXPR: val = (cmp > 0); break; ++ case GE_EXPR: val = (cmp < 0); break; ++ default: ++ val = false; ++ } ++ if (val) ++ return fold_build2 (code2, boolean_type_node, op2a, op2b); ++ } ++ else if (code2 == NE_EXPR) ++ { ++ bool val; ++ switch (code1) ++ { ++ case EQ_EXPR: val = (cmp == 0); break; ++ case NE_EXPR: val = (cmp != 0); break; ++ case LT_EXPR: val = (cmp <= 0); break; ++ case GT_EXPR: val = (cmp >= 0); break; ++ case LE_EXPR: val = (cmp < 0); break; ++ case GE_EXPR: val = (cmp > 0); break; ++ default: ++ val = false; ++ } ++ if (val) ++ return fold_build2 (code1, boolean_type_node, op1a, op1b); ++ } ++ ++ /* Chose the more restrictive of two < or <= comparisons. */ ++ else if ((code1 == LT_EXPR || code1 == LE_EXPR) ++ && (code2 == LT_EXPR || code2 == LE_EXPR)) ++ { ++ if ((cmp < 0) || (cmp == 0 && code1 == LT_EXPR)) ++ return fold_build2 (code1, boolean_type_node, op1a, op1b); ++ else ++ return fold_build2 (code2, boolean_type_node, op2a, op2b); ++ } ++ ++ /* Likewise chose the more restrictive of two > or >= comparisons. */ ++ else if ((code1 == GT_EXPR || code1 == GE_EXPR) ++ && (code2 == GT_EXPR || code2 == GE_EXPR)) ++ { ++ if ((cmp > 0) || (cmp == 0 && code1 == GT_EXPR)) ++ return fold_build2 (code1, boolean_type_node, op1a, op1b); ++ else ++ return fold_build2 (code2, boolean_type_node, op2a, op2b); ++ } ++ ++ /* Check for singleton ranges. */ ++ else if (cmp == 0 ++ && ((code1 == LE_EXPR && code2 == GE_EXPR) ++ || (code1 == GE_EXPR && code2 == LE_EXPR))) ++ return fold_build2 (EQ_EXPR, boolean_type_node, op1a, op2b); ++ ++ /* Check for disjoint ranges. */ ++ else if (cmp <= 0 ++ && (code1 == LT_EXPR || code1 == LE_EXPR) ++ && (code2 == GT_EXPR || code2 == GE_EXPR)) ++ return boolean_false_node; ++ else if (cmp >= 0 ++ && (code1 == GT_EXPR || code1 == GE_EXPR) ++ && (code2 == LT_EXPR || code2 == LE_EXPR)) ++ return boolean_false_node; ++ } ++ ++ /* Perhaps the first comparison is (NAME != 0) or (NAME == 1) where ++ NAME's definition is a truth value. See if there are any simplifications ++ that can be done against the NAME's definition. */ ++ if (TREE_CODE (op1a) == SSA_NAME ++ && (code1 == NE_EXPR || code1 == EQ_EXPR) ++ && (integer_zerop (op1b) || integer_onep (op1b))) ++ { ++ bool invert = ((code1 == EQ_EXPR && integer_zerop (op1b)) ++ || (code1 == NE_EXPR && integer_onep (op1b))); ++ gimple stmt = SSA_NAME_DEF_STMT (op1a); ++ switch (gimple_code (stmt)) ++ { ++ case GIMPLE_ASSIGN: ++ /* Try to simplify by copy-propagating the definition. */ ++ return and_var_with_comparison (op1a, invert, code2, op2a, op2b); ++ ++ case GIMPLE_PHI: ++ /* If every argument to the PHI produces the same result when ++ ANDed with the second comparison, we win. ++ Do not do this unless the type is bool since we need a bool ++ result here anyway. */ ++ if (TREE_CODE (TREE_TYPE (op1a)) == BOOLEAN_TYPE) ++ { ++ tree result = NULL_TREE; ++ unsigned i; ++ for (i = 0; i < gimple_phi_num_args (stmt); i++) ++ { ++ tree arg = gimple_phi_arg_def (stmt, i); ++ ++ /* If this PHI has itself as an argument, ignore it. ++ If all the other args produce the same result, ++ we're still OK. */ ++ if (arg == gimple_phi_result (stmt)) ++ continue; ++ else if (TREE_CODE (arg) == INTEGER_CST) ++ { ++ if (invert ? integer_nonzerop (arg) : integer_zerop (arg)) ++ { ++ if (!result) ++ result = boolean_false_node; ++ else if (!integer_zerop (result)) ++ return NULL_TREE; ++ } ++ else if (!result) ++ result = fold_build2 (code2, boolean_type_node, ++ op2a, op2b); ++ else if (!same_bool_comparison_p (result, ++ code2, op2a, op2b)) ++ return NULL_TREE; ++ } ++ else if (TREE_CODE (arg) == SSA_NAME) ++ { ++ tree temp = and_var_with_comparison (arg, invert, ++ code2, op2a, op2b); ++ if (!temp) ++ return NULL_TREE; ++ else if (!result) ++ result = temp; ++ else if (!same_bool_result_p (result, temp)) ++ return NULL_TREE; ++ } ++ else ++ return NULL_TREE; ++ } ++ return result; ++ } ++ ++ default: ++ break; ++ } ++ } ++ return NULL_TREE; ++} ++ ++/* Try to simplify the AND of two comparisons, specified by ++ (OP1A CODE1 OP1B) and (OP2B CODE2 OP2B), respectively. ++ If this can be simplified to a single expression (without requiring ++ introducing more SSA variables to hold intermediate values), ++ return the resulting tree. Otherwise return NULL_TREE. ++ If the result expression is non-null, it has boolean type. */ ++ ++tree ++maybe_fold_and_comparisons (enum tree_code code1, tree op1a, tree op1b, ++ enum tree_code code2, tree op2a, tree op2b) ++{ ++ tree t = and_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b); ++ if (t) ++ return t; ++ else ++ return and_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b); ++} ++ ++/* Helper function for or_comparisons_1: try to simplify the OR of the ++ ssa variable VAR with the comparison specified by (OP2A CODE2 OP2B). ++ If INVERT is true, invert the value of VAR before doing the OR. ++ Return NULL_EXPR if we can't simplify this to a single expression. */ ++ ++static tree ++or_var_with_comparison (tree var, bool invert, ++ enum tree_code code2, tree op2a, tree op2b) ++{ ++ tree t; ++ gimple stmt = SSA_NAME_DEF_STMT (var); ++ ++ /* We can only deal with variables whose definitions are assignments. */ ++ if (!is_gimple_assign (stmt)) ++ return NULL_TREE; ++ ++ /* If we have an inverted comparison, apply DeMorgan's law and rewrite ++ !var OR (op2a code2 op2b) => !(var AND !(op2a code2 op2b)) ++ Then we only have to consider the simpler non-inverted cases. */ ++ if (invert) ++ t = and_var_with_comparison_1 (stmt, ++ invert_tree_comparison (code2, false), ++ op2a, op2b); ++ else ++ t = or_var_with_comparison_1 (stmt, code2, op2a, op2b); ++ return canonicalize_bool (t, invert); ++} ++ ++/* Try to simplify the OR of the ssa variable defined by the assignment ++ STMT with the comparison specified by (OP2A CODE2 OP2B). ++ Return NULL_EXPR if we can't simplify this to a single expression. */ ++ ++static tree ++or_var_with_comparison_1 (gimple stmt, ++ enum tree_code code2, tree op2a, tree op2b) ++{ ++ tree var = gimple_assign_lhs (stmt); ++ tree true_test_var = NULL_TREE; ++ tree false_test_var = NULL_TREE; ++ enum tree_code innercode = gimple_assign_rhs_code (stmt); ++ ++ /* Check for identities like (var OR (var != 0)) => true . */ ++ if (TREE_CODE (op2a) == SSA_NAME ++ && TREE_CODE (TREE_TYPE (var)) == BOOLEAN_TYPE) ++ { ++ if ((code2 == NE_EXPR && integer_zerop (op2b)) ++ || (code2 == EQ_EXPR && integer_nonzerop (op2b))) ++ { ++ true_test_var = op2a; ++ if (var == true_test_var) ++ return var; ++ } ++ else if ((code2 == EQ_EXPR && integer_zerop (op2b)) ++ || (code2 == NE_EXPR && integer_nonzerop (op2b))) ++ { ++ false_test_var = op2a; ++ if (var == false_test_var) ++ return boolean_true_node; ++ } ++ } ++ ++ /* If the definition is a comparison, recurse on it. */ ++ if (TREE_CODE_CLASS (innercode) == tcc_comparison) ++ { ++ tree t = or_comparisons_1 (innercode, ++ gimple_assign_rhs1 (stmt), ++ gimple_assign_rhs2 (stmt), ++ code2, ++ op2a, ++ op2b); ++ if (t) ++ return t; ++ } ++ ++ /* If the definition is an AND or OR expression, we may be able to ++ simplify by reassociating. */ ++ if (innercode == TRUTH_AND_EXPR ++ || innercode == TRUTH_OR_EXPR ++ || (TREE_CODE (TREE_TYPE (var)) == BOOLEAN_TYPE ++ && (innercode == BIT_AND_EXPR || innercode == BIT_IOR_EXPR))) ++ { ++ tree inner1 = gimple_assign_rhs1 (stmt); ++ tree inner2 = gimple_assign_rhs2 (stmt); ++ gimple s; ++ tree t; ++ tree partial = NULL_TREE; ++ bool is_or = (innercode == TRUTH_OR_EXPR || innercode == BIT_IOR_EXPR); ++ ++ /* Check for boolean identities that don't require recursive examination ++ of inner1/inner2: ++ inner1 OR (inner1 OR inner2) => inner1 OR inner2 => var ++ inner1 OR (inner1 AND inner2) => inner1 ++ !inner1 OR (inner1 OR inner2) => true ++ !inner1 OR (inner1 AND inner2) => !inner1 OR inner2 ++ */ ++ if (inner1 == true_test_var) ++ return (is_or ? var : inner1); ++ else if (inner2 == true_test_var) ++ return (is_or ? var : inner2); ++ else if (inner1 == false_test_var) ++ return (is_or ++ ? boolean_true_node ++ : or_var_with_comparison (inner2, false, code2, op2a, op2b)); ++ else if (inner2 == false_test_var) ++ return (is_or ++ ? boolean_true_node ++ : or_var_with_comparison (inner1, false, code2, op2a, op2b)); ++ ++ /* Next, redistribute/reassociate the OR across the inner tests. ++ Compute the first partial result, (inner1 OR (op2a code op2b)) */ ++ if (TREE_CODE (inner1) == SSA_NAME ++ && is_gimple_assign (s = SSA_NAME_DEF_STMT (inner1)) ++ && TREE_CODE_CLASS (gimple_assign_rhs_code (s)) == tcc_comparison ++ && (t = maybe_fold_or_comparisons (gimple_assign_rhs_code (s), ++ gimple_assign_rhs1 (s), ++ gimple_assign_rhs2 (s), ++ code2, op2a, op2b))) ++ { ++ /* Handle the OR case, where we are reassociating: ++ (inner1 OR inner2) OR (op2a code2 op2b) ++ => (t OR inner2) ++ If the partial result t is a constant, we win. Otherwise ++ continue on to try reassociating with the other inner test. */ ++ if (innercode == TRUTH_OR_EXPR) ++ { ++ if (integer_onep (t)) ++ return boolean_true_node; ++ else if (integer_zerop (t)) ++ return inner2; ++ } ++ ++ /* Handle the AND case, where we are redistributing: ++ (inner1 AND inner2) OR (op2a code2 op2b) ++ => (t AND (inner2 OR (op2a code op2b))) */ ++ else ++ { ++ if (integer_zerop (t)) ++ return boolean_false_node; ++ else ++ /* Save partial result for later. */ ++ partial = t; ++ } ++ } ++ ++ /* Compute the second partial result, (inner2 OR (op2a code op2b)) */ ++ if (TREE_CODE (inner2) == SSA_NAME ++ && is_gimple_assign (s = SSA_NAME_DEF_STMT (inner2)) ++ && TREE_CODE_CLASS (gimple_assign_rhs_code (s)) == tcc_comparison ++ && (t = maybe_fold_or_comparisons (gimple_assign_rhs_code (s), ++ gimple_assign_rhs1 (s), ++ gimple_assign_rhs2 (s), ++ code2, op2a, op2b))) ++ { ++ /* Handle the OR case, where we are reassociating: ++ (inner1 OR inner2) OR (op2a code2 op2b) ++ => (inner1 OR t) */ ++ if (innercode == TRUTH_OR_EXPR) ++ { ++ if (integer_zerop (t)) ++ return inner1; ++ else if (integer_onep (t)) ++ return boolean_true_node; ++ } ++ ++ /* Handle the AND case, where we are redistributing: ++ (inner1 AND inner2) OR (op2a code2 op2b) ++ => (t AND (inner1 OR (op2a code2 op2b))) ++ => (t AND partial) */ ++ else ++ { ++ if (integer_zerop (t)) ++ return boolean_false_node; ++ else if (partial) ++ { ++ /* We already got a simplification for the other ++ operand to the redistributed AND expression. The ++ interesting case is when at least one is true. ++ Or, if both are the same, we can apply the identity ++ (x AND x) == true. */ ++ if (integer_onep (partial)) ++ return t; ++ else if (integer_onep (t)) ++ return partial; ++ else if (same_bool_result_p (t, partial)) ++ return boolean_true_node; ++ } ++ } ++ } ++ } ++ return NULL_TREE; ++} ++ ++/* Try to simplify the OR of two comparisons defined by ++ (OP1A CODE1 OP1B) and (OP2A CODE2 OP2B), respectively. ++ If this can be done without constructing an intermediate value, ++ return the resulting tree; otherwise NULL_TREE is returned. ++ This function is deliberately asymmetric as it recurses on SSA_DEFs ++ in the first comparison but not the second. */ ++ ++static tree ++or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b, ++ enum tree_code code2, tree op2a, tree op2b) ++{ ++ /* First check for ((x CODE1 y) OR (x CODE2 y)). */ ++ if (operand_equal_p (op1a, op2a, 0) ++ && operand_equal_p (op1b, op2b, 0)) ++ { ++ tree t = combine_comparisons (UNKNOWN_LOCATION, ++ TRUTH_ORIF_EXPR, code1, code2, ++ boolean_type_node, op1a, op1b); ++ if (t) ++ return t; ++ } ++ ++ /* Likewise the swapped case of the above. */ ++ if (operand_equal_p (op1a, op2b, 0) ++ && operand_equal_p (op1b, op2a, 0)) ++ { ++ tree t = combine_comparisons (UNKNOWN_LOCATION, ++ TRUTH_ORIF_EXPR, code1, ++ swap_tree_comparison (code2), ++ boolean_type_node, op1a, op1b); ++ if (t) ++ return t; ++ } ++ ++ /* If both comparisons are of the same value against constants, we might ++ be able to merge them. */ ++ if (operand_equal_p (op1a, op2a, 0) ++ && TREE_CODE (op1b) == INTEGER_CST ++ && TREE_CODE (op2b) == INTEGER_CST) ++ { ++ int cmp = tree_int_cst_compare (op1b, op2b); ++ ++ /* If we have (op1a != op1b), we should either be able to ++ return that or TRUE, depending on whether the constant op1b ++ also satisfies the other comparison against op2b. */ ++ if (code1 == NE_EXPR) ++ { ++ bool done = true; ++ bool val; ++ switch (code2) ++ { ++ case EQ_EXPR: val = (cmp == 0); break; ++ case NE_EXPR: val = (cmp != 0); break; ++ case LT_EXPR: val = (cmp < 0); break; ++ case GT_EXPR: val = (cmp > 0); break; ++ case LE_EXPR: val = (cmp <= 0); break; ++ case GE_EXPR: val = (cmp >= 0); break; ++ default: done = false; ++ } ++ if (done) ++ { ++ if (val) ++ return boolean_true_node; ++ else ++ return fold_build2 (code1, boolean_type_node, op1a, op1b); ++ } ++ } ++ /* Likewise if the second comparison is a != comparison. */ ++ else if (code2 == NE_EXPR) ++ { ++ bool done = true; ++ bool val; ++ switch (code1) ++ { ++ case EQ_EXPR: val = (cmp == 0); break; ++ case NE_EXPR: val = (cmp != 0); break; ++ case LT_EXPR: val = (cmp > 0); break; ++ case GT_EXPR: val = (cmp < 0); break; ++ case LE_EXPR: val = (cmp >= 0); break; ++ case GE_EXPR: val = (cmp <= 0); break; ++ default: done = false; ++ } ++ if (done) ++ { ++ if (val) ++ return boolean_true_node; ++ else ++ return fold_build2 (code2, boolean_type_node, op2a, op2b); ++ } ++ } ++ ++ /* See if an equality test is redundant with the other comparison. */ ++ else if (code1 == EQ_EXPR) ++ { ++ bool val; ++ switch (code2) ++ { ++ case EQ_EXPR: val = (cmp == 0); break; ++ case NE_EXPR: val = (cmp != 0); break; ++ case LT_EXPR: val = (cmp < 0); break; ++ case GT_EXPR: val = (cmp > 0); break; ++ case LE_EXPR: val = (cmp <= 0); break; ++ case GE_EXPR: val = (cmp >= 0); break; ++ default: ++ val = false; ++ } ++ if (val) ++ return fold_build2 (code2, boolean_type_node, op2a, op2b); ++ } ++ else if (code2 == EQ_EXPR) ++ { ++ bool val; ++ switch (code1) ++ { ++ case EQ_EXPR: val = (cmp == 0); break; ++ case NE_EXPR: val = (cmp != 0); break; ++ case LT_EXPR: val = (cmp > 0); break; ++ case GT_EXPR: val = (cmp < 0); break; ++ case LE_EXPR: val = (cmp >= 0); break; ++ case GE_EXPR: val = (cmp <= 0); break; ++ default: ++ val = false; ++ } ++ if (val) ++ return fold_build2 (code1, boolean_type_node, op1a, op1b); ++ } ++ ++ /* Chose the less restrictive of two < or <= comparisons. */ ++ else if ((code1 == LT_EXPR || code1 == LE_EXPR) ++ && (code2 == LT_EXPR || code2 == LE_EXPR)) ++ { ++ if ((cmp < 0) || (cmp == 0 && code1 == LT_EXPR)) ++ return fold_build2 (code2, boolean_type_node, op2a, op2b); ++ else ++ return fold_build2 (code1, boolean_type_node, op1a, op1b); ++ } ++ ++ /* Likewise chose the less restrictive of two > or >= comparisons. */ ++ else if ((code1 == GT_EXPR || code1 == GE_EXPR) ++ && (code2 == GT_EXPR || code2 == GE_EXPR)) ++ { ++ if ((cmp > 0) || (cmp == 0 && code1 == GT_EXPR)) ++ return fold_build2 (code2, boolean_type_node, op2a, op2b); ++ else ++ return fold_build2 (code1, boolean_type_node, op1a, op1b); ++ } ++ ++ /* Check for singleton ranges. */ ++ else if (cmp == 0 ++ && ((code1 == LT_EXPR && code2 == GT_EXPR) ++ || (code1 == GT_EXPR && code2 == LT_EXPR))) ++ return fold_build2 (NE_EXPR, boolean_type_node, op1a, op2b); ++ ++ /* Check for less/greater pairs that don't restrict the range at all. */ ++ else if (cmp >= 0 ++ && (code1 == LT_EXPR || code1 == LE_EXPR) ++ && (code2 == GT_EXPR || code2 == GE_EXPR)) ++ return boolean_true_node; ++ else if (cmp <= 0 ++ && (code1 == GT_EXPR || code1 == GE_EXPR) ++ && (code2 == LT_EXPR || code2 == LE_EXPR)) ++ return boolean_true_node; ++ } ++ ++ /* Perhaps the first comparison is (NAME != 0) or (NAME == 1) where ++ NAME's definition is a truth value. See if there are any simplifications ++ that can be done against the NAME's definition. */ ++ if (TREE_CODE (op1a) == SSA_NAME ++ && (code1 == NE_EXPR || code1 == EQ_EXPR) ++ && (integer_zerop (op1b) || integer_onep (op1b))) ++ { ++ bool invert = ((code1 == EQ_EXPR && integer_zerop (op1b)) ++ || (code1 == NE_EXPR && integer_onep (op1b))); ++ gimple stmt = SSA_NAME_DEF_STMT (op1a); ++ switch (gimple_code (stmt)) ++ { ++ case GIMPLE_ASSIGN: ++ /* Try to simplify by copy-propagating the definition. */ ++ return or_var_with_comparison (op1a, invert, code2, op2a, op2b); ++ ++ case GIMPLE_PHI: ++ /* If every argument to the PHI produces the same result when ++ ORed with the second comparison, we win. ++ Do not do this unless the type is bool since we need a bool ++ result here anyway. */ ++ if (TREE_CODE (TREE_TYPE (op1a)) == BOOLEAN_TYPE) ++ { ++ tree result = NULL_TREE; ++ unsigned i; ++ for (i = 0; i < gimple_phi_num_args (stmt); i++) ++ { ++ tree arg = gimple_phi_arg_def (stmt, i); ++ ++ /* If this PHI has itself as an argument, ignore it. ++ If all the other args produce the same result, ++ we're still OK. */ ++ if (arg == gimple_phi_result (stmt)) ++ continue; ++ else if (TREE_CODE (arg) == INTEGER_CST) ++ { ++ if (invert ? integer_zerop (arg) : integer_nonzerop (arg)) ++ { ++ if (!result) ++ result = boolean_true_node; ++ else if (!integer_onep (result)) ++ return NULL_TREE; ++ } ++ else if (!result) ++ result = fold_build2 (code2, boolean_type_node, ++ op2a, op2b); ++ else if (!same_bool_comparison_p (result, ++ code2, op2a, op2b)) ++ return NULL_TREE; ++ } ++ else if (TREE_CODE (arg) == SSA_NAME) ++ { ++ tree temp = or_var_with_comparison (arg, invert, ++ code2, op2a, op2b); ++ if (!temp) ++ return NULL_TREE; ++ else if (!result) ++ result = temp; ++ else if (!same_bool_result_p (result, temp)) ++ return NULL_TREE; ++ } ++ else ++ return NULL_TREE; ++ } ++ return result; ++ } ++ ++ default: ++ break; ++ } ++ } ++ return NULL_TREE; ++} ++ ++/* Try to simplify the OR of two comparisons, specified by ++ (OP1A CODE1 OP1B) and (OP2B CODE2 OP2B), respectively. ++ If this can be simplified to a single expression (without requiring ++ introducing more SSA variables to hold intermediate values), ++ return the resulting tree. Otherwise return NULL_TREE. ++ If the result expression is non-null, it has boolean type. */ ++ ++tree ++maybe_fold_or_comparisons (enum tree_code code1, tree op1a, tree op1b, ++ enum tree_code code2, tree op2a, tree op2b) ++{ ++ tree t = or_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b); ++ if (t) ++ return t; ++ else ++ return or_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b); ++} ++ + /* Try to optimize out __builtin_stack_restore. Optimize it out + if there is another __builtin_stack_restore in the same basic + block and no calls or ASM_EXPRs are in between, or if this block's + +=== modified file 'gcc/tree-ssa-ifcombine.c' +--- old/gcc/tree-ssa-ifcombine.c 2009-11-25 10:55:54 +0000 ++++ new/gcc/tree-ssa-ifcombine.c 2010-07-30 13:21:51 +0000 +@@ -366,21 +366,16 @@ + + /* See if we have two comparisons that we can merge into one. */ + else if (TREE_CODE_CLASS (gimple_cond_code (inner_cond)) == tcc_comparison +- && TREE_CODE_CLASS (gimple_cond_code (outer_cond)) == tcc_comparison +- && operand_equal_p (gimple_cond_lhs (inner_cond), +- gimple_cond_lhs (outer_cond), 0) +- && operand_equal_p (gimple_cond_rhs (inner_cond), +- gimple_cond_rhs (outer_cond), 0)) ++ && TREE_CODE_CLASS (gimple_cond_code (outer_cond)) == tcc_comparison) + { +- enum tree_code code1 = gimple_cond_code (inner_cond); +- enum tree_code code2 = gimple_cond_code (outer_cond); + tree t; + +- if (!(t = combine_comparisons (UNKNOWN_LOCATION, +- TRUTH_ANDIF_EXPR, code1, code2, +- boolean_type_node, +- gimple_cond_lhs (outer_cond), +- gimple_cond_rhs (outer_cond)))) ++ if (!(t = maybe_fold_and_comparisons (gimple_cond_code (inner_cond), ++ gimple_cond_lhs (inner_cond), ++ gimple_cond_rhs (inner_cond), ++ gimple_cond_code (outer_cond), ++ gimple_cond_lhs (outer_cond), ++ gimple_cond_rhs (outer_cond)))) + return false; + t = canonicalize_cond_expr_cond (t); + if (!t) +@@ -518,22 +513,17 @@ + /* See if we have two comparisons that we can merge into one. + This happens for C++ operator overloading where for example + GE_EXPR is implemented as GT_EXPR || EQ_EXPR. */ +- else if (TREE_CODE_CLASS (gimple_cond_code (inner_cond)) == tcc_comparison +- && TREE_CODE_CLASS (gimple_cond_code (outer_cond)) == tcc_comparison +- && operand_equal_p (gimple_cond_lhs (inner_cond), +- gimple_cond_lhs (outer_cond), 0) +- && operand_equal_p (gimple_cond_rhs (inner_cond), +- gimple_cond_rhs (outer_cond), 0)) ++ else if (TREE_CODE_CLASS (gimple_cond_code (inner_cond)) == tcc_comparison ++ && TREE_CODE_CLASS (gimple_cond_code (outer_cond)) == tcc_comparison) + { +- enum tree_code code1 = gimple_cond_code (inner_cond); +- enum tree_code code2 = gimple_cond_code (outer_cond); + tree t; + +- if (!(t = combine_comparisons (UNKNOWN_LOCATION, +- TRUTH_ORIF_EXPR, code1, code2, +- boolean_type_node, +- gimple_cond_lhs (outer_cond), +- gimple_cond_rhs (outer_cond)))) ++ if (!(t = maybe_fold_or_comparisons (gimple_cond_code (inner_cond), ++ gimple_cond_lhs (inner_cond), ++ gimple_cond_rhs (inner_cond), ++ gimple_cond_code (outer_cond), ++ gimple_cond_lhs (outer_cond), ++ gimple_cond_rhs (outer_cond)))) + return false; + t = canonicalize_cond_expr_cond (t); + if (!t) + +=== modified file 'gcc/tree-ssa-reassoc.c' +--- old/gcc/tree-ssa-reassoc.c 2010-01-13 15:04:38 +0000 ++++ new/gcc/tree-ssa-reassoc.c 2010-07-30 13:21:51 +0000 +@@ -1159,6 +1159,117 @@ + return changed; + } + ++/* If OPCODE is BIT_IOR_EXPR or BIT_AND_EXPR and CURR is a comparison ++ expression, examine the other OPS to see if any of them are comparisons ++ of the same values, which we may be able to combine or eliminate. ++ For example, we can rewrite (a < b) | (a == b) as (a <= b). */ ++ ++static bool ++eliminate_redundant_comparison (enum tree_code opcode, ++ VEC (operand_entry_t, heap) **ops, ++ unsigned int currindex, ++ operand_entry_t curr) ++{ ++ tree op1, op2; ++ enum tree_code lcode, rcode; ++ gimple def1, def2; ++ int i; ++ operand_entry_t oe; ++ ++ if (opcode != BIT_IOR_EXPR && opcode != BIT_AND_EXPR) ++ return false; ++ ++ /* Check that CURR is a comparison. */ ++ if (TREE_CODE (curr->op) != SSA_NAME) ++ return false; ++ def1 = SSA_NAME_DEF_STMT (curr->op); ++ if (!is_gimple_assign (def1)) ++ return false; ++ lcode = gimple_assign_rhs_code (def1); ++ if (TREE_CODE_CLASS (lcode) != tcc_comparison) ++ return false; ++ op1 = gimple_assign_rhs1 (def1); ++ op2 = gimple_assign_rhs2 (def1); ++ ++ /* Now look for a similar comparison in the remaining OPS. */ ++ for (i = currindex + 1; ++ VEC_iterate (operand_entry_t, *ops, i, oe); ++ i++) ++ { ++ tree t; ++ ++ if (TREE_CODE (oe->op) != SSA_NAME) ++ continue; ++ def2 = SSA_NAME_DEF_STMT (oe->op); ++ if (!is_gimple_assign (def2)) ++ continue; ++ rcode = gimple_assign_rhs_code (def2); ++ if (TREE_CODE_CLASS (rcode) != tcc_comparison) ++ continue; ++ ++ /* If we got here, we have a match. See if we can combine the ++ two comparisons. */ ++ if (opcode == BIT_IOR_EXPR) ++ t = maybe_fold_or_comparisons (lcode, op1, op2, ++ rcode, gimple_assign_rhs1 (def2), ++ gimple_assign_rhs2 (def2)); ++ else ++ t = maybe_fold_and_comparisons (lcode, op1, op2, ++ rcode, gimple_assign_rhs1 (def2), ++ gimple_assign_rhs2 (def2)); ++ if (!t) ++ continue; ++ ++ /* maybe_fold_and_comparisons and maybe_fold_or_comparisons ++ always give us a boolean_type_node value back. If the original ++ BIT_AND_EXPR or BIT_IOR_EXPR was of a wider integer type, ++ we need to convert. */ ++ if (!useless_type_conversion_p (TREE_TYPE (curr->op), TREE_TYPE (t))) ++ t = fold_convert (TREE_TYPE (curr->op), t); ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "Equivalence: "); ++ print_generic_expr (dump_file, curr->op, 0); ++ fprintf (dump_file, " %s ", op_symbol_code (opcode)); ++ print_generic_expr (dump_file, oe->op, 0); ++ fprintf (dump_file, " -> "); ++ print_generic_expr (dump_file, t, 0); ++ fprintf (dump_file, "\n"); ++ } ++ ++ /* Now we can delete oe, as it has been subsumed by the new combined ++ expression t. */ ++ VEC_ordered_remove (operand_entry_t, *ops, i); ++ reassociate_stats.ops_eliminated ++; ++ ++ /* If t is the same as curr->op, we're done. Otherwise we must ++ replace curr->op with t. Special case is if we got a constant ++ back, in which case we add it to the end instead of in place of ++ the current entry. */ ++ if (TREE_CODE (t) == INTEGER_CST) ++ { ++ VEC_ordered_remove (operand_entry_t, *ops, currindex); ++ add_to_ops_vec (ops, t); ++ } ++ else if (!operand_equal_p (t, curr->op, 0)) ++ { ++ tree tmpvar; ++ gimple sum; ++ enum tree_code subcode; ++ tree newop1; ++ tree newop2; ++ tmpvar = create_tmp_var (TREE_TYPE (t), NULL); ++ add_referenced_var (tmpvar); ++ extract_ops_from_tree (t, &subcode, &newop1, &newop2); ++ sum = build_and_add_sum (tmpvar, newop1, newop2, subcode); ++ curr->op = gimple_get_lhs (sum); ++ } ++ return true; ++ } ++ ++ return false; ++} + + /* Perform various identities and other optimizations on the list of + operand entries, stored in OPS. The tree code for the binary +@@ -1220,7 +1331,8 @@ + if (eliminate_not_pairs (opcode, ops, i, oe)) + return; + if (eliminate_duplicate_pair (opcode, ops, &done, i, oe, oelast) +- || (!done && eliminate_plus_minus_pair (opcode, ops, i, oe))) ++ || (!done && eliminate_plus_minus_pair (opcode, ops, i, oe)) ++ || (!done && eliminate_redundant_comparison (opcode, ops, i, oe))) + { + if (done) + return; + |