Commit 5a956111 by Patrick Palka Committed by Jeff Law

tree-ssa-threadedge.c (simplify_control_stmt_condition): Split out into ...

2016-04-29  Patrick Palka  <ppalka@gcc.gnu.org>

	* tree-ssa-threadedge.c (simplify_control_stmt_condition): Split
	out into ...
	(simplify_control_stmt_condition_1): ... here.  Recurse into
	BIT_AND_EXPRs and BIT_IOR_EXPRs.

	* gcc.dg/tree-ssa/ssa-thread-14.c: New test.
	* gcc.dg/tree-ssa/ssa-thread-11.c: Update expected output.

From-SVN: r235653
parent e7ff0319
2016-04-29 Patrick Palka <ppalka@gcc.gnu.org>
* tree-ssa-threadedge.c (simplify_control_stmt_condition): Split
out into ...
(simplify_control_stmt_condition_1): ... here. Recurse into
BIT_AND_EXPRs and BIT_IOR_EXPRs.
2016-04-29 David Edelsohn <dje.gcc@gmail.com> 2016-04-29 David Edelsohn <dje.gcc@gmail.com>
PR target/69810 PR target/69810
......
2016-04-29 Patrick Palka <ppalka@gcc.gnu.org>
* gcc.dg/tree-ssa/ssa-thread-14.c: New test.
* gcc.dg/tree-ssa/ssa-thread-11.c: Update expected output.
2016-04-29 Cesar Philippidis <cesar@codesourcery.com> 2016-04-29 Cesar Philippidis <cesar@codesourcery.com>
PR middle-end/70626 PR middle-end/70626
......
/* { dg-do compile { target { ! { logical_op_short_circuit || { m68k*-*-* mep*-*-* bfin*-*-* v850*-*-* moxie*-*-* m32c*-*-* fr30*-*-* mcore*-*-* frv-*-* h8300-*-* m32r-*-* mn10300-*-* msp430-*-* pdp11-*-* rl78-*-* rx-*-* vax-*-*} } } } } */ /* { dg-do compile { target { ! { logical_op_short_circuit || { m68k*-*-* mep*-*-* bfin*-*-* v850*-*-* moxie*-*-* m32c*-*-* fr30*-*-* mcore*-*-* frv-*-* h8300-*-* m32r-*-* mn10300-*-* msp430-*-* pdp11-*-* rl78-*-* rx-*-* vax-*-*} } } } } */
/* { dg-options "-O2 -fdump-tree-vrp2-details" } */ /* { dg-options "-O2 -fdump-tree-vrp2-details" } */
/* { dg-final { scan-tree-dump-not "IRREDUCIBLE_LOOP" "vrp2" } } */ /* { dg-final { scan-tree-dump-not "IRREDUCIBLE_LOOP" "vrp2" } } */
/* { dg-final { scan-tree-dump "FSM" "vrp2" } } */
void abort (void); void abort (void);
typedef struct bitmap_head_def *bitmap; typedef struct bitmap_head_def *bitmap;
......
/* { dg-do compile } */
/* { dg-additional-options "-O2 -fdump-tree-vrp" } */
/* { dg-final { scan-tree-dump-times "Threaded jump" 8 "vrp1" } } */
void foo (void);
void bar (void);
void blah (void);
/* One jump threaded here. */
void
baz_1 (int a, int b, int c)
{
if (a && b)
foo ();
if (!b && c)
bar ();
}
/* One jump threaded here. */
void
baz_2 (int a, int b, int c)
{
if (a && b)
foo ();
if (b || c)
bar ();
}
/* One jump threaded here. */
void
baz_3 (int a, int b, int c)
{
if (a && b > 10)
foo ();
if (b < 5 && c)
bar ();
}
/* Two jumps threaded here. */
void
baz_4 (int a, int b, int c)
{
if (a && b)
{
foo ();
if (c)
bar ();
}
if (b && c)
blah ();
}
/* Two jumps threaded here. */
void
baz_5 (int a, int b, int c)
{
if (a && b)
{
foo ();
if (c)
bar ();
}
if (!b || !c)
blah ();
}
/* One jump threaded here. */
void
baz_6 (int a, int b, int c)
{
if (a == 39 && b == 41)
foo ();
if (c == 12 || b == 41)
bar ();
}
...@@ -376,6 +376,12 @@ record_temporary_equivalences_from_stmts_at_dest (edge e, ...@@ -376,6 +376,12 @@ record_temporary_equivalences_from_stmts_at_dest (edge e,
return stmt; return stmt;
} }
static tree simplify_control_stmt_condition_1 (edge, gimple *,
class avail_exprs_stack *,
tree, enum tree_code, tree,
gcond *, pfn_simplify, bool,
unsigned);
/* Simplify the control statement at the end of the block E->dest. /* Simplify the control statement at the end of the block E->dest.
To avoid allocating memory unnecessarily, a scratch GIMPLE_COND To avoid allocating memory unnecessarily, a scratch GIMPLE_COND
...@@ -436,52 +442,14 @@ simplify_control_stmt_condition (edge e, ...@@ -436,52 +442,14 @@ simplify_control_stmt_condition (edge e,
} }
} }
if (handle_dominating_asserts) const unsigned recursion_limit = 4;
{
/* Now see if the operand was consumed by an ASSERT_EXPR
which dominates E->src. If so, we want to replace the
operand with the LHS of the ASSERT_EXPR. */
if (TREE_CODE (op0) == SSA_NAME)
op0 = lhs_of_dominating_assert (op0, e->src, stmt);
if (TREE_CODE (op1) == SSA_NAME)
op1 = lhs_of_dominating_assert (op1, e->src, stmt);
}
/* We may need to canonicalize the comparison. For
example, op0 might be a constant while op1 is an
SSA_NAME. Failure to canonicalize will cause us to
miss threading opportunities. */
if (tree_swap_operands_p (op0, op1, false))
{
cond_code = swap_tree_comparison (cond_code);
std::swap (op0, op1);
}
/* Stuff the operator and operands into our dummy conditional cached_lhs
expression. */ = simplify_control_stmt_condition_1 (e, stmt, avail_exprs_stack,
gimple_cond_set_code (dummy_cond, cond_code); op0, cond_code, op1,
gimple_cond_set_lhs (dummy_cond, op0); dummy_cond, simplify,
gimple_cond_set_rhs (dummy_cond, op1); handle_dominating_asserts,
recursion_limit);
/* We absolutely do not care about any type conversions
we only care about a zero/nonzero value. */
fold_defer_overflow_warnings ();
cached_lhs = fold_binary (cond_code, boolean_type_node, op0, op1);
if (cached_lhs)
while (CONVERT_EXPR_P (cached_lhs))
cached_lhs = TREE_OPERAND (cached_lhs, 0);
fold_undefer_overflow_warnings ((cached_lhs
&& is_gimple_min_invariant (cached_lhs)),
stmt, WARN_STRICT_OVERFLOW_CONDITIONAL);
/* If we have not simplified the condition down to an invariant,
then use the pass specific callback to simplify the condition. */
if (!cached_lhs
|| !is_gimple_min_invariant (cached_lhs))
cached_lhs = (*simplify) (dummy_cond, stmt, avail_exprs_stack);
/* If we were testing an integer/pointer against a constant, then /* If we were testing an integer/pointer against a constant, then
we can use the FSM code to trace the value of the SSA_NAME. If we can use the FSM code to trace the value of the SSA_NAME. If
...@@ -560,6 +528,197 @@ simplify_control_stmt_condition (edge e, ...@@ -560,6 +528,197 @@ simplify_control_stmt_condition (edge e,
return cached_lhs; return cached_lhs;
} }
/* Recursive helper for simplify_control_stmt_condition. */
static tree
simplify_control_stmt_condition_1 (edge e,
gimple *stmt,
class avail_exprs_stack *avail_exprs_stack,
tree op0,
enum tree_code cond_code,
tree op1,
gcond *dummy_cond,
pfn_simplify simplify,
bool handle_dominating_asserts,
unsigned limit)
{
if (limit == 0)
return NULL_TREE;
/* We may need to canonicalize the comparison. For
example, op0 might be a constant while op1 is an
SSA_NAME. Failure to canonicalize will cause us to
miss threading opportunities. */
if (tree_swap_operands_p (op0, op1, false))
{
cond_code = swap_tree_comparison (cond_code);
std::swap (op0, op1);
}
/* If the condition has the form (A & B) CMP 0 or (A | B) CMP 0 then
recurse into the LHS to see if there is a dominating ASSERT_EXPR
of A or of B that makes this condition always true or always false
along the edge E. */
if (handle_dominating_asserts
&& (cond_code == EQ_EXPR || cond_code == NE_EXPR)
&& TREE_CODE (op0) == SSA_NAME
&& integer_zerop (op1))
{
gimple *def_stmt = SSA_NAME_DEF_STMT (op0);
if (gimple_code (def_stmt) != GIMPLE_ASSIGN)
;
else if (gimple_assign_rhs_code (def_stmt) == BIT_AND_EXPR
|| gimple_assign_rhs_code (def_stmt) == BIT_IOR_EXPR)
{
enum tree_code rhs_code = gimple_assign_rhs_code (def_stmt);
const tree rhs1 = gimple_assign_rhs1 (def_stmt);
const tree rhs2 = gimple_assign_rhs2 (def_stmt);
const tree zero_cst = build_zero_cst (TREE_TYPE (op0));
const tree one_cst = build_one_cst (TREE_TYPE (op0));
/* Is A != 0 ? */
const tree res1
= simplify_control_stmt_condition_1 (e, def_stmt, avail_exprs_stack,
rhs1, NE_EXPR, op1,
dummy_cond, simplify,
handle_dominating_asserts,
limit - 1);
if (res1 == NULL_TREE)
;
else if (rhs_code == BIT_AND_EXPR && integer_zerop (res1))
{
/* If A == 0 then (A & B) != 0 is always false. */
if (cond_code == NE_EXPR)
return zero_cst;
/* If A == 0 then (A & B) == 0 is always true. */
if (cond_code == EQ_EXPR)
return one_cst;
}
else if (rhs_code == BIT_IOR_EXPR && integer_nonzerop (res1))
{
/* If A != 0 then (A | B) != 0 is always true. */
if (cond_code == NE_EXPR)
return one_cst;
/* If A != 0 then (A | B) == 0 is always false. */
if (cond_code == EQ_EXPR)
return zero_cst;
}
/* Is B != 0 ? */
const tree res2
= simplify_control_stmt_condition_1 (e, def_stmt, avail_exprs_stack,
rhs2, NE_EXPR, op1,
dummy_cond, simplify,
handle_dominating_asserts,
limit - 1);
if (res2 == NULL_TREE)
;
else if (rhs_code == BIT_AND_EXPR && integer_zerop (res2))
{
/* If B == 0 then (A & B) != 0 is always false. */
if (cond_code == NE_EXPR)
return zero_cst;
/* If B == 0 then (A & B) == 0 is always true. */
if (cond_code == EQ_EXPR)
return one_cst;
}
else if (rhs_code == BIT_IOR_EXPR && integer_nonzerop (res2))
{
/* If B != 0 then (A | B) != 0 is always true. */
if (cond_code == NE_EXPR)
return one_cst;
/* If B != 0 then (A | B) == 0 is always false. */
if (cond_code == EQ_EXPR)
return zero_cst;
}
if (res1 != NULL_TREE && res2 != NULL_TREE)
{
if (rhs_code == BIT_AND_EXPR
&& TYPE_PRECISION (TREE_TYPE (op0)) == 1
&& integer_nonzerop (res1)
&& integer_nonzerop (res2))
{
/* If A != 0 and B != 0 then (bool)(A & B) != 0 is true. */
if (cond_code == NE_EXPR)
return one_cst;
/* If A != 0 and B != 0 then (bool)(A & B) == 0 is false. */
if (cond_code == EQ_EXPR)
return zero_cst;
}
if (rhs_code == BIT_IOR_EXPR
&& integer_zerop (res1)
&& integer_zerop (res2))
{
/* If A == 0 and B == 0 then (A | B) != 0 is false. */
if (cond_code == NE_EXPR)
return zero_cst;
/* If A == 0 and B == 0 then (A | B) == 0 is true. */
if (cond_code == EQ_EXPR)
return one_cst;
}
}
}
/* Handle (A CMP B) CMP 0. */
else if (TREE_CODE_CLASS (gimple_assign_rhs_code (def_stmt))
== tcc_comparison)
{
tree rhs1 = gimple_assign_rhs1 (def_stmt);
tree rhs2 = gimple_assign_rhs2 (def_stmt);
tree_code new_cond = gimple_assign_rhs_code (def_stmt);
if (cond_code == EQ_EXPR)
new_cond = invert_tree_comparison (new_cond, false);
tree res
= simplify_control_stmt_condition_1 (e, def_stmt, avail_exprs_stack,
rhs1, new_cond, rhs2,
dummy_cond, simplify,
handle_dominating_asserts,
limit - 1);
if (res != NULL_TREE && is_gimple_min_invariant (res))
return res;
}
}
if (handle_dominating_asserts)
{
/* Now see if the operand was consumed by an ASSERT_EXPR
which dominates E->src. If so, we want to replace the
operand with the LHS of the ASSERT_EXPR. */
if (TREE_CODE (op0) == SSA_NAME)
op0 = lhs_of_dominating_assert (op0, e->src, stmt);
if (TREE_CODE (op1) == SSA_NAME)
op1 = lhs_of_dominating_assert (op1, e->src, stmt);
}
gimple_cond_set_code (dummy_cond, cond_code);
gimple_cond_set_lhs (dummy_cond, op0);
gimple_cond_set_rhs (dummy_cond, op1);
/* We absolutely do not care about any type conversions
we only care about a zero/nonzero value. */
fold_defer_overflow_warnings ();
tree res = fold_binary (cond_code, boolean_type_node, op0, op1);
if (res)
while (CONVERT_EXPR_P (res))
res = TREE_OPERAND (res, 0);
fold_undefer_overflow_warnings ((res && is_gimple_min_invariant (res)),
stmt, WARN_STRICT_OVERFLOW_CONDITIONAL);
/* If we have not simplified the condition down to an invariant,
then use the pass specific callback to simplify the condition. */
if (!res
|| !is_gimple_min_invariant (res))
res = (*simplify) (dummy_cond, stmt, avail_exprs_stack);
return res;
}
/* Copy debug stmts from DEST's chain of single predecessors up to /* Copy debug stmts from DEST's chain of single predecessors up to
SRC, so that we don't lose the bindings as PHI nodes are introduced SRC, so that we don't lose the bindings as PHI nodes are introduced
when DEST gains new predecessors. */ when DEST gains new predecessors. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment