aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2024-12-18 11:44:36 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2024-12-18 11:44:36 +0100
commitc7f725cd8d8e418818a8283fd5ef393a977753d5 (patch)
treeaaadc467dc46e8d513112714bfcf4576ce07c626
parent18aff7644ad1e44dc146d36a2b7e397977aa47ac (diff)
downloadgcc-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.cc14
-rw-r--r--gcc/common.md5
-rw-r--r--gcc/cp/semantics.cc14
-rw-r--r--gcc/doc/md.texi7
-rw-r--r--gcc/genpreds.cc6
-rw-r--r--gcc/stmt.cc20
-rw-r--r--gcc/testsuite/c-c++-common/toplevel-asm-4.c9
-rw-r--r--gcc/testsuite/c-c++-common/toplevel-asm-5.c28
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" } */
+}