From 7fd9012e478d7f759500bfa32ace358227853c2b Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Wed, 12 Aug 2015 14:27:40 +0000 Subject: [PATCH] tree-ssa-sccvn.c (vn_nary_op_compute_hash): Also canonicalize comparison operand order and commutative ternary op operand order. 2015-08-12 Richard Biener * tree-ssa-sccvn.c (vn_nary_op_compute_hash): Also canonicalize comparison operand order and commutative ternary op operand order. (sccvn_dom_walker::cond_stack): New state to track temporary expressions. (sccvn_dom_walker::after_dom_children): Remove tempoary expressions no longer valid. (sccvn_dom_walker::record_cond): Add a single temporary conditional expression. (sccvn_dom_walker::record_conds): Add a temporary conditional expressions and all related expressions also true/false. (sccvn_dom_walker::before_dom_children): Record temporary expressions based on the controlling condition of a single predecessor. When trying to simplify a conditional statement lookup expressions we might have inserted earlier. * gcc.dg/tree-ssa/ssa-fre-47.c: New testcase. * gcc.dg/tree-ssa/ssa-fre-48.c: Likewise. * gcc.dg/tree-ssa/ssa-fre-49.c: Likewise. * g++.dg/tree-ssa/pr61034.C: Adjust. * gcc.dg/fold-compare-2.c: Likewise. * gcc.dg/pr50763.c: Likewise. * gcc.dg/predict-3.c: Likewise. * gcc.dg/tree-ssa/20030709-2.c: Likewise. * gcc.dg/tree-ssa/pr19831-3.c: Likewise. * gcc.dg/tree-ssa/pr20657.c: Likewise. * gcc.dg/tree-ssa/pr21001.c: Likewise. * gcc.dg/tree-ssa/pr37508.c: Likewise. * gcc.dg/tree-ssa/vrp04.c: Likewise. * gcc.dg/tree-ssa/vrp07.c: Likewise. * gcc.dg/tree-ssa/vrp09.c: Likewise. * gcc.dg/tree-ssa/vrp16.c: Likewise. * gcc.dg/tree-ssa/vrp20.c: Likewise. * gcc.dg/tree-ssa/vrp25.c: Likewise. * gcc.dg/tree-ssa/vrp87.c: Likewise. From-SVN: r226814 --- gcc/ChangeLog | 17 +++ gcc/testsuite/ChangeLog | 22 +++ gcc/testsuite/g++.dg/tree-ssa/pr61034.C | 2 +- gcc/testsuite/gcc.dg/fold-compare-2.c | 4 +- gcc/testsuite/gcc.dg/pr50763.c | 4 +- gcc/testsuite/gcc.dg/predict-3.c | 6 +- gcc/testsuite/gcc.dg/tree-ssa/20030709-2.c | 8 +- gcc/testsuite/gcc.dg/tree-ssa/pr19831-3.c | 2 +- gcc/testsuite/gcc.dg/tree-ssa/pr20657.c | 2 +- gcc/testsuite/gcc.dg/tree-ssa/pr21001.c | 2 +- gcc/testsuite/gcc.dg/tree-ssa/pr37508.c | 12 +- gcc/testsuite/gcc.dg/tree-ssa/vrp04.c | 2 +- gcc/testsuite/gcc.dg/tree-ssa/vrp07.c | 2 +- gcc/testsuite/gcc.dg/tree-ssa/vrp09.c | 2 +- gcc/testsuite/gcc.dg/tree-ssa/vrp16.c | 9 +- gcc/testsuite/gcc.dg/tree-ssa/vrp20.c | 2 +- gcc/testsuite/gcc.dg/tree-ssa/vrp25.c | 2 +- gcc/testsuite/gcc.dg/tree-ssa/vrp87.c | 13 +- gcc/tree-ssa-sccvn.c | 149 ++++++++++++++++++++- 19 files changed, 223 insertions(+), 39 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 06650098dc9..6028d26a38b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +2015-08-12 Richard Biener + + * tree-ssa-sccvn.c (vn_nary_op_compute_hash): Also canonicalize + comparison operand order and commutative ternary op operand order. + (sccvn_dom_walker::cond_stack): New state to track temporary + expressions. + (sccvn_dom_walker::after_dom_children): Remove tempoary expressions + no longer valid. + (sccvn_dom_walker::record_cond): Add a single temporary conditional + expression. + (sccvn_dom_walker::record_conds): Add a temporary conditional + expressions and all related expressions also true/false. + (sccvn_dom_walker::before_dom_children): Record temporary + expressions based on the controlling condition of a single + predecessor. When trying to simplify a conditional statement + lookup expressions we might have inserted earlier. + 2015-08-12 Yvan Roux PR target/67127 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index b712e5f0e8b..15b0b41a7b5 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,25 @@ +2015-08-12 Richard Biener + + * gcc.dg/tree-ssa/ssa-fre-47.c: New testcase. + * gcc.dg/tree-ssa/ssa-fre-48.c: Likewise. + * gcc.dg/tree-ssa/ssa-fre-49.c: Likewise. + * g++.dg/tree-ssa/pr61034.C: Adjust. + * gcc.dg/fold-compare-2.c: Likewise. + * gcc.dg/pr50763.c: Likewise. + * gcc.dg/predict-3.c: Likewise. + * gcc.dg/tree-ssa/20030709-2.c: Likewise. + * gcc.dg/tree-ssa/pr19831-3.c: Likewise. + * gcc.dg/tree-ssa/pr20657.c: Likewise. + * gcc.dg/tree-ssa/pr21001.c: Likewise. + * gcc.dg/tree-ssa/pr37508.c: Likewise. + * gcc.dg/tree-ssa/vrp04.c: Likewise. + * gcc.dg/tree-ssa/vrp07.c: Likewise. + * gcc.dg/tree-ssa/vrp09.c: Likewise. + * gcc.dg/tree-ssa/vrp16.c: Likewise. + * gcc.dg/tree-ssa/vrp20.c: Likewise. + * gcc.dg/tree-ssa/vrp25.c: Likewise. + * gcc.dg/tree-ssa/vrp87.c: Likewise. + 2015-08-12 Nathan Sidwell * gcc.dg/vrp-min-max-1.c: New. diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr61034.C b/gcc/testsuite/g++.dg/tree-ssa/pr61034.C index 14fd85ae6f8..628eb10278f 100644 --- a/gcc/testsuite/g++.dg/tree-ssa/pr61034.C +++ b/gcc/testsuite/g++.dg/tree-ssa/pr61034.C @@ -43,5 +43,5 @@ bool f(I a, I b, I c, I d) { // This works only if everything is inlined into 'f'. // { dg-final { scan-tree-dump-times ";; Function" 1 "fre2" } } -// { dg-final { scan-tree-dump-times "free" 18 "fre2" } } +// { dg-final { scan-tree-dump-times "free" 10 "fre2" } } // { dg-final { scan-tree-dump-times "unreachable" 11 "fre2" } } diff --git a/gcc/testsuite/gcc.dg/fold-compare-2.c b/gcc/testsuite/gcc.dg/fold-compare-2.c index f94fe042717..16f0fd9cdc3 100644 --- a/gcc/testsuite/gcc.dg/fold-compare-2.c +++ b/gcc/testsuite/gcc.dg/fold-compare-2.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fno-tree-tail-merge -fdump-tree-vrp1" } */ +/* { dg-options "-O2 -fdump-tree-fre1" } */ extern void abort (void); @@ -15,5 +15,5 @@ main(void) return 0; } -/* { dg-final { scan-tree-dump-times "Removing basic block" 2 "vrp1" } } */ +/* { dg-final { scan-tree-dump-times "Removing basic block" 2 "fre1" } } */ diff --git a/gcc/testsuite/gcc.dg/pr50763.c b/gcc/testsuite/gcc.dg/pr50763.c index b233e93ee5e..102056f1dcb 100644 --- a/gcc/testsuite/gcc.dg/pr50763.c +++ b/gcc/testsuite/gcc.dg/pr50763.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -ftree-tail-merge -fno-tree-dominator-opts -fdump-tree-pre" } */ +/* { dg-options "-O2 -ftree-tail-merge -fno-tree-dominator-opts" } */ int bar (int i); @@ -11,5 +11,3 @@ foo (int c, int d) d = 33; while (c == d); } - -/* { dg-final { scan-tree-dump-times "== 33" 2 "pre"} } */ diff --git a/gcc/testsuite/gcc.dg/predict-3.c b/gcc/testsuite/gcc.dg/predict-3.c index 2335201626e..e1be7cc3c95 100644 --- a/gcc/testsuite/gcc.dg/predict-3.c +++ b/gcc/testsuite/gcc.dg/predict-3.c @@ -12,6 +12,10 @@ void foo (int bound) { if (i < bound - 2) global += bar (i); + /* The following test is redundant with the loop bound check in the + for stmt and thus eliminated by FRE which makes the controlled + stmt always executed and thus equivalent to 100%. Thus the + heuristic only applies three times. */ if (i <= bound) global += bar (i); if (i + 1 < bound) @@ -21,4 +25,4 @@ void foo (int bound) } } -/* { dg-final { scan-tree-dump-times "loop iv compare heuristics: 100.0%" 4 "profile_estimate"} } */ +/* { dg-final { scan-tree-dump-times "loop iv compare heuristics: 100.0%" 3 "profile_estimate"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030709-2.c b/gcc/testsuite/gcc.dg/tree-ssa/20030709-2.c index aeff3418c50..d4f42f932f1 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/20030709-2.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030709-2.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fdump-tree-cddce2" } */ +/* { dg-options "-O -fdump-tree-dce2" } */ struct rtx_def; typedef struct rtx_def *rtx; @@ -42,13 +42,13 @@ get_alias_set (t) /* There should be precisely one load of ->decl.rtl. If there is more than, then the dominator optimizations failed. */ -/* { dg-final { scan-tree-dump-times "->decl\\.rtl" 1 "cddce2"} } */ +/* { dg-final { scan-tree-dump-times "->decl\\.rtl" 1 "dce2"} } */ /* There should be no loads of .rtmem since the complex return statement is just "return 0". */ -/* { dg-final { scan-tree-dump-times ".rtmem" 0 "cddce2"} } */ +/* { dg-final { scan-tree-dump-times ".rtmem" 0 "dce2"} } */ /* There should be one IF statement (the complex return statement should collapse down to a simple return 0 without any conditionals). */ -/* { dg-final { scan-tree-dump-times "if " 1 "cddce2"} } */ +/* { dg-final { scan-tree-dump-times "if " 1 "dce2"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr19831-3.c b/gcc/testsuite/gcc.dg/tree-ssa/pr19831-3.c index f78a17ff468..f5cb72daa33 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/pr19831-3.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr19831-3.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fdump-tree-optimized" } */ +/* { dg-options "-O2 -fno-ipa-icf -fdump-tree-optimized" } */ void test2(void) { diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr20657.c b/gcc/testsuite/gcc.dg/tree-ssa/pr20657.c index c1317a705b7..727ca4c116a 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/pr20657.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr20657.c @@ -3,7 +3,7 @@ statement, which was needed to eliminate the second "if" statement. */ /* { dg-do compile } */ -/* { dg-options "-O2 -fno-tree-dominator-opts -fdump-tree-vrp1-details" } */ +/* { dg-options "-O2 -fno-tree-dominator-opts -fno-tree-fre -fdump-tree-vrp1-details" } */ int foo (int a) diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr21001.c b/gcc/testsuite/gcc.dg/tree-ssa/pr21001.c index 05b495bd575..482d530e9ab 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/pr21001.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr21001.c @@ -5,7 +5,7 @@ range information out of the conditional. */ /* { dg-do compile } */ -/* { dg-options "-O2 -fno-tree-dominator-opts -fdump-tree-vrp1-details" } */ +/* { dg-options "-O2 -fno-tree-dominator-opts -fno-tree-fre -fdump-tree-vrp1-details" } */ int foo (int a) diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr37508.c b/gcc/testsuite/gcc.dg/tree-ssa/pr37508.c index aa33626a658..0963cd99281 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/pr37508.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr37508.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fdump-tree-vrp1" } */ +/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp1" } */ struct foo1 { int i:1; @@ -10,9 +10,10 @@ struct foo2 { int test1 (struct foo1 *x) { - if (x->i == 0) + int i = x->i; + if (i == 0) return 1; - else if (x->i == -1) + else if (i == -1) return 1; return 0; } @@ -37,9 +38,10 @@ int test3 (struct foo1 *x) int test4 (struct foo2 *x) { - if (x->i == 0) + unsigned int i = x->i; + if (i == 0) return 1; - else if (x->i == 1) + else if (i == 1) return 1; return 0; } diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp04.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp04.c index 8af269f11e1..61b7a47a194 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/vrp04.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp04.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fdump-tree-vrp1" } */ +/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp1" } */ int foo (int a, int b) diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp07.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp07.c index 3bc6869c576..a5bd6708d9f 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/vrp07.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp07.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fdump-tree-vrp1-details -fdelete-null-pointer-checks" } */ +/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp1-details -fdelete-null-pointer-checks" } */ int foo (int i, int *p) diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp09.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp09.c index 98be0af62df..d42a566a99f 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/vrp09.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp09.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fdump-tree-vrp1 -std=gnu89" } */ +/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp1 -std=gnu89" } */ foo (int *p) { diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp16.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp16.c index 00a8e1a78f9..8f5d5c85b93 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/vrp16.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp16.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fdump-tree-vrp1-details" } */ +/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp1-details" } */ extern void abort (void) __attribute__ ((__noreturn__)); @@ -12,9 +12,10 @@ struct rtx_def int nonlocal_mentioned_p (rtx x) { - if (x->code == 6 || x->code == 7) - if (x->code == 7) - if (x->code != 7) + int code = x->code; + if (code == 6 || code == 7) + if (code == 7) + if (code != 7) abort (); } diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp20.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp20.c index 012d05a6427..60d17313152 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/vrp20.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp20.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-fwrapv -O1 -ftree-vrp -fdump-tree-vrp1" } */ +/* { dg-options "-fwrapv -O1 -fno-tree-fre -ftree-vrp -fdump-tree-vrp1" } */ extern void abort (); extern void exit (int); diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp25.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp25.c index 30da3330c09..cbc4ec354c4 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/vrp25.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp25.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fdump-tree-vrp1-details" } */ +/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp1-details" } */ extern void abort (); extern void arf (); diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp87.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp87.c index 7641c974cc5..e81dd3603b7 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/vrp87.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp87.c @@ -1,8 +1,8 @@ /* Setting LOGICAL_OP_NON_SHORT_CIRCUIT to 0 leads to two conditional jumps - when evaluating an && condition. VRP is not able to optimize this. */ + when evaluating an && condition. */ /* { dg-do compile { target { ! { logical_op_short_circuit || { m68k*-*-* mmix*-*-* mep*-*-* bfin*-*-* v850*-*-* moxie*-*-* cris*-*-* m32c*-*-* fr30*-*-* mcore*-*-* powerpc*-*-* xtensa*-*-* hppa*-*-* } } } } } */ -/* { dg-options "-O2 -fdump-tree-vrp2-details -fdump-tree-cddce2-details" } */ +/* { dg-options "-O2 -fdump-tree-fre1-details" } */ struct bitmap_head_def; typedef struct bitmap_head_def *bitmap; @@ -74,9 +74,6 @@ bitmap_ior_into (bitmap a, const_bitmap b) return changed; } -/* Verify that VRP simplified an "if" statement. */ -/* { dg-final { scan-tree-dump "Folded into: if.*" "vrp2"} } */ -/* Verify that DCE after VRP2 eliminates a dead conversion - to a (Bool). */ -/* { dg-final { scan-tree-dump "Deleting.*_Bool.*;" "cddce2"} } */ - +/* Verify that FRE simplified an if stmt. */ +/* { dg-final { scan-tree-dump "Replaced a_elt_\[0-9\]+ != 0B with 1" "fre1" } } */ +/* { dg-final { scan-tree-dump "Replaced _\[0-9\]+ & _\[0-9\]+ with _\[0-9\]+" "fre1" } } */ diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c index eca0d44cdaf..003433ccbc7 100644 --- a/gcc/tree-ssa-sccvn.c +++ b/gcc/tree-ssa-sccvn.c @@ -2365,10 +2365,18 @@ vn_nary_op_compute_hash (const vn_nary_op_t vno1) if (TREE_CODE (vno1->op[i]) == SSA_NAME) vno1->op[i] = SSA_VAL (vno1->op[i]); - if (vno1->length == 2 - && commutative_tree_code (vno1->opcode) + if (((vno1->length == 2 + && commutative_tree_code (vno1->opcode)) + || (vno1->length == 3 + && commutative_ternary_tree_code (vno1->opcode))) && tree_swap_operands_p (vno1->op[0], vno1->op[1], false)) std::swap (vno1->op[0], vno1->op[1]); + else if (TREE_CODE_CLASS (vno1->opcode) == tcc_comparison + && tree_swap_operands_p (vno1->op[0], vno1->op[1], false)) + { + std::swap (vno1->op[0], vno1->op[1]); + vno1->opcode = swap_tree_comparison (vno1->opcode); + } hstate.add_int (vno1->opcode); for (i = 0; i < vno1->length; ++i) @@ -4281,13 +4289,105 @@ set_hashtable_value_ids (void) class sccvn_dom_walker : public dom_walker { public: - sccvn_dom_walker () : dom_walker (CDI_DOMINATORS), fail (false) {} + sccvn_dom_walker () + : dom_walker (CDI_DOMINATORS), fail (false), cond_stack (vNULL) {} virtual void before_dom_children (basic_block); + virtual void after_dom_children (basic_block); + + void record_cond (basic_block, + enum tree_code code, tree lhs, tree rhs, bool value); + void record_conds (basic_block, + enum tree_code code, tree lhs, tree rhs, bool value); bool fail; + vec > > + cond_stack; }; +/* Record a temporary condition for the BB and its dominated blocks. */ + +void +sccvn_dom_walker::record_cond (basic_block bb, + enum tree_code code, tree lhs, tree rhs, + bool value) +{ + tree ops[2] = { lhs, rhs }; + vn_nary_op_t old = NULL; + if (vn_nary_op_lookup_pieces (2, code, boolean_type_node, ops, &old)) + current_info->nary->remove_elt_with_hash (old, old->hashcode); + vn_nary_op_t cond + = vn_nary_op_insert_pieces (2, code, boolean_type_node, ops, + value + ? boolean_true_node + : boolean_false_node, 0); + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Recording temporarily "); + print_generic_expr (dump_file, ops[0], TDF_SLIM); + fprintf (dump_file, " %s ", get_tree_code_name (code)); + print_generic_expr (dump_file, ops[1], TDF_SLIM); + fprintf (dump_file, " == %s%s\n", + value ? "true" : "false", + old ? " (old entry saved)" : ""); + } + cond_stack.safe_push (std::make_pair (bb, std::make_pair (cond, old))); +} + +/* Record temporary conditions for the BB and its dominated blocks + according to LHS CODE RHS == VALUE and its dominated conditions. */ + +void +sccvn_dom_walker::record_conds (basic_block bb, + enum tree_code code, tree lhs, tree rhs, + bool value) +{ + /* Record the original condition. */ + record_cond (bb, code, lhs, rhs, value); + + if (!value) + return; + + /* Record dominated conditions if the condition is true. Note that + the inversion is already recorded. */ + switch (code) + { + case LT_EXPR: + case GT_EXPR: + record_cond (bb, code == LT_EXPR ? LE_EXPR : GE_EXPR, lhs, rhs, true); + record_cond (bb, NE_EXPR, lhs, rhs, true); + record_cond (bb, EQ_EXPR, lhs, rhs, false); + break; + + case EQ_EXPR: + record_cond (bb, LE_EXPR, lhs, rhs, true); + record_cond (bb, GE_EXPR, lhs, rhs, true); + record_cond (bb, LT_EXPR, lhs, rhs, false); + record_cond (bb, GT_EXPR, lhs, rhs, false); + break; + + default: + break; + } +} + +/* Restore expressions and values derived from conditionals. */ + +void +sccvn_dom_walker::after_dom_children (basic_block bb) +{ + while (!cond_stack.is_empty () + && cond_stack.last ().first == bb) + { + vn_nary_op_t cond = cond_stack.last ().second.first; + vn_nary_op_t old = cond_stack.last ().second.second; + current_info->nary->remove_elt_with_hash (cond, cond->hashcode); + if (old) + vn_nary_op_insert_into (old, current_info->nary, false); + cond_stack.pop (); + } +} + /* Value number all statements in BB. */ void @@ -4320,6 +4420,39 @@ sccvn_dom_walker::before_dom_children (basic_block bb) return; } + /* If we have a single predecessor record the equivalence from a + possible condition on the predecessor edge. */ + if (single_pred_p (bb)) + { + edge e = single_pred_edge (bb); + /* Check if there are multiple executable successor edges in + the source block. Otherwise there is no additional info + to be recorded. */ + edge e2; + FOR_EACH_EDGE (e2, ei, e->src->succs) + if (e2 != e + && e2->flags & EDGE_EXECUTABLE) + break; + if (e2 && (e2->flags & EDGE_EXECUTABLE)) + { + + gimple stmt = last_stmt (e->src); + if (stmt + && gimple_code (stmt) == GIMPLE_COND) + { + enum tree_code code = gimple_cond_code (stmt); + tree lhs = gimple_cond_lhs (stmt); + tree rhs = gimple_cond_rhs (stmt); + record_conds (bb, code, lhs, rhs, + (e->flags & EDGE_TRUE_VALUE) != 0); + code = invert_tree_comparison (code, HONOR_NANS (lhs)); + if (code != ERROR_MARK) + record_conds (bb, code, lhs, rhs, + (e->flags & EDGE_TRUE_VALUE) == 0); + } + } + } + /* Value-number all defs in the basic-block. */ for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi)) @@ -4389,6 +4522,16 @@ sccvn_dom_walker::before_dom_children (basic_block bb) rhs = vn_get_expr_for (rhs); val = fold_binary (gimple_cond_code (stmt), boolean_type_node, lhs, rhs); + /* If that didn't simplify to a constant see if we have recorded + temporary expressions from taken edges. */ + if (!val || TREE_CODE (val) != INTEGER_CST) + { + tree ops[2]; + ops[0] = gimple_cond_lhs (stmt); + ops[1] = gimple_cond_rhs (stmt); + val = vn_nary_op_lookup_pieces (2, gimple_cond_code (stmt), + boolean_type_node, ops, NULL); + } break; } case GIMPLE_SWITCH: -- 2.30.2