===================================================================
@@ -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" } }
===================================================================
@@ -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" } } */
===================================================================
@@ -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"} } */
===================================================================
@@ -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"} } */
===================================================================
@@ -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"} } */
===================================================================
@@ -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)
{
===================================================================
@@ -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)
===================================================================
@@ -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)
===================================================================
@@ -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;
}
===================================================================
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-fre1" } */
+
+int foo (int i)
+{
+ if (i)
+ {
+ if (i)
+ return 0;
+ else
+ return 1;
+ }
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump "return 0;" "fre1" } } */
===================================================================
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-fre1-details" } */
+
+int foo (int i)
+{
+ if (i)
+ {
+ if (i)
+ return 1;
+ else
+ return 0;
+ }
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump "Removing unexecutable edge" "fre1" } } */
===================================================================
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-fre1" } */
+
+int foo (int i, int j)
+{
+ if (i < j)
+ {
+ if (i <= j)
+ return j > i;
+ else
+ return 0;
+ }
+ return 1;
+}
+
+/* { dg-final { scan-tree-dump "return 1;" "fre1" } } */
===================================================================
@@ -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)
===================================================================
@@ -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)
===================================================================
@@ -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)
{
===================================================================
@@ -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 ();
}
===================================================================
@@ -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);
===================================================================
@@ -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 ();
===================================================================
@@ -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
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" } } */
===================================================================
@@ -2365,10 +2365,18 @@ vn_nary_op_compute_hash (const vn_nary_o
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<std::pair <basic_block, std::pair <vn_nary_op_t, vn_nary_op_t> > >
+ 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 (b
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 (b
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: