Message ID | ZytFsoNeLG7ZAuDN@tucnak |
---|---|
State | New |
Headers | show |
Series | [RFC] inline asm, v2: Add new constraint for symbol definitions | expand |
On Wed, 6 Nov 2024, Jakub Jelinek wrote: > On Wed, Nov 06, 2024 at 09:08:10AM +0100, Richard Biener wrote: > > It would probably be cleanest to have a separate print modifier for > > "symbol for assembler label definition" or so, but given this feature > > See the patch I'll post next. > > > targets existing uses those already know how to emit the definition > > without any operand or print modifier - something that should continue > > to work. So maybe we should document that there isn't any print > > modifier and users need to arrange for mangling for themselves? > > > > Otherwise I expected a symbol definition to be an asm output, > > not an input, but that's probably a bikeshedding minor detail. > > I've considered that, but it would be much harder internally (output > operands generally need an lvalue, so this would need to be an exception > everywhere) and the operand argument is address of something (especially > so that one can just use function names in the operand and having another > exception to avoid function to function-pointer or array to pointer > promotions given specific constraints would be a nightmare), so that > certainly isn't modified. Ah, good enough reason then. > Anyway, testing showed that @ isn't a good character, while the generic > code doesn't mention @ anywhere, some targets use @ in the output > constraints for the =@cc<something> syntax of testing flags; > while the @ I was proposing was an input constraint and in theory I could > just remove that > + case '@': > + error ("%<@%> constraint used for output operand"); > + return false; > hunk from the patch, if @ means something different in output > vs. input constraints, it would just confuse people. > > So, here is the patch reworked to use : instead of @. > Mnemotechnically, : is better, the : character is what is used > in many assemblers after the symbol names for the symbol definitions. I probably couldn't care less ... sure, ':' works for me. '.' would be available as well, so would ".set" or ".def" (it doesn't need to be a single letter?). So fine with me, please leave frontend folks and others some time to comment. It warrants a changes.html entry and the documentation should probably be amended with a more complete example also using the 'cc' print modifier? Thanks, Richard. > 2024-11-06 Jakub Jelinek <jakub@redhat.com> > > gcc/ > * genpreds.cc (mangle): Add ':' mangling. > (add_constraint): Allow : constraint. > * common.md (:): New define_constraint. > * stmt.cc (parse_output_constraint): Diagnose "=:". > (parse_input_constraint): Handle ":" and diagnose invalid > uses. > * doc/md.texi (Simple Constraints): Document ":" constraint. > gcc/c/ > * c-typeck.cc (build_asm_expr): Diagnose invalid ":" constraint > uses. > gcc/cp/ > * semantics.cc (finish_asm_stmt): Diagnose invalid ":" constraint > uses. > gcc/testsuite/ > * c-c++-common/toplevel-asm-4.c: New test. > * c-c++-common/toplevel-asm-5.c: New test. > > --- gcc/genpreds.cc.jj 2024-02-10 11:25:10.404468273 +0100 > +++ gcc/genpreds.cc 2024-11-05 14:57:14.193060528 +0100 > @@ -753,6 +753,7 @@ mangle (const char *name) > case '_': obstack_grow (rtl_obstack, "__", 2); break; > case '<': obstack_grow (rtl_obstack, "_l", 2); break; > case '>': obstack_grow (rtl_obstack, "_g", 2); break; > + case ':': obstack_grow (rtl_obstack, "_c", 2); break; > default: obstack_1grow (rtl_obstack, *name); break; > } > > @@ -797,12 +798,13 @@ add_constraint (const char *name, const > for (p = name; *p; p++) > if (!ISALNUM (*p)) > { > - if (*p == '<' || *p == '>' || *p == '_') > + if (*p == '<' || *p == '>' || *p == '_' || *p == ':') > need_mangled_name = true; > else > { > error_at (loc, "constraint name '%s' must be composed of letters," > - " digits, underscores, and angle brackets", name); > + " digits, underscores, colon and angle brackets", > + name); > return; > } > } > --- gcc/common.md.jj 2024-01-03 11:51:24.519828508 +0100 > +++ gcc/common.md 2024-11-05 14:51:29.098989927 +0100 > @@ -100,6 +100,11 @@ (define_constraint "s" > (match_test "!CONST_SCALAR_INT_P (op)") > (match_test "!flag_pic || LEGITIMATE_PIC_OPERAND_P (op)"))) > > +(define_constraint ":" > + "Defines a symbol." > + (and (match_test "CONSTANT_P (op)") > + (match_test "!CONST_SCALAR_INT_P (op)"))) > + > (define_constraint "n" > "Matches a non-symbolic integer constant." > (and (match_test "CONST_SCALAR_INT_P (op)") > --- gcc/stmt.cc.jj 2024-10-25 10:00:29.523767070 +0200 > +++ gcc/stmt.cc 2024-11-05 18:31:11.518948252 +0100 > @@ -278,6 +278,10 @@ parse_output_constraint (const char **co > error ("matching constraint not valid in output operand"); > return false; > > + case ':': > + error ("%<:%> constraint used for output operand"); > + return false; > + > case '<': case '>': > /* ??? Before flow, auto inc/dec insns are not supposed to exist, > excepting those that expand_call created. So match memory > @@ -325,6 +329,7 @@ parse_input_constraint (const char **con > size_t c_len = strlen (constraint); > size_t j; > bool saw_match = false; > + bool at_checked = false; > > /* Assume the constraint doesn't allow the use of either > a register or memory. */ > @@ -362,6 +367,21 @@ parse_input_constraint (const char **con > case 'N': case 'O': case 'P': case ',': > break; > > + case ':': > + /* Verify that if : is used, it is just ":" or say ":,:" but not > + mixed with other constraints or say ",:,," etc. */ > + if (!at_checked) > + { > + for (size_t k = 0; k < c_len; ++k) > + if (constraint[k] != ((k & 1) ? ',' : ':') || (c_len & 1) == 0) > + { > + error ("%<:%> constraint mixed with other constraints"); > + return false; > + } > + at_checked = true; > + } > + break; > + > /* Whether or not a numeric constraint allows a register is > decided by the matching constraint, and so there is no need > to do anything special with them. We must handle them in > --- gcc/doc/md.texi.jj 2024-10-16 14:41:45.553757783 +0200 > +++ gcc/doc/md.texi 2024-11-05 18:46:30.795896301 +0100 > @@ -1504,6 +1504,13 @@ as the predicate in the @code{match_oper > the mode specified in the @code{match_operand} as the mode of the memory > reference for which the address would be valid. > > +@cindex @samp{:} in constraint > +@item @samp{:} > +This constraint, allowed only in input operands, says the inline @code{asm} > +pattern defines specific function or variable symbol. The constraint > +shouldn't be mixed with other constraints on the same operand and > +the operand should be address of a function or non-automatic variable. > + > @cindex other register constraints > @cindex extensible constraints > @item @var{other-letters} > --- gcc/c/c-typeck.cc.jj 2024-11-05 14:44:35.904892730 +0100 > +++ gcc/c/c-typeck.cc 2024-11-05 18:25:34.837723892 +0100 > @@ -12246,6 +12246,20 @@ build_asm_expr (location_t loc, tree str > error_at (loc, "invalid constraint outside of a function"); > input = error_mark_node; > } > + if (constraint[0] == ':' && input != error_mark_node) > + { > + tree t = input; > + STRIP_NOPS (t); > + if (TREE_CODE (t) != ADDR_EXPR > + || !(TREE_CODE (TREE_OPERAND (t, 0)) == FUNCTION_DECL > + || (VAR_P (TREE_OPERAND (t, 0)) > + && is_global_var (TREE_OPERAND (t, 0))))) > + { > + error_at (loc, "%<:%> constraint operand is not address " > + "of a function or non-automatic variable"); > + input = error_mark_node; > + } > + } > } > else > input = error_mark_node; > --- gcc/cp/semantics.cc.jj 2024-11-05 14:44:35.911892630 +0100 > +++ gcc/cp/semantics.cc 2024-11-05 18:27:05.162442682 +0100 > @@ -2325,6 +2325,20 @@ finish_asm_stmt (location_t loc, int vol > error_at (loc, "invalid constraint outside of a function"); > operand = error_mark_node; > } > + if (constraint[0] == ':' && operand != error_mark_node) > + { > + tree t = operand; > + STRIP_NOPS (t); > + if (TREE_CODE (t) != ADDR_EXPR > + || !(TREE_CODE (TREE_OPERAND (t, 0)) == FUNCTION_DECL > + || (VAR_P (TREE_OPERAND (t, 0)) > + && is_global_var (TREE_OPERAND (t, 0))))) > + { > + error_at (loc, "%<:%> constraint operand is not address " > + "of a function or non-automatic variable"); > + operand = error_mark_node; > + } > + } > } > else > operand = error_mark_node; > --- gcc/testsuite/c-c++-common/toplevel-asm-4.c.jj 2024-11-05 18:13:20.062136936 +0100 > +++ gcc/testsuite/c-c++-common/toplevel-asm-4.c 2024-11-05 18:36:26.800476151 +0100 > @@ -0,0 +1,9 @@ > +/* PR c/41045 */ > +/* { dg-do compile } */ > +/* { dg-options "-O0" } */ > +/* { dg-additional-options "-fno-pie" { target pie } } */ > + > +int v[42], w; > +void foo (void); > + > +asm ("# %c0: %c1:" :: ":" (foo), ":" (v), ":" (&w)); > --- gcc/testsuite/c-c++-common/toplevel-asm-5.c.jj 2024-11-05 18:14:44.449941185 +0100 > +++ gcc/testsuite/c-c++-common/toplevel-asm-5.c 2024-11-05 18:36:57.873035404 +0100 > @@ -0,0 +1,16 @@ > +/* PR c/41045 */ > +/* { dg-do compile } */ > +/* { dg-options "-O0" } */ > +/* { dg-additional-options "-fno-pie" { target pie } } */ > + > +extern int v[42]; > + > +asm ("# %0" : "=:" (32)); /* { dg-error "lvalue required in 'asm' statement" } */ > + /* { dg-error "':' constraint used for output operand" "" { target *-*-* } .-1 } */ > +asm ("# %0" : "=:" (v)); /* { dg-error "':' constraint used for output operand" } */ > +asm ("# %0" : : "i:" (v)); /* { dg-error "':' constraint mixed with other constraints" } */ > +asm ("# %0" : : ":i" (v)); /* { dg-error "':' constraint mixed with other constraints" } */ > +asm ("# %0" : : ",:" (v)); /* { dg-error "':' constraint mixed with other constraints" } */ > +asm ("# %0" : : ":,:" (v)); > +asm ("# %0" : : ":," (v)); /* { dg-error "':' constraint mixed with other constraints" } */ > +asm ("# %0" : : ":,,:" (v)); /* { dg-error "':' constraint mixed with other constraints" } */ > > Jakub > >
On Wed, Nov 06, 2024 at 03:13:10PM +0100, Richard Biener wrote: > I probably couldn't care less ... sure, ':' works for me. '.' would > be available as well, so would ".set" or ".def" (it doesn't need to be > a single letter?). > > So fine with me, please leave frontend folks and others some time > to comment. The patch also depends on the toplevel asm patch, so I need to wait for that too. > > It warrants a changes.html entry Sure, plan to do that for various recent changes. > and the documentation should probably > be amended with a more complete example also using the 'cc' print > modifier? The cc modifier patch adds an example there. Jakub
--- gcc/genpreds.cc.jj 2024-02-10 11:25:10.404468273 +0100 +++ gcc/genpreds.cc 2024-11-05 14:57:14.193060528 +0100 @@ -753,6 +753,7 @@ mangle (const char *name) case '_': obstack_grow (rtl_obstack, "__", 2); break; case '<': obstack_grow (rtl_obstack, "_l", 2); break; case '>': obstack_grow (rtl_obstack, "_g", 2); break; + case ':': obstack_grow (rtl_obstack, "_c", 2); break; default: obstack_1grow (rtl_obstack, *name); break; } @@ -797,12 +798,13 @@ add_constraint (const char *name, const for (p = name; *p; p++) if (!ISALNUM (*p)) { - if (*p == '<' || *p == '>' || *p == '_') + if (*p == '<' || *p == '>' || *p == '_' || *p == ':') need_mangled_name = true; else { error_at (loc, "constraint name '%s' must be composed of letters," - " digits, underscores, and angle brackets", name); + " digits, underscores, colon and angle brackets", + name); return; } } --- gcc/common.md.jj 2024-01-03 11:51:24.519828508 +0100 +++ gcc/common.md 2024-11-05 14:51:29.098989927 +0100 @@ -100,6 +100,11 @@ (define_constraint "s" (match_test "!CONST_SCALAR_INT_P (op)") (match_test "!flag_pic || LEGITIMATE_PIC_OPERAND_P (op)"))) +(define_constraint ":" + "Defines a symbol." + (and (match_test "CONSTANT_P (op)") + (match_test "!CONST_SCALAR_INT_P (op)"))) + (define_constraint "n" "Matches a non-symbolic integer constant." (and (match_test "CONST_SCALAR_INT_P (op)") --- gcc/stmt.cc.jj 2024-10-25 10:00:29.523767070 +0200 +++ gcc/stmt.cc 2024-11-05 18:31:11.518948252 +0100 @@ -278,6 +278,10 @@ parse_output_constraint (const char **co error ("matching constraint not valid in output operand"); return false; + case ':': + error ("%<:%> constraint used for output operand"); + return false; + case '<': case '>': /* ??? Before flow, auto inc/dec insns are not supposed to exist, excepting those that expand_call created. So match memory @@ -325,6 +329,7 @@ parse_input_constraint (const char **con size_t c_len = strlen (constraint); size_t j; bool saw_match = false; + bool at_checked = false; /* Assume the constraint doesn't allow the use of either a register or memory. */ @@ -362,6 +367,21 @@ parse_input_constraint (const char **con case 'N': case 'O': case 'P': case ',': break; + case ':': + /* Verify that if : is used, it is just ":" or say ":,:" but not + mixed with other constraints or say ",:,," etc. */ + if (!at_checked) + { + for (size_t k = 0; k < c_len; ++k) + if (constraint[k] != ((k & 1) ? ',' : ':') || (c_len & 1) == 0) + { + error ("%<:%> constraint mixed with other constraints"); + return false; + } + at_checked = true; + } + break; + /* Whether or not a numeric constraint allows a register is decided by the matching constraint, and so there is no need to do anything special with them. We must handle them in --- gcc/doc/md.texi.jj 2024-10-16 14:41:45.553757783 +0200 +++ gcc/doc/md.texi 2024-11-05 18:46:30.795896301 +0100 @@ -1504,6 +1504,13 @@ as the predicate in the @code{match_oper the mode specified in the @code{match_operand} as the mode of the memory reference for which the address would be valid. +@cindex @samp{:} in constraint +@item @samp{:} +This constraint, allowed only in input operands, says the inline @code{asm} +pattern defines specific function or variable symbol. The constraint +shouldn't be mixed with other constraints on the same operand and +the operand should be address of a function or non-automatic variable. + @cindex other register constraints @cindex extensible constraints @item @var{other-letters} --- gcc/c/c-typeck.cc.jj 2024-11-05 14:44:35.904892730 +0100 +++ gcc/c/c-typeck.cc 2024-11-05 18:25:34.837723892 +0100 @@ -12246,6 +12246,20 @@ build_asm_expr (location_t loc, tree str error_at (loc, "invalid constraint outside of a function"); input = error_mark_node; } + if (constraint[0] == ':' && input != error_mark_node) + { + tree t = input; + STRIP_NOPS (t); + if (TREE_CODE (t) != ADDR_EXPR + || !(TREE_CODE (TREE_OPERAND (t, 0)) == FUNCTION_DECL + || (VAR_P (TREE_OPERAND (t, 0)) + && is_global_var (TREE_OPERAND (t, 0))))) + { + error_at (loc, "%<:%> constraint operand is not address " + "of a function or non-automatic variable"); + input = error_mark_node; + } + } } else input = error_mark_node; --- gcc/cp/semantics.cc.jj 2024-11-05 14:44:35.911892630 +0100 +++ gcc/cp/semantics.cc 2024-11-05 18:27:05.162442682 +0100 @@ -2325,6 +2325,20 @@ finish_asm_stmt (location_t loc, int vol error_at (loc, "invalid constraint outside of a function"); operand = error_mark_node; } + if (constraint[0] == ':' && operand != error_mark_node) + { + tree t = operand; + STRIP_NOPS (t); + if (TREE_CODE (t) != ADDR_EXPR + || !(TREE_CODE (TREE_OPERAND (t, 0)) == FUNCTION_DECL + || (VAR_P (TREE_OPERAND (t, 0)) + && is_global_var (TREE_OPERAND (t, 0))))) + { + error_at (loc, "%<:%> constraint operand is not address " + "of a function or non-automatic variable"); + operand = error_mark_node; + } + } } else operand = error_mark_node; --- gcc/testsuite/c-c++-common/toplevel-asm-4.c.jj 2024-11-05 18:13:20.062136936 +0100 +++ gcc/testsuite/c-c++-common/toplevel-asm-4.c 2024-11-05 18:36:26.800476151 +0100 @@ -0,0 +1,9 @@ +/* PR c/41045 */ +/* { dg-do compile } */ +/* { dg-options "-O0" } */ +/* { dg-additional-options "-fno-pie" { target pie } } */ + +int v[42], w; +void foo (void); + +asm ("# %c0: %c1:" :: ":" (foo), ":" (v), ":" (&w)); --- gcc/testsuite/c-c++-common/toplevel-asm-5.c.jj 2024-11-05 18:14:44.449941185 +0100 +++ gcc/testsuite/c-c++-common/toplevel-asm-5.c 2024-11-05 18:36:57.873035404 +0100 @@ -0,0 +1,16 @@ +/* PR c/41045 */ +/* { dg-do compile } */ +/* { dg-options "-O0" } */ +/* { dg-additional-options "-fno-pie" { target pie } } */ + +extern int v[42]; + +asm ("# %0" : "=:" (32)); /* { dg-error "lvalue required in 'asm' statement" } */ + /* { dg-error "':' constraint used for output operand" "" { target *-*-* } .-1 } */ +asm ("# %0" : "=:" (v)); /* { dg-error "':' constraint used for output operand" } */ +asm ("# %0" : : "i:" (v)); /* { dg-error "':' constraint mixed with other constraints" } */ +asm ("# %0" : : ":i" (v)); /* { dg-error "':' constraint mixed with other constraints" } */ +asm ("# %0" : : ",:" (v)); /* { dg-error "':' constraint mixed with other constraints" } */ +asm ("# %0" : : ":,:" (v)); +asm ("# %0" : : ":," (v)); /* { dg-error "':' constraint mixed with other constraints" } */ +asm ("# %0" : : ":,,:" (v)); /* { dg-error "':' constraint mixed with other constraints" } */