ix86_split_stlf_stall_load splits a V2DF load from a PARM_DECL into
movlpd + movhpd, which needs the load address offset by 8.  When the
original address already uses the largest encodable displacement, e.g.

  (mem/c:V2DF (plus:DI (reg/f:DI 7 sp)
                       (const_int 2147483640 [0x7ffffff8])))

adding 8 gives 0x80000000, which is out of range for the signed 32-bit
displacement field of an x86 address, and adjust_address ICEs in
change_address_1 since the address can no longer be validated after
reload.  Skip the split in that case.

Boostrapped and regtested on x86_64-pc-linux-gnu{-m32,}.
Ok?

gcc/ChangeLog:

        PR target/127500
        * config/i386/i386.cc (ix86_split_stlf_stall_load): Don't split
        the load when the address adjusted by 8 is not a valid memory
        address.

gcc/testsuite/ChangeLog:

        PR target/127500
        * gcc.target/i386/pr127500.c: New test.
---
 gcc/config/i386/i386.cc                  | 12 +++++++++++-
 gcc/testsuite/gcc.target/i386/pr127500.c |  8 ++++++++
 2 files changed, 19 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/pr127500.c

diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index bbb60163a75..29e1d2c5808 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -25083,7 +25083,17 @@ ix86_split_stlf_stall_load ()
             register.  */
          || GET_MODE (src) != E_V2DFmode
          || !MEM_EXPR (src)
-         || TREE_CODE (get_base_address (MEM_EXPR (src))) != PARM_DECL)
+         || TREE_CODE (get_base_address (MEM_EXPR (src))) != PARM_DECL
+         /* Avoid invalid memory address.
+            i.e.
+            (mem/c:V2DF (plus:DI (reg/f:DI 7 sp)
+                                 (const_int 2147483640 [0x7ffffff8])))
+            Adjusting it by 8 puts the displacement at 0x80000000, out of
+            range for the signed 32-bit field an x86 address can encode.  */
+         || !memory_address_addr_space_p (DFmode,
+                                          XEXP (adjust_address_nv (src, DFmode,
+                                                                   8), 0),
+                                          MEM_ADDR_SPACE (src)))
        continue;
 
       rtx zero = CONST0_RTX (V2DFmode);
diff --git a/gcc/testsuite/gcc.target/i386/pr127500.c 
b/gcc/testsuite/gcc.target/i386/pr127500.c
new file mode 100644
index 00000000000..cde6058fd6f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr127500.c
@@ -0,0 +1,8 @@
+/* { dg-do compile  { target { ! ia32 } } } */
+/* { dg-options "-msse2 -O2" } */
+
+typedef double v2df __attribute__((vector_size (16)));
+
+struct big { char pad[0x7FFFFFF0]; v2df v; };
+
+v2df f (struct big b) { return b.v; }
-- 
2.34.1

Reply via email to