On Thu, Jun 25, 2026 at 07:25:45PM +0200, Richard Biener wrote:
> 
> 
> > Am 25.06.2026 um 19:23 schrieb Richard Biener <[email protected]>:
> > 
> > 
> > 
> >> Am 25.06.2026 um 18:45 schrieb Stefan Schulze Frielinghaus 
> >> <[email protected]>:
> >> 
> >> On Thu, Jun 25, 2026 at 03:26:36PM +0200, Richard Biener wrote:
> >>>> On Sun, May 24, 2026 at 7:40 PM Stefan Schulze Frielinghaus
> >>>> <[email protected]> wrote:
> >>>> 
> >>>> From: Stefan Schulze Frielinghaus <[email protected]>
> >>>> 
> >>>> This is a followup to
> >>>> https://gcc.gnu.org/pipermail/gcc-patches/2026-May/717097.html
> >>>> with the following changes:
> >>>> 
> >>>> I have renamed -fdemote-register-asm into -fstrict-extended-asm.  This 
> >>>> should
> >>>> give users a better intuition if things break.  I'm using
> >>>> -fstrict-extended-asm here instead of -fstrict-register-asm since the
> >>>> analysis happens at extended asms, or in other words you could still have
> >>>> unusual usages of register asm across multiple extended asms which are 
> >>>> not
> >>>> diagnosed, i.e., the analysis is limited to a single extended asm 
> >>>> statement.
> >>>> 
> >>>> Speaking of diagnostics, I have added -Wstrict-extended-asm which is 
> >>>> enabled by
> >>>> -Wall for C/C++ in order to diagnose cases for which we error out with
> >>>> -fstrict-register-asm (see new tests asm-hard-reg-strict-*.c).
> >>>> 
> >>>> I have generalized the odd ball cases if an lvalue is used for multiple 
> >>>> output
> >>>> operands.  Previously, we diagnosed
> >>>> 
> >>>> register int x __asm__ ("5");
> >>>> __asm__ __volatile__ ("" : "=r" (x), "=r" (x));
> >>>> 
> >>>> with an error: "invalid hard register usage between output operands"
> >>>> This was done only for register asm objects during expand.  Now, I 
> >>>> diagnose if
> >>>> any two output operands refer to the same lvalue.  This is done 
> >>>> independently
> >>>> of constraints and types of output operands.  In order to align all those
> >>>> different combinations I went for diagnosing those with: "multiple 
> >>>> outputs to
> >>>> lvalue 'x'".  Therefore, for the register asm example from above the
> >>>> diagnostics change.  I guess having "non-stable" error messages for the 
> >>>> sake of
> >>>> streamlining is fine ... just wanted to make it clear here.
> >>>> 
> >>>> While working on the diagnostics I somehow thought that it would be nice 
> >>>> here
> >>>> and there to refer to a concrete operand.  For example, with this patch I
> >>>> diagnose
> >>>> 
> >>>> register int x __asm__ ("5") = 42;
> >>>> asm ("" : "+r" (x) : "r" (x));
> >>>> 
> >>>> with
> >>>> 
> >>>> t.c:11:3: warning: multiple inputs to hard register: %r5 
> >>>> [-Wstrict-extended-asm]
> >>>>  11 |   __asm__ __volatile__ ("" : "+r" (x) : "r" (x));
> >>>>     |   ^~~~~~~
> >>>> 
> >>>> Instead of just pointing to the asm statement it would be nice to have 
> >>>> some
> >>>> ascii art in order to point to the concrete operands as for example
> >>>> 
> >>>> t.c:11:3: warning: multiple inputs to hard register: %r5 
> >>>> [-Wstrict-extended-asm]
> >>>>  11 |   __asm__ __volatile__ ("" : "+r" (x) : "r" (x));
> >>>>     |                                    ^~~~~~~~~~^
> >>>> 
> >>>> Of course, this example behaved good in the sense that it is easy to 
> >>>> draw a
> >>>> line between operands.  It would be more complicated if operands were 
> >>>> aligned
> >>>> in different rows and what not.  So maybe this is just wishful thinking.
> >>>> Anyhow, I'm not familiar with the diagnostics system at all, however, if
> >>>> someone has a pointer for me, I'm happy to take a look-see.
> >>>> 
> >>>> Cheers,
> >>>> Stefan
> >>>> 
> >>>> -- >8 --
> >>>> 
> >>>> Currently local register asm assignments materialize during expand into
> >>>> assignments utilizing hard registers.  Since 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 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)
> >>>> {
> >>>> register int tmp asm ("r5");
> >>>> int x = x0;
> >>>> int y = tmp;
> >>>> 
> >>>> 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;
> >>>> }
> >>>> 
> >>>> 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.  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.
> >>>> 
> >>>> 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 warning.
> >>>> 
> >>>> Note, uninitialized register asm objects may be used as inputs.  Thus,
> >>>> if naively translated into hard register constraints, this would
> >>>> introduce reads from uninitialized objects which init-regs pass would
> >>>> fix up which in turn would mean that once hard register constraints
> >>>> materialize, respective registers would be zeroed (see comment in
> >>>> gimplify.cc for more details).  This is solved by initializing every
> >>>> uninitialized register asm object by a fresh register asm object
> >>>> ensuring that it contains the respective register value.  Subsequent
> >>>> passes remove dead stores in case those objects are eventually
> >>>> initialized at later points or are used exclusively as output operands.
> >>>> Therefore, in most cases, those temporary register asm objects won't
> >>>> materialize.  This is not pretty at all but required in order to compile
> >>>> real world applications as e.g. glibc for target powerpc64le.
> >>> 
> >>> I wonder if we can fix init-regs to not consider an asm use as use
> >>> and skip initialization?  (init-regs should go away anyway)
> >>> Is there user-level documentation about this "feature"?
> >> 
> >> Even if I disable init-regs temporarily and prevent asmcons to introduce
> >> any manual reload, LRA will do and assign a different register to the
> >> uninitialized pseudo.  For example, prior LRA we have
> >> 
> >> (insn 6 7 12 2 (set (reg:SI 62 [ x ])
> >>       (asm_operands:SI ("# %0") ("={0}") 0 [
> >>               (reg/v:SI 60 [ x ])
> >>           ]
> >>            [
> >>               (asm_input:SI ("0") t.c:5)
> >>           ]
> >>            [] t.c:5)) "t.c":5:3 -1
> >>    (expr_list:REG_DEAD (reg/v:SI 60 [ x ])
> >>       (nil)))
> >> 
> >> where pseudo 60 has no other use.  During LRA, an input reload is
> >> introduced and pseudo 60 is assigned a different register than 0 which
> >> renders this even worse than just zeroing:
> >> 
> >> (insn 17 7 6 2 (set (reg/v:SI 0 %r0 [orig:60 x ] [60])
> >>       (reg/v:SI 2 %r2 [orig:60 x ] [60])) "t.c":5:3 1949 {*movsi_zarch}
> >>    (nil))
> >> (insn 6 17 18 2 (set (reg/v:SI 0 %r0 [orig:60 x ] [60])
> >>       (asm_operands:SI ("# %0") ("={0}") 0 [
> >>               (reg/v:SI 0 %r0 [orig:60 x ] [60])
> >>           ]
> >>            [
> >>               (asm_input:SI ("0") t.c:5)
> >>           ]
> >>            [] t.c:5)) "t.c":5:3 -1
> >>    (nil))
> >> 
> >> Now, r2 is copied into r0 instead of just zeroing it.
> >> 
> >>> 
> >>> I'd like to see us enable -Wstrict-extended-asm by default
> >> 
> >> With this patch version -Wstrict-extended-asm is enabled if -Wall is
> >> given.  Do you mean by enabling by default also in case -Wall is not
> >> given?
> >> 
> >>> and
> >>> document that -fstrict-extended-asm while default off for now
> >>> will be enabled by default in a future release.
> >>> 
> >>> The patch looks good to me apart from the uninit reg case which indeed
> >>> is ugly.  We can eventually live with this, but it would keep pre-RA
> >>> local hardregs which is ... unwanted (and fragile as well).
> >> 
> >> Absolutely agree.  I was a bit shivering when implementing it ;-) It is
> >> a pity that we didn't warn about this previously.  Though, what I
> >> haven't mentioned so far is that if -Wall is used we of course warn
> >> about this.  Assuming that this hack is removed for:
> >> 
> >> int
> >> test ()
> >> {
> >> register int x __asm__ ("0");
> >> __asm__ ("# %0" : "+r" (x));
> >> return x;
> >> }
> >> 
> >> we get:
> >> 
> >> t.c: In function 'test':
> >> t.c:5:3: warning: 'x' is used uninitialized [-Wuninitialized]
> >>   5 |   __asm__ ("# %0" : "+r" (x));
> >>     |   ^~~~~~~
> >> t.c:4:16: note: 'x' was declared here
> >>   4 |   register int x __asm__ ("0");
> >>     |                ^
> >> 
> >> My initial intentions were to keep the current behaviour in order to
> >> have a broader acceptance ... maybe I went a little bit to far here
> >> since preserving the behaviour of uninitialized reads doesn't resonate
> >> well on IL.  If there is consensus to keep the current behaviour maybe
> >> another solution would be to tackle this during LRA ... something I
> >> would need to think about.
> > 
> > Yeah, it’s a bit odd that we see initialization from another register 
> > there.  But I also question whether there was any well-defined behavior 
> > before this proposed change.  Certainly the position of the uninit read 
> > would have been quite random.
> 
> Meaning, I’d say we can document it as undefined with -fstrict-extended-asm 
> and get the zero initialized behavior.  If we can get an uninit diagnostic by 
> default would be nice (I can try to fix that)

Ok, I will come up with a v3 then.  In case of -fstrict-extended-asm
-Wuninitialized and without this ugly hack we get a diagnostics in all
my simple tests and also while building glibc for powerpc64le:

In file included from ../sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h:23,
                 from ../sysdeps/powerpc/nptl/tls.h:49,
                 from ../include/link.h:51,
                 from ../include/dlfcn.h:4,
                 from ../sysdeps/generic/ldsodefs.h:32,
                 from ../sysdeps/powerpc/ldsodefs.h:67,
                 from ../sysdeps/gnu/ldsodefs.h:46,
                 from ../sysdeps/unix/sysv/linux/ldsodefs.h:25,
                 from 
../sysdeps/unix/sysv/linux/powerpc/powerpc64/ldsodefs.h:22,
                 from ../sysdeps/nptl/dl-tls_init_tp.c:20:
../sysdeps/nptl/dl-tls_init_tp.c: In function '__tls_init_tp':
../sysdeps/unix/sysv/linux/powerpc/sysdep.h:109:5: error: 'r4' is used 
uninitialized [-Werror=uninitialized]
  109 |     __asm__ __volatile__                        \
      |     ^~~~~~~

So at least users have a fair chance of being warned.

Cheers,
Stefan

> 
> Richard 
> 
> > 
> > Richard
> > 
> >> 
> >> Cheers,
> >> Stefan
> >> 
> >>> 
> >>> Richard.
> >>> 
> >>>> 
> >>>> 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_decl_expr): Deal with uninitialized
> >>>>       register asm objects.
> >>>>       (gimplify_demote_register_asm): Helper for gimplify_asm_expr in
> >>>>       order to prepare demotion of a register asm object into an 
> >>>> orderinary
> >>>>       one by rewriting constaints.
> >>>>       (gimplify_asm_expr): Add diagnostics logic for new warning.
> >>>>       (gimplify_body): Cleanup helper hash set.
> >>>>       * stmt.cc (rclass_entails_registers): Helper while parsing
> >>>>       constraints.
> >>>>       (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/common.opt                               |   8 +
> >>>> gcc/doc/invoke.texi                          |  61 ++++-
> >>>> gcc/gimplify.cc                              | 247 ++++++++++++++++---
> >>>> gcc/stmt.cc                                  |  42 ++++
> >>>> 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 +++++
> >>>> 9 files changed, 532 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
> >>>> 
> >>>> 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..c394c8e864f 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,15 @@ 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}).  
> >>>> Among other
> >>>> +things, 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.  See also
> >>>> +@option{-Wstrict-extended-asm}.
> >>>> +
> >>>> @opindex fsso-struct
> >>>> @item -fsso-struct=@var{endianness}
> >>>> Set the default scalar storage order of structures and unions to the
> >>>> @@ -8990,6 +8999,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..951fd69a98b 100644
> >>>> --- a/gcc/gimplify.cc
> >>>> +++ b/gcc/gimplify.cc
> >>>> @@ -2246,6 +2246,40 @@ gimplify_decl_expr (tree *stmt_p, gimple_seq 
> >>>> *seq_p)
> >>>>             && clear_padding_type_may_have_padding_p (TREE_TYPE (decl)))
> >>>>           gimple_add_padding_init_for_auto_var (decl, is_vla, seq_p);
> >>>>       }
> >>>> +      else if (flag_strict_extended_asm && !init && DECL_HARD_REGISTER 
> >>>> (decl))
> >>>> +       {
> >>>> +         /* Register asm objects may be used uninitialized as inputs.
> >>>> +            Therefore, a naive translation into hard register 
> >>>> constraints
> >>>> +            would render the demoted objects to be default initialized 
> >>>> by
> >>>> +            init-regs and as a consequence, once hard register 
> >>>> constraints
> >>>> +            materialize for an Extended Asm, hard registers would be 
> >>>> zeroed
> >>>> +            which didn't happen before.  Therefore, to overcome this,
> >>>> +            initialize each demoted object with the current contents of 
> >>>> the
> >>>> +            hard register it previously referred to.  For example, 
> >>>> translate
> >>>> +
> >>>> +            register int x asm ("r5");
> >>>> +            int y;
> >>>> +            asm ("..." : "=r" (y) : "r" (x));
> >>>> +
> >>>> +            to
> >>>> +
> >>>> +            register int tmp asm ("r5");
> >>>> +            int x = tmp;
> >>>> +            int y;
> >>>> +            asm ("..." : "=r" (y) : "{r5}" (x));
> >>>> +
> >>>> +            Do this unconditionally for all uninitialized register asm 
> >>>> objects
> >>>> +            and let subsequent passes remove dead stores in case those 
> >>>> objects
> >>>> +            are initialized at later points or are used exclusively as 
> >>>> output
> >>>> +            operands.  */
> >>>> +         tree tmp = create_tmp_var (TREE_TYPE (decl), "regasm");
> >>>> +         SET_DECL_ASSEMBLER_NAME (tmp, DECL_ASSEMBLER_NAME (decl));
> >>>> +         DECL_REGISTER (tmp) = 1;
> >>>> +         DECL_HARD_REGISTER (tmp) = 1;
> >>>> +         DECL_INITIAL (decl) = tmp;
> >>>> +         *stmt_p = stmt;
> >>>> +         return gimplify_decl_expr (stmt_p, seq_p);
> >>>> +       }
> >>>>    }
> >>>> 
> >>>>  return GS_ALL_DONE;
> >>>> @@ -7976,6 +8010,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)
> >>>> +       {
> >>>> +         /* At this point we have a constraint which entails all the
> >>>> +            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 +8162,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 +8362,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 +8380,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 +8398,55 @@ gimplify_asm_expr (tree *expr_p, gimple_seq 
> >>>> *pre_p, gimple_seq *post_p)
> >>>>           }
> >>>>       }
> >>>> 
> >>>> +      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))
> >>>> +                   {
> >>>> +                     tree id2 = DECL_ASSEMBLER_NAME (inputv2);
> >>>> +                     const char *regname2 = IDENTIFIER_POINTER (id2);
> >>>> +                     ++regname2;
> >>>> +                     int regno2 = decode_reg_name (regname2);
> >>>> +                     if (regno2 < 0)
> >>>> +                       continue;
> >>>> +                     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 +8516,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 +22032,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..cb98d6197fa 100644
> >>>> --- a/gcc/stmt.cc
> >>>> +++ b/gcc/stmt.cc
> >>>> @@ -249,6 +249,15 @@ hardreg_ok_p (int reg_number, machine_mode mode, 
> >>>> int operand_num)
> >>>>  return false;
> >>>> }
> >>>> 
> >>>> +static inline bool
> >>>> +rclass_entails_registers (enum reg_class rclass, int regno, int nregs)
> >>>> +{
> >>>> +  for (int i = regno; i < regno + nregs ; ++i)
> >>>> +    if (!TEST_HARD_REG_BIT (reg_class_contents[rclass], i))
> >>>> +      return false;
> >>>> +  return true;
> >>>> +}
> >>>> +
> >>>> /* Parse the output constraint pointed to by *CONSTRAINT_P.  It is the
> >>>>   OPERAND_NUMth output operand, indexed from zero.  There are NINPUTS
> >>>>   inputs and NOUTPUTS outputs to this extended-asm.  Upon return,
> >>>> @@ -499,6 +508,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));
> >>>> +               int nregs = hard_regno_nregs (regno, mode);
> >>>> +               if (rclass != NO_REGS
> >>>> +                   && !rclass_entails_registers (rclass, regno, nregs))
> >>>> +                 {
> >>>> +                   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 +782,22 @@ 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));
> >>>> +             int nregs = hard_regno_nregs (regno, mode);
> >>>> +             if (rclass != NO_REGS
> >>>> +                 && !rclass_entails_registers (rclass, regno, nregs))
> >>>> +               {
> >>>> +                 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;
> >>>> +}
> >>>> --
> >>>> 2.54.0
> >>>> 

Reply via email to