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? 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 > > > >
