Home | History | Annotate | Line # | Download | only in gcc
      1 /* Generate insn-target-def.h, an automatically-generated part of targetm.
      2    Copyright (C) 1987-2022 Free Software Foundation, Inc.
      3 
      4 This file is part of GCC.
      5 
      6 GCC is free software; you can redistribute it and/or modify it under
      7 the terms of the GNU General Public License as published by the Free
      8 Software Foundation; either version 3, or (at your option) any later
      9 version.
     10 
     11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
     12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14 for more details.
     15 
     16 You should have received a copy of the GNU General Public License
     17 along with GCC; see the file COPYING3.  If not see
     18 <http://www.gnu.org/licenses/>.  */
     19 
     20 #include "bconfig.h"
     21 #include "system.h"
     22 #include "coretypes.h"
     23 #include "tm.h"
     24 #include "rtl.h"
     25 #include "errors.h"
     26 #include "read-md.h"
     27 #include "gensupport.h"
     28 #include "hash-table.h"
     29 
     30 /* This class hashes define_insns and define_expands by name.  */
     31 struct insn_hasher : nofree_ptr_hash <rtx_def>
     32 {
     33   typedef rtx value_type;
     34   typedef const char *compare_type;
     35 
     36   static inline hashval_t hash (rtx);
     37   static inline bool equal (rtx, const char *);
     38 };
     39 
     40 hashval_t
     41 insn_hasher::hash (rtx x)
     42 {
     43   return htab_hash_string (XSTR (x, 0));
     44 }
     45 
     46 bool
     47 insn_hasher::equal (rtx x, const char *y)
     48 {
     49   return strcmp (XSTR (x, 0), y) == 0;
     50 }
     51 
     52 /* All define_insns and define_expands, hashed by name.  */
     53 static hash_table <insn_hasher> *insns;
     54 
     55 /* Records the prototype suffix X for each invalid_X stub that has been
     56    generated.  */
     57 static hash_table <nofree_string_hash> *stubs;
     58 
     59 /* Records which C conditions have been wrapped in functions, as a mapping
     60    from the C condition to the function name.  */
     61 static hash_map <nofree_string_hash, const char *> *have_funcs;
     62 
     63 /* Return true if the part of the prototype at P is for an argument
     64    name.  If so, point *END_OUT to the first character after the name.
     65    If OPNO_OUT is nonnull, set *OPNO_OUT to the number of the associated
     66    operand.  If REQUIRED_OUT is nonnull, set *REQUIRED_OUT to whether the
     67    .md pattern is required to match the operand.  */
     68 
     69 static bool
     70 parse_argument (const char *p, const char **end_out,
     71 		unsigned int *opno_out = 0,
     72 		bool *required_out = 0)
     73 {
     74   while (ISSPACE (*p))
     75     p++;
     76   if (p[0] == 'x' && ISDIGIT (p[1]))
     77     {
     78       p += 1;
     79       if (required_out)
     80 	*required_out = true;
     81     }
     82   else if (p[0] == 'o' && p[1] == 'p' && p[2] == 't' && ISDIGIT (p[3]))
     83     {
     84       p += 3;
     85       if (required_out)
     86 	*required_out = false;
     87     }
     88   else
     89     return false;
     90 
     91   char *endptr;
     92   unsigned int opno = strtol (p, &endptr, 10);
     93   if (opno_out)
     94     *opno_out = opno;
     95   *end_out = endptr;
     96   return true;
     97 }
     98 
     99 
    100 /* Output hook definitions for pattern NAME, which has target-insns.def
    101    prototype PROTOTYPE.  */
    102 
    103 static void
    104 def_target_insn (const char *name, const char *prototype)
    105 {
    106   /* Get an upper-case form of NAME.  */
    107   unsigned int i;
    108   char *upper_name = XALLOCAVEC (char, strlen (name) + 1);
    109   for (i = 0; name[i]; ++i)
    110     upper_name[i] = TOUPPER (name[i]);
    111   upper_name[i] = 0;
    112 
    113   /* Check that the prototype is valid and concatenate the types
    114      together to get a suffix.  */
    115   char *suffix = XALLOCAVEC (char, strlen (prototype) + 1);
    116   i = 0;
    117   unsigned int opno = 0;
    118   unsigned int required_ops = 0;
    119   unsigned int this_opno;
    120   bool required_p;
    121   for (const char *p = prototype; *p; ++p)
    122     if (parse_argument (p, &p, &this_opno, &required_p))
    123       {
    124 	if (this_opno != opno || (*p != ',' && *p != ')'))
    125 	  {
    126 	    error ("invalid prototype for '%s'", name);
    127 	    exit (FATAL_EXIT_CODE);
    128 	  }
    129 	if (required_p && required_ops < opno)
    130 	  {
    131 	    error ("prototype for '%s' has required operands after"
    132 		   " optional operands", name);
    133 	    exit (FATAL_EXIT_CODE);
    134 	  }
    135 	opno += 1;
    136 	if (required_p)
    137 	  required_ops = opno;
    138 	/* Skip over ')'s.  */
    139 	if (*p == ',')
    140 	  suffix[i++] = '_';
    141       }
    142     else if (*p == ')' || *p == ',')
    143       {
    144 	/* We found the end of a parameter without finding a
    145 	   parameter name.  */
    146 	if (strcmp (prototype, "(void)") != 0)
    147 	  {
    148 	    error ("argument %d of '%s' did not have the expected name",
    149 		   opno, name);
    150 	    exit (FATAL_EXIT_CODE);
    151 	  }
    152       }
    153     else if (*p != '(' && !ISSPACE (*p))
    154       suffix[i++] = *p;
    155   suffix[i] = 0;
    156 
    157   /* See whether we have an implementation of this pattern.  */
    158   hashval_t hash = htab_hash_string (name);
    159   int truth = 0;
    160   const char *have_name = name;
    161   if (rtx insn = insns->find_with_hash (name, hash))
    162     {
    163       pattern_stats stats;
    164       get_pattern_stats (&stats, XVEC (insn, 1));
    165       unsigned int actual_ops = stats.num_generator_args;
    166       if (opno == required_ops && opno != actual_ops)
    167 	error_at (get_file_location (insn),
    168 		  "'%s' must have %d operands (excluding match_dups)",
    169 		  name, required_ops);
    170       else if (actual_ops < required_ops)
    171 	error_at (get_file_location (insn),
    172 		  "'%s' must have at least %d operands (excluding match_dups)",
    173 		  name, required_ops);
    174       else if (actual_ops > opno)
    175 	error_at (get_file_location (insn),
    176 		  "'%s' must have no more than %d operands"
    177 		  " (excluding match_dups)", name, opno);
    178 
    179       const char *test = XSTR (insn, 2);
    180       truth = maybe_eval_c_test (test);
    181       gcc_assert (truth != 0);
    182       if (truth < 0)
    183 	{
    184 	  /* Try to reuse an existing function that performs the same test.  */
    185 	  bool existed;
    186 	  const char *&entry = have_funcs->get_or_insert (test, &existed);
    187 	  if (!existed)
    188 	    {
    189 	      entry = name;
    190 	      printf ("\nstatic bool\n");
    191 	      printf ("target_have_%s (void)\n", name);
    192 	      printf ("{\n");
    193 	      printf ("  return ");
    194 	      rtx_reader_ptr->print_c_condition (test);
    195 	      printf (";\n");
    196 	      printf ("}\n");
    197 	    }
    198 	  have_name = entry;
    199 	}
    200       printf ("\nstatic rtx_insn *\n");
    201       printf ("target_gen_%s ", name);
    202       /* Print the prototype with the argument names after ACTUAL_OPS
    203 	 removed.  */
    204       const char *p = prototype, *end;
    205       while (*p)
    206 	if (parse_argument (p, &end, &this_opno) && this_opno >= actual_ops)
    207 	  p = end;
    208 	else
    209 	  fputc (*p++, stdout);
    210 
    211       printf ("\n{\n");
    212       if (truth < 0)
    213 	printf ("  gcc_checking_assert (targetm.have_%s ());\n", name);
    214       printf ("  return insnify (gen_%s (", name);
    215       for (i = 0; i < actual_ops; ++i)
    216 	printf ("%s%s%d", i == 0 ? "" : ", ",
    217 		i < required_ops ? "x" : "opt", i);
    218       printf ("));\n");
    219       printf ("}\n");
    220     }
    221   else
    222     {
    223       const char **slot = stubs->find_slot (suffix, INSERT);
    224       if (!*slot)
    225 	{
    226 	  *slot = xstrdup (suffix);
    227 	  printf ("\nstatic rtx_insn *\n");
    228 	  printf ("invalid_%s ", suffix);
    229 	  /* Print the prototype with the argument names removed.  */
    230 	  const char *p = prototype;
    231 	  while (*p)
    232 	    if (!parse_argument (p, &p))
    233 	      fputc (*p++, stdout);
    234 	  printf ("\n{\n");
    235 	  printf ("  gcc_unreachable ();\n");
    236 	  printf ("}\n");
    237 	}
    238     }
    239   printf ("\n#undef TARGET_HAVE_%s\n", upper_name);
    240   printf ("#define TARGET_HAVE_%s ", upper_name);
    241   if (truth == 0)
    242     printf ("hook_bool_void_false\n");
    243   else if (truth == 1)
    244     printf ("hook_bool_void_true\n");
    245   else
    246     printf ("target_have_%s\n", have_name);
    247 
    248   printf ("#undef TARGET_GEN_%s\n", upper_name);
    249   printf ("#define TARGET_GEN_%s ", upper_name);
    250   if (truth == 0)
    251     printf ("invalid_%s\n", suffix);
    252   else
    253     printf ("target_gen_%s\n", name);
    254 
    255   printf ("#undef TARGET_CODE_FOR_%s\n", upper_name);
    256   printf ("#define TARGET_CODE_FOR_%s ", upper_name);
    257   if (truth == 0)
    258     printf ("CODE_FOR_nothing\n");
    259   else
    260     printf ("CODE_FOR_%s\n", name);
    261 }
    262 
    263 /* Record the DEFINE_INSN or DEFINE_EXPAND described by INFO.  */
    264 
    265 static void
    266 add_insn (md_rtx_info *info)
    267 {
    268   rtx def = info->def;
    269   const char *name = XSTR (def, 0);
    270   if (name[0] == 0 || name[0] == '*')
    271     return;
    272 
    273   hashval_t hash = htab_hash_string (name);
    274   rtx *slot = insns->find_slot_with_hash (name, hash, INSERT);
    275   if (*slot)
    276     error_at (info->loc, "duplicate definition of '%s'", name);
    277   else
    278     *slot = def;
    279 }
    280 
    281 int
    282 main (int argc, const char **argv)
    283 {
    284   progname = "gentarget-def";
    285 
    286   if (!init_rtx_reader_args (argc, argv))
    287     return (FATAL_EXIT_CODE);
    288 
    289   insns = new hash_table <insn_hasher> (31);
    290   stubs = new hash_table <nofree_string_hash> (31);
    291   have_funcs = new hash_map <nofree_string_hash, const char *>;
    292 
    293   md_rtx_info info;
    294   while (read_md_rtx (&info))
    295     switch (GET_CODE (info.def))
    296       {
    297       case DEFINE_INSN:
    298       case DEFINE_EXPAND:
    299 	add_insn (&info);
    300 	break;
    301 
    302       default:
    303 	break;
    304       }
    305 
    306   printf ("/* Generated automatically by the program `gentarget-def'.  */\n");
    307   printf ("#ifndef GCC_INSN_TARGET_DEF_H\n");
    308   printf ("#define GCC_INSN_TARGET_DEF_H\n");
    309 
    310   /* Output a routine to convert an rtx to an rtx_insn sequence.
    311      ??? At some point the gen_* functions themselves should return
    312 	 rtx_insns.  */
    313   printf ("\nstatic inline rtx_insn *\n");
    314   printf ("insnify (rtx x)\n");
    315   printf ("{\n");
    316   printf ("  if (!x)\n");
    317   printf ("    return NULL;\n");
    318   printf ("  if (rtx_insn *insn = dyn_cast <rtx_insn *> (x))\n");
    319   printf ("    return insn;\n");
    320   printf ("  start_sequence ();\n");
    321   printf ("  emit (x, false);\n");
    322   printf ("  rtx_insn *res = get_insns ();\n");
    323   printf ("  end_sequence ();\n");
    324   printf ("  return res;\n");
    325   printf ("}\n");
    326 
    327 #define DEF_TARGET_INSN(INSN, ARGS) \
    328   def_target_insn (#INSN, #ARGS);
    329 #include "target-insns.def"
    330 #undef DEF_TARGET_INSN
    331 
    332   printf ("\n#endif /* GCC_INSN_TARGET_DEF_H */\n");
    333 
    334   if (have_error || ferror (stdout) || fflush (stdout) || fclose (stdout))
    335     return FATAL_EXIT_CODE;
    336 
    337   return SUCCESS_EXIT_CODE;
    338 }
    339