For an output operand whose constraint allows both a register and
memory (e.g. "=rm"), expand_asm_stmt only binds the operand directly
to the address of its underlying storage when the operand's value is
a bare, non-ADDR_EXPR-based MEM_REF or a plain, memory-resident DECL.
Every other lvalue -- most commonly a struct/union member, an array
element, or a complex number's real/imaginary part -- is instead
always routed through a fresh pseudo register that gets copied to the
real destination in a separate insn after the asm, even though
nothing about the constraint requires it.

Extend the set of output values eligible for direct addressing to
also cover COMPONENT_REF (except through a bit-field, which is not
byte-addressable and still needs the existing register-based
read-modify-write handling), ARRAY_REF, ARRAY_RANGE_REF, REALPART_EXPR
and IMAGPART_EXPR.

Assisted-by: Claude Sonnet 5

PR target/124209

gcc/ChangeLog:

* cfgexpand.cc (expand_asm_stmt): Also bind an output operand
directly to the address of its storage when its value is a
COMPONENT_REF (of a non-bit-field), ARRAY_REF, ARRAY_RANGE_REF,
REALPART_EXPR, or IMAGPART_EXPR and the constraint allows memory.

gcc/testsuite/ChangeLog:

* gcc.target/i386/pr124209-1.c: New test.
* gcc.target/i386/pr124209-2.c: New test.
* gcc.target/i386/pr124209-3.c: New test.
* gcc.target/i386/pr124209-4.c: New test.
* gcc.target/i386/pr124209-5.c: New test.

Bootstrapped and regression tested on x86_64-linux-gnu {,-m32}.

OK for trunk?

Uros.
diff --git a/gcc/cfgexpand.cc b/gcc/cfgexpand.cc
index 4bd311b11a3..317ccce7bb2 100644
--- a/gcc/cfgexpand.cc
+++ b/gcc/cfgexpand.cc
@@ -3672,8 +3672,14 @@ expand_asm_stmt (gasm *stmt)
       generating_concat_p = 0;
 
       gcc_assert (TREE_CODE (val) != INDIRECT_REF);
-      if (((TREE_CODE (val) == MEM_REF
-           && TREE_CODE (TREE_OPERAND (val, 0)) != ADDR_EXPR)
+      if ((((TREE_CODE (val) == MEM_REF
+            && TREE_CODE (TREE_OPERAND (val, 0)) != ADDR_EXPR)
+           || (TREE_CODE (val) == COMPONENT_REF
+               && ! DECL_BIT_FIELD (TREE_OPERAND (val, 1)))
+           || TREE_CODE (val) == ARRAY_REF
+           || TREE_CODE (val) == ARRAY_RANGE_REF
+           || TREE_CODE (val) == REALPART_EXPR
+           || TREE_CODE (val) == IMAGPART_EXPR)
           && allows_mem)
          || (DECL_P (val)
              && (allows_mem || REG_P (DECL_RTL (val)))
diff --git a/gcc/testsuite/gcc.target/i386/pr124209-1.c 
b/gcc/testsuite/gcc.target/i386/pr124209-1.c
new file mode 100644
index 00000000000..4611b137e91
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr124209-1.c
@@ -0,0 +1,16 @@
+/* PR target/124209 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -masm=att" } */
+
+struct s {
+  short a;
+  short b;
+} m;
+
+void
+foo (void)
+{
+  asm ("movw %%fs, %0" : "=rm" (m.b));
+}
+
+/* { dg-final { scan-assembler-times "movw" 1 } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr124209-2.c 
b/gcc/testsuite/gcc.target/i386/pr124209-2.c
new file mode 100644
index 00000000000..177549bae96
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr124209-2.c
@@ -0,0 +1,16 @@
+/* PR target/124209 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -masm=att" } */
+
+struct s {
+  short a;
+  short b;
+};
+
+void
+foo (struct s *m)
+{
+  asm ("movw %%fs, %0" : "=rm" (m->b));
+}
+
+/* { dg-final { scan-assembler-times "movw" 1 } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr124209-3.c 
b/gcc/testsuite/gcc.target/i386/pr124209-3.c
new file mode 100644
index 00000000000..813029c7c1b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr124209-3.c
@@ -0,0 +1,13 @@
+/* PR target/124209 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -masm=att" } */
+
+short m[8];
+
+void
+foo (__SIZE_TYPE__ i)
+{
+  asm ("movw %%fs, %0" : "=rm" (m[i]));
+}
+
+/* { dg-final { scan-assembler-times "movw" 1 } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr124209-4.c 
b/gcc/testsuite/gcc.target/i386/pr124209-4.c
new file mode 100644
index 00000000000..60c08432c75
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr124209-4.c
@@ -0,0 +1,19 @@
+/* PR target/124209 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -masm=att" } */
+
+_Complex short m;
+
+void
+foo (void)
+{
+  asm ("movw %%fs, %0" : "=rm" (__real__ m));
+}
+
+void
+bar (void)
+{
+  asm ("movw %%fs, %0" : "=rm" (__imag__ m));
+}
+
+/* { dg-final { scan-assembler-times "movw" 2 } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr124209-5.c 
b/gcc/testsuite/gcc.target/i386/pr124209-5.c
new file mode 100644
index 00000000000..433379a890b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr124209-5.c
@@ -0,0 +1,17 @@
+/* PR target/124209 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -masm=att" } */
+
+struct s {
+  int a:5;
+  int b:16;
+  int c;
+} m;
+
+void
+foo (void)
+{
+  asm ("movw %%fs, %0" : "=rm" (m.b));
+}
+
+/* { dg-final { scan-assembler-times "sall" 1 } } */

Reply via email to