re PR rtl-optimization/34503 (Issues with constant/copy propagation implementation in gcse.c)

2015-04-24  Thomas Preud'homme  <thomas.preudhomme@arm.com>
            Steven Bosscher <steven@gcc.gnu.org>

    gcc/
    PR rtl-optimization/34503
    * cprop.c (cprop_reg_p): New.
    (hash_scan_set): Use above function to check if register can be
    propagated.
    (find_avail_set): Return up to two sets, one whose source is a
    register and one whose source is a constant.  Sets are returned in an
    array passed as parameter rather than as a return value.
    (cprop_insn): Use a do while loop rather than a goto.  Try each of the
    sets returned by find_avail_set, starting with the one whose source is
    a constant. Use cprop_reg_p to check if register can be propagated.
    (do_local_cprop): Use cprop_reg_p to check if register can be
    propagated.
    (implicit_set_cond_p): Likewise.

    gcc/testsuite/
    PR rtl-optimization/34503
    * gcc.target/arm/pr64616.c: New file.

Co-Authored-By: Steven Bosscher <steven@gcc.gnu.org>

From-SVN: r222398
This commit is contained in:
Thomas Preud'homme 2015-04-24 04:49:34 +00:00 committed by Thomas Preud'homme
parent 62d47a8827
commit 8fceae614f
4 changed files with 102 additions and 65 deletions

View File

@ -1,3 +1,20 @@
2015-04-24 Thomas Preud'homme <thomas.preudhomme@arm.com>
Steven Bosscher <steven@gcc.gnu.org>
PR rtl-optimization/34503
* cprop.c (cprop_reg_p): New.
(hash_scan_set): Use above function to check if register can be
propagated.
(find_avail_set): Return up to two sets, one whose source is a
register and one whose source is a constant. Sets are returned in an
array passed as parameter rather than as a return value.
(cprop_insn): Use a do while loop rather than a goto. Try each of the
sets returned by find_avail_set, starting with the one whose source is
a constant. Use cprop_reg_p to check if register can be propagated.
(do_local_cprop): Use cprop_reg_p to check if register can be
propagated.
(implicit_set_cond_p): Likewise.
2015-04-23 Jan Hubicka <hubicka@ucw.cz> 2015-04-23 Jan Hubicka <hubicka@ucw.cz>
* ipa-icf.c (sem_function::equals_wpa): Compare thunk info. * ipa-icf.c (sem_function::equals_wpa): Compare thunk info.

View File

