diff options
author | Jakub Jelinek <jakub@redhat.com> | 2024-12-18 11:44:36 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2024-12-18 11:44:36 +0100 |
commit | c7f725cd8d8e418818a8283fd5ef393a977753d5 (patch) | |
tree | aaadc467dc46e8d513112714bfcf4576ce07c626 | |
parent | 18aff7644ad1e44dc146d36a2b7e397977aa47ac (diff) | |
download | gcc-c7f725cd8d8e418818a8283fd5ef393a977753d5.zip gcc-c7f725cd8d8e418818a8283fd5ef393a977753d5.tar.gz gcc-c7f725cd8d8e418818a8283fd5ef393a977753d5.tar.bz2 |
inline asm: Add new constraint for symbol definitions
The following patch on top of the PR41045 toplevel extended asm patch
allows marking inline asms (both toplevel and function-local, admittedly
it is less useful for the latter, so if you want, I can add restrictions)
as defining symbols, either functions or variables.
As most remaining constraint letters are used at least on some targets,
I'm using : as the new constraint. It is similar to "s" in that it
wants CONSTANT_P && !CONST_SCALAR_INT_P, but
1) it specially requires an address of a function or variable declaration,
so for functions the expected use is
void foo (void);
...
":" (foo)
or
":" (&foo)
and for variables (unless they are arrays)
extern int var;
...
":" (&var)
2) it makes no sense to say that either something is defined or it is
used in a register or something similar, so the patch diagnoses if
one attempts to mix it with other constraints; ":,:,:" is allowed
just because one could be using 3 alternatives in some other operand
3) unlike "s", the constraint doesn't check LEGITIMATE_PIC_OPERAND_P for
-fpic, even in -fpic one should be able to use it the same way
4) the cgraph portion needs to be really added later
5) and last but not least, I'm afraid %c0 print modifier isn't very
good for printing it; it works fine without -fpic/-fpie, but 'c'
modifier is handled as
if (CONSTANT_ADDRESS_P (operands[opnum]))
output_addr_const (asm_out_file, operands[opnum]);
else
output_operand (operands[opnum], 'c');
and because at least on some arches like x86 CONSTANT_ADDRESS_P
is redefined to do backend specific PIC mess, it will just
output_operand and likely just be rejected (on x86 with an error
that the argument is not a comparison)
Guess for x86 one can use %p0 instead.
But I'm afraid we are mostly out of generic modifiers,
and targetm.asm_out.print_operand_punct_valid_p seems to use most
of the punctuation characters as well.
I think ` is unused, but wonder if we want to use up the last
remaining letter that way, perhaps make %`<letter>0?
Or extend the existing generic modifiers, keep %c0 behave as it
does right now and make %cc0 be a 2 letter modifier which is
PIC friendly and prints using output_addr_const anything that can
be printed that way? A follow-up patch implements the %cc0 version.
2024-12-18 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.
-rw-r--r-- | gcc/c/c-typeck.cc | 14 | ||||
-rw-r--r-- | gcc/common.md | 5 | ||||
-rw-r--r-- | gcc/cp/semantics.cc | 14 | ||||
-rw-r--r-- | gcc/doc/md.texi | 7 | ||||
-rw-r--r-- | gcc/genpreds.cc | 6 | ||||
-rw-r--r-- | gcc/stmt.cc | 20 | ||||
-rw-r--r-- | gcc/testsuite/c-c++-common/toplevel-asm-4.c | 9 | ||||
-rw-r--r-- | gcc/testsuite/c-c++-common/toplevel-asm-5.c | 28 |
8 files changed, 101 insertions, 2 deletions
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 902898d..7be645f 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -12378,6 +12378,20 @@ build_asm_expr (location_t loc, tree string, tree outputs, tree inputs, "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; diff --git a/gcc/common.md b/gcc/common.md index f233812..6a2d453 100644 --- a/gcc/common.md +++ b/gcc/common.md @@ -100,6 +100,11 @@ (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)") diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 8dc687f..948eb89 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -2326,6 +2326,20 @@ finish_asm_stmt (location_t loc, int volatile_p, tree string, "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; diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index 32faede..4a65091 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -1504,6 +1504,13 @@ as the predicate in the @code{match_operand}. This predicate interprets 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} diff --git a/gcc/genpreds.cc b/gcc/genpreds.cc index b8f3bf2..3485ff2 100644 --- a/gcc/genpreds.cc +++ b/gcc/genpreds.cc @@ -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 char *regclass, 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; } } diff --git a/gcc/stmt.cc b/gcc/stmt.cc index 1a76e05..6789eee 100644 --- a/gcc/stmt.cc +++ b/gcc/stmt.cc @@ -277,6 +277,10 @@ parse_output_constraint (const char **constraint_p, int operand_num, 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 @@ -324,6 +328,7 @@ parse_input_constraint (const char **constraint_p, int input_num, 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. */ @@ -361,6 +366,21 @@ parse_input_constraint (const char **constraint_p, int input_num, 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 diff --git a/gcc/testsuite/c-c++-common/toplevel-asm-4.c b/gcc/testsuite/c-c++-common/toplevel-asm-4.c new file mode 100644 index 0000000..c9a2089 --- /dev/null +++ b/gcc/testsuite/c-c++-common/toplevel-asm-4.c @@ -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)); diff --git a/gcc/testsuite/c-c++-common/toplevel-asm-5.c b/gcc/testsuite/c-c++-common/toplevel-asm-5.c new file mode 100644 index 0000000..c9c1d7f --- /dev/null +++ b/gcc/testsuite/c-c++-common/toplevel-asm-5.c @@ -0,0 +1,28 @@ +/* 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" } */ +asm ("" : : ":" (0)); /* { dg-error "constraint operand is not address of a function or non-automatic variable" } */ + +void +foo (int x) +{ + int y; + l:; + asm ("" : : ":" (&x)); /* { dg-error "constraint operand is not address of a function or non-automatic variable" } */ + asm ("" : : ":" (&&l)); /* { dg-error "constraint operand is not address of a function or non-automatic variable" } */ + asm ("" : : ":" (&y)); /* { dg-error "constraint operand is not address of a function or non-automatic variable" } */ + asm ("" : : ":" (0)); /* { dg-error "constraint operand is not address of a function or non-automatic variable" } */ +} |