This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] EVRP edge info refactoring and simple improvement
- From: Richard Biener <rguenther at suse dot de>
- To: gcc-patches at gcc dot gnu dot org
- Date: Fri, 2 Dec 2016 13:11:56 +0100 (CET)
- Subject: [PATCH] EVRP edge info refactoring and simple improvement
- Authentication-results: sourceware.org; auth=none
The following refactors range extraction from edges and makes EVRP
able to merge such edge based ranges for the case of multiple
predecessors. This allows it to catch anti-ranges from
if (a < 4 || a > 8) if that is not re-written to a single test like
when using gotos.
I don't expect this to catch very much in practice but the refactoring
means we can incorporate the tricks from register_edge_assert_for
more easily (we "simply" have to use extract_ranges_from_edge as the
one-and-true kind-of interface).
Motivated by Martin Sebors work on b_o_s and the appearant inability
of EVRP to do anything useful for him.
Bootstrap & regtest running on x86_64-unknown-linux-gnu.
Richard.
2016-12-02 Richard Biener <rguenther@suse.de>
* tree-vrp.c (evrp_dom_walker::extract_ranges_from_edge): New method
split out from evrp_dom_walker::before_dom_children.
(evrp_dom_walker::before_dom_children): Use it and implement merging
of edge range info from multiple predecessors.
* gcc.dg/tree-ssa/evrp7.c: New testcase.
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp7.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp7.c
new file mode 100644
index 0000000..c28347d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp7.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fgimple -fdump-tree-evrp" } */
+
+void __GIMPLE (startwith("evrp"))
+f (unsigned int a)
+{
+ if (a < 4U)
+ goto x;
+ else
+ goto bb_3;
+
+bb_3:
+ if (a > 8U)
+ goto x;
+ else
+ goto bb_4;
+
+x:
+ if (a == 5U)
+ goto bb_5;
+ else
+ goto bb_4;
+
+bb_5:
+ __builtin_abort ();
+
+bb_4:
+ return;
+}
+
+/* { dg-final { scan-tree-dump-times "evrp" 0 "if" } } */
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 600634d..592d3b0 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -10700,6 +10700,7 @@ public:
void push_value_range (tree var, value_range *vr);
value_range *pop_value_range (tree var);
value_range *try_find_new_range (tree op, tree_code code, tree limit);
+ void extract_ranges_from_edge (edge, vec<std::pair <tree, value_range*> > &);
/* Cond_stack holds the old VR. */
auto_vec<std::pair <tree, value_range*> > stack;
@@ -10736,13 +10737,69 @@ evrp_dom_walker::try_find_new_range (tree op, tree_code code, tree limit)
return NULL;
}
+/* Extract ranges on E and store them into V. */
+
+void
+evrp_dom_walker::extract_ranges_from_edge (edge e,
+ vec<std::pair
+ <tree, value_range*> > & v)
+{
+ gimple *stmt = last_stmt (e->src);
+ tree op0;
+ if (stmt
+ && gimple_code (stmt) == GIMPLE_COND
+ && (op0 = gimple_cond_lhs (stmt))
+ && TREE_CODE (op0) == SSA_NAME
+ && (INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt)))
+ || POINTER_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt)))))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Visiting controlling predicate ");
+ print_gimple_stmt (dump_file, stmt, 0, 0);
+ }
+ /* Entering a new scope. Try to see if we can find a VR
+ here. */
+ tree op1 = gimple_cond_rhs (stmt);
+ tree_code code = gimple_cond_code (stmt);
+
+ if (TREE_OVERFLOW_P (op1))
+ op1 = drop_tree_overflow (op1);
+
+ /* If condition is false, invert the cond. */
+ if (e->flags & EDGE_FALSE_VALUE)
+ code = invert_tree_comparison (gimple_cond_code (stmt),
+ HONOR_NANS (op0));
+ /* Add VR when (OP0 CODE OP1) condition is true. */
+ value_range *op0_range = try_find_new_range (op0, code, op1);
+
+ /* Register ranges for y in x < y where
+ y might have ranges that are useful. */
+ tree limit;
+ tree_code new_code;
+ if (TREE_CODE (op1) == SSA_NAME
+ && extract_code_and_val_from_cond_with_ops (op1, code,
+ op0, op1,
+ false,
+ &new_code, &limit))
+ {
+ /* Add VR when (OP1 NEW_CODE LIMIT) condition is true. */
+ value_range *op1_range = try_find_new_range (op1, new_code, limit);
+ if (op1_range)
+ v.safe_push (std::make_pair (op1, op1_range));
+ }
+
+ if (op0_range)
+ v.safe_push (std::make_pair (op0, op0_range));
+ }
+}
+
/* See if there is any new scope is entered with new VR and set that VR to
ssa_name before visiting the statements in the scope. */
edge
evrp_dom_walker::before_dom_children (basic_block bb)
{
- tree op0 = NULL_TREE;
edge_iterator ei;
edge e;
@@ -10768,53 +10825,10 @@ evrp_dom_walker::before_dom_children (basic_block bb)
}
if (pred_e)
{
- gimple *stmt = last_stmt (pred_e->src);
- if (stmt
- && gimple_code (stmt) == GIMPLE_COND
- && (op0 = gimple_cond_lhs (stmt))
- && TREE_CODE (op0) == SSA_NAME
- && (INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt)))
- || POINTER_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt)))))
- {
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- fprintf (dump_file, "Visiting controlling predicate ");
- print_gimple_stmt (dump_file, stmt, 0, 0);
- }
- /* Entering a new scope. Try to see if we can find a VR
- here. */
- tree op1 = gimple_cond_rhs (stmt);
- tree_code code = gimple_cond_code (stmt);
-
- if (TREE_OVERFLOW_P (op1))
- op1 = drop_tree_overflow (op1);
-
- /* If condition is false, invert the cond. */
- if (pred_e->flags & EDGE_FALSE_VALUE)
- code = invert_tree_comparison (gimple_cond_code (stmt),
- HONOR_NANS (op0));
- /* Add VR when (OP0 CODE OP1) condition is true. */
- value_range *op0_range = try_find_new_range (op0, code, op1);
-
- /* Register ranges for y in x < y where
- y might have ranges that are useful. */
- tree limit;
- tree_code new_code;
- if (TREE_CODE (op1) == SSA_NAME
- && extract_code_and_val_from_cond_with_ops (op1, code,
- op0, op1,
- false,
- &new_code, &limit))
- {
- /* Add VR when (OP1 NEW_CODE LIMIT) condition is true. */
- value_range *op1_range = try_find_new_range (op1, new_code, limit);
- if (op1_range)
- push_value_range (op1, op1_range);
- }
-
- if (op0_range)
- push_value_range (op0, op0_range);
- }
+ auto_vec<std::pair<tree, value_range *>, 2> ranges;
+ extract_ranges_from_edge (pred_e, ranges);
+ for (unsigned i = 0; i < ranges.length (); ++i)
+ push_value_range (ranges[i].first, ranges[i].second);
}
/* Visit PHI stmts and discover any new VRs possible. */
@@ -10827,6 +10841,71 @@ evrp_dom_walker::before_dom_children (basic_block bb)
break;
}
+ /* If we have multiple predecessors try merging range info from them. */
+ edge first = NULL;
+ if (! pred_e
+ && ! has_unvisited_preds)
+ FOR_EACH_EDGE (e, ei, bb->preds)
+ if ((e->flags & EDGE_EXECUTABLE)
+ && ! dominated_by_p (CDI_DOMINATORS, e->dest, e->src))
+ {
+ first = e;
+ break;
+ }
+ if (first)
+ {
+ auto_vec<std::pair<tree, value_range *>, 2> ranges;
+ extract_ranges_from_edge (first, ranges);
+ if (! ranges.is_empty ())
+ {
+ FOR_EACH_EDGE (e, ei, bb->preds)
+ {
+ if (! (e->flags & EDGE_EXECUTABLE)
+ || e == first)
+ continue;
+ bool can_use_lattice_for_edge
+ = dominated_by_p (CDI_DOMINATORS, e->dest, e->src);
+ auto_vec<std::pair<tree, value_range *>, 2> e_ranges;
+ extract_ranges_from_edge (e, e_ranges);
+ /* ??? Sort the range vectors once we may get more than two
+ ranges and remove the quadratic seach below. */
+ for (unsigned i = 0; i < ranges.length ();)
+ {
+ tree name = ranges[i].first;
+ bool found = false;
+ for (unsigned j = 0; j < e_ranges.length (); ++j)
+ {
+ if (e_ranges[j].first == name)
+ {
+ found = true;
+ vrp_meet (ranges[i].second, e_ranges[j].second);
+ }
+ }
+ if (! found
+ && can_use_lattice_for_edge)
+ {
+ found = true;
+ vrp_meet (ranges[i].second, get_value_range (name));
+ }
+ if (! found
+ || ranges[i].second->type == VR_VARYING)
+ {
+ vrp_value_range_pool.remove (ranges[i].second);
+ ranges.unordered_remove (i);
+ continue;
+ }
+ ++i;
+ }
+ for (unsigned i = 0; i < e_ranges.length (); ++i)
+ vrp_value_range_pool.remove (e_ranges[i].second);
+ if (ranges.is_empty ())
+ break;
+ }
+ for (unsigned i = 0; i < ranges.length (); ++i)
+ push_value_range (ranges[i].first, ranges[i].second);
+ }
+ }
+
for (gphi_iterator gpi = gsi_start_phis (bb);
!gsi_end_p (gpi); gsi_next (&gpi))
{