https://gcc.gnu.org/g:35c4a383d6d8f7a9a094d364201daf0d098e4f42
commit r15-6327-g35c4a383d6d8f7a9a094d364201daf0d098e4f42 Author: Jakub Jelinek <ja...@redhat.com> Date: Wed Dec 18 11:50:26 2024 +0100 inline-asm: Add - constraint modifier support for toplevel extended asm [PR41045] The following patch adds - constraint modifier support (only in toplevel asms), which one can use to allow i, s and n constraint to accept SYMBOL_REFs even with -fpic. So, the recommended way mark toplevel asm as defining some symbol would be ":" constraint (usually with cc modifier in the pattern), while to mark toplevel asm as using some symbol (again, either function or variable), one would use "-s" constraint again with address of that function or variable. 2024-12-18 Jakub Jelinek <ja...@redhat.com> PR c/41045 gcc/ * stmt.cc (parse_output_constraint, parse_input_constraint): Handle - modifier. * recog.h (raw_constraint_p): Declare. * recog.cc (raw_constraint_p): New variable. (asm_operand_ok, constrain_operands): Handle - modifier. * common.md (i, s, n): For raw_constraint_p don't require LEGITIMATE_PIC_OPERAND_P. * doc/md.texi: Document - constraint modifier. gcc/c/ * c-typeck.cc (build_asm_expr): Reject - constraint modifier inside of a function. gcc/cp/ * semantics.cc (finish_asm_stmt): Reject - constraint modifier inside of a function. gcc/testsuite/ * c-c++-common/toplevel-asm-4.c: Add missing %cc2 use in template, add bar, x, &y operands with "-i" and "-s" constraints. (x, y): New variables. (bar): Declare. * c-c++-common/toplevel-asm-7.c: New test. * c-c++-common/toplevel-asm-8.c: New test. Diff: --- gcc/c/c-typeck.cc | 10 ++++++++++ gcc/common.md | 6 +++--- gcc/cp/semantics.cc | 10 ++++++++++ gcc/doc/md.texi | 22 ++++++++++++++++++++++ gcc/recog.cc | 19 ++++++++++++++++++- gcc/recog.h | 3 +++ gcc/stmt.cc | 4 ++-- gcc/testsuite/c-c++-common/toplevel-asm-4.c | 4 +++- gcc/testsuite/c-c++-common/toplevel-asm-7.c | 16 ++++++++++++++++ gcc/testsuite/c-c++-common/toplevel-asm-8.c | 13 +++++++++++++ 10 files changed, 100 insertions(+), 7 deletions(-) diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 7be645fdf198..9756edaae084 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -12332,6 +12332,11 @@ build_asm_expr (location_t loc, tree string, tree outputs, tree inputs, } } } + else if (output != error_mark_node && strstr (constraint, "-")) + { + error_at (loc, "%<-%> modifier used inside of a function"); + output = error_mark_node; + } TREE_VALUE (tail) = output; } @@ -12417,6 +12422,11 @@ build_asm_expr (location_t loc, tree string, tree outputs, tree inputs, } } } + else if (input != error_mark_node && strstr (constraint, "-")) + { + error_at (loc, "%<-%> modifier used inside of a function"); + input = error_mark_node; + } TREE_VALUE (tail) = input; } diff --git a/gcc/common.md b/gcc/common.md index 6a2d453eeb1d..3cefa93cb813 100644 --- a/gcc/common.md +++ b/gcc/common.md @@ -92,13 +92,13 @@ (define_constraint "i" "Matches a general integer constant." (and (match_test "CONSTANT_P (op)") - (match_test "!flag_pic || LEGITIMATE_PIC_OPERAND_P (op)"))) + (match_test "!flag_pic || raw_constraint_p || LEGITIMATE_PIC_OPERAND_P (op)"))) (define_constraint "s" "Matches a symbolic integer constant." (and (match_test "CONSTANT_P (op)") (match_test "!CONST_SCALAR_INT_P (op)") - (match_test "!flag_pic || LEGITIMATE_PIC_OPERAND_P (op)"))) + (match_test "!flag_pic || raw_constraint_p || LEGITIMATE_PIC_OPERAND_P (op)"))) (define_constraint ":" "Defines a symbol." @@ -108,7 +108,7 @@ (define_constraint "n" "Matches a non-symbolic integer constant." (and (match_test "CONST_SCALAR_INT_P (op)") - (match_test "!flag_pic || LEGITIMATE_PIC_OPERAND_P (op)"))) + (match_test "!flag_pic || raw_constraint_p || LEGITIMATE_PIC_OPERAND_P (op)"))) (define_constraint "E" "Matches a floating-point constant." diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 948eb8996786..9912c5e50c49 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -2255,6 +2255,11 @@ finish_asm_stmt (location_t loc, int volatile_p, tree string, } } } + else if (operand != error_mark_node && strstr (constraint, "-")) + { + error_at (loc, "%<-%> modifier used inside of a function"); + operand = error_mark_node; + } TREE_VALUE (t) = operand; } @@ -2383,6 +2388,11 @@ finish_asm_stmt (location_t loc, int volatile_p, tree string, } } } + else if (operand != error_mark_node && strstr (constraint, "-")) + { + error_at (loc, "%<-%> modifier used inside of a function"); + operand = error_mark_node; + } TREE_VALUE (t) = operand; } diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index 0ed1bc121438..0457bb56dcd0 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -1889,6 +1889,28 @@ register preferences. @dots{}) @end smallexample @end ifset + +@cindex @samp{-} in constraint +@item - +Says that the selected following constraints within the same alternative +should be matched differently. Normally in PIC code symbolic operands +in constraints like @samp{i}, @samp{s} or @samp{n} are not allowed at all +or severely restricted. The @samp{-} modifier, which is only allowed +outside of functions, allows symbolic operands even in PIC code. This +modifier is usually used together with the @code{cc} operand modifier. + +@smallexample +extern void foo (void), bar (void); +int v; +extern int w; +asm (".globl %cc0, %cc2; .text; %cc0: call %cc1; ret; .data; %cc2: .word %cc3" + :: ":" (foo), "-s" (&bar), ":" (&w), "-i" (&v)); +@end smallexample + +This asm declaration tells the compiler it defines function @code{foo} and +variable @code{w} and uses function @code{bar} and variable @code{v}. This +will compile even with PIC, but it is up to the user to ensure it will +assemble correctly and have the expected behavior. @end table @node Machine Constraints diff --git a/gcc/recog.cc b/gcc/recog.cc index d1811f3618d2..f4f1a6b6a90a 100644 --- a/gcc/recog.cc +++ b/gcc/recog.cc @@ -86,6 +86,9 @@ static operand_alternative asm_op_alt[MAX_RECOG_OPERANDS int which_alternative; +/* True for inline asm operands with - constraint modifier. */ +bool raw_constraint_p; + /* Nonzero after end of reload pass. Set to 1 or 0 by toplev.cc. Controls the significance of (SUBREG (MEM)). */ @@ -2287,6 +2290,7 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints) switch (c) { case ',': + raw_constraint_p = false; constraint++; continue; @@ -2337,6 +2341,11 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints) result = 1; break; + case '-': + raw_constraint_p = true; + constraint++; + continue; + case '<': case '>': /* ??? Before auto-inc-dec, auto inc/dec insns are not supposed @@ -2394,8 +2403,12 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints) constraint++; while (--len && *constraint && *constraint != ','); if (len) - return 0; + { + raw_constraint_p = false; + return 0; + } } + raw_constraint_p = false; /* For operands without < or > constraints reject side-effects. */ if (AUTO_INC_DEC && !incdec_ok && result && MEM_P (op)) @@ -3189,6 +3202,9 @@ constrain_operands (int strict, alternative_mask alternatives) case ',': c = '\0'; break; + case '-': + raw_constraint_p = true; + break; case '#': /* Ignore rest of this alternative as far as @@ -3344,6 +3360,7 @@ constrain_operands (int strict, alternative_mask alternatives) } while (p += len, c); + raw_constraint_p = false; constraints[opno] = p; /* If this operand did not win somehow, this alternative loses. */ diff --git a/gcc/recog.h b/gcc/recog.h index 17ccdb6296be..b37af086570d 100644 --- a/gcc/recog.h +++ b/gcc/recog.h @@ -362,6 +362,9 @@ private: matched. */ extern int which_alternative; +/* True for inline asm operands with - constraint modifier. */ +extern bool raw_constraint_p; + /* The following vectors hold the results from insn_extract. */ struct recog_data_d diff --git a/gcc/stmt.cc b/gcc/stmt.cc index 6789eeeea2dc..8ee4333a50b1 100644 --- a/gcc/stmt.cc +++ b/gcc/stmt.cc @@ -268,7 +268,7 @@ parse_output_constraint (const char **constraint_p, int operand_num, case 'E': case 'F': case 'G': case 'H': case 's': case 'i': case 'n': case 'I': case 'J': case 'K': case 'L': case 'M': - case 'N': case 'O': case 'P': case ',': + case 'N': case 'O': case 'P': case ',': case '-': break; case '0': case '1': case '2': case '3': case '4': @@ -363,7 +363,7 @@ parse_input_constraint (const char **constraint_p, int input_num, case 'E': case 'F': case 'G': case 'H': case 's': case 'i': case 'n': case 'I': case 'J': case 'K': case 'L': case 'M': - case 'N': case 'O': case 'P': case ',': + case 'N': case 'O': case 'P': case ',': case '-': break; case ':': diff --git a/gcc/testsuite/c-c++-common/toplevel-asm-4.c b/gcc/testsuite/c-c++-common/toplevel-asm-4.c index 2f100a65f426..392eef5e4788 100644 --- a/gcc/testsuite/c-c++-common/toplevel-asm-4.c +++ b/gcc/testsuite/c-c++-common/toplevel-asm-4.c @@ -3,6 +3,8 @@ /* { dg-options "-O0" } */ extern int v[42], w; +int x[42], y; void foo (void); +void bar (void) {} -asm ("# %cc0: %cc1:" :: ":" (foo), ":" (v), ":" (&w)); +asm ("# %cc0: %cc1: %cc2: %cc3 %cc4 %cc5" :: ":" (foo), ":" (v), ":" (&w), "-i" (bar), "-s" (x), "-s" (&y)); diff --git a/gcc/testsuite/c-c++-common/toplevel-asm-7.c b/gcc/testsuite/c-c++-common/toplevel-asm-7.c new file mode 100644 index 000000000000..ed2603ffef0f --- /dev/null +++ b/gcc/testsuite/c-c++-common/toplevel-asm-7.c @@ -0,0 +1,16 @@ +/* PR c/41045 */ +/* { dg-do compile } */ +/* { dg-options "-O0" } */ +/* { dg-additional-options "-fpic" { target fpic } } */ + +struct S { char a; long long b; int c; }; +enum E { E0, E1 = sizeof (struct S) + 15 }; +int v[42]; +void foo (void) {} + +asm ("# %0 %1 %2 %cc3 %cc4 %% %=" + :: "i" (sizeof (struct S)), + "i" (__builtin_offsetof (struct S, c)), + "i" (E1), + "-s" (foo), + "-i" (v)); diff --git a/gcc/testsuite/c-c++-common/toplevel-asm-8.c b/gcc/testsuite/c-c++-common/toplevel-asm-8.c new file mode 100644 index 000000000000..3b8f471fc2cd --- /dev/null +++ b/gcc/testsuite/c-c++-common/toplevel-asm-8.c @@ -0,0 +1,13 @@ +/* PR c/41045 */ +/* { dg-do compile } */ +/* { dg-options "-O0" } */ + +void +foo (void) +{ + int m; + asm ("" : "=-m" (m)); /* { dg-error "'-' modifier used inside of a function" } */ + asm ("" : : "-m" (m)); /* { dg-error "'-' modifier used inside of a function" } */ + asm ("" : : "-i" (32)); /* { dg-error "'-' modifier used inside of a function" } */ + asm ("" : : "-s" (foo)); /* { dg-error "'-' modifier used inside of a function" } */ +}