diff mbox series

[RFC,3/4] genoutput: Verify hard register constraints

Message ID 20240910142121.3285492-4-stefansf@gcc.gnu.org
State New
Headers show
Series Hard Register Constraints | expand

Commit Message

Stefan Schulze Frielinghaus Sept. 10, 2024, 2:21 p.m. UTC
Since genoutput has no information about hard register names we cannot
statically verify those names in constraints of the machine description.
Therefore, we have to do it at runtime.  Although verification shouldn't
be too expensive, restrict it to checking builds.  This should be
sufficient since hard register constraints in machine descriptions
probably change rarely, and each commit should be tested with checking
anyway, or at the very least before a release is taken.
---
 gcc/genoutput.cc | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 gcc/output.h     |  2 ++
 gcc/toplev.cc    |  4 ++++
 3 files changed, 52 insertions(+)
diff mbox series

Patch

diff --git a/gcc/genoutput.cc b/gcc/genoutput.cc
index 2ffb2fb28d2..4f4fde83608 100644
--- a/gcc/genoutput.cc
+++ b/gcc/genoutput.cc
@@ -200,6 +200,8 @@  static const char indep_constraints[] = ",=+%*?!^$#&g";
 static class constraint_data *
 constraints_by_letter_table[1 << CHAR_BIT];
 
+static hash_set<free_string_hash> used_reg_names;
+
 static int mdep_constraint_len (const char *, file_location, int);
 static void note_constraint (md_rtx_info *);
 
@@ -1156,6 +1158,45 @@  main (int argc, const char **argv)
   output_insn_data ();
   output_get_insn_name ();
 
+  /* Since genoutput has no information about hard register names we cannot
+     statically verify hard register names in constraints of the machine
+     description.  Therefore, we have to do it at runtime.  Although
+     verification shouldn't be too expensive, restrict it to checking builds.
+   */
+  printf ("\n\n#if CHECKING_P\n");
+  if (used_reg_names.is_empty ())
+    printf ("void verify_reg_names_in_constraints () { }\n");
+  else
+    {
+      size_t max_len = 0;
+      for (auto it = used_reg_names.begin (); it != used_reg_names.end (); ++it)
+	{
+	  size_t len = strlen (*it);
+	  if (len > max_len)
+	    max_len = len;
+	}
+      printf ("void\nverify_reg_names_in_constraints ()\n{\n");
+      printf ("  static const char hregnames[%zu][%zu] = {\n",
+	      used_reg_names.elements (), max_len + 1);
+      auto it = used_reg_names.begin ();
+      while (it != used_reg_names.end ())
+	{
+	  printf ("    \"%s\"", *it);
+	  ++it;
+	  if (it != used_reg_names.end ())
+	    printf (",");
+	  printf ("\n");
+	}
+      printf ("  };\n");
+      printf ("  for (size_t i = 0; i < %zu; ++i)\n",
+	      used_reg_names.elements ());
+      printf ("    if (decode_reg_name (hregnames[i]) < 0)\n");
+      printf ("      internal_error (\"invalid register %%qs used in "
+	      "constraint of machine description\", hregnames[i]);\n");
+      printf ("}\n");
+    }
+  printf ("#endif\n");
+
   fflush (stdout);
   return (ferror (stdout) != 0 || have_error
 	? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
@@ -1294,6 +1335,11 @@  mdep_constraint_len (const char *s, file_location loc, int opno)
       ptrdiff_t len = end - s;
       if (*end == '}' && len > 1 && len < 31)
 	{
+	  char *regname = new char[len];
+	  memcpy (regname, s + 1, len - 1);
+	  regname[len - 1] = '\0';
+	  if (used_reg_names.add (regname))
+	    delete[] regname;
 	  return len + 1;
 	}
     }
diff --git a/gcc/output.h b/gcc/output.h
index 46b0033b221..5f0f8a6098c 100644
--- a/gcc/output.h
+++ b/gcc/output.h
@@ -636,4 +636,6 @@  extern int default_address_cost (rtx, machine_mode, addr_space_t, bool);
 /* Stack usage.  */
 extern void output_stack_usage (void);
 
+extern void verify_reg_names_in_constraints ();
+
 #endif /* ! GCC_OUTPUT_H */
diff --git a/gcc/toplev.cc b/gcc/toplev.cc
index bc442a08c63..34c372ad1a2 100644
--- a/gcc/toplev.cc
+++ b/gcc/toplev.cc
@@ -1817,6 +1817,10 @@  backend_init_target (void)
 static void
 backend_init (void)
 {
+#if CHECKING_P
+  verify_reg_names_in_constraints ();
+#endif
+
   init_emit_once ();
 
   init_rtlanal ();