On Thu, Jul 2, 2026 at 10:26 AM Stefan Schulze Frielinghaus
<[email protected]> wrote:
>
> On Thu, Jul 02, 2026 at 09:29:07AM +0200, Richard Biener wrote:
> > On Wed, Jul 1, 2026 at 9:55 PM Stefan Schulze Frielinghaus
> > <[email protected]> wrote:
> > >
> > > On Tue, Jun 30, 2026 at 02:53:32PM +0200, Richard Biener wrote:
> > > > On Sun, Jun 28, 2026 at 2:25 PM Stefan Schulze Frielinghaus
> > > > <[email protected]> wrote:
> > > > >
> > > > > From: Stefan Schulze Frielinghaus <[email protected]>
> > > > >
> > > > > This is a follow-up to
> > > > > https://gcc.gnu.org/pipermail/gcc-patches/2026-May/717805.html
> > > > > with the following changes:
> > > > >
> > > > > - Make usage of uninitialized register asm input operands undefined by
> > > > >   removing the hack during gimplify_asm_expr() and document it as
> > > > >   undefined.
> > > > > - Remove redundant helper stmt.cc:rclass_entails_registers and use
> > > > >   existing function in_hard_reg_set_p instead which computes the same.
> > > > > - Add testsuite/gcc.dg/asm-hard-reg-strict-6.c in order to test for an
> > > > >   uninit diagnostics.  Of course, in case of -fno-strict-extended-asm
> > > > >   -Wstrict-extended-asm -W{maybe-,}uninitialized we still don't get a
> > > > >   diagnostics.
> > > > >
> > > > > Cheers,
> > > > > Stefan
> > > > >
> > > > > -- 8< --
> > > > >
> > > > > Currently local register asm assignments materialize during expand 
> > > > > into
> > > > > assignments utilizing hard registers.  Since prior register 
> > > > > allocation,
> > > > > hard registers or more precisely objects residing in hard registers 
> > > > > are
> > > > > not tracked individually, those are subject to be clobbered.  Well 
> > > > > known
> > > > > and documented are function calls which may clobber hard registers 
> > > > > used
> > > > > for register asm objects.  For example, compiling on aarch64
> > > > >
> > > > > register int x asm ("x0") = 0x123;
> > > > > register int y asm ("x1") = *ptr;
> > > > >
> > > > > using address sanitizers results after expand in
> > > > >
> > > > > x0:SI=0x123
> > > > > x0:DI=r104:DI
> > > > > call [`__asan_load4'] argc:0
> > > > > x1:SI=[r104:DI]
> > > > >
> > > > > The implicit function call added by the address sanitizer clobbers
> > > > > argument register x0 which was previously set for the register asm
> > > > > object.
> > > > >
> > > > > With the advent of hard register constraints, this can be overcome.
> > > > > Instead of expanding a register asm assignment directly into a hard
> > > > > register assignment, keep the register asm object in a pseudo for as
> > > > > long as possible and use a hard register constraint in Extended Asm
> > > > > statements which ensures that the object is finally allocated the
> > > > > respective hard register.  Since local register asm is supposed to 
> > > > > have
> > > > > an effect only for Extended Asm statements, this coincides with hard
> > > > > register constraints which materialize for the respective insn.
> > > > >
> > > > > This patch adds the feature of rewriting local register asm into code
> > > > > which exploits hard register constraints.  For example
> > > > >
> > > > > register int global asm ("r3");
> > > > >
> > > > > int foo (int x0)
> > > > > {
> > > > >   register int x asm ("r4") = x0;
> > > > >   register int y asm ("r5");
> > > > >
> > > > >   asm ("bar\t%0,%1,%2" : "=r" (x) : "0" (x), "r" (global));
> > > > >   x += 42;
> > > > >   asm ("baz\t%0,%1" : "=r" (y) : "r" (x));
> > > > >
> > > > >   return y;
> > > > > }
> > > > >
> > > > > is rewritten during gimplification into
> > > > >
> > > > > register int global asm ("r3");
> > > > >
> > > > > int foo (int x0)
> > > > > {
> > > > >   int x = x0;
> > > > >   int y;
> > > > >
> > > > >   asm ("bar\t%0,%1,%2" : "={r4}" (x) : "0" (x), "r" (global));
> > > > >   x += 42;
> > > > >   asm ("baz\t%0,%1" : "={r5}" (y) : "{r4}" (x));
> > > > >
> > > > >   return y;
> > > > > }
> > > > >
> > > > > The resulting code solely relies on hard register constraints modulo
> > > > > global register asm.  Thus, for GIMPLE we fall back to ordinary
> > > > > SSA_NAMES and finally for RTL to pseudos.
> > > > >
> > > > > Note, since hard register constraints are more strict in order to
> > > > > prevent subtle bugs, this in turn means that certain programs are not
> > > > > valid after register asm demotion anymore.  For example,
> > > > >
> > > > > register int x asm ("r5") = 42;
> > > > > asm ("" : "+r" (x) : "r" (x));
> > > > >
> > > > > is rewritten into
> > > > >
> > > > > int x = 42;
> > > > > asm ("" : "={r5}" (x) : "0" (x), "{r5}" (x));
> > > > >
> > > > > Two inputs refer to the very same register which is invalid when using
> > > > > hard register constraints.  Therefore, currently the transformation is
> > > > > hidden behind new flag -fstrict-extended-asm which is disabled by
> > > > > default.  This patch also adds the new warning -Wstrict-extended-asm
> > > > > which is enabled by -Wall in order to diagnose cases for which
> > > > > -fstrict-extended-asm errors out.
> > > > >
> > > > > Another incompatibility which is worthwhile to mention are usages of
> > > > > uninitialized register asm input operands which is undefined for
> > > > > -fstrict-extended-asm.  In case -W{maybe-,}uninitialized is specified 
> > > > > a
> > > > > diagnostics may be emitted.
> > > > >
> > > > > In order to automatically rewrite register asm into hard register
> > > > > constraints, it is crucial that the register referred to by the 
> > > > > register
> > > > > asm operand is entailed in the register class of the corresponding
> > > > > constraint of the operand.  If this is not the case, then error out in
> > > > > case of -fstrict-extended-asm, or in case of -fno-strict-extended-asm
> > > > > -Wstrict-extended-asm emit a diagnostics.
> > > >
> > > > Some comments inline
> > > >
> > > > > gcc/ChangeLog:
> > > > >
> > > > >         * common.opt (Wstrict-extended-asm): New warning.
> > > > >         (fstrict-extended-asm) New flag.
> > > > >         * doc/invoke.texi: Document new warning and flag.
> > > > >         * gimplify.cc (gimplify_demote_register_asm): Helper for
> > > > >         gimplify_asm_expr in order to prepare demotion of a register
> > > > >         asm object into an ordinary one by rewriting constraints.
> > > > >         (gimplify_asm_expr): Add diagnostics logic for new warning.
> > > > >         (gimplify_body): Cleanup helper hash set.
> > > > >         * stmt.cc (parse_output_constraint): Diagnose if register asm 
> > > > > and
> > > > >         constraint do not coincide.
> > > > >         (parse_input_constraint): Ditto.
> > > > >
> > > > > gcc/testsuite/ChangeLog:
> > > > >
> > > > >         * gcc.dg/asm-hard-reg-strict-1.c: New test.
> > > > >         * gcc.dg/asm-hard-reg-strict-2.c: New test.
> > > > >         * gcc.dg/asm-hard-reg-strict-3.c: New test.
> > > > >         * gcc.dg/asm-hard-reg-strict-4.c: New test.
> > > > >         * gcc.dg/asm-hard-reg-strict-5.c: New test.
> > > > >         * gcc.dg/asm-hard-reg-strict-6.c: New test.
> > > > > ---
> > > > >  gcc/common.opt                               |   8 +
> > > > >  gcc/doc/invoke.texi                          |  63 +++++-
> > > > >  gcc/gimplify.cc                              | 213 
> > > > > +++++++++++++++----
> > > > >  gcc/stmt.cc                                  |  32 +++
> > > > >  gcc/testsuite/gcc.dg/asm-hard-reg-strict-1.c |  51 +++++
> > > > >  gcc/testsuite/gcc.dg/asm-hard-reg-strict-2.c |  54 +++++
> > > > >  gcc/testsuite/gcc.dg/asm-hard-reg-strict-3.c |  22 ++
> > > > >  gcc/testsuite/gcc.dg/asm-hard-reg-strict-4.c |  25 +++
> > > > >  gcc/testsuite/gcc.dg/asm-hard-reg-strict-5.c |  65 ++++++
> > > > >  gcc/testsuite/gcc.dg/asm-hard-reg-strict-6.c |  13 ++
> > > > >  10 files changed, 503 insertions(+), 43 deletions(-)
> > > > >  create mode 100644 gcc/testsuite/gcc.dg/asm-hard-reg-strict-1.c
> > > > >  create mode 100644 gcc/testsuite/gcc.dg/asm-hard-reg-strict-2.c
> > > > >  create mode 100644 gcc/testsuite/gcc.dg/asm-hard-reg-strict-3.c
> > > > >  create mode 100644 gcc/testsuite/gcc.dg/asm-hard-reg-strict-4.c
> > > > >  create mode 100644 gcc/testsuite/gcc.dg/asm-hard-reg-strict-5.c
> > > > >  create mode 100644 gcc/testsuite/gcc.dg/asm-hard-reg-strict-6.c
> > > > >
> > > > > diff --git a/gcc/common.opt b/gcc/common.opt
> > > > > index 3ad1444cc88..933f791aeb4 100644
> > > > > --- a/gcc/common.opt
> > > > > +++ b/gcc/common.opt
> > > > > @@ -936,6 +936,10 @@ Wzero-init-padding-bits=
> > > > >  Common Joined RejectNegative Enum(zero_init_padding_bits_kind) 
> > > > > Var(warn_zero_init_padding_bits) 
> > > > > Init(ZERO_INIT_PADDING_BITS_STANDARD) Warning
> > > > >  -Wzero-init-padding-bits=[standard|unions|all] Warn about 
> > > > > initializers that might not zero padding bits.
> > > > >
> > > > > +Wstrict-extended-asm
> > > > > +Common Var(warn_strict_extended_asm) Warning LangEnabledBy(C 
> > > > > C++,Wall)
> > > > > +Warn about constructs for which -fstrict-extended-asm fails.
> > > > > +
> > > > >  Xassembler
> > > > >  Driver Separate
> > > > >
> > > > > @@ -3588,6 +3592,10 @@ fverbose-asm
> > > > >  Common Var(flag_verbose_asm)
> > > > >  Add extra commentary to assembler output.
> > > > >
> > > > > +fstrict-extended-asm
> > > > > +Common Var(flag_strict_extended_asm) Init(0)
> > > > > +Apply strict rules for extended asm comprising hard register 
> > > > > constraint rules.
> > > > > +
> > > > >  fvisibility=
> > > > >  Common Joined RejectNegative Enum(symbol_visibility) 
> > > > > Var(default_visibility) Init(VISIBILITY_DEFAULT)
> > > > >  -fvisibility=[default|internal|hidden|protected]       Set the 
> > > > > default symbol visibility.
> > > > > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> > > > > index 6d1da9f610e..c98887cc5b3 100644
> > > > > --- a/gcc/doc/invoke.texi
> > > > > +++ b/gcc/doc/invoke.texi
> > > > > @@ -210,7 +210,7 @@ in the following sections.
> > > > >  -fpermitted-flt-eval-methods=@var{standard}
> > > > >  -fplan9-extensions  -fsigned-bitfields  -funsigned-bitfields
> > > > >  -fsigned-char  -funsigned-char  -fstrict-flex-arrays[=@var{n}]
> > > > > --fsso-struct=@var{endianness}  --ansi}
> > > > > +-fstrict-extended-asm -fsso-struct=@var{endianness}  --ansi}
> > > > >
> > > > >  @item C++ Language Options
> > > > >  @xref{C++ Dialect Options,,Options Controlling C++ Dialect}.
> > > > > @@ -448,7 +448,7 @@ Objective-C and Objective-C++ Dialects}.
> > > > >  -Wstrict-aliasing=@var{n}  -Wstrict-overflow  
> > > > > -Wstrict-overflow=@var{n}
> > > > >  -Wstring-compare
> > > > >  -Wno-stringop-overflow  -Wno-stringop-overread
> > > > > --Wno-stringop-truncation  -Wstrict-flex-arrays
> > > > > +-Wno-stringop-truncation  -Wstrict-flex-arrays -Wstrict-extended-asm
> > > > >  -Wsuggest-attribute=@var{attribute-name}
> > > > >  -Wswitch  -Wno-switch-bool  -Wswitch-default  -Wswitch-enum
> > > > >  -Wno-switch-outside-range  -Wno-switch-unreachable  -Wsync-nand
> > > > > @@ -2976,6 +2976,17 @@ The @option{-fstrict_flex_arrays} option 
> > > > > interacts with the
> > > > >  @option{-Wstrict-flex-arrays} option.  @xref{Warning Options}, for 
> > > > > more
> > > > >  information.
> > > > >
> > > > > +@opindex fstrict-extended-asm
> > > > > +@opindex fno-strict-extended-asm
> > > > > +@item -fstrict-extended-asm
> > > > > +Apply strict rules for extended @code{asm} (@pxref{Extended Asm}).  
> > > > > In
> > > > > +particular this means that local register @code{asm} operands must 
> > > > > follow the
> > > > > +rules for hard register constraints.  For example, don't allow 
> > > > > multiple input
> > > > > +operands to refer to the same register.  Note, any use of an 
> > > > > uninitialized
> > > > > +register asm input operand is undefined.  See also
> > > > > +@option{-Wstrict-extended-asm}.  This flag is currently disabled by 
> > > > > default and
> > > > > +will eventually be enabled by default in a future release.
> > > > > +
> > > > >  @opindex fsso-struct
> > > > >  @item -fsso-struct=@var{endianness}
> > > > >  Set the default scalar storage order of structures and unions to the
> > > > > @@ -8990,6 +9001,54 @@ This option is more effective when 
> > > > > @option{-ftree-vrp} is active (the
> > > > >  default for @option{-O2} and above) but some warnings may be 
> > > > > diagnosed
> > > > >  even without optimization.
> > > > >
> > > > > +@opindex Wstrict-extended-asm
> > > > > +@opindex Wno-strict-extended-asm
> > > > > +@item -Wstrict-extended-asm
> > > > > +Warn about extended @code{asm} (@pxref{Extended Asm}) usages which 
> > > > > could lead
> > > > > +to subtle bugs and for which @option{-fstrict-extended-asm} errors 
> > > > > out.  For
> > > > > +example, warn if an lvalue is used by multiple output operands:
> > > > > +
> > > > > +@smallexample
> > > > > +int x;
> > > > > +asm ("..." : "=r" (x), "=r" (x));
> > > > > +@end smallexample
> > > > > +
> > > > > +Both output operands get a different register assigned but outside 
> > > > > of the
> > > > > +extended @code{asm} only one is bound to @code{x}.
> > > > > +
> > > > > +Furthermore, warn about register @code{asm} usages, if multiple 
> > > > > operands refer
> > > > > +to the same register (including overlaps in case of register pairs).
> > > > > +
> > > > > +@smallexample
> > > > > +register int x asm ("r5") = 42;
> > > > > +register int y asm ("r5") = 24;
> > > > > +asm ("..." : "=r" (x) : "r" (x), "r" (y));
> > > > > +@end smallexample
> > > > > +
> > > > > +Here @code{x} and @code{y} refer to the same register @code{r5}.  
> > > > > Note, this also
> > > > > +includes more subtle cases as for example:
> > > > > +
> > > > > +@smallexample
> > > > > +register int x asm ("r5") = 42;
> > > > > +asm ("..." : "+r" (x) : "r" (x));
> > > > > +@end smallexample
> > > > > +
> > > > > +After multiplying out the in-out operand we are faced with two 
> > > > > inputs which
> > > > > +refer to the same register.  One time indirectly via @code{"0" (x)} 
> > > > > and the
> > > > > +other one directly via @code{"r" (x)}.
> > > > > +
> > > > > +Also diagnose if a register @code{asm} operand does not coincide 
> > > > > with its
> > > > > +corresponding constraint.  Assume in the following that @code{f5} is 
> > > > > a
> > > > > +floating-point register which is not entailed in the register class 
> > > > > associated
> > > > > +with constraint @code{r}.
> > > > > +
> > > > > +@smallexample
> > > > > +register float x asm ("f5");
> > > > > +asm ("..." : "=r" (x));
> > > > > +@end smallexample
> > > > > +
> > > > > +This indicates a subtle bug which is diagnosed.
> > > > > +
> > > > >  @opindex Wsuggest-attribute=
> > > > >  @opindex Wno-suggest-attribute=
> > > > >  @item -Wsuggest-attribute=@var{attribute-name}
> > > > > diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
> > > > > index e4db4b1d9bd..d524a82c0bb 100644
> > > > > --- a/gcc/gimplify.cc
> > > > > +++ b/gcc/gimplify.cc
> > > > > @@ -7976,6 +7976,71 @@ num_alternatives (const_tree link)
> > > > >    return num + 1;
> > > > >  }
> > > > >
> > > > > +/* Keep track of all register asm which have been replaced by hard 
> > > > > register
> > > > > +   constraints.  After all asm statements of a function have been 
> > > > > processed,
> > > > > +   demote those to ordinary objects.  */
> > > > > +static hash_set<tree> demote_register_asm;
> > > > > +
> > > > > +/* If -fstrict-extended-asm is specified, rewrite constraints of 
> > > > > Extended Asm
> > > > > +   operands which refer to local register asm objects into hard 
> > > > > register
> > > > > +   constraints.  Also mark those objects to be demoted from register 
> > > > > asm
> > > > > +   objects to ordinary objects which is done basically after 
> > > > > gimplification of
> > > > > +   the function body.  */
> > > > > +
> > > > > +static void
> > > > > +gimplify_demote_register_asm (tree link)
> > > > > +{
> > > > > +  tree op = TREE_VALUE (link);
> > > > > +  if (!VAR_P (op) || !DECL_HARD_REGISTER (op) || is_global_var (op))
> > > > > +    return;
> > > > > +  tree id = DECL_ASSEMBLER_NAME (op);
> > > > > +  const char *regname = IDENTIFIER_POINTER (id);
> > > > > +  ++regname;
> > > > > +  int regno = decode_reg_name (regname);
> > > > > +  if (regno < 0)
> > > > > +    /* This indicates an error and we error out later on.  */
> > > > > +    return;
> > > > > +  /* Currently, fixed registers cannot be used for hard register 
> > > > > constraints
> > > > > +     which is why we skip those for the moment.  */
> > > > > +  if (fixed_regs[regno])
> > > > > +    return;
> > > > > +  const char *constraint
> > > > > +    = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
> > > > > +  auto_vec<char, 64> constraint_new;
> > > > > +  for (const char *p = constraint; *p; )
> > > > > +    {
> > > > > +      bool changed_p = false;
> > > > > +      enum constraint_num cn = lookup_constraint (p);
> > > > > +      enum reg_class rclass = reg_class_for_constraint (cn);
> > > > > +      if (rclass != NO_REGS)
> > > > > +       {
> > > > > +         /* During parse_{input,output}_constraint() we ensured that 
> > > > > rclass
> > > > > +            entails all registers required by the register asm 
> > > > > operand.
> > > > > +            Therefore, rewrite the constraint into a corresponding 
> > > > > hard
> > > > > +            register constraint.  */
> > > > > +         constraint_new.safe_push ('{');
> > > > > +         size_t len = strlen (regname);
> > > > > +         for (size_t i = 0; i < len; ++i)
> > > > > +           constraint_new.safe_push (regname[i]);
> > > > > +         constraint_new.safe_push ('}');
> > > > > +         changed_p = true;
> > > > > +       }
> > > > > +
> > > > > +      for (size_t len = CONSTRAINT_LEN (*p, p); len; len--, p++)
> > > > > +       {
> > > > > +         if (!changed_p)
> > > > > +           constraint_new.safe_push (*p);
> > > > > +         if (*p == '\0')
> > > > > +           break;
> > > > > +       }
> > > > > +    }
> > > > > +  constraint_new.safe_push ('\0');
> > > > > +  unsigned int len = constraint_new.length ();
> > > > > +  tree str = build_string (len, constraint_new.address ());
> > > > > +  TREE_VALUE (TREE_PURPOSE (link)) = str;
> > > > > +  demote_register_asm.add (op);
> > > > > +}
> > > > > +
> > > > >  /* Gimplify the operands of an ASM_EXPR.  Input operands should be a 
> > > > > gimple
> > > > >     value; output operands should be a gimple lvalue.  */
> > > > >
> > > > > @@ -8063,6 +8128,43 @@ gimplify_asm_expr (tree *expr_p, gimple_seq 
> > > > > *pre_p, gimple_seq *post_p)
> > > > >           is_inout = false;
> > > > >         }
> > > > >
> > > > > +      /* In case of -fstrict-extended-asm or for hard register 
> > > > > constraints,
> > > > > +        error out if an lvalue is used for more than one output 
> > > > > operand.
> > > > > +        Otherwise emit at most a warning.  For example, error out for
> > > > > +
> > > > > +          asm ("" : "={0}" (x), "={1}" (x));
> > > > > +          asm ("" : "=r" (x), "={1}" (x));
> > > > > +
> > > > > +        and emit a warning for
> > > > > +
> > > > > +          int x;
> > > > > +          asm ("" : "=r" (x), "=r" (x));
> > > > > +
> > > > > +        if -fno-strict-extended-asm -Wstrict-register-asm is given.  
> > > > > */
> > > > > +
> > > > > +      for (tree i = link_next; i; i = TREE_CHAIN (i))
> > > > > +       {
> > > > > +         tree op1 = TREE_VALUE (link);
> > > > > +         tree op2 = TREE_VALUE (i);
> > > > > +         if (op1 != op2)
> > > > > +           continue;
> > > > > +         const char *constraint2
> > > > > +           = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (i)));
> > > > > +         if (flag_strict_extended_asm
> > > > > +             || strchr (constraint, '{') != nullptr
> > > > > +             || strchr (constraint2, '{') != nullptr
> > > > > +             /* We already diagnose global/local register asm cases 
> > > > > during
> > > > > +                expand as errors.  Therefore, do here, too.  */
> > > > > +             || (VAR_P (op2) && DECL_HARD_REGISTER (op2)))
> > > > > +           {
> > > > > +             error ("multiple outputs to lvalue %qE", op2);
> > > > > +             return GS_ERROR;
> > > > > +           }
> > > > > +         else
> > > > > +           warning (OPT_Wstrict_extended_asm, "multiple outputs to 
> > > > > lvalue %qE",
> > > > > +                    op2);
> > > > > +       }
> > > > > +
> > > > >        /* If we can't make copies, we can only accept memory.
> > > > >          Similarly for VLAs.  */
> > > > >        tree outtype = TREE_TYPE (TREE_VALUE (link));
> > > > > @@ -8226,45 +8328,6 @@ gimplify_asm_expr (tree *expr_p, gimple_seq 
> > > > > *pre_p, gimple_seq *post_p)
> > > > >         }
> > > > >      }
> > > > >
> > > > > -  /* After all output operands have been gimplified, verify that 
> > > > > each output
> > > > > -     operand is used at most once in case of hard register 
> > > > > constraints.  Thus,
> > > > > -     error out in cases like
> > > > > -       asm ("" : "={0}" (x), "={1}" (x));
> > > > > -     or even for
> > > > > -       asm ("" : "=r" (x), "={1}" (x));
> > > > > -
> > > > > -     FIXME: Ideally we would also error out for cases like
> > > > > -       int x;
> > > > > -       asm ("" : "=r" (x), "=r" (x));
> > > > > -     However, since code like that was previously accepted, erroring 
> > > > > out now might
> > > > > -     break existing code.  On the other hand, we already error out 
> > > > > for register
> > > > > -     asm like
> > > > > -       register int x asm ("0");
> > > > > -       asm ("" : "=r" (x), "=r" (x));
> > > > > -     Thus, maybe it wouldn't be too bad to also error out in the 
> > > > > former
> > > > > -     non-register-asm case.
> > > > > -  */
> > > > > -  for (unsigned i = 0; i < vec_safe_length (outputs); ++i)
> > > > > -    {
> > > > > -      tree link = (*outputs)[i];
> > > > > -      tree op1 = TREE_VALUE (link);
> > > > > -      const char *constraint
> > > > > -       = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
> > > > > -      if (strchr (constraint, '{') != nullptr)
> > > > > -       for (unsigned j = 0; j < vec_safe_length (outputs); ++j)
> > > > > -         {
> > > > > -           if (i == j)
> > > > > -             continue;
> > > > > -           tree link2 = (*outputs)[j];
> > > > > -           tree op2 = TREE_VALUE (link2);
> > > > > -           if (op1 == op2)
> > > > > -             {
> > > > > -               error ("multiple outputs to lvalue %qE", op2);
> > > > > -               return GS_ERROR;
> > > > > -             }
> > > > > -         }
> > > > > -    }
> > > > > -
> > > > >    link_next = NULL_TREE;
> > > > >    int input_num = 0;
> > > > >    for (link = ASM_INPUTS (expr); link; ++input_num, ++i, link = 
> > > > > link_next)
> > > > > @@ -8283,8 +8346,10 @@ gimplify_asm_expr (tree *expr_p, gimple_seq 
> > > > > *pre_p, gimple_seq *post_p)
> > > > >           is_inout = false;
> > > > >         }
> > > > >
> > > > > +      tree inputv = TREE_VALUE (link);
> > > > > +      tree intype = TREE_TYPE (inputv);
> > > > > +
> > > > >        /* If we can't make copies, we can only accept memory.  */
> > > > > -      tree intype = TREE_TYPE (TREE_VALUE (link));
> > > > >        if (TREE_ADDRESSABLE (intype)
> > > > >           || !COMPLETE_TYPE_P (intype)
> > > > >           || !tree_fits_poly_uint64_p (TYPE_SIZE_UNIT (intype)))
> > > > > @@ -8299,10 +8364,55 @@ gimplify_asm_expr (tree *expr_p, gimple_seq 
> > > > > *pre_p, gimple_seq *post_p)
> > > > >             }
> > > > >         }
> > > > >
> > > >
> > > > A comment before this block would be useful
> > > >
> > > > > +      if (VAR_P (inputv)
> > > > > +         && DECL_HARD_REGISTER (inputv)
> > > > > +         && !is_global_var (inputv))
> > > > > +       {
> > > > > +         tree id1 = DECL_ASSEMBLER_NAME (inputv);
> > > > > +         const char *regname1 = IDENTIFIER_POINTER (id1);
> > > > > +         ++regname1;
> > > > > +         int regno1 = decode_reg_name (regname1);
> > > > > +         if (regno1 >= 0)
> > > > > +           {
> > > > > +             HARD_REG_SET hreg_set1;
> > > > > +             CLEAR_HARD_REG_SET (hreg_set1);
> > > > > +             add_to_hard_reg_set (&hreg_set1, TYPE_MODE (intype), 
> > > > > regno1);
> > > > > +             for (tree i = link_next; i; i = TREE_CHAIN (i))
> > > > > +               {
> > > > > +                 tree inputv2 = TREE_VALUE (i);
> > > > > +                 if (VAR_P (inputv2)
> > > > > +                     && DECL_HARD_REGISTER (inputv2)
> > > > > +                     && !is_global_var (inputv2))
> > > >
> > > > Seeing this, I wonder what we do to
> > > >
> > > >  void foo()
> > > > {
> > > >    register int x asm ("%rax");
> > > >    void bar()
> > > >    {
> > > >       asm ("" : : "r" (x));
> > > >    }
> > > > }
> > > >
> > > > aka register asm "crossing" nested function context?  Because 
> > > > !is_global_var
> > > > isn't the same as auto_var_in_fn_p (inputv2, current_function_decl).
> > > >
> > > > Maybe a local_register_var_p (tree) predicate would help making this 
> > > > less
> > > > repetitive?
> > >
> > > Giving this a second thought, I mean a third thought, I don't see a
> > > reason to differentiate between local and global register asm here.
> > > When I came up with hard register constraints two years ago and thought
> > > about -fdemote-register-asm I only had local register asm in mind
> > > because this is the only one I was about to rewrite.  However, whether
> > > in
> > >
> > >          register int x asm ("5") = 42;
> > >          register int y asm ("5") = 24;
> > >          asm ("" : "+r" (x) : "r" (y));
> > >
> > > x and y are both local, one local and one global, or both global
> > > register asm doesn't really change anything w.r.t. to error-proneness.
> > >
> > > Certainly only checking for the case where both are local is not enough.
> > > The case where one is local and one global must be diagnosed since
> > > otherwise after demotion we would fail during RA since r5 couldn't be
> > > assigned because that is excluded due to the global register asm which
> > > of course isn't demoted.
> >
> > But with global register asms there's nothing wrong with a conflict, like
> >
> >  asm ("" : "+r" (x), "+r5" (x):);
> >
> > as it's not guaranteed that the first output is mapped to r5?  That is,
> > we might not diagnose such case and it is valid for RA to map the
> > input/output to another register just initialized from the global register 
> > var?
> >
> > So I would say this is sth different and not about "strict extended asm"?
>
> Good question.  My reading so far was that local and global register asm
> operands do not differ for Extended Asm, i.e., both lead to pin the asm
> operand to a particular register for the Extended Asm with the only
> difference that global register asm objects reside also outside of the
> Extended Asm in the particular register.  Maybe my intuition is wrong
> here?
>
> From https://gcc.gnu.org/onlinedocs/gcc/Global-Register-Variables.html:
>
>  "If the variable is referenced in inline assembly, the type of access
>   must be provided to the compiler via constraints (see Constraints for
>   asm Operands). Accesses from basic asms are not supported."
>
> This was the only thing I found which leaves a lot of room for
> interpretation.
>
> What I have observed so far is that global register asm operands always
> ended up in the respective register for Extended Asm.  However, while
> digging into this over the course of the last two years my focus was
> clearly on local register asm.  Furthermore, I haven't neither used
> global register asm myself nor have I seen any serious project using
> them.  Thus, my intuition might be completely off here.
>
> Anyhow, from a user perspective I think that the example is error-prone.
> That means, even if there is no guarantee that all operands reside in r5
> for the Extended Asm statement there is still the question what value
> should `x` have afterwards, i.e., which write does eventually win?

Good point, but then I'd go foward without touching the global asm case.

Richard.

> Cheers,
> Stefan
>
> >
> > > Since quite a few changes accumulated over the last day, I will come up
> > > with another version of this.
> > >
> > > Cheers,
> > > Stefan
> > >
> > > >
> > > > > +                   {
> > > > > +                     tree id2 = DECL_ASSEMBLER_NAME (inputv2);
> > > > > +                     const char *regname2 = IDENTIFIER_POINTER (id2);
> > > > > +                     ++regname2;
> > > > > +                     int regno2 = decode_reg_name (regname2);
> > > > > +                     if (regno2 < 0)
> > > > > +                       continue;
> > > >
> > > > And an overload to decode_reg_name taking the decl?
> > > >
> > > > Otherwise LGTM.
> > > >
> > > > Thanks,
> > > > Richard.
> > > >
> > > > > +                     tree intype2 = TREE_TYPE (inputv2);
> > > > > +                     int nregs2
> > > > > +                       = hard_regno_nregs (regno2, TYPE_MODE 
> > > > > (intype2));
> > > > > +                     for (int j = regno2; j < regno2 + nregs2; ++j)
> > > > > +                       {
> > > > > +                         if (!TEST_HARD_REG_BIT (hreg_set1, j))
> > > > > +                           continue;
> > > > > +                         if (flag_strict_extended_asm)
> > > > > +                           error ("multiple inputs to hard register: 
> > > > > %s",
> > > > > +                                  reg_names[j]);
> > > > > +                         else
> > > > > +                           warning (OPT_Wstrict_extended_asm,
> > > > > +                                    "multiple inputs to hard 
> > > > > register: %s",
> > > > > +                                    reg_names[j]);
> > > > > +                       }
> > > > > +                   }
> > > > > +               }
> > > > > +           }
> > > > > +       }
> > > > > +
> > > > >        /* If the operand is a memory input, it should be an lvalue.  
> > > > > */
> > > > >        if (!allows_reg && allows_mem)
> > > > >         {
> > > > > -         tree inputv = TREE_VALUE (link);
> > > > >           STRIP_NOPS (inputv);
> > > > >           if (TREE_CODE (inputv) == PREDECREMENT_EXPR
> > > > >               || TREE_CODE (inputv) == PREINCREMENT_EXPR
> > > > > @@ -8372,6 +8482,20 @@ gimplify_asm_expr (tree *expr_p, gimple_seq 
> > > > > *pre_p, gimple_seq *post_p)
> > > > >    /* Do not add ASMs with errors to the gimple IL stream.  */
> > > > >    if (ret != GS_ERROR)
> > > > >      {
> > > > > +      if (flag_strict_extended_asm)
> > > > > +       {
> > > > > +         for (unsigned i = 0; i < vec_safe_length (outputs); ++i)
> > > > > +           {
> > > > > +             tree link = (*outputs)[i];
> > > > > +             gimplify_demote_register_asm (link);
> > > > > +           }
> > > > > +         for (unsigned i = 0; i < vec_safe_length (inputs); ++i)
> > > > > +           {
> > > > > +             tree link = (*inputs)[i];
> > > > > +             gimplify_demote_register_asm (link);
> > > > > +           }
> > > > > +       }
> > > > > +
> > > > >        stmt = gimple_build_asm_vec (TREE_STRING_POINTER (ASM_STRING 
> > > > > (expr)),
> > > > >                                    inputs, outputs, clobbers, labels);
> > > > >
> > > > > @@ -21874,6 +21998,13 @@ gimplify_body (tree fndecl, bool do_parms)
> > > > >           }
> > > > >      }
> > > > >
> > > > > +  for (auto op : demote_register_asm)
> > > > > +    {
> > > > > +      DECL_REGISTER (op) = 0;
> > > > > +      DECL_HARD_REGISTER (op) = 0;
> > > > > +    }
> > > > > +  demote_register_asm.empty ();
> > > > > +
> > > > >    if ((flag_openacc || flag_openmp || flag_openmp_simd)
> > > > >        && gimplify_omp_ctxp)
> > > > >      {
> > > > > diff --git a/gcc/stmt.cc b/gcc/stmt.cc
> > > > > index 382a2d75c07..97cb55ea775 100644
> > > > > --- a/gcc/stmt.cc
> > > > > +++ b/gcc/stmt.cc
> > > > > @@ -499,6 +499,23 @@ parse_output_constraint (const char 
> > > > > **constraint_p, int operand_num,
> > > > >                            reg_names[overlap_regno]);
> > > > >                     return false;
> > > > >                   }
> > > > > +               enum reg_class rclass = reg_class_for_constraint (cn);
> > > > > +               machine_mode mode = TYPE_MODE (TREE_TYPE 
> > > > > (reg_info->operand));
> > > > > +               if (rclass != NO_REGS
> > > > > +                   && !in_hard_reg_set_p 
> > > > > (reg_class_contents[rclass], mode,
> > > > > +                                          regno))
> > > > > +                 {
> > > > > +                   if (flag_strict_extended_asm)
> > > > > +                     {
> > > > > +                       error
> > > > > +                         ("constraint and register %<asm%> do not 
> > > > > coincide");
> > > > > +                       return false;
> > > > > +                     }
> > > > > +                   else
> > > > > +                     warning
> > > > > +                       (OPT_Wstrict_extended_asm,
> > > > > +                        "constraint and register %<asm%> do not 
> > > > > coincide");
> > > > > +                 }
> > > > >                 reg_info->set_reg_asm_output (regno);
> > > > >                 if (early_clobbered)
> > > > >                   reg_info->set_early_clobbered (alt, operand_num, 
> > > > > regno);
> > > > > @@ -756,6 +773,21 @@ repeat:
> > > > >                          reg_names[overlap_regno]);
> > > > >                   return false;
> > > > >                 }
> > > > > +             enum reg_class rclass = reg_class_for_constraint (cn);
> > > > > +             machine_mode mode = TYPE_MODE (TREE_TYPE 
> > > > > (reg_info->operand));
> > > > > +             if (rclass != NO_REGS
> > > > > +                 && !in_hard_reg_set_p (reg_class_contents[rclass], 
> > > > > mode,
> > > > > +                                        regno))
> > > > > +               {
> > > > > +                 if (flag_strict_extended_asm)
> > > > > +                   {
> > > > > +                     error ("constraint and register %<asm%> do not 
> > > > > coincide");
> > > > > +                     return false;
> > > > > +                   }
> > > > > +                 else
> > > > > +                   warning (OPT_Wstrict_extended_asm,
> > > > > +                            "constraint and register %<asm%> do not 
> > > > > coincide");
> > > > > +               }
> > > > >               reg_info->set_reg_asm_input (regno);
> > > > >               if ((constraint == orig_constraint
> > > > >                    && reg_info->test_early_clobbered_alt (alt, regno))
> > > > > diff --git a/gcc/testsuite/gcc.dg/asm-hard-reg-strict-1.c 
> > > > > b/gcc/testsuite/gcc.dg/asm-hard-reg-strict-1.c
> > > > > new file mode 100644
> > > > > index 00000000000..f8c7cad48a5
> > > > > --- /dev/null
> > > > > +++ b/gcc/testsuite/gcc.dg/asm-hard-reg-strict-1.c
> > > > > @@ -0,0 +1,51 @@
> > > > > +/* { dg-do compile { target aarch64*-*-* s390*-*-* x86_64-*-* } } */
> > > > > +/* { dg-additional-options "-fstrict-extended-asm" } */
> > > > > +/* { dg-additional-options "-msse2" { target x86_64-*-* } } */
> > > > > +
> > > > > +#if __aarch64__
> > > > > +# define GPR "r5"
> > > > > +# define FPR "d5"
> > > > > +# define CSTR_GPR "r"
> > > > > +# define CSTR_FPR "w"
> > > > > +#elif __s390__
> > > > > +# define GPR "r5"
> > > > > +# define FPR "f5"
> > > > > +# define CSTR_GPR "r"
> > > > > +# define CSTR_FPR "f"
> > > > > +#elif __x86_64__
> > > > > +# define GPR "cx"
> > > > > +# define FPR "xmm5"
> > > > > +# define CSTR_GPR "r"
> > > > > +# define CSTR_FPR "x"
> > > > > +#else
> > > > > +# error unsupported target
> > > > > +#endif
> > > > > +
> > > > > +int
> > > > > +test ()
> > > > > +{
> > > > > +  register int x __asm__ (GPR) = 42;
> > > > > +  register float y __asm__ (FPR) = 42;
> > > > > +
> > > > > +  __asm__ ("" : "="CSTR_FPR (x)); /* { dg-error "constraint and 
> > > > > register 'asm' do not coincide" } */
> > > > > +  __asm__ ("" : "="CSTR_FPR","CSTR_FPR (x)); /* { dg-error 
> > > > > "constraint and register 'asm' do not coincide" } */
> > > > > +  __asm__ ("" : "="CSTR_GPR","CSTR_FPR (x)); /* { dg-error 
> > > > > "constraint and register 'asm' do not coincide" } */
> > > > > +  __asm__ ("" : "="CSTR_FPR","CSTR_GPR (x)); /* { dg-error 
> > > > > "constraint and register 'asm' do not coincide" } */
> > > > > +
> > > > > +  __asm__ __volatile ("" :: CSTR_FPR (x)); /* { dg-error "constraint 
> > > > > and register 'asm' do not coincide" } */
> > > > > +  __asm__ __volatile ("" :: CSTR_FPR","CSTR_FPR (x)); /* { dg-error 
> > > > > "constraint and register 'asm' do not coincide" } */
> > > > > +  __asm__ __volatile ("" :: CSTR_GPR","CSTR_FPR (x)); /* { dg-error 
> > > > > "constraint and register 'asm' do not coincide" } */
> > > > > +  __asm__ __volatile ("" :: CSTR_FPR","CSTR_GPR (x)); /* { dg-error 
> > > > > "constraint and register 'asm' do not coincide" } */
> > > > > +
> > > > > +  __asm__ ("" : "="CSTR_GPR (y)); /* { dg-error "constraint and 
> > > > > register 'asm' do not coincide" } */
> > > > > +  __asm__ ("" : "="CSTR_GPR","CSTR_GPR (y)); /* { dg-error 
> > > > > "constraint and register 'asm' do not coincide" } */
> > > > > +  __asm__ ("" : "="CSTR_FPR","CSTR_GPR (y)); /* { dg-error 
> > > > > "constraint and register 'asm' do not coincide" } */
> > > > > +  __asm__ ("" : "="CSTR_GPR","CSTR_FPR (y)); /* { dg-error 
> > > > > "constraint and register 'asm' do not coincide" } */
> > > > > +
> > > > > +  __asm__ __volatile ("" :: CSTR_GPR (y)); /* { dg-error "constraint 
> > > > > and register 'asm' do not coincide" } */
> > > > > +  __asm__ __volatile ("" :: CSTR_GPR","CSTR_GPR (y)); /* { dg-error 
> > > > > "constraint and register 'asm' do not coincide" } */
> > > > > +  __asm__ __volatile ("" :: CSTR_FPR","CSTR_GPR (y)); /* { dg-error 
> > > > > "constraint and register 'asm' do not coincide" } */
> > > > > +  __asm__ __volatile ("" :: CSTR_GPR","CSTR_FPR (y)); /* { dg-error 
> > > > > "constraint and register 'asm' do not coincide" } */
> > > > > +
> > > > > +  return x + y;
> > > > > +}
> > > > > diff --git a/gcc/testsuite/gcc.dg/asm-hard-reg-strict-2.c 
> > > > > b/gcc/testsuite/gcc.dg/asm-hard-reg-strict-2.c
> > > > > new file mode 100644
> > > > > index 00000000000..cfa783d4e94
> > > > > --- /dev/null
> > > > > +++ b/gcc/testsuite/gcc.dg/asm-hard-reg-strict-2.c
> > > > > @@ -0,0 +1,54 @@
> > > > > +/* { dg-do compile { target aarch64*-*-* s390*-*-* x86_64-*-* } } */
> > > > > +/* { dg-additional-options "-fno-strict-extended-asm 
> > > > > -Wstrict-extended-asm" } */
> > > > > +/* { dg-additional-options "-msse2" { target x86_64-*-* } } */
> > > > > +
> > > > > +/* This is a copy of asm-hard-reg-strict-1.c for 
> > > > > -fno-strict-register-asm where
> > > > > +   we expect warnings instead of errors.  */
> > > > > +
> > > > > +#if __aarch64__
> > > > > +# define GPR "r5"
> > > > > +# define FPR "d5"
> > > > > +# define CSTR_GPR "r"
> > > > > +# define CSTR_FPR "w"
> > > > > +#elif __s390__
> > > > > +# define GPR "r5"
> > > > > +# define FPR "f5"
> > > > > +# define CSTR_GPR "r"
> > > > > +# define CSTR_FPR "f"
> > > > > +#elif __x86_64__
> > > > > +# define GPR "cx"
> > > > > +# define FPR "xmm5"
> > > > > +# define CSTR_GPR "r"
> > > > > +# define CSTR_FPR "x"
> > > > > +#else
> > > > > +# error unsupported target
> > > > > +#endif
> > > > > +
> > > > > +int
> > > > > +test ()
> > > > > +{
> > > > > +  register int x __asm__ (GPR) = 42;
> > > > > +  register float y __asm__ (FPR) = 42;
> > > > > +
> > > > > +  __asm__ ("" : "="CSTR_FPR (x)); /* { dg-warning "constraint and 
> > > > > register 'asm' do not coincide" } */
> > > > > +  __asm__ ("" : "="CSTR_FPR","CSTR_FPR (x)); /* { dg-warning 
> > > > > "constraint and register 'asm' do not coincide" } */
> > > > > +  __asm__ ("" : "="CSTR_GPR","CSTR_FPR (x)); /* { dg-warning 
> > > > > "constraint and register 'asm' do not coincide" } */
> > > > > +  __asm__ ("" : "="CSTR_FPR","CSTR_GPR (x)); /* { dg-warning 
> > > > > "constraint and register 'asm' do not coincide" } */
> > > > > +
> > > > > +  __asm__ __volatile ("" :: CSTR_FPR (x)); /* { dg-warning 
> > > > > "constraint and register 'asm' do not coincide" } */
> > > > > +  __asm__ __volatile ("" :: CSTR_FPR","CSTR_FPR (x)); /* { 
> > > > > dg-warning "constraint and register 'asm' do not coincide" } */
> > > > > +  __asm__ __volatile ("" :: CSTR_GPR","CSTR_FPR (x)); /* { 
> > > > > dg-warning "constraint and register 'asm' do not coincide" } */
> > > > > +  __asm__ __volatile ("" :: CSTR_FPR","CSTR_GPR (x)); /* { 
> > > > > dg-warning "constraint and register 'asm' do not coincide" } */
> > > > > +
> > > > > +  __asm__ ("" : "="CSTR_GPR (y)); /* { dg-warning "constraint and 
> > > > > register 'asm' do not coincide" } */
> > > > > +  __asm__ ("" : "="CSTR_GPR","CSTR_GPR (y)); /* { dg-warning 
> > > > > "constraint and register 'asm' do not coincide" } */
> > > > > +  __asm__ ("" : "="CSTR_FPR","CSTR_GPR (y)); /* { dg-warning 
> > > > > "constraint and register 'asm' do not coincide" } */
> > > > > +  __asm__ ("" : "="CSTR_GPR","CSTR_FPR (y)); /* { dg-warning 
> > > > > "constraint and register 'asm' do not coincide" } */
> > > > > +
> > > > > +  __asm__ __volatile ("" :: CSTR_GPR (y)); /* { dg-warning 
> > > > > "constraint and register 'asm' do not coincide" } */
> > > > > +  __asm__ __volatile ("" :: CSTR_GPR","CSTR_GPR (y)); /* { 
> > > > > dg-warning "constraint and register 'asm' do not coincide" } */
> > > > > +  __asm__ __volatile ("" :: CSTR_FPR","CSTR_GPR (y)); /* { 
> > > > > dg-warning "constraint and register 'asm' do not coincide" } */
> > > > > +  __asm__ __volatile ("" :: CSTR_GPR","CSTR_FPR (y)); /* { 
> > > > > dg-warning "constraint and register 'asm' do not coincide" } */
> > > > > +
> > > > > +  return x + y;
> > > > > +}
> > > > > diff --git a/gcc/testsuite/gcc.dg/asm-hard-reg-strict-3.c 
> > > > > b/gcc/testsuite/gcc.dg/asm-hard-reg-strict-3.c
> > > > > new file mode 100644
> > > > > index 00000000000..f3732a028a5
> > > > > --- /dev/null
> > > > > +++ b/gcc/testsuite/gcc.dg/asm-hard-reg-strict-3.c
> > > > > @@ -0,0 +1,22 @@
> > > > > +/* { dg-do compile { target aarch64*-*-* s390*-*-* x86_64-*-* } } */
> > > > > +/* { dg-additional-options "-fstrict-extended-asm" } */
> > > > > +
> > > > > +void
> > > > > +test ()
> > > > > +{
> > > > > +  register int x __asm__ ("5") = 42;
> > > > > +  register int y __asm__ ("5") = 24;
> > > > > +  int z;
> > > > > +
> > > > > +  __asm__ __volatile__ ("" : "+r" (x) : "r" (x));           /* { 
> > > > > dg-error "multiple inputs to hard register" } */
> > > > > +  __asm__ __volatile__ ("" : "=r" (x) : "0" (x), "r" (x));  /* { 
> > > > > dg-error "multiple inputs to hard register" } */
> > > > > +  __asm__ __volatile__ ("" :          : "r" (x), "r" (x));  /* { 
> > > > > dg-error "multiple inputs to hard register" } */
> > > > > +  __asm__ __volatile__ ("" :          : "r" (x), "r" (y));  /* { 
> > > > > dg-error "multiple inputs to hard register" } */
> > > > > +
> > > > > +  __asm__ __volatile__ ("" : "=r" (x), "=r" (x)); /* { dg-error 
> > > > > "multiple outputs to lvalue 'x'" } */
> > > > > +
> > > > > +  __asm__ __volatile__ ("" : "=r" (z), "=r" (z)); /* { dg-error 
> > > > > "multiple outputs to lvalue 'z'" } */
> > > > > +  __asm__ __volatile__ ("" : "=m" (z), "=r" (z)); /* { dg-error 
> > > > > "multiple outputs to lvalue 'z'" } */
> > > > > +  __asm__ __volatile__ ("" : "=r" (z), "=m" (z)); /* { dg-error 
> > > > > "multiple outputs to lvalue 'z'" } */
> > > > > +  __asm__ __volatile__ ("" : "=m" (z), "=m" (z)); /* { dg-error 
> > > > > "multiple outputs to lvalue 'z'" } */
> > > > > +}
> > > > > diff --git a/gcc/testsuite/gcc.dg/asm-hard-reg-strict-4.c 
> > > > > b/gcc/testsuite/gcc.dg/asm-hard-reg-strict-4.c
> > > > > new file mode 100644
> > > > > index 00000000000..98eb0386b3b
> > > > > --- /dev/null
> > > > > +++ b/gcc/testsuite/gcc.dg/asm-hard-reg-strict-4.c
> > > > > @@ -0,0 +1,25 @@
> > > > > +/* { dg-do compile { target aarch64*-*-* s390*-*-* x86_64-*-* } } */
> > > > > +/* { dg-additional-options "-fno-strict-extended-asm 
> > > > > -Wstrict-extended-asm" } */
> > > > > +
> > > > > +/* This is a copy of asm-hard-reg-strict-3.c for 
> > > > > -fno-strict-register-asm where
> > > > > +   we expect warnings instead of errors.  */
> > > > > +
> > > > > +void
> > > > > +test ()
> > > > > +{
> > > > > +  register int x __asm__ ("5") = 42;
> > > > > +  register int y __asm__ ("5") = 24;
> > > > > +  int z;
> > > > > +
> > > > > +  __asm__ __volatile__ ("" : "+r" (x) : "r" (x));           /* { 
> > > > > dg-warning "multiple inputs to hard register" } */
> > > > > +  __asm__ __volatile__ ("" : "=r" (x) : "0" (x), "r" (x));  /* { 
> > > > > dg-warning "multiple inputs to hard register" } */
> > > > > +  __asm__ __volatile__ ("" :          : "r" (x), "r" (x));  /* { 
> > > > > dg-warning "multiple inputs to hard register" } */
> > > > > +  __asm__ __volatile__ ("" :          : "r" (x), "r" (y));  /* { 
> > > > > dg-warning "multiple inputs to hard register" } */
> > > > > +
> > > > > +  __asm__ __volatile__ ("" : "=r" (x), "=r" (x)); /* { dg-error 
> > > > > "multiple outputs to lvalue 'x'" } */
> > > > > +
> > > > > +  __asm__ __volatile__ ("" : "=r" (z), "=r" (z)); /* { dg-warning 
> > > > > "multiple outputs to lvalue 'z'" } */
> > > > > +  __asm__ __volatile__ ("" : "=m" (z), "=r" (z)); /* { dg-warning 
> > > > > "multiple outputs to lvalue 'z'" } */
> > > > > +  __asm__ __volatile__ ("" : "=r" (z), "=m" (z)); /* { dg-warning 
> > > > > "multiple outputs to lvalue 'z'" } */
> > > > > +  __asm__ __volatile__ ("" : "=m" (z), "=m" (z)); /* { dg-warning 
> > > > > "multiple outputs to lvalue 'z'" } */
> > > > > +}
> > > > > diff --git a/gcc/testsuite/gcc.dg/asm-hard-reg-strict-5.c 
> > > > > b/gcc/testsuite/gcc.dg/asm-hard-reg-strict-5.c
> > > > > new file mode 100644
> > > > > index 00000000000..699bed70a43
> > > > > --- /dev/null
> > > > > +++ b/gcc/testsuite/gcc.dg/asm-hard-reg-strict-5.c
> > > > > @@ -0,0 +1,65 @@
> > > > > +/* { dg-do compile { target aarch64*-*-* s390*-*-* x86_64-*-* } } */
> > > > > +/* { dg-additional-options "-fstrict-extended-asm 
> > > > > -fdump-tree-gimple" } */
> > > > > +/* { dg-additional-options "-msse2" { target x86_64-*-* } } */
> > > > > +
> > > > > +/* Test rewriting constraints into hard register constraints and 
> > > > > demote
> > > > > +   register asm objects into ordinary objects.  */
> > > > > +
> > > > > +#if __aarch64__
> > > > > +# define GPR "r5"
> > > > > +# define FPR "d5"
> > > > > +# define CSTR_GPR "r"
> > > > > +# define CSTR_FPR "w"
> > > > > +/* { dg-final { scan-tree-dump-times "__asm__\\(\"\" : \"=\{r5\}\" 
> > > > > x0\\);" 1 "gimple" { target aarch64-*-* } } } */
> > > > > +/* { dg-final { scan-tree-dump-times "__asm__\\(\"\" : 
> > > > > \"=g,!\{r5\}\" x0\\);" 1 "gimple" { target aarch64-*-* } } } */
> > > > > +/* { dg-final { scan-tree-dump-times "__asm__\\(\"\" : 
> > > > > \"=!\{r5\},g\" x0\\);" 1 "gimple" { target aarch64-*-* } } } */
> > > > > +/* { dg-final { scan-tree-dump-times "__asm__\\(\"\" : \"=\{d5\}\" 
> > > > > x1\\);" 1 "gimple" { target aarch64-*-* } } } */
> > > > > +/* { dg-final { scan-tree-dump-times "__asm__\\(\"\" : 
> > > > > \"=g,!\{d5\}\" x1\\);" 1 "gimple" { target aarch64-*-* } } } */
> > > > > +/* { dg-final { scan-tree-dump-times "__asm__\\(\"\" : 
> > > > > \"=!\{d5\},g\" x1\\);" 1 "gimple" { target aarch64-*-* } } } */
> > > > > +#elif __s390__
> > > > > +# define GPR "r5"
> > > > > +# define FPR "f5"
> > > > > +# define CSTR_GPR "r"
> > > > > +# define CSTR_FPR "f"
> > > > > +/* { dg-final { scan-tree-dump-times "__asm__\\(\"\" : \"=\{r5\}\" 
> > > > > x0\\);" 1 "gimple" { target s390*-*-* } } } */
> > > > > +/* { dg-final { scan-tree-dump-times "__asm__\\(\"\" : 
> > > > > \"=g,!\{r5\}\" x0\\);" 1 "gimple" { target s390*-*-* } } } */
> > > > > +/* { dg-final { scan-tree-dump-times "__asm__\\(\"\" : 
> > > > > \"=!\{r5\},g\" x0\\);" 1 "gimple" { target s390*-*-* } } } */
> > > > > +/* { dg-final { scan-tree-dump-times "__asm__\\(\"\" : \"=\{f5\}\" 
> > > > > x1\\);" 1 "gimple" { target s390*-*-* } } } */
> > > > > +/* { dg-final { scan-tree-dump-times "__asm__\\(\"\" : 
> > > > > \"=g,!\{f5\}\" x1\\);" 1 "gimple" { target s390*-*-* } } } */
> > > > > +/* { dg-final { scan-tree-dump-times "__asm__\\(\"\" : 
> > > > > \"=!\{f5\},g\" x1\\);" 1 "gimple" { target s390*-*-* } } } */
> > > > > +#elif __x86_64__
> > > > > +# define GPR "cx"
> > > > > +# define FPR "xmm5"
> > > > > +# define CSTR_GPR "r"
> > > > > +# define CSTR_FPR "x"
> > > > > +/* { dg-final { scan-tree-dump-times "__asm__\\(\"\" : \"=\{cx\}\" 
> > > > > x0\\);" 1 "gimple" { target x86_64-*-* } } } */
> > > > > +/* { dg-final { scan-tree-dump-times "__asm__\\(\"\" : 
> > > > > \"=g,!\{cx\}\" x0\\);" 1 "gimple" { target x86_64-*-* } } } */
> > > > > +/* { dg-final { scan-tree-dump-times "__asm__\\(\"\" : 
> > > > > \"=!\{cx\},g\" x0\\);" 1 "gimple" { target x86_64-*-* } } } */
> > > > > +/* { dg-final { scan-tree-dump-times "__asm__\\(\"\" : \"=\{xmm5\}\" 
> > > > > x1\\);" 1 "gimple" { target x86_64-*-* } } } */
> > > > > +/* { dg-final { scan-tree-dump-times "__asm__\\(\"\" : 
> > > > > \"=g,!\{xmm5\}\" x1\\);" 1 "gimple" { target x86_64-*-* } } } */
> > > > > +/* { dg-final { scan-tree-dump-times "__asm__\\(\"\" : 
> > > > > \"=!\{xmm5\},g\" x1\\);" 1 "gimple" { target x86_64-*-* } } } */
> > > > > +#else
> > > > > +# error unsupported target
> > > > > +#endif
> > > > > +
> > > > > +int
> > > > > +test_gpr (void)
> > > > > +{
> > > > > +/* { dg-final { scan-tree-dump-times "int x0;" 1 "gimple" } } */
> > > > > +  register int x0 __asm__ (GPR);
> > > > > +  __asm__ ("" : "="CSTR_GPR (x0));
> > > > > +  __asm__ ("" : "=g,!"CSTR_GPR (x0));
> > > > > +  __asm__ ("" : "=!"CSTR_GPR",g" (x0));
> > > > > +  return x0;
> > > > > +}
> > > > > +
> > > > > +float
> > > > > +test_fpr (void)
> > > > > +{
> > > > > +/* { dg-final { scan-tree-dump-times "float x1;" 1 "gimple" } } */
> > > > > +  register float x1 __asm__ (FPR);
> > > > > +  __asm__ ("" : "="CSTR_FPR (x1));
> > > > > +  __asm__ ("" : "=g,!"CSTR_FPR (x1));
> > > > > +  __asm__ ("" : "=!"CSTR_FPR",g" (x1));
> > > > > +  return x1;
> > > > > +}
> > > > > diff --git a/gcc/testsuite/gcc.dg/asm-hard-reg-strict-6.c 
> > > > > b/gcc/testsuite/gcc.dg/asm-hard-reg-strict-6.c
> > > > > new file mode 100644
> > > > > index 00000000000..bb6fe71d5f5
> > > > > --- /dev/null
> > > > > +++ b/gcc/testsuite/gcc.dg/asm-hard-reg-strict-6.c
> > > > > @@ -0,0 +1,13 @@
> > > > > +/* { dg-do compile { target aarch64*-*-* s390*-*-* x86_64-*-* } } */
> > > > > +/* { dg-additional-options "-fstrict-extended-asm -Wuninitialized" } 
> > > > > */
> > > > > +
> > > > > +/* Since for -fstrict-extended-asm usage of uninitialized register 
> > > > > asm input
> > > > > +   operands is undefined, test for uninit warnings.  */
> > > > > +
> > > > > +int
> > > > > +test (void)
> > > > > +{
> > > > > +  register int x __asm__ ("5");
> > > > > +  __asm__ ("" : "+r" (x)); /* { dg-warning "is used uninitialized" } 
> > > > > */
> > > > > +  return x;
> > > > > +}
> > > > > --
> > > > > 2.54.0
> > > > >

Reply via email to