]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
middle-end/113622 - handle store with variable index to register
authorRichard Biener <rguenther@suse.de>
Mon, 29 Jan 2024 09:24:39 +0000 (10:24 +0100)
committerRichard Biener <rguenther@suse.de>
Mon, 29 Jan 2024 13:25:10 +0000 (14:25 +0100)
The following implements storing to a non-MEM_P with a variable
offset.  We usually avoid this by forcing expansion to memory but
this doesn't work for hard register variables.  The solution is
to spill and operate on the stack.

PR middle-end/113622
* expr.cc (expand_assignment): Spill hard registers if
we index them with a variable offset.

* gcc.target/i386/pr113622-2.c: New testcase.
* gcc.target/i386/pr113622-3.c: Likewise.

gcc/expr.cc
gcc/testsuite/gcc.target/i386/pr113622-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/pr113622-3.c [new file with mode: 0644]

index ee822c11dce632bd7901a3ad9f045c4ba108859d..fc5e998e3292063d093af4b54fb0e957ea433431 100644 (file)
@@ -6061,6 +6061,7 @@ expand_assignment (tree to, tree from, bool nontemporal)
            to_rtx = adjust_address (to_rtx, BLKmode, 0);
        }
  
+      rtx stemp = NULL_RTX, old_to_rtx = NULL_RTX;
       if (offset != 0)
        {
          machine_mode address_mode;
@@ -6070,9 +6071,22 @@ expand_assignment (tree to, tree from, bool nontemporal)
            {
              /* We can get constant negative offsets into arrays with broken
                 user code.  Translate this to a trap instead of ICEing.  */
-             gcc_assert (TREE_CODE (offset) == INTEGER_CST);
-             expand_builtin_trap ();
-             to_rtx = gen_rtx_MEM (BLKmode, const0_rtx);
+             if (TREE_CODE (offset) == INTEGER_CST)
+               {
+                 expand_builtin_trap ();
+                 to_rtx = gen_rtx_MEM (BLKmode, const0_rtx);
+               }
+             /* Else spill for variable offset to the destination.  We expect
+                to run into this only for hard registers.  */
+             else
+               {
+                 gcc_assert (VAR_P (tem) && DECL_HARD_REGISTER (tem));
+                 stemp = assign_stack_temp (GET_MODE (to_rtx),
+                                            GET_MODE_SIZE (GET_MODE (to_rtx)));
+                 emit_move_insn (stemp, to_rtx);
+                 old_to_rtx = to_rtx;
+                 to_rtx = stemp;
+               }
            }
 
          offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM);
@@ -6305,6 +6319,9 @@ expand_assignment (tree to, tree from, bool nontemporal)
                                  bitregion_start, bitregion_end,
                                  mode1, from, get_alias_set (to),
                                  nontemporal, reversep);
+         /* Move the temporary storage back to the non-MEM_P.  */
+         if (stemp)
+           emit_move_insn (old_to_rtx, stemp);
        }
 
       if (result)
diff --git a/gcc/testsuite/gcc.target/i386/pr113622-2.c b/gcc/testsuite/gcc.target/i386/pr113622-2.c
new file mode 100644 (file)
index 0000000..7bcc12a
--- /dev/null
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-msse -w" } */
+
+typedef double __attribute__ ((vector_size (16))) vec;
+register vec a asm("xmm5"), b asm("xmm6"), c asm("xmm7");
+
+void
+test (void)
+{
+  for (int i = 0; i < 2; i++)
+    c[i] = a[i] < b[i] ? 0.1 : 0.2;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr113622-3.c b/gcc/testsuite/gcc.target/i386/pr113622-3.c
new file mode 100644 (file)
index 0000000..ca79d4a
--- /dev/null
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-msse" } */
+
+typedef double __attribute__ ((vector_size (16))) vec;
+
+void
+test (void)
+{
+  register vec a asm("xmm5"), b asm("xmm6"), c asm("xmm7");
+  for (int i = 0; i < 2; i++)
+    c[i] = a[i] < b[i] ? 0.1 : 0.2;
+}