diff options
author | Vladimir N. Makarov <vmakarov@redhat.com> | 2021-01-12 11:26:15 -0500 |
---|---|---|
committer | Vladimir N. Makarov <vmakarov@redhat.com> | 2021-01-12 11:27:29 -0500 |
commit | cf2ac1c30af0fa783c8d72e527904dda5d8cc330 (patch) | |
tree | a4bc0604739c4732d2e9770af00f7eabcde03d2a /gcc/lra-eliminations.c | |
parent | e0bec6ceac47752616dd9fe0801344ed45db2fd3 (diff) | |
download | gcc-cf2ac1c30af0fa783c8d72e527904dda5d8cc330.zip gcc-cf2ac1c30af0fa783c8d72e527904dda5d8cc330.tar.gz gcc-cf2ac1c30af0fa783c8d72e527904dda5d8cc330.tar.bz2 |
[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.
Diffstat (limited to 'gcc/lra-eliminations.c')
-rw-r--r-- | gcc/lra-eliminations.c | 28 |
1 files changed, 27 insertions, 1 deletions
diff --git a/gcc/lra-eliminations.c b/gcc/lra-eliminations.c index b28f3c4..ebcadd1 100644 --- a/gcc/lra-eliminations.c +++ b/gcc/lra-eliminations.c @@ -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 |