[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:
Vladimir N. Makarov 2021-01-12 11:26:15 -05:00
parent e0bec6ceac
commit cf2ac1c30a
2 changed files with 81 additions and 1 deletions

View File

@ -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

View 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);
}
}