Commit bf4787b2 by Jakub Jelinek Committed by Jakub Jelinek

tree-ssa-ifcombine.c (forwarder_block_to): New function.

	* tree-ssa-ifcombine.c (forwarder_block_to): New function.
	(tree_ssa_ifcombine_bb_1): New function.
	(tree_ssa_ifcombine_bb): Use it.  Handle also cases where else_bb
	is an empty forwarder block to then_bb or vice versa and then_bb
	and else_bb are effectively swapped.

	* gcc.dg/tree-ssa/ssa-ifcombine-12.c: New test.
	* gcc.dg/tree-ssa/ssa-ifcombine-13.c: New test.
	* gcc.dg/tree-ssa/phi-opt-2.c: Pass -mbranch-cost=1 if
	possible, only test for exactly one if if -mbranch-cost=1
	has been passed.

From-SVN: r208512
parent 7d55b948
2014-03-12 Jakub Jelinek <jakub@redhat.com>
* tree-ssa-ifcombine.c (forwarder_block_to): New function.
(tree_ssa_ifcombine_bb_1): New function.
(tree_ssa_ifcombine_bb): Use it. Handle also cases where else_bb
is an empty forwarder block to then_bb or vice versa and then_bb
and else_bb are effectively swapped.
2014-03-12 Christian Bruel <christian.bruel@st.com> 2014-03-12 Christian Bruel <christian.bruel@st.com>
PR target/60264 PR target/60264
......
2014-03-12 Jakub Jelinek <jakub@redhat.com>
* gcc.dg/tree-ssa/ssa-ifcombine-12.c: New test.
* gcc.dg/tree-ssa/ssa-ifcombine-13.c: New test.
* gcc.dg/tree-ssa/phi-opt-2.c: Pass -mbranch-cost=1 if
possible, only test for exactly one if if -mbranch-cost=1
has been passed.
2014-03-12 Christian Bruel <christian.bruel@st.com> 2014-03-12 Christian Bruel <christian.bruel@st.com>
PR target/60264 PR target/60264
......
/* { dg-do compile } */ /* { dg-do compile } */
/* { dg-options "-O1 -fdump-tree-optimized" } */ /* { dg-options "-O1 -fdump-tree-optimized" } */
/* { dg-additional-options "-mbranch-cost=1" { target { i?86-*-* x86_64-*-* mips*-*-* s390*-*-* avr*-*-* } } } */
_Bool f1(_Bool a, _Bool b) _Bool f1(_Bool a, _Bool b)
{ {
...@@ -17,6 +18,8 @@ _Bool f1(_Bool a, _Bool b) ...@@ -17,6 +18,8 @@ _Bool f1(_Bool a, _Bool b)
/* There should be only one if, the outer one; the inner one /* There should be only one if, the outer one; the inner one
should have been changed to straight line code with the should have been changed to straight line code with the
value of b (except that we don't fold ! (b != 0) into b value of b (except that we don't fold ! (b != 0) into b
which can be fixed in a different patch). */ which can be fixed in a different patch).
/* { dg-final { scan-tree-dump-times "if" 1 "optimized"} } */ Test this only when known to be !LOGICAL_OP_NON_SHORT_CIRCUIT,
otherwise ifcombine may convert this into return a & b;. */
/* { dg-final { scan-tree-dump-times "if" 1 "optimized" { target { i?86-*-* x86_64-*-* mips*-*-* s390*-*-* avr*-*-* } } } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */ /* { dg-final { cleanup-tree-dump "optimized" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -fno-tree-vrp -fdump-tree-optimized" } */
/* Testcase for PR31657. */
int f(int x, int a, int b)
{
int t = 0;
int c = 1 << a;
if (!(x & 1))
t = 0;
else
if (x & (1 << 2))
t = 3;
else
t = 0;
return t;
}
/* { dg-final { scan-tree-dump "& 5" "optimized" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */
/* { dg-do compile } */
/* { dg-options "-O1 -fdump-tree-optimized" } */
/* { dg-additional-options "-mbranch-cost=2" { target { i?86-*-* x86_64-*-* mips*-*-* s390*-*-* avr*-*-* } } } */
_Bool f1(_Bool a, _Bool b)
{
if (a)
{
if (b)
return 1;
else
return 0;
}
return 0;
}
/* For LOGICAL_OP_NON_SHORT_CIRCUIT, this should be optimized
into return a & b;, with no ifs. */
/* { dg-final { scan-tree-dump-not "if" "optimized" { target { i?86-*-* x86_64-*-* mips*-*-* s390*-*-* avr*-*-* } } } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */
...@@ -135,6 +135,16 @@ bb_no_side_effects_p (basic_block bb) ...@@ -135,6 +135,16 @@ bb_no_side_effects_p (basic_block bb)
return true; return true;
} }
/* Return true if BB is an empty forwarder block to TO_BB. */
static bool
forwarder_block_to (basic_block bb, basic_block to_bb)
{
return empty_block_p (bb)
&& single_succ_p (bb)
&& single_succ (bb) == to_bb;
}
/* Verify if all PHI node arguments in DEST for edges from BB1 or /* Verify if all PHI node arguments in DEST for edges from BB1 or
BB2 to DEST are the same. This makes the CFG merge point BB2 to DEST are the same. This makes the CFG merge point
free from side-effects. Return true in this case, else false. */ free from side-effects. Return true in this case, else false. */
...@@ -561,6 +571,99 @@ ifcombine_ifandif (basic_block inner_cond_bb, bool inner_inv, ...@@ -561,6 +571,99 @@ ifcombine_ifandif (basic_block inner_cond_bb, bool inner_inv,
return false; return false;
} }
/* Helper function for tree_ssa_ifcombine_bb. Recognize a CFG pattern and
dispatch to the appropriate if-conversion helper for a particular
set of INNER_COND_BB, OUTER_COND_BB, THEN_BB and ELSE_BB.
PHI_PRED_BB should be one of INNER_COND_BB, THEN_BB or ELSE_BB. */
static bool
tree_ssa_ifcombine_bb_1 (basic_block inner_cond_bb, basic_block outer_cond_bb,
basic_block then_bb, basic_block else_bb,
basic_block phi_pred_bb)
{
/* The && form is characterized by a common else_bb with
the two edges leading to it mergable. The latter is
guaranteed by matching PHI arguments in the else_bb and
the inner cond_bb having no side-effects. */
if (phi_pred_bb != else_bb
&& recognize_if_then_else (outer_cond_bb, &inner_cond_bb, &else_bb)
&& same_phi_args_p (outer_cond_bb, phi_pred_bb, else_bb)
&& bb_no_side_effects_p (inner_cond_bb))
{
/* We have
<outer_cond_bb>
if (q) goto inner_cond_bb; else goto else_bb;
<inner_cond_bb>
if (p) goto ...; else goto else_bb;
...
<else_bb>
...
*/
return ifcombine_ifandif (inner_cond_bb, false, outer_cond_bb, false,
false);
}
/* And a version where the outer condition is negated. */
if (phi_pred_bb != else_bb
&& recognize_if_then_else (outer_cond_bb, &else_bb, &inner_cond_bb)
&& same_phi_args_p (outer_cond_bb, phi_pred_bb, else_bb)
&& bb_no_side_effects_p (inner_cond_bb))
{
/* We have
<outer_cond_bb>
if (q) goto else_bb; else goto inner_cond_bb;
<inner_cond_bb>
if (p) goto ...; else goto else_bb;
...
<else_bb>
...
*/
return ifcombine_ifandif (inner_cond_bb, false, outer_cond_bb, true,
false);
}
/* The || form is characterized by a common then_bb with the
two edges leading to it mergable. The latter is guaranteed
by matching PHI arguments in the then_bb and the inner cond_bb
having no side-effects. */
if (phi_pred_bb != then_bb
&& recognize_if_then_else (outer_cond_bb, &then_bb, &inner_cond_bb)
&& same_phi_args_p (outer_cond_bb, phi_pred_bb, then_bb)
&& bb_no_side_effects_p (inner_cond_bb))
{
/* We have
<outer_cond_bb>
if (q) goto then_bb; else goto inner_cond_bb;
<inner_cond_bb>
if (q) goto then_bb; else goto ...;
<then_bb>
...
*/
return ifcombine_ifandif (inner_cond_bb, true, outer_cond_bb, true,
true);
}
/* And a version where the outer condition is negated. */
if (phi_pred_bb != then_bb
&& recognize_if_then_else (outer_cond_bb, &inner_cond_bb, &then_bb)
&& same_phi_args_p (outer_cond_bb, phi_pred_bb, then_bb)
&& bb_no_side_effects_p (inner_cond_bb))
{
/* We have
<outer_cond_bb>
if (q) goto inner_cond_bb; else goto then_bb;
<inner_cond_bb>
if (q) goto then_bb; else goto ...;
<then_bb>
...
*/
return ifcombine_ifandif (inner_cond_bb, true, outer_cond_bb, false,
true);
}
return false;
}
/* Recognize a CFG pattern and dispatch to the appropriate /* Recognize a CFG pattern and dispatch to the appropriate
if-conversion helper. We start with BB as the innermost if-conversion helper. We start with BB as the innermost
worker basic-block. Returns true if a transformation was done. */ worker basic-block. Returns true if a transformation was done. */
...@@ -585,80 +688,33 @@ tree_ssa_ifcombine_bb (basic_block inner_cond_bb) ...@@ -585,80 +688,33 @@ tree_ssa_ifcombine_bb (basic_block inner_cond_bb)
{ {
basic_block outer_cond_bb = single_pred (inner_cond_bb); basic_block outer_cond_bb = single_pred (inner_cond_bb);
/* The && form is characterized by a common else_bb with if (tree_ssa_ifcombine_bb_1 (inner_cond_bb, outer_cond_bb,
the two edges leading to it mergable. The latter is then_bb, else_bb, inner_cond_bb))
guaranteed by matching PHI arguments in the else_bb and return true;
the inner cond_bb having no side-effects. */
if (recognize_if_then_else (outer_cond_bb, &inner_cond_bb, &else_bb)
&& same_phi_args_p (outer_cond_bb, inner_cond_bb, else_bb)
&& bb_no_side_effects_p (inner_cond_bb))
{
/* We have
<outer_cond_bb>
if (q) goto inner_cond_bb; else goto else_bb;
<inner_cond_bb>
if (p) goto ...; else goto else_bb;
...
<else_bb>
...
*/
return ifcombine_ifandif (inner_cond_bb, false, outer_cond_bb, false,
false);
}
/* And a version where the outer condition is negated. */ if (forwarder_block_to (else_bb, then_bb))
if (recognize_if_then_else (outer_cond_bb, &else_bb, &inner_cond_bb)
&& same_phi_args_p (outer_cond_bb, inner_cond_bb, else_bb)
&& bb_no_side_effects_p (inner_cond_bb))
{ {
/* We have /* Other possibilities for the && form, if else_bb is
<outer_cond_bb> empty forwarder block to then_bb. Compared to the above simpler
if (q) goto else_bb; else goto inner_cond_bb; forms this can be treated as if then_bb and else_bb were swapped,
<inner_cond_bb> and the corresponding inner_cond_bb not inverted because of that.
if (p) goto ...; else goto else_bb; For same_phi_args_p we look at equality of arguments between
... edge from outer_cond_bb and the forwarder block. */
<else_bb> if (tree_ssa_ifcombine_bb_1 (inner_cond_bb, outer_cond_bb, else_bb,
... then_bb, else_bb))
*/ return true;
return ifcombine_ifandif (inner_cond_bb, false, outer_cond_bb, true,
false);
} }
else if (forwarder_block_to (then_bb, else_bb))
/* The || form is characterized by a common then_bb with the
two edges leading to it mergable. The latter is guaranteed
by matching PHI arguments in the then_bb and the inner cond_bb
having no side-effects. */
if (recognize_if_then_else (outer_cond_bb, &then_bb, &inner_cond_bb)
&& same_phi_args_p (outer_cond_bb, inner_cond_bb, then_bb)
&& bb_no_side_effects_p (inner_cond_bb))
{
/* We have
<outer_cond_bb>
if (q) goto then_bb; else goto inner_cond_bb;
<inner_cond_bb>
if (q) goto then_bb; else goto ...;
<then_bb>
...
*/
return ifcombine_ifandif (inner_cond_bb, true, outer_cond_bb, true,
true);
}
/* And a version where the outer condition is negated. */
if (recognize_if_then_else (outer_cond_bb, &inner_cond_bb, &then_bb)
&& same_phi_args_p (outer_cond_bb, inner_cond_bb, then_bb)
&& bb_no_side_effects_p (inner_cond_bb))
{ {
/* We have /* Other possibilities for the || form, if then_bb is
<outer_cond_bb> empty forwarder block to else_bb. Compared to the above simpler
if (q) goto inner_cond_bb; else goto then_bb; forms this can be treated as if then_bb and else_bb were swapped,
<inner_cond_bb> and the corresponding inner_cond_bb not inverted because of that.
if (q) goto then_bb; else goto ...; For same_phi_args_p we look at equality of arguments between
<then_bb> edge from outer_cond_bb and the forwarder block. */
... if (tree_ssa_ifcombine_bb_1 (inner_cond_bb, outer_cond_bb, else_bb,
*/ then_bb, then_bb))
return ifcombine_ifandif (inner_cond_bb, true, outer_cond_bb, false, return true;
true);
} }
} }
......
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