tree-cfg.c (assert_unreachable_fallthru_edge_p): New function.
* tree-cfg.c (assert_unreachable_fallthru_edge_p): New function. * tree-cfg.h (assert_unreachable_fallthru_edge_p): New prototype. * tree-vrp.c (all_imm_uses_in_stmt_or_feed_cond): New function. (remove_range_assertions): If ASSERT_EXPR_VAR has no other immediate uses but in the condition and ASSERT_EXPR and the other successor of the predecessor bb is __builtin_unreachable (), set_range_info of the ASSERT_EXPR_VAR to the range info of the ASSERT_EXPR's lhs. From-SVN: r204255
This commit is contained in:
parent
b319f79c92
commit
d8202b848c
|
@ -1,3 +1,13 @@
|
|||
2013-10-31 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* tree-cfg.c (assert_unreachable_fallthru_edge_p): New function.
|
||||
* tree-cfg.h (assert_unreachable_fallthru_edge_p): New prototype.
|
||||
* tree-vrp.c (all_imm_uses_in_stmt_or_feed_cond): New function.
|
||||
(remove_range_assertions): If ASSERT_EXPR_VAR has no other immediate
|
||||
uses but in the condition and ASSERT_EXPR and the other successor of
|
||||
the predecessor bb is __builtin_unreachable (), set_range_info of the
|
||||
ASSERT_EXPR_VAR to the range info of the ASSERT_EXPR's lhs.
|
||||
|
||||
2013-10-31 Martin Jambor <mjambor@suse.cz>
|
||||
|
||||
PR rtl-optimization/58934
|
||||
|
|
|
@ -381,6 +381,50 @@ computed_goto_p (gimple t)
|
|||
&& TREE_CODE (gimple_goto_dest (t)) != LABEL_DECL);
|
||||
}
|
||||
|
||||
/* Returns true for edge E where e->src ends with a GIMPLE_COND and
|
||||
the other edge points to a bb with just __builtin_unreachable ().
|
||||
I.e. return true for C->M edge in:
|
||||
<bb C>:
|
||||
...
|
||||
if (something)
|
||||
goto <bb N>;
|
||||
else
|
||||
goto <bb M>;
|
||||
<bb N>:
|
||||
__builtin_unreachable ();
|
||||
<bb M>: */
|
||||
|
||||
bool
|
||||
assert_unreachable_fallthru_edge_p (edge e)
|
||||
{
|
||||
basic_block pred_bb = e->src;
|
||||
gimple last = last_stmt (pred_bb);
|
||||
if (last && gimple_code (last) == GIMPLE_COND)
|
||||
{
|
||||
basic_block other_bb = EDGE_SUCC (pred_bb, 0)->dest;
|
||||
if (other_bb == e->dest)
|
||||
other_bb = EDGE_SUCC (pred_bb, 1)->dest;
|
||||
if (EDGE_COUNT (other_bb->succs) == 0)
|
||||
{
|
||||
gimple_stmt_iterator gsi = gsi_after_labels (other_bb);
|
||||
gimple stmt;
|
||||
|
||||
if (gsi_end_p (gsi))
|
||||
return false;
|
||||
stmt = gsi_stmt (gsi);
|
||||
if (is_gimple_debug (stmt))
|
||||
{
|
||||
gsi_next_nondebug (&gsi);
|
||||
if (gsi_end_p (gsi))
|
||||
return false;
|
||||
stmt = gsi_stmt (gsi);
|
||||
}
|
||||
return gimple_call_builtin_p (stmt, BUILT_IN_UNREACHABLE);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* Search the CFG for any computed gotos. If found, factor them to a
|
||||
common computed goto site. Also record the location of that site so
|
||||
|
|
|
@ -51,6 +51,7 @@ extern bool is_ctrl_stmt (gimple);
|
|||
extern bool is_ctrl_altering_stmt (gimple);
|
||||
extern bool simple_goto_p (gimple);
|
||||
extern bool stmt_ends_bb_p (gimple);
|
||||
extern bool assert_unreachable_fallthru_edge_p (edge);
|
||||
extern void delete_tree_cfg_annotations (void);
|
||||
extern gimple first_stmt (basic_block);
|
||||
extern gimple last_stmt (basic_block);
|
||||
|
|
|
@ -6459,6 +6459,33 @@ check_all_array_refs (void)
|
|||
}
|
||||
}
|
||||
|
||||
/* Return true if all imm uses of VAR are either in STMT, or
|
||||
feed (optionally through a chain of single imm uses) GIMPLE_COND
|
||||
in basic block COND_BB. */
|
||||
|
||||
static bool
|
||||
all_imm_uses_in_stmt_or_feed_cond (tree var, gimple stmt, basic_block cond_bb)
|
||||
{
|
||||
use_operand_p use_p, use2_p;
|
||||
imm_use_iterator iter;
|
||||
|
||||
FOR_EACH_IMM_USE_FAST (use_p, iter, var)
|
||||
if (USE_STMT (use_p) != stmt)
|
||||
{
|
||||
gimple use_stmt = USE_STMT (use_p);
|
||||
if (is_gimple_debug (use_stmt))
|
||||
continue;
|
||||
while (is_gimple_assign (use_stmt)
|
||||
&& single_imm_use (gimple_assign_lhs (use_stmt),
|
||||
&use2_p, &use_stmt))
|
||||
;
|
||||
if (gimple_code (use_stmt) != GIMPLE_COND
|
||||
|| gimple_bb (use_stmt) != cond_bb)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Convert range assertion expressions into the implied copies and
|
||||
copy propagate away the copies. Doing the trivial copy propagation
|
||||
here avoids the need to run the full copy propagation pass after
|
||||
|
@ -6488,12 +6515,16 @@ remove_range_assertions (void)
|
|||
{
|
||||
basic_block bb;
|
||||
gimple_stmt_iterator si;
|
||||
/* 1 if looking at ASSERT_EXPRs immediately at the beginning of
|
||||
a basic block preceeded by GIMPLE_COND branching to it and
|
||||
__builtin_trap, -1 if not yet checked, 0 otherwise. */
|
||||
int is_unreachable;
|
||||
|
||||
/* Note that the BSI iterator bump happens at the bottom of the
|
||||
loop and no bump is necessary if we're removing the statement
|
||||
referenced by the current BSI. */
|
||||
FOR_EACH_BB (bb)
|
||||
for (si = gsi_start_bb (bb); !gsi_end_p (si);)
|
||||
for (si = gsi_after_labels (bb), is_unreachable = -1; !gsi_end_p (si);)
|
||||
{
|
||||
gimple stmt = gsi_stmt (si);
|
||||
gimple use_stmt;
|
||||
|
@ -6501,6 +6532,7 @@ remove_range_assertions (void)
|
|||
if (is_gimple_assign (stmt)
|
||||
&& gimple_assign_rhs_code (stmt) == ASSERT_EXPR)
|
||||
{
|
||||
tree lhs = gimple_assign_lhs (stmt);
|
||||
tree rhs = gimple_assign_rhs1 (stmt);
|
||||
tree var;
|
||||
tree cond = fold (ASSERT_EXPR_COND (rhs));
|
||||
|
@ -6509,22 +6541,49 @@ remove_range_assertions (void)
|
|||
|
||||
gcc_assert (cond != boolean_false_node);
|
||||
|
||||
/* Propagate the RHS into every use of the LHS. */
|
||||
var = ASSERT_EXPR_VAR (rhs);
|
||||
FOR_EACH_IMM_USE_STMT (use_stmt, iter,
|
||||
gimple_assign_lhs (stmt))
|
||||
gcc_assert (TREE_CODE (var) == SSA_NAME);
|
||||
|
||||
if (!POINTER_TYPE_P (TREE_TYPE (lhs))
|
||||
&& SSA_NAME_RANGE_INFO (lhs))
|
||||
{
|
||||
if (is_unreachable == -1)
|
||||
{
|
||||
is_unreachable = 0;
|
||||
if (single_pred_p (bb)
|
||||
&& assert_unreachable_fallthru_edge_p
|
||||
(single_pred_edge (bb)))
|
||||
is_unreachable = 1;
|
||||
}
|
||||
/* Handle
|
||||
if (x_7 >= 10 && x_7 < 20)
|
||||
__builtin_unreachable ();
|
||||
x_8 = ASSERT_EXPR <x_7, ...>;
|
||||
if the only uses of x_7 are in the ASSERT_EXPR and
|
||||
in the condition. In that case, we can copy the
|
||||
range info from x_8 computed in this pass also
|
||||
for x_7. */
|
||||
if (is_unreachable
|
||||
&& all_imm_uses_in_stmt_or_feed_cond (var, stmt,
|
||||
single_pred (bb)))
|
||||
set_range_info (var, SSA_NAME_RANGE_INFO (lhs)->min,
|
||||
SSA_NAME_RANGE_INFO (lhs)->max);
|
||||
}
|
||||
|
||||
/* Propagate the RHS into every use of the LHS. */
|
||||
FOR_EACH_IMM_USE_STMT (use_stmt, iter, lhs)
|
||||
FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
|
||||
{
|
||||
SET_USE (use_p, var);
|
||||
gcc_assert (TREE_CODE (var) == SSA_NAME);
|
||||
}
|
||||
SET_USE (use_p, var);
|
||||
|
||||
/* And finally, remove the copy, it is not needed. */
|
||||
gsi_remove (&si, true);
|
||||
release_defs (stmt);
|
||||
}
|
||||
else
|
||||
gsi_next (&si);
|
||||
{
|
||||
gsi_next (&si);
|
||||
is_unreachable = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue