https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116236

--- Comment #6 from Michael Matz <matz at gcc dot gnu.org> ---
This works for me for the full testcase.
a) accept pseudos during lra_in_progress only when they're allocated to the
   right hardreg
b) but _only_ do (a) if the pseudo is not one of those generated _during_ LRA
   (the >= lra_new_regno_start test)
c) when base+disp (and base being allocated the wrong class) needs
   to be reloaded into a new reg, then accept the base as deconstructed,
   don't insist on base and base_term being the same

Case (c) is for insns like the problematic one, where the address needs to be
reloaded for whatever reason.

We have for instance: 
  (insn 49 48 52 6 (set (reg/v:SI 96 [ __y0 ])
        (plus:SI (plus:SI (sign_extend:SI (reg/v:HI 134 [ y ]))
                (reg:SI 144))
            (const_int 1468000 [0x166660]))) "../../include/chrono":1768:18 421
{*lea}

The address operand here is
  (plus:SI (plus:SI (sign_extend:SI (reg/v:HI 134 [ y ]))
                (reg:SI 144))
            (const_int 1468000 [0x166660]))
and decomposition makes ad->base be '(sign_extend:SI (reg/v:HI 134 [ y ]))'
(and hence ad->base_term be '(reg/v:HI 134 [ y ])').  That's suboptimal but
okay.  Further, this base+index+disp operand needs reloading (due to the
suboptimal decomposition and hence suboptimal register class assignment).

So LRA wants to reload base+disp (i.e. (sign_extend:SI (reg/v:HI 134 [ y ]))
plus (const_int 1468000 [0x166660])), via base_plus_disp_to_reg(), but
for whatever reason insists on the base being the same as the base_term,
i.e. be a simple pseudo only.

But in this case it's completely fine (and correct) to just form the
plus of the given base plus offset.  (As I don't know the reason for the
assert it's of course quite possible that this will create problems in other
cases).

I haven't checked more that just compilation of the large and small testcases
here.  Probably stuff is miscompiled.  I lack an overview of how LRA is
supposed
to work in presence of more complicated address forms given that it doesn't
call the backend with any strict checking.

----

diff --git a/gcc/config/m68k/m68k.cc b/gcc/config/m68k/m68k.cc
index 79ba4d5343c..650084566e2 100644
--- a/gcc/config/m68k/m68k.cc
+++ b/gcc/config/m68k/m68k.cc
@@ -306,8 +306,8 @@ static machine_mode m68k_c_mode_for_floating_type (enum tre
 #define TARGET_ASM_OUTPUT_DWARF_DTPREL m68k_output_dwarf_dtprel
 #endif

-#undef TARGET_LRA_P
-#define TARGET_LRA_P hook_bool_void_false
+//#undef TARGET_LRA_P
+//#define TARGET_LRA_P hook_bool_void_false

 #undef TARGET_LEGITIMATE_ADDRESS_P
 #define TARGET_LEGITIMATE_ADDRESS_P    m68k_legitimate_address_p
@@ -2026,20 +2026,27 @@ m68k_output_bftst (rtx zxop0, rtx zxop1, rtx zxop2, rtx
   return code;
 }
 ^L
+extern int lra_new_regno_start;
 /* Return true if X is a legitimate base register.  STRICT_P says
    whether we need strict checking.  */

 bool
 m68k_legitimate_base_reg_p (rtx x, bool strict_p)
 {
+  int regno;
   /* Allow SUBREG everywhere we allow REG.  This results in better code.  */
   if (!strict_p && GET_CODE (x) == SUBREG)
     x = SUBREG_REG (x);

-  return (REG_P (x)
-         && (strict_p
-             ? REGNO_OK_FOR_BASE_P (REGNO (x))
-             : REGNO_OK_FOR_BASE_NONSTRICT_P (REGNO (x))));
+  if (!REG_P (x))
+    return false;
+  regno = REGNO (x);
+  if (lra_in_progress && regno >= lra_new_regno_start)
+    return true;
+
+  return (strict_p || lra_in_progress
+         ? REGNO_OK_FOR_BASE_P (regno)
+         : REGNO_OK_FOR_BASE_NONSTRICT_P (regno));
 }

 /* Return true if X is a legitimate index register.  STRICT_P says
@@ -2048,13 +2055,19 @@ m68k_legitimate_base_reg_p (rtx x, bool strict_p)
 bool
 m68k_legitimate_index_reg_p (rtx x, bool strict_p)
 {
+  int regno;
   if (!strict_p && GET_CODE (x) == SUBREG)
     x = SUBREG_REG (x);

-  return (REG_P (x)
-         && (strict_p
-             ? REGNO_OK_FOR_INDEX_P (REGNO (x))
-             : REGNO_OK_FOR_INDEX_NONSTRICT_P (REGNO (x))));
+  if (!REG_P (x))
+    return false;
+  regno = REGNO (x);
+  if (lra_in_progress && regno >= lra_new_regno_start)
+    return true;
+
+  return (strict_p || lra_in_progress
+         ? REGNO_OK_FOR_INDEX_P (regno)
+         : REGNO_OK_FOR_INDEX_NONSTRICT_P (regno));
 }

 /* Return true if X is a legitimate index expression for a (d8,An,Xn) or
diff --git a/gcc/lra-constraints.cc b/gcc/lra-constraints.cc
index 92b343fa99a..4ccab7e3395 100644
--- a/gcc/lra-constraints.cc
+++ b/gcc/lra-constraints.cc
@@ -3473,12 +3473,11 @@ base_plus_disp_to_reg (struct address_info *ad, rtx dis
   enum reg_class cl;
   rtx new_reg;

-  lra_assert (ad->base == ad->base_term);
   cl = base_reg_class (ad->mode, ad->as, ad->base_outer_code,
                       get_index_code (ad));
-  new_reg = lra_create_new_reg (GET_MODE (*ad->base_term), NULL_RTX, cl, NULL,
+  new_reg = lra_create_new_reg (GET_MODE (*ad->base), NULL_RTX, cl, NULL,
                                "base + disp");
-  lra_emit_add (new_reg, *ad->base_term, disp);
+  lra_emit_add (new_reg, *ad->base, disp);
   return new_reg;
 }

Reply via email to