get_memreg_parts can return a memory base other than a REG, when the
memory address in question is a PLUS with other than a REG as its
first operand.  This leads to an ICE with rtl checking enabled on the
following, since the callers of get_memreg_parts expect a REG.

(gdb) p debug_rtx(addr_rtx)
(plus:DI (plus:DI (reg/f:DI 9 9 [162])
        (const_int 65536 [0x10000]))
    (const_int -31752 [0xffffffffffff83f8]))

Bootstrapped and regression tested powerpc64-linux.  OK for stage4?

        PR target/65182
        * config/rs6000/rs6000.c (get_memref_parts): Only return true
        when *base is a reg.  Handle nested plus addresses.  Simplify
        pre_modify test.

Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c  (revision 220902)
+++ gcc/config/rs6000/rs6000.c  (working copy)
@@ -27172,25 +27172,21 @@ get_memref_parts (rtx mem, rtx *base, HOST_WIDE_IN
   else
     return false;
 
-  if (GET_CODE (XEXP (mem, 0)) == PRE_MODIFY)
-    addr_rtx = XEXP (XEXP (mem, 0), 1);
-  else
-    addr_rtx = (XEXP (mem, 0));
+  addr_rtx = (XEXP (mem, 0));
+  if (GET_CODE (addr_rtx) == PRE_MODIFY)
+    addr_rtx = XEXP (addr_rtx, 1);
 
-  if (GET_CODE (addr_rtx) == REG)
+  *offset = 0;
+  while (GET_CODE (addr_rtx) == PLUS
+        && CONST_INT_P (XEXP (addr_rtx, 1)))
     {
-      *base = addr_rtx;
-      *offset = 0;
+      *offset += INTVAL (XEXP (addr_rtx, 1));
+      addr_rtx = XEXP (addr_rtx, 0);
     }
-  else if (GET_CODE (addr_rtx) == PLUS
-          && CONST_INT_P (XEXP (addr_rtx, 1)))
-    {
-      *base = XEXP (addr_rtx, 0);
-      *offset = INTVAL (XEXP (addr_rtx, 1));
-    }
-  else
+  if (!REG_P (addr_rtx))
     return false;
 
+  *base = addr_rtx;
   return true;
 }
 

-- 
Alan Modra
Australia Development Lab, IBM

Reply via email to