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:
parent
62d47a8827
commit
8fceae614f
|
@ -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.
|
||||
|
|
130
gcc/cprop.c
130
gcc/cprop.c
|
@ -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. */
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 } } */
|
Loading…
Reference in New Issue