[RTL-ifcvt] PR rtl-optimization/68841: Make sure one basic block doesn't clobber CC reg usage of the other

PR rtl-optimization/68841
        * ifcvt.c (struct noce_if_info): Add orig_x field.
        (bbs_ok_for_cmove_arith): Add to_rename parameter.
        Don't record conflicts on to_rename if it's present.
        Allow memory destinations in sets.
        (noce_try_cmove_arith): Call bbs_ok_for_cmove_arith even on simple
        blocks, passing orig_x to the checks.
        (noce_process_if_block): Set if_info->orig_x appropriately.

        * gcc.dg/pr68841.c: New test.
        * gcc.c-torture/execute/pr68841.c: New test.

From-SVN: r232223
This commit is contained in:
Kyrylo Tkachov 2016-01-11 12:13:50 +00:00
parent 1c5211b13c
commit 5baf45323b
5 changed files with 106 additions and 10 deletions

View File

@ -1,3 +1,15 @@
2016-01-11 Bernd Schmidt <bschmidt@redhat.com>
Kyrylo Tkachov <kyrylo.tkachov@arm.com>
PR rtl-optimization/68841
* ifcvt.c (struct noce_if_info): Add orig_x field.
(bbs_ok_for_cmove_arith): Add to_rename parameter.
Don't record conflicts on to_rename if it's present.
Allow memory destinations in sets.
(noce_try_cmove_arith): Call bbs_ok_for_cmove_arith even on simple
blocks, passing orig_x to the checks.
(noce_process_if_block): Set if_info->orig_x appropriately.
2016-01-11 Tom de Vries <tom@codesourcery.com>
PR tree-optimization/69069

View File

@ -793,6 +793,9 @@ struct noce_if_info
/* The SET_DEST of INSN_A. */
rtx x;
/* The original set destination that the THEN and ELSE basic blocks finally
write their result to. */
rtx orig_x;
/* True if this if block is not canonical. In the canonical form of
if blocks, the THEN_BB is the block reached via the fallthru edge
from TEST_BB. For the noce transformations, we allow the symmetric
@ -1867,11 +1870,13 @@ insn_valid_noce_process_p (rtx_insn *insn, rtx cc)
}
/* Return true iff the registers that the insns in BB_A set do not
get used in BB_B. */
/* Return true iff the registers that the insns in BB_A set do not get
used in BB_B. If TO_RENAME is non-NULL then it is a location that will be
renamed later by the caller and so conflicts on it should be ignored
in this function. */
static bool
bbs_ok_for_cmove_arith (basic_block bb_a, basic_block bb_b)
bbs_ok_for_cmove_arith (basic_block bb_a, basic_block bb_b, rtx to_rename)
{
rtx_insn *a_insn;
bitmap bba_sets = BITMAP_ALLOC (&reg_obstack);
@ -1891,10 +1896,10 @@ bbs_ok_for_cmove_arith (basic_block bb_a, basic_block bb_b)
BITMAP_FREE (bba_sets);
return false;
}
/* Record all registers that BB_A sets. */
FOR_EACH_INSN_DEF (def, a_insn)
bitmap_set_bit (bba_sets, DF_REF_REGNO (def));
if (!(to_rename && DF_REF_REG (def) == to_rename))
bitmap_set_bit (bba_sets, DF_REF_REGNO (def));
}
rtx_insn *b_insn;
@ -1913,8 +1918,15 @@ bbs_ok_for_cmove_arith (basic_block bb_a, basic_block bb_b)
}
/* Make sure this is a REG and not some instance
of ZERO_EXTRACT or SUBREG or other dangerous stuff. */
if (!REG_P (SET_DEST (sset_b)))
of ZERO_EXTRACT or SUBREG or other dangerous stuff.
If we have a memory destination then we have a pair of simple
basic blocks performing an operation of the form [addr] = c ? a : b.
bb_valid_for_noce_process_p will have ensured that these are
the only stores present. In that case [addr] should be the location
to be renamed. Assert that the callers set this up properly. */
if (MEM_P (SET_DEST (sset_b)))
gcc_assert (rtx_equal_p (SET_DEST (sset_b), to_rename));
else if (!REG_P (SET_DEST (sset_b)))
{
BITMAP_FREE (bba_sets);
return false;
@ -2083,9 +2095,9 @@ noce_try_cmove_arith (struct noce_if_info *if_info)
}
}
if (then_bb && else_bb && !a_simple && !b_simple
&& (!bbs_ok_for_cmove_arith (then_bb, else_bb)
|| !bbs_ok_for_cmove_arith (else_bb, then_bb)))
if (then_bb && else_bb
&& (!bbs_ok_for_cmove_arith (then_bb, else_bb, if_info->orig_x)
|| !bbs_ok_for_cmove_arith (else_bb, then_bb, if_info->orig_x)))
return FALSE;
start_sequence ();
@ -3403,6 +3415,7 @@ noce_process_if_block (struct noce_if_info *if_info)
/* Only operate on register destinations, and even then avoid extending
the lifetime of hard registers on small register class machines. */
orig_x = x;
if_info->orig_x = orig_x;
if (!REG_P (x)
|| (HARD_REGISTER_P (x)
&& targetm.small_register_classes_for_mode_p (GET_MODE (x))))

View File

@ -1,3 +1,9 @@
2016-01-11 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
PR rtl-optimization/68841
* gcc.dg/pr68841.c: New test.
* gcc.c-torture/execute/pr68841.c: New test.
2016-01-11 Yuri Rumyantsev <ysrumyan@gmail.com>
PR rtl-optimization/68920

View File

@ -0,0 +1,31 @@
static inline int
foo (int *x, int y)
{
int z = *x;
while (y > z)
z *= 2;
return z;
}
int
main ()
{
int i;
for (i = 1; i < 17; i++)
{
int j;
int k;
j = foo (&i, 7);
if (i >= 7)
k = i;
else if (i >= 4)
k = 8 + (i - 4) * 2;
else if (i == 3)
k = 12;
else
k = 8;
if (j != k)
__builtin_abort ();
}
return 0;
}

View File

@ -0,0 +1,34 @@
/* { dg-do run } */
/* { dg-options "-Og -fif-conversion -flive-range-shrinkage -fpeel-loops -frerun-cse-after-loop" } */
static inline int
foo (int *x, int y)
{
int z = *x;
while (y > z)
z *= 2;
return z;
}
int
main ()
{
int i;
for (i = 1; i < 17; i++)
{
int j;
int k;
j = foo (&i, 7);
if (i >= 7)
k = i;
else if (i >= 4)
k = 8 + (i - 4) * 2;
else if (i == 3)
k = 12;
else
k = 8;
if (j != k)
__builtin_abort ();
}
return 0;
}