[PR97969] LRA: Transform pattern `plus (plus (hard reg, const), pseudo)` after elimin...
[gcc.git] / gcc / lra-eliminations.c
index b28f3c410d31acd2729d6fddb70d8d4aecaca578..ebcadd1006cee227008c8965c3ce40fe1066551d 100644 (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