aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Biener <rguenther@suse.de>2024-01-29 10:24:39 +0100
committerRichard Biener <rguenther@suse.de>2024-01-29 14:25:10 +0100
commit0f7945417f913c85bd556904c0c4e7bf77793488 (patch)
tree24700b01ee855989ea99bc6a68ddf6cff989ed31
parent96bc048d78f804bac0fa7b2ca3b6dd3a04c68217 (diff)
downloadgcc-0f7945417f913c85bd556904c0c4e7bf77793488.zip
gcc-0f7945417f913c85bd556904c0c4e7bf77793488.tar.gz
gcc-0f7945417f913c85bd556904c0c4e7bf77793488.tar.bz2
middle-end/113622 - handle store with variable index to register
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.
-rw-r--r--gcc/expr.cc23
-rw-r--r--gcc/testsuite/gcc.target/i386/pr113622-2.c12
-rw-r--r--gcc/testsuite/gcc.target/i386/pr113622-3.c12
3 files changed, 44 insertions, 3 deletions
diff --git a/gcc/expr.cc b/gcc/expr.cc
index ee822c1..fc5e998 100644
--- a/gcc/expr.cc
+++ b/gcc/expr.cc
@@ -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
index 0000000..7bcc12a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr113622-2.c
@@ -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
index 0000000..ca79d4a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr113622-3.c
@@ -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;
+}