On Wed, 3 Jul 2024, Jakub Jelinek wrote:

> On Tue, Jun 11, 2024 at 01:20:50PM +0200, Richard Biener wrote:
> > When the operand is gimplified to an extract of a register or a
> > register we have to disallow memory as we otherwise fail to
> > gimplify it properly.  Instead of
> > 
> >   __asm__("" : "=rm" __imag <r>);
> > 
> > we want
> > 
> >   __asm__("" : "=rm" D.2772);
> >   _1 = REALPART_EXPR <r>;
> >   r = COMPLEX_EXPR <_1, D.2772>;
> > 
> > otherwise SSA rewrite will fail and generate wrong code with 'r'
> > left bare in the asm output.
> > 
> > Bootstrap and regtest in progress on x86_64-unknown-linux-gnu.
> > 
> > I've made the testcase hopefully generic enough (the bug used =X
> > which I'm not sure is portable - I've used _Complex int so 'r'
> > has a chance to work).
> 
> > --- a/gcc/gimplify.cc
> > +++ b/gcc/gimplify.cc
> > @@ -7044,6 +7044,22 @@ gimplify_asm_expr (tree *expr_p, gimple_seq *pre_p, 
> > gimple_seq *post_p)
> >       ret = tret;
> >     }
> >  
> > +      /* If the gimplified operand is a register we do not allow memory.  
> > */
> > +      if (allows_mem
> > +     && (is_gimple_reg (TREE_VALUE (link))
> > +         || (handled_component_p (TREE_VALUE (link))
> > +             && is_gimple_reg (TREE_OPERAND (TREE_VALUE (link), 0)))))
> > +   {
> > +     if (allows_reg)
> > +       allows_mem = 0;
> > +     else
> > +       {
> > +         error ("impossible constraint in %<asm%>");
> > +         error ("non-memory output %d must stay in memory", i);
> > +         return GS_ERROR;
> 
> Does this else part ever trigger or could it be just gcc_assert (allows_reg)?

I've added this just for completeness, so I think I can make it an
assert if we consider this invalid GENERIC.

> E.g. C FE build_asm_expr has
>                 /* If the operand is going to end up in memory,
>                    mark it addressable.  */
>                 if (!allows_reg && !c_mark_addressable (output))
> Or C++ FE finish_asm_stmt:
>               /* If the operand is going to end up in memory,
>                  mark it addressable.  */
>               if (!allows_reg && !cxx_mark_addressable (*op))
> 
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/pr115426.c
> > @@ -0,0 +1,9 @@
> > +/* { dg-do compile } */
> > +/* { dg-options "-std=gnu11" } */
> > +
> > +_Complex int fcs()
> > +{
> > +  _Complex int r;
> 
> It would be useful to initialize r or at least __real__ r
> before the asm as we return it whole and I think the bug
> should trigger with that too.

The bug triggers also for

_Complex int fcs (_Complex int r)
{
  __asm__("" : "=rm" (__imag__ r));
  return r;
}


> > +  __asm__("" : "=rm" (__imag__ r));
> > +  return r;
> > +}
> 
> Also, it would be nice to cover also the "=m" case in another
> function to make sure that still works.

Done.

I'm re-testing the following.

Richard.

>From 40023cac83562a1451aba550533d042fec1c144e Mon Sep 17 00:00:00 2001
From: Richard Biener <rguent...@suse.de>
Date: Tue, 11 Jun 2024 13:11:08 +0200
Subject: [PATCH] middle-end/115426 - wrong gimplification of "rm" asm output
 operand
To: gcc-patches@gcc.gnu.org

When the operand is gimplified to an extract of a register or a
register we have to disallow memory as we otherwise fail to
gimplify it properly.  Instead of

  __asm__("" : "=rm" __imag <r>);

we want

  __asm__("" : "=rm" D.2772);
  _1 = REALPART_EXPR <r>;
  r = COMPLEX_EXPR <_1, D.2772>;

otherwise SSA rewrite will fail and generate wrong code with 'r'
left bare in the asm output.

        PR middle-end/115426
        * gimplify.cc (gimplify_asm_expr): Handle "rm" output
        constraint gimplified to a register (operation).

        * gcc.dg/pr115426.c: New testcase.
---
 gcc/gimplify.cc                 | 10 ++++++++++
 gcc/testsuite/gcc.dg/pr115426.c | 14 ++++++++++++++
 2 files changed, 24 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/pr115426.c

diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index 04875e8df29..13189ddee99 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -7044,6 +7044,16 @@ gimplify_asm_expr (tree *expr_p, gimple_seq *pre_p, 
gimple_seq *post_p)
          ret = tret;
        }
 
+      /* If the gimplified operand is a register we do not allow memory.  */
+      if (allows_mem
+         && (is_gimple_reg (TREE_VALUE (link))
+             || (handled_component_p (TREE_VALUE (link))
+                 && is_gimple_reg (TREE_OPERAND (TREE_VALUE (link), 0)))))
+       {
+         gcc_assert (allows_reg);
+         allows_mem = 0;
+       }
+
       /* If the constraint does not allow memory make sure we gimplify
          it to a register if it is not already but its base is.  This
         happens for complex and vector components.  */
diff --git a/gcc/testsuite/gcc.dg/pr115426.c b/gcc/testsuite/gcc.dg/pr115426.c
new file mode 100644
index 00000000000..02bfc3f21fa
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr115426.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-std=gnu11" } */
+
+_Complex int fcs (_Complex int r)
+{
+  __asm__("" : "=rm" (__imag__ r));
+  return r;
+}
+
+_Complex int fcs2 (_Complex int r)
+{
+  __asm__("" : "=m" (__imag__ r));
+  return r;
+}
-- 
2.35.3

Reply via email to