mirror of
https://gcc.gnu.org/git/gcc.git
synced 2025-01-07 11:33:45 +08:00
[PR97969] LRA: Transform pattern plus (plus (hard reg, const), pseudo)
after elimination
LRA can loop infinitely on targets without `reg + imm` insns. Register elimination on such targets can increase register pressure resulting in permanent stack size increase and changing elimination offset. To avoid such situation, a simple transformation can be done to avoid register pressure increase after generating reload insns containing eliminated hard regs. gcc/ChangeLog: PR target/97969 * lra-eliminations.c (eliminate_regs_in_insn): Add transformation of pattern 'plus (plus (hard reg, const), pseudo)'. gcc/testsuite/ChangeLog: PR target/97969 * gcc.target/arm/pr97969.c: New.
This commit is contained in:
parent
e0bec6ceac
commit
cf2ac1c30a
@ -885,7 +885,7 @@ eliminate_regs_in_insn (rtx_insn *insn, bool replace_p, bool first_p,
|
||||
poly_int64 update_sp_offset)
|
||||
{
|
||||
int icode = recog_memoized (insn);
|
||||
rtx old_set = single_set (insn);
|
||||
rtx set, old_set = single_set (insn);
|
||||
bool validate_p;
|
||||
int i;
|
||||
rtx substed_operand[MAX_RECOG_OPERANDS];
|
||||
@ -1038,6 +1038,32 @@ eliminate_regs_in_insn (rtx_insn *insn, bool replace_p, bool first_p,
|
||||
for (i = 0; i < static_id->n_dups; i++)
|
||||
*id->dup_loc[i] = substed_operand[(int) static_id->dup_num[i]];
|
||||
|
||||
/* Transform plus (plus (hard reg, const), pseudo) to plus (plus (pseudo,
|
||||
const), hard reg) in order to keep insn containing eliminated register
|
||||
after all reloads calculating its offset. This permits to keep register
|
||||
pressure under control and helps to avoid LRA cycling in patalogical
|
||||
cases. */
|
||||
if (! replace_p && (set = single_set (insn)) != NULL
|
||||
&& GET_CODE (SET_SRC (set)) == PLUS
|
||||
&& GET_CODE (XEXP (SET_SRC (set), 0)) == PLUS)
|
||||
{
|
||||
rtx reg1, reg2, op1, op2;
|
||||
|
||||
reg1 = op1 = XEXP (XEXP (SET_SRC (set), 0), 0);
|
||||
reg2 = op2 = XEXP (SET_SRC (set), 1);
|
||||
if (GET_CODE (reg1) == SUBREG)
|
||||
reg1 = SUBREG_REG (reg1);
|
||||
if (GET_CODE (reg2) == SUBREG)
|
||||
reg2 = SUBREG_REG (reg2);
|
||||
if (REG_P (reg1) && REG_P (reg2)
|
||||
&& REGNO (reg1) < FIRST_PSEUDO_REGISTER
|
||||
&& REGNO (reg2) >= FIRST_PSEUDO_REGISTER)
|
||||
{
|
||||
XEXP (XEXP (SET_SRC (set), 0), 0) = op2;
|
||||
XEXP (SET_SRC (set), 1) = op1;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we had a move insn but now we don't, re-recognize it.
|
||||
This will cause spurious re-recognition if the old move had a
|
||||
PARALLEL since the new one still will, but we can't call
|
||||
|
54
gcc/testsuite/gcc.target/arm/pr97969.c
Normal file
54
gcc/testsuite/gcc.target/arm/pr97969.c
Normal file
@ -0,0 +1,54 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-std=c99 -fno-omit-frame-pointer -mthumb -w -Os" } */
|
||||
|
||||
typedef a[23];
|
||||
enum { b };
|
||||
typedef struct {
|
||||
int c;
|
||||
char *e;
|
||||
char f
|
||||
} d;
|
||||
typedef enum { g = 1 } h;
|
||||
typedef struct {
|
||||
h i;
|
||||
int j
|
||||
} k;
|
||||
typedef struct {
|
||||
a l;
|
||||
int a;
|
||||
int m;
|
||||
int n;
|
||||
int o;
|
||||
short p;
|
||||
int q;
|
||||
k r;
|
||||
char e;
|
||||
char *s;
|
||||
d t;
|
||||
d *u;
|
||||
short v;
|
||||
int w
|
||||
} aa;
|
||||
c(char x, int y, char z, int ab) {
|
||||
aa ac;
|
||||
ac.r.i = 0;
|
||||
d ad;
|
||||
ac.t = ad;
|
||||
ac.u = 0;
|
||||
ae(&ac.v, 0, 0);
|
||||
ac.w = 0;
|
||||
af(&ac, x + y, z, z + ab);
|
||||
if (ag(0))
|
||||
return 0;
|
||||
if (x)
|
||||
ac.s = z + ab;
|
||||
else
|
||||
ac.s = x + y;
|
||||
ac.o |= g;
|
||||
if (!setjmp()) {
|
||||
ah(ac);
|
||||
ai(b);
|
||||
ac.e = z + ab;
|
||||
aj(ac);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user