]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Handle arithmetic on eliminated address indices [PR116413]
authorRichard Sandiford <richard.sandiford@arm.com>
Tue, 27 Aug 2024 08:48:28 +0000 (09:48 +0100)
committerRichard Sandiford <richard.sandiford@arm.com>
Tue, 27 Aug 2024 08:48:28 +0000 (09:48 +0100)
This patch fixes gcc.c-torture/compile/opout.c for m68k with LRA
enabled.  The test has:

...
z (a, b)
{
  return (int) &a + (int) &b + (int) x + (int) z;
}

so it adds the address of two incoming arguments.  This ends up
being treated as an LEA in which the "index" is the incoming
argument pointer, which the LEA multiplies by 2.  The incoming
argument pointer is then eliminated, leading to:

(plus:SI (plus:SI (ashift:SI (plus:SI (reg/f:SI 24 %argptr)
                (const_int -4 [0xfffffffffffffffc]))
            (const_int 1 [0x1]))
        (reg/f:SI 41 [ _6 ]))
    (const_int 20 [0x14]))

In the address_info scheme, the innermost plus has to be treated
as the index "term", since that's the thing that's subject to
index_reg_class.

gcc/
PR middle-end/116413
* rtl.h (address_info): Update commentary.
* rtlanal.cc (valid_base_or_index_term_p): New function, split
out from...
(get_base_term, get_index_term): ...here.  Handle elimination PLUSes.

gcc/rtl.h
gcc/rtlanal.cc

index 2370d6081614ba9e2f12d77e56cd7a4a876548cf..1ef6432fd9c16927b221c5f52c36a68f362c91ea 100644 (file)
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -2225,11 +2225,21 @@ struct address_info {
        reloading.
 
      - *BASE is a variable expression representing a base address.
-       It contains exactly one REG, SUBREG or MEM, pointed to by BASE_TERM.
+       It contains exactly one "term", pointed to by BASE_TERM.
+       This term can be one of the following:
+
+       (1) a REG, or a SUBREG of a REG
+       (2) an eliminated REG (a PLUS of (1) and a constant)
+       (3) a MEM, or a SUBREG of a MEM
+       (4) a SCRATCH
+
+       This term is the one that base_reg_class constrains.
 
      - *INDEX is a variable expression representing an index value.
        It may be a scaled expression, such as a MULT.  It has exactly
-       one REG, SUBREG or MEM, pointed to by INDEX_TERM.
+       one "term", pointed to by INDEX_TERM.  The possible terms are
+       the same as for BASE.  This term is the one that index_reg_class
+       constrains.
 
      - *DISP is a constant, possibly mutated.  DISP_TERM points to the
        unmutated RTX_CONST_OBJ.  */
index 71207ee4f417ac40f8c8dea5dcda78956ef89108..8afbb32f2206096f094e92e9f7a615804a568b8e 100644 (file)
@@ -6494,6 +6494,25 @@ binary_scale_code_p (enum rtx_code code)
           || code == ROTATERT);
 }
 
+/* Return true if X appears to be a valid base or index term.  */
+static bool
+valid_base_or_index_term_p (rtx x)
+{
+  if (GET_CODE (x) == SCRATCH)
+    return true;
+  /* Handle what appear to be eliminated forms of a register.  If we reach
+     here, the elimination occurs outside of the outermost PLUS tree,
+     and so the elimination offset cannot be treated as a displacement
+     of the main address.  Instead, we need to treat the whole PLUS as
+     the base or index term.  The address can only be made legitimate by
+     reloading the PLUS.  */
+  if (GET_CODE (x) == PLUS && CONST_SCALAR_INT_P (XEXP (x, 1)))
+    x = XEXP (x, 0);
+  if (GET_CODE (x) == SUBREG)
+    x = SUBREG_REG (x);
+  return REG_P (x) || MEM_P (x);
+}
+
 /* If *INNER can be interpreted as a base, return a pointer to the inner term
    (see address_info).  Return null otherwise.  */
 
@@ -6502,10 +6521,7 @@ get_base_term (rtx *inner)
 {
   if (GET_CODE (*inner) == LO_SUM)
     inner = strip_address_mutations (&XEXP (*inner, 0));
-  if (REG_P (*inner)
-      || MEM_P (*inner)
-      || GET_CODE (*inner) == SUBREG
-      || GET_CODE (*inner) == SCRATCH)
+  if (valid_base_or_index_term_p (*inner))
     return inner;
   return 0;
 }
@@ -6519,10 +6535,7 @@ get_index_term (rtx *inner)
   /* At present, only constant scales are allowed.  */
   if (binary_scale_code_p (GET_CODE (*inner)) && CONSTANT_P (XEXP (*inner, 1)))
     inner = strip_address_mutations (&XEXP (*inner, 0));
-  if (REG_P (*inner)
-      || MEM_P (*inner)
-      || GET_CODE (*inner) == SUBREG
-      || GET_CODE (*inner) == SCRATCH)
+  if (valid_base_or_index_term_p (*inner))
     return inner;
   return 0;
 }