@ -285,6 +285,15 @@ cprop_constant_p (const_rtx x)
return CONSTANT_P (x) && (GET_CODE (x) != CONST || shared_const_p (x)); return CONSTANT_P (x) && (GET_CODE (x) != CONST || shared_const_p (x));
} }
/* Determine whether the rtx X should be treated as a register that can
be propagated. Any pseudo-register is fine. */
static bool
cprop_reg_p (const_rtx x)
{
return REG_P (x) && !HARD_REGISTER_P (x);
}
/* Scan SET present in INSN and add an entry to the hash TABLE. /* Scan SET present in INSN and add an entry to the hash TABLE.
IMPLICIT is true if it's an implicit set, false otherwise. */ IMPLICIT is true if it's an implicit set, false otherwise. */
@ -295,8 +304,7 @@ hash_scan_set (rtx set, rtx_insn *insn, struct hash_table_d *table,
rtx src = SET_SRC (set); rtx src = SET_SRC (set);
rtx dest = SET_DEST (set); rtx dest = SET_DEST (set);
if (REG_P (dest) if (cprop_reg_p (dest)
&& ! HARD_REGISTER_P (dest)
&& reg_available_p (dest, insn) && reg_available_p (dest, insn)
&& can_copy_p (GET_MODE (dest))) && can_copy_p (GET_MODE (dest)))
{ {
@ -321,9 +329,8 @@ hash_scan_set (rtx set, rtx_insn *insn, struct hash_table_d *table,
src = XEXP (note, 0), set = gen_rtx_SET (VOIDmode, dest, src); src = XEXP (note, 0), set = gen_rtx_SET (VOIDmode, dest, src);
/* Record sets for constant/copy propagation. */ /* Record sets for constant/copy propagation. */
if ((REG_P (src) if ((cprop_reg_p (src)
&& src != dest && src != dest
&& ! HARD_REGISTER_P (src)
&& reg_available_p (src, insn)) && reg_available_p (src, insn))
|| cprop_constant_p (src)) || cprop_constant_p (src))
insert_set_in_table (dest, src, insn, table, implicit); insert_set_in_table (dest, src, insn, table, implicit);
@ -821,15 +828,15 @@ try_replace_reg (rtx from, rtx to, rtx_insn *insn)
return success; return success;
} }
/* Find a set of REGNOs that are available on entry to INSN's block. Return /* Find a set of REGNOs that are available on entry to INSN's block. If found,
NULL no such set is found. */ SET_RET[0] will be assigned a set with a register source and SET_RET[1] a
set with a constant source. If not found the corresponding entry is set to
NULL. */
static struct cprop_expr * static void
find_avail_set (int regno, rtx_insn *insn) find_avail_set (int regno, rtx_insn *insn, struct cprop_expr *set_ret[2])
{ {
/* SET1 contains the last set found that can be returned to the caller for set_ret[0] = set_ret[1] = NULL;
use in a substitution. */
struct cprop_expr *set1 = 0;
/* Loops are not possible here. To get a loop we would need two sets /* Loops are not possible here. To get a loop we would need two sets
available at the start of the block containing INSN. i.e. we would available at the start of the block containing INSN. i.e. we would
@ -869,8 +876,10 @@ find_avail_set (int regno, rtx_insn *insn)
If the source operand changed, we may still use it for the next If the source operand changed, we may still use it for the next
iteration of this loop, but we may not use it for substitutions. */ iteration of this loop, but we may not use it for substitutions. */
if (cprop_constant_p (src) || reg_not_set_p (src, insn)) if (cprop_constant_p (src))
set1 = set; set_ret[1] = set;
else if (reg_not_set_p (src, insn))
set_ret[0] = set;
/* If the source of the set is anything except a register, then /* If the source of the set is anything except a register, then
we have reached the end of the copy chain. */ we have reached the end of the copy chain. */
@ -881,10 +890,6 @@ find_avail_set (int regno, rtx_insn *insn)
and see if we have an available copy into SRC. */ and see if we have an available copy into SRC. */
regno = REGNO (src); regno = REGNO (src);
} }
/* SET1 holds the last set that was available and anticipatable at
INSN. */
return set1;
} }
/* Subroutine of cprop_insn that tries to propagate constants into /* Subroutine of cprop_insn that tries to propagate constants into
@ -1048,40 +1053,40 @@ cprop_insn (rtx_insn *insn)
int changed = 0, changed_this_round; int changed = 0, changed_this_round;
rtx note; rtx note;
retry: do
changed_this_round = 0;
reg_use_count = 0;
note_uses (&PATTERN (insn), find_used_regs, NULL);
/* We may win even when propagating constants into notes. */
note = find_reg_equal_equiv_note (insn);
if (note)
find_used_regs (&XEXP (note, 0), NULL);
for (i = 0; i < reg_use_count; i++)
{ {
rtx reg_used = reg_use_table[i]; changed_this_round = 0;
unsigned int regno = REGNO (reg_used); reg_use_count = 0;
rtx src; note_uses (&PATTERN (insn), find_used_regs, NULL);
struct cprop_expr *set;
/* If the register has already been set in this block, there's /* We may win even when propagating constants into notes. */
nothing we can do. */ note = find_reg_equal_equiv_note (insn);
if (! reg_not_set_p (reg_used, insn)) if (note)
continue; find_used_regs (&XEXP (note, 0), NULL);
/* Find an assignment that sets reg_used and is available for (i = 0; i < reg_use_count; i++)
at the start of the block. */
set = find_avail_set (regno, insn);
if (! set)
continue;
src = set->src;
/* Constant propagation. */
if (cprop_constant_p (src))
{ {
if (constprop_register (reg_used, src, insn)) rtx reg_used = reg_use_table[i];
unsigned int regno = REGNO (reg_used);
rtx src_cst = NULL, src_reg = NULL;
struct cprop_expr *set[2];
/* If the register has already been set in this block, there's
nothing we can do. */
if (! reg_not_set_p (reg_used, insn))
continue;
/* Find an assignment that sets reg_used and is available
at the start of the block. */
find_avail_set (regno, insn, set);
if (set[0])
src_reg = set[0]->src;
if (set[1])
src_cst = set[1]->src;
/* Constant propagation. */
if (src_cst && cprop_constant_p (src_cst)
&& constprop_register (reg_used, src_cst, insn))
{ {
changed_this_round = changed = 1; changed_this_round = changed = 1;
global_const_prop_count++; global_const_prop_count++;
@ -1091,18 +1096,16 @@ retry:
"GLOBAL CONST-PROP: Replacing reg %d in ", regno); "GLOBAL CONST-PROP: Replacing reg %d in ", regno);
fprintf (dump_file, "insn %d with constant ", fprintf (dump_file, "insn %d with constant ",
INSN_UID (insn)); INSN_UID (insn));
print_rtl (dump_file, src); print_rtl (dump_file, src_cst);
fprintf (dump_file, "\n"); fprintf (dump_file, "\n");
} }
if (insn->deleted ()) if (insn->deleted ())
return 1; return 1;
} }
} /* Copy propagation. */
else if (REG_P (src) else if (src_reg && cprop_reg_p (src_reg)
&& REGNO (src) >= FIRST_PSEUDO_REGISTER && REGNO (src_reg) != regno
&& REGNO (src) != regno) && try_replace_reg (reg_used, src_reg, insn))
{
if (try_replace_reg (reg_used, src, insn))
{ {
changed_this_round = changed = 1; changed_this_round = changed = 1;
global_copy_prop_count++; global_copy_prop_count++;
@ -1111,7 +1114,7 @@ retry:
fprintf (dump_file, fprintf (dump_file,
"GLOBAL COPY-PROP: Replacing reg %d in insn %d", "GLOBAL COPY-PROP: Replacing reg %d in insn %d",
regno, INSN_UID (insn)); regno, INSN_UID (insn));
fprintf (dump_file, " with reg %d\n", REGNO (src)); fprintf (dump_file, " with reg %d\n", REGNO (src_reg));
} }
/* The original insn setting reg_used may or may not now be /* The original insn setting reg_used may or may not now be
@ -1121,12 +1124,10 @@ retry:
and made things worse. */ and made things worse. */
} }
} }
/* If try_replace_reg simplified the insn, the regs found
by find_used_regs may not be valid anymore. Start over. */
if (changed_this_round)
goto retry;
} }
/* If try_replace_reg simplified the insn, the regs found by find_used_regs
may not be valid anymore. Start over. */
while (changed_this_round);
if (changed && DEBUG_INSN_P (insn)) if (changed && DEBUG_INSN_P (insn))
return 0; return 0;
@ -1189,7 +1190,7 @@ do_local_cprop (rtx x, rtx_insn *insn)
/* Rule out USE instructions and ASM statements as we don't want to /* Rule out USE instructions and ASM statements as we don't want to
change the hard registers mentioned. */ change the hard registers mentioned. */
if (REG_P (x) if (REG_P (x)
&& (REGNO (x) >= FIRST_PSEUDO_REGISTER && (cprop_reg_p (x)
|| (GET_CODE (PATTERN (insn)) != USE || (GET_CODE (PATTERN (insn)) != USE
&& asm_noperands (PATTERN (insn)) < 0))) && asm_noperands (PATTERN (insn)) < 0)))
{ {
@ -1205,7 +1206,7 @@ do_local_cprop (rtx x, rtx_insn *insn)
if (cprop_constant_p (this_rtx)) if (cprop_constant_p (this_rtx))
newcnst = this_rtx; newcnst = this_rtx;
if (REG_P (this_rtx) && REGNO (this_rtx) >= FIRST_PSEUDO_REGISTER if (cprop_reg_p (this_rtx)
/* Don't copy propagate if it has attached REG_EQUIV note. /* Don't copy propagate if it has attached REG_EQUIV note.
At this point this only function parameters should have At this point this only function parameters should have
REG_EQUIV notes and if the argument slot is used somewhere REG_EQUIV notes and if the argument slot is used somewhere
@ -1326,9 +1327,8 @@ implicit_set_cond_p (const_rtx cond)
if (GET_CODE (cond) != EQ && GET_CODE (cond) != NE) if (GET_CODE (cond) != EQ && GET_CODE (cond) != NE)
return false; return false;
/* The first operand of COND must be a pseudo-reg. */ /* The first operand of COND must be a register we can propagate. */
if (! REG_P (XEXP (cond, 0)) if (!cprop_reg_p (XEXP (cond, 0)))
|| HARD_REGISTER_P (XEXP (cond, 0)))
return false; return false;
/* The second operand of COND must be a suitable constant. */ /* The second operand of COND must be a suitable constant. */

View File

@ -1,3 +1,9 @@
2015-04-24 Thomas Preud'homme <thomas.preudhomme@arm.com>
Steven Bosscher <steven@gcc.gnu.org>
PR rtl-optimization/34503
* gcc.target/arm/pr64616.c: New file.
2015-04-24 Bin Cheng <bin.cheng@arm.com> 2015-04-24 Bin Cheng <bin.cheng@arm.com>
* gcc.target/arm/pr42172-1.c: Check str instead of ldr. * gcc.target/arm/pr42172-1.c: Check str instead of ldr.

View File

@ -0,0 +1,14 @@
/* { dg-do compile } */
/* { dg-options "-O2" } */
int f (int);
unsigned int glob;
void
g ()
{
while (f (glob));
glob = 5;
}
/* { dg-final { scan-assembler-times "ldr" 2 } } */