diff gcc/gentarget-def.c @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents
children 84e7813d76e9
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gcc/gentarget-def.c	Fri Oct 27 22:46:09 2017 +0900
@@ -0,0 +1,338 @@
+/* Generate insn-target-def.h, an automatically-generated part of targetm.
+   Copyright (C) 1987-2017 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "bconfig.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "rtl.h"
+#include "errors.h"
+#include "read-md.h"
+#include "gensupport.h"
+#include "hash-table.h"
+
+/* This class hashes define_insns and define_expands by name.  */
+struct insn_hasher : nofree_ptr_hash <rtx_def>
+{
+  typedef rtx value_type;
+  typedef const char *compare_type;
+
+  static inline hashval_t hash (rtx);
+  static inline bool equal (rtx, const char *);
+};
+
+hashval_t
+insn_hasher::hash (rtx x)
+{
+  return htab_hash_string (XSTR (x, 0));
+}
+
+bool
+insn_hasher::equal (rtx x, const char *y)
+{
+  return strcmp (XSTR (x, 0), y) == 0;
+}
+
+/* All define_insns and define_expands, hashed by name.  */
+static hash_table <insn_hasher> *insns;
+
+/* Records the prototype suffix X for each invalid_X stub that has been
+   generated.  */
+static hash_table <nofree_string_hash> *stubs;
+
+/* Records which C conditions have been wrapped in functions, as a mapping
+   from the C condition to the function name.  */
+static hash_map <nofree_string_hash, const char *> *have_funcs;
+
+/* Return true if the part of the prototype at P is for an argument
+   name.  If so, point *END_OUT to the first character after the name.
+   If OPNO_OUT is nonnull, set *OPNO_OUT to the number of the associated
+   operand.  If REQUIRED_OUT is nonnull, set *REQUIRED_OUT to whether the
+   .md pattern is required to match the operand.  */
+
+static bool
+parse_argument (const char *p, const char **end_out,
+		unsigned int *opno_out = 0,
+		bool *required_out = 0)
+{
+  while (ISSPACE (*p))
+    p++;
+  if (p[0] == 'x' && ISDIGIT (p[1]))
+    {
+      p += 1;
+      if (required_out)
+	*required_out = true;
+    }
+  else if (p[0] == 'o' && p[1] == 'p' && p[2] == 't' && ISDIGIT (p[3]))
+    {
+      p += 3;
+      if (required_out)
+	*required_out = false;
+    }
+  else
+    return false;
+
+  char *endptr;
+  unsigned int opno = strtol (p, &endptr, 10);
+  if (opno_out)
+    *opno_out = opno;
+  *end_out = endptr;
+  return true;
+}
+
+
+/* Output hook definitions for pattern NAME, which has target-insns.def
+   prototype PROTOTYPE.  */
+
+static void
+def_target_insn (const char *name, const char *prototype)
+{
+  /* Get an upper-case form of NAME.  */
+  unsigned int i;
+  char *upper_name = XALLOCAVEC (char, strlen (name) + 1);
+  for (i = 0; name[i]; ++i)
+    upper_name[i] = TOUPPER (name[i]);
+  upper_name[i] = 0;
+
+  /* Check that the prototype is valid and concatenate the types
+     together to get a suffix.  */
+  char *suffix = XALLOCAVEC (char, strlen (prototype) + 1);
+  i = 0;
+  unsigned int opno = 0;
+  unsigned int required_ops = 0;
+  unsigned int this_opno;
+  bool required_p;
+  for (const char *p = prototype; *p; ++p)
+    if (parse_argument (p, &p, &this_opno, &required_p))
+      {
+	if (this_opno != opno || (*p != ',' && *p != ')'))
+	  {
+	    error ("invalid prototype for '%s'", name);
+	    exit (FATAL_EXIT_CODE);
+	  }
+	if (required_p && required_ops < opno)
+	  {
+	    error ("prototype for '%s' has required operands after"
+		   " optional operands", name);
+	    exit (FATAL_EXIT_CODE);
+	  }
+	opno += 1;
+	if (required_p)
+	  required_ops = opno;
+	/* Skip over ')'s.  */
+	if (*p == ',')
+	  suffix[i++] = '_';
+      }
+    else if (*p == ')' || *p == ',')
+      {
+	/* We found the end of a parameter without finding a
+	   parameter name.  */
+	if (strcmp (prototype, "(void)") != 0)
+	  {
+	    error ("argument %d of '%s' did not have the expected name",
+		   opno, name);
+	    exit (FATAL_EXIT_CODE);
+	  }
+      }
+    else if (*p != '(' && !ISSPACE (*p))
+      suffix[i++] = *p;
+  suffix[i] = 0;
+
+  /* See whether we have an implementation of this pattern.  */
+  hashval_t hash = htab_hash_string (name);
+  int truth = 0;
+  const char *have_name = name;
+  if (rtx insn = insns->find_with_hash (name, hash))
+    {
+      pattern_stats stats;
+      get_pattern_stats (&stats, XVEC (insn, 1));
+      unsigned int actual_ops = stats.num_generator_args;
+      if (opno == required_ops && opno != actual_ops)
+	error_at (get_file_location (insn),
+		  "'%s' must have %d operands (excluding match_dups)",
+		  name, required_ops);
+      else if (actual_ops < required_ops)
+	error_at (get_file_location (insn),
+		  "'%s' must have at least %d operands (excluding match_dups)",
+		  name, required_ops);
+      else if (actual_ops > opno)
+	error_at (get_file_location (insn),
+		  "'%s' must have no more than %d operands"
+		  " (excluding match_dups)", name, opno);
+
+      const char *test = XSTR (insn, 2);
+      truth = maybe_eval_c_test (test);
+      gcc_assert (truth != 0);
+      if (truth < 0)
+	{
+	  /* Try to reuse an existing function that performs the same test.  */
+	  bool existed;
+	  const char *&entry = have_funcs->get_or_insert (test, &existed);
+	  if (!existed)
+	    {
+	      entry = name;
+	      printf ("\nstatic bool\n");
+	      printf ("target_have_%s (void)\n", name);
+	      printf ("{\n");
+	      printf ("  return ");
+	      rtx_reader_ptr->print_c_condition (test);
+	      printf (";\n");
+	      printf ("}\n");
+	    }
+	  have_name = entry;
+	}
+      printf ("\nstatic rtx_insn *\n");
+      printf ("target_gen_%s ", name);
+      /* Print the prototype with the argument names after ACTUAL_OPS
+	 removed.  */
+      const char *p = prototype, *end;
+      while (*p)
+	if (parse_argument (p, &end, &this_opno) && this_opno >= actual_ops)
+	  p = end;
+	else
+	  fputc (*p++, stdout);
+
+      printf ("\n{\n");
+      if (truth < 0)
+	printf ("  gcc_checking_assert (targetm.have_%s ());\n", name);
+      printf ("  return insnify (gen_%s (", name);
+      for (i = 0; i < actual_ops; ++i)
+	printf ("%s%s%d", i == 0 ? "" : ", ",
+		i < required_ops ? "x" : "opt", i);
+      printf ("));\n");
+      printf ("}\n");
+    }
+  else
+    {
+      const char **slot = stubs->find_slot (suffix, INSERT);
+      if (!*slot)
+	{
+	  *slot = xstrdup (suffix);
+	  printf ("\nstatic rtx_insn *\n");
+	  printf ("invalid_%s ", suffix);
+	  /* Print the prototype with the argument names removed.  */
+	  const char *p = prototype;
+	  while (*p)
+	    if (!parse_argument (p, &p))
+	      fputc (*p++, stdout);
+	  printf ("\n{\n");
+	  printf ("  gcc_unreachable ();\n");
+	  printf ("}\n");
+	}
+    }
+  printf ("\n#undef TARGET_HAVE_%s\n", upper_name);
+  printf ("#define TARGET_HAVE_%s ", upper_name);
+  if (truth == 0)
+    printf ("hook_bool_void_false\n");
+  else if (truth == 1)
+    printf ("hook_bool_void_true\n");
+  else
+    printf ("target_have_%s\n", have_name);
+
+  printf ("#undef TARGET_GEN_%s\n", upper_name);
+  printf ("#define TARGET_GEN_%s ", upper_name);
+  if (truth == 0)
+    printf ("invalid_%s\n", suffix);
+  else
+    printf ("target_gen_%s\n", name);
+
+  printf ("#undef TARGET_CODE_FOR_%s\n", upper_name);
+  printf ("#define TARGET_CODE_FOR_%s ", upper_name);
+  if (truth == 0)
+    printf ("CODE_FOR_nothing\n");
+  else
+    printf ("CODE_FOR_%s\n", name);
+}
+
+/* Record the DEFINE_INSN or DEFINE_EXPAND described by INFO.  */
+
+static void
+add_insn (md_rtx_info *info)
+{
+  rtx def = info->def;
+  const char *name = XSTR (def, 0);
+  if (name[0] == 0 || name[0] == '*')
+    return;
+
+  hashval_t hash = htab_hash_string (name);
+  rtx *slot = insns->find_slot_with_hash (name, hash, INSERT);
+  if (*slot)
+    error_at (info->loc, "duplicate definition of '%s'", name);
+  else
+    *slot = def;
+}
+
+int
+main (int argc, const char **argv)
+{
+  progname = "gentarget-def";
+
+  if (!init_rtx_reader_args (argc, argv))
+    return (FATAL_EXIT_CODE);
+
+  insns = new hash_table <insn_hasher> (31);
+  stubs = new hash_table <nofree_string_hash> (31);
+  have_funcs = new hash_map <nofree_string_hash, const char *>;
+
+  md_rtx_info info;
+  while (read_md_rtx (&info))
+    switch (GET_CODE (info.def))
+      {
+      case DEFINE_INSN:
+      case DEFINE_EXPAND:
+	add_insn (&info);
+	break;
+
+      default:
+	break;
+      }
+
+  printf ("/* Generated automatically by the program `gentarget-def'.  */\n");
+  printf ("#ifndef GCC_INSN_TARGET_DEF_H\n");
+  printf ("#define GCC_INSN_TARGET_DEF_H\n");
+
+  /* Output a routine to convert an rtx to an rtx_insn sequence.
+     ??? At some point the gen_* functions themselves should return
+	 rtx_insns.  */
+  printf ("\nstatic inline rtx_insn *\n");
+  printf ("insnify (rtx x)\n");
+  printf ("{\n");
+  printf ("  if (!x)\n");
+  printf ("    return NULL;\n");
+  printf ("  if (rtx_insn *insn = dyn_cast <rtx_insn *> (x))\n");
+  printf ("    return insn;\n");
+  printf ("  start_sequence ();\n");
+  printf ("  emit (x, false);\n");
+  printf ("  rtx_insn *res = get_insns ();\n");
+  printf ("  end_sequence ();\n");
+  printf ("  return res;\n");
+  printf ("}\n");
+
+#define DEF_TARGET_INSN(INSN, ARGS) \
+  def_target_insn (#INSN, #ARGS);
+#include "target-insns.def"
+#undef DEF_TARGET_INSN
+
+  printf ("\n#endif /* GCC_INSN_TARGET_DEF_H */\n");
+
+  if (have_error || ferror (stdout) || fflush (stdout) || fclose (stdout))
+    return FATAL_EXIT_CODE;
+
+  return SUCCESS_EXIT_CODE;
+}