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>
|
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.
|
||||||
|
|
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));
|
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. */
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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