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>
* 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));
}
/* 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.
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 dest = SET_DEST (set);
if (REG_P (dest)
&& ! HARD_REGISTER_P (dest)
if (cprop_reg_p (dest)
&& reg_available_p (dest, insn)
&& 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);
/* Record sets for constant/copy propagation. */
if ((REG_P (src)
if ((cprop_reg_p (src)
&& src != dest
&& ! HARD_REGISTER_P (src)
&& reg_available_p (src, insn))
|| cprop_constant_p (src))
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;
}
/* Find a set of REGNOs that are available on entry to INSN's block. Return
NULL no such set is found. */
/* Find a set of REGNOs that are available on entry to INSN's block. If 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 *
find_avail_set (int regno, rtx_insn *insn)
static void
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
use in a substitution. */
struct cprop_expr *set1 = 0;
set_ret[0] = set_ret[1] = NULL;
/* 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
@ -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
iteration of this loop, but we may not use it for substitutions. */
if (cprop_constant_p (src) || reg_not_set_p (src, insn))
set1 = set;
if (cprop_constant_p (src))
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
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. */
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
@ -1048,40 +1053,40 @@ cprop_insn (rtx_insn *insn)
int changed = 0, changed_this_round;
rtx note;
retry:
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++)
do
{
rtx reg_used = reg_use_table[i];
unsigned int regno = REGNO (reg_used);
rtx src;
struct cprop_expr *set;
changed_this_round = 0;
reg_use_count = 0;
note_uses (&PATTERN (insn), find_used_regs, NULL);
/* 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;
/* 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);
/* Find an assignment that sets reg_used and is available
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))
for (i = 0; i < reg_use_count; i++)
{
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;
global_const_prop_count++;
@ -1091,18 +1096,16 @@ retry:
"GLOBAL CONST-PROP: Replacing reg %d in ", regno);
fprintf (dump_file, "insn %d with constant ",
INSN_UID (insn));
print_rtl (dump_file, src);
print_rtl (dump_file, src_cst);
fprintf (dump_file, "\n");
}
if (insn->deleted ())
return 1;
}
}
else if (REG_P (src)
&& REGNO (src) >= FIRST_PSEUDO_REGISTER
&& REGNO (src) != regno)
{
if (try_replace_reg (reg_used, src, insn))
/* Copy propagation. */
else if (src_reg && cprop_reg_p (src_reg)
&& REGNO (src_reg) != regno
&& try_replace_reg (reg_used, src_reg, insn))
{
changed_this_round = changed = 1;
global_copy_prop_count++;
@ -1111,7 +1114,7 @@ retry:
fprintf (dump_file,
"GLOBAL COPY-PROP: Replacing reg %d in insn %d",
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
@ -1121,12 +1124,10 @@ retry:
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))
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
change the hard registers mentioned. */
if (REG_P (x)
&& (REGNO (x) >= FIRST_PSEUDO_REGISTER
&& (cprop_reg_p (x)
|| (GET_CODE (PATTERN (insn)) != USE
&& asm_noperands (PATTERN (insn)) < 0)))
{
@ -1205,7 +1206,7 @@ do_local_cprop (rtx x, rtx_insn *insn)
if (cprop_constant_p (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.
At this point this only function parameters should have
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)
return false;
/* The first operand of COND must be a pseudo-reg. */
if (! REG_P (XEXP (cond, 0))
|| HARD_REGISTER_P (XEXP (cond, 0)))
/* The first operand of COND must be a register we can propagate. */
if (!cprop_reg_p (XEXP (cond, 0)))
return false;
/* 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>
* 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 } } */