]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
inline asm: Add new constraint for symbol definitions
authorJakub Jelinek <jakub@redhat.com>
Wed, 18 Dec 2024 10:44:36 +0000 (11:44 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 18 Dec 2024 10:44:36 +0000 (11:44 +0100)
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.

gcc/c/c-typeck.cc
gcc/common.md
gcc/cp/semantics.cc
gcc/doc/md.texi
gcc/genpreds.cc
gcc/stmt.cc
gcc/testsuite/c-c++-common/toplevel-asm-4.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/toplevel-asm-5.c [new file with mode: 0644]

index 902898d1944b3cc214ffbb99df2e60eb12e97236..7be645fdf198ee54f1fbd04385539092c7f436a4 100644 (file)
@@ -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;
index f23381227ee4aae1cb703bffc83e805b1c0266f8..6a2d453eeb1de493d6843102237ad001876e5422 100644 (file)
        (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)")
index 8dc687f1001ab19bcbe84eacf46ac455db6a4cf2..948eb899678660eb0c6dd79a5375ea3930dfcebd 100644 (file)
@@ -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;
index 32faede817ad69a2361aacbddf9eed07f15bb010..4a65091168405a4b6f27968abee85146511bd63c 100644 (file)
@@ -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}
index b8f3bf279d979ab6e666658a8233b2941d7f9d26..3485ff29ec22484aae785138536dc969883ecd3b 100644 (file)
@@ -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;
          }
       }
index 1a76e05de2dbee04e2dcfc13ff6f94e3d147a40e..6789eeeea2dcff1b12567cd3e511cd2747115745 100644 (file)
@@ -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 (file)
index 0000000..c9a2089
--- /dev/null
@@ -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 (file)
index 0000000..c9c1d7f
--- /dev/null
@@ -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" } */
+}