https://gcc.gnu.org/g:c7f725cd8d8e418818a8283fd5ef393a977753d5

commit r15-6325-gc7f725cd8d8e418818a8283fd5ef393a977753d5
Author: Jakub Jelinek <ja...@redhat.com>
Date:   Wed Dec 18 11:44:36 2024 +0100

    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  <ja...@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.

Diff:
---
 gcc/c/c-typeck.cc                           | 14 ++++++++++++++
 gcc/common.md                               |  5 +++++
 gcc/cp/semantics.cc                         | 14 ++++++++++++++
 gcc/doc/md.texi                             |  7 +++++++
 gcc/genpreds.cc                             |  6 ++++--
 gcc/stmt.cc                                 | 20 ++++++++++++++++++++
 gcc/testsuite/c-c++-common/toplevel-asm-4.c |  9 +++++++++
 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 902898d1944b..7be645fdf198 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 f23381227ee4..6a2d453eeb1d 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 8dc687f1001a..948eb8996786 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 32faede817ad..4a6509116840 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 b8f3bf279d97..3485ff29ec22 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 1a76e05de2db..6789eeeea2dc 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 000000000000..c9a2089fba53
--- /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 000000000000..c9c1d7f77fbb
--- /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" } */
+}

Reply via email to