Home | History | Annotate | Line # | Download | only in gcc
genopinit.cc revision 1.1.1.1
      1 /* Generate code to initialize optabs from machine description.
      2    Copyright (C) 1993-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 
     21 #include "bconfig.h"
     22 #include "system.h"
     23 #include "coretypes.h"
     24 #include "tm.h"
     25 #include "rtl.h"
     26 #include "errors.h"
     27 #include "gensupport.h"
     28 
     29 
     30 #define DEF_RTL_EXPR(V, N, X, C) #V,
     31 
     32 static const char * const rtx_upname[] = {
     33 #include "rtl.def"
     34 };
     35 
     36 #undef DEF_RTL_EXPR
     37 
     38 /* Vector in which to collect insns that match.  */
     39 static vec<optab_pattern> patterns;
     40 
     41 static void
     42 gen_insn (md_rtx_info *info)
     43 {
     44   optab_pattern p;
     45   if (find_optab (&p, XSTR (info->def, 0)))
     46     patterns.safe_push (p);
     47 }
     48 
     49 static int
     50 pattern_cmp (const void *va, const void *vb)
     51 {
     52   const optab_pattern *a = (const optab_pattern *)va;
     53   const optab_pattern *b = (const optab_pattern *)vb;
     54   return a->sort_num - b->sort_num;
     55 }
     56 
     57 static int
     58 optab_kind_cmp (const void *va, const void *vb)
     59 {
     60   const optab_def *a = (const optab_def *)va;
     61   const optab_def *b = (const optab_def *)vb;
     62   int diff = a->kind - b->kind;
     63   if (diff == 0)
     64     diff = a->op - b->op;
     65   return diff;
     66 }
     67 
     68 static int
     69 optab_rcode_cmp (const void *va, const void *vb)
     70 {
     71   const optab_def *a = (const optab_def *)va;
     72   const optab_def *b = (const optab_def *)vb;
     73   return a->rcode - b->rcode;
     74 }
     75 
     76 static const char *header_file_name = "init-opinit.h";
     77 static const char *source_file_name = "init-opinit.c";
     78 
     79 static bool
     80 handle_arg (const char *arg)
     81 {
     82   switch (arg[1])
     83     {
     84     case 'h':
     85       header_file_name = &arg[2];
     86       return true;
     87     case 'c':
     88       source_file_name = &arg[2];
     89       return true;
     90     default:
     91       return false;
     92     }
     93 }
     94 
     95 static FILE *
     96 open_outfile (const char *file_name)
     97 {
     98   FILE *f = fopen (file_name, "w");
     99   if (!f)
    100     fatal ("cannot open file %s: %s", file_name, xstrerror (errno));
    101   fprintf (f,
    102 	   "/* Generated automatically by the program `genopinit'\n"
    103 	   "   from the machine description file `md'.  */\n\n");
    104   return f;
    105 }
    106 
    107 /* Declare the maybe_code_for_* function for ONAME, and provide
    108    an inline definition of the assserting code_for_* wrapper.  */
    109 
    110 static void
    111 handle_overloaded_code_for (FILE *file, overloaded_name *oname)
    112 {
    113   fprintf (file, "\nextern insn_code maybe_code_for_%s (", oname->name);
    114   for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
    115     fprintf (file, "%s%s", i == 0 ? "" : ", ", oname->arg_types[i]);
    116   fprintf (file, ");\n");
    117 
    118   fprintf (file, "inline insn_code\ncode_for_%s (", oname->name);
    119   for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
    120     fprintf (file, "%s%s arg%d", i == 0 ? "" : ", ", oname->arg_types[i], i);
    121   fprintf (file, ")\n{\n  insn_code code = maybe_code_for_%s (", oname->name);
    122   for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
    123     fprintf (file, "%sarg%d", i == 0 ? "" : ", ", i);
    124   fprintf (file,
    125 	   ");\n"
    126 	   "  gcc_assert (code != CODE_FOR_nothing);\n"
    127 	   "  return code;\n"
    128 	   "}\n");
    129 }
    130 
    131 /* Declare the maybe_gen_* function for ONAME, and provide
    132    an inline definition of the assserting gen_* wrapper.  */
    133 
    134 static void
    135 handle_overloaded_gen (FILE *file, overloaded_name *oname)
    136 {
    137   unsigned HOST_WIDE_INT seen = 0;
    138   for (overloaded_instance *instance = oname->first_instance->next;
    139        instance; instance = instance->next)
    140     {
    141       pattern_stats stats;
    142       get_pattern_stats (&stats, XVEC (instance->insn, 1));
    143       unsigned HOST_WIDE_INT mask
    144 	= HOST_WIDE_INT_1U << stats.num_generator_args;
    145       if (seen & mask)
    146 	continue;
    147 
    148       seen |= mask;
    149 
    150       fprintf (file, "\nextern rtx maybe_gen_%s (", oname->name);
    151       for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
    152 	fprintf (file, "%s%s", i == 0 ? "" : ", ", oname->arg_types[i]);
    153       for (int i = 0; i < stats.num_generator_args; ++i)
    154 	fprintf (file, ", rtx");
    155       fprintf (file, ");\n");
    156 
    157       fprintf (file, "inline rtx\ngen_%s (", oname->name);
    158       for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
    159 	fprintf (file, "%s%s arg%d", i == 0 ? "" : ", ",
    160 		 oname->arg_types[i], i);
    161       for (int i = 0; i < stats.num_generator_args; ++i)
    162 	fprintf (file, ", rtx x%d", i);
    163       fprintf (file, ")\n{\n  rtx res = maybe_gen_%s (", oname->name);
    164       for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
    165 	fprintf (file, "%sarg%d", i == 0 ? "" : ", ", i);
    166       for (int i = 0; i < stats.num_generator_args; ++i)
    167 	fprintf (file, ", x%d", i);
    168       fprintf (file,
    169 	       ");\n"
    170 	       "  gcc_assert (res);\n"
    171 	       "  return res;\n"
    172 	       "}\n");
    173     }
    174 }
    175 
    176 int
    177 main (int argc, const char **argv)
    178 {
    179   FILE *h_file, *s_file;
    180   unsigned int i, j, n, last_kind[5];
    181   optab_pattern *p;
    182 
    183   progname = "genopinit";
    184 
    185   if (NUM_OPTABS > 0xffff || MAX_MACHINE_MODE >= 0xff)
    186     fatal ("genopinit range assumptions invalid");
    187 
    188   if (!init_rtx_reader_args_cb (argc, argv, handle_arg))
    189     return (FATAL_EXIT_CODE);
    190 
    191   h_file = open_outfile (header_file_name);
    192   s_file = open_outfile (source_file_name);
    193 
    194   /* Read the machine description.  */
    195   md_rtx_info info;
    196   while (read_md_rtx (&info))
    197     switch (GET_CODE (info.def))
    198       {
    199       case DEFINE_INSN:
    200       case DEFINE_EXPAND:
    201 	gen_insn (&info);
    202 	break;
    203 
    204       default:
    205 	break;
    206       }
    207 
    208   /* Sort the collected patterns.  */
    209   patterns.qsort (pattern_cmp);
    210 
    211   /* Now that we've handled the "extra" patterns, eliminate them from
    212      the optabs array.  That way they don't get in the way below.  */
    213   n = num_optabs;
    214   for (i = 0; i < n; )
    215     if (optabs[i].base == NULL)
    216       optabs[i] = optabs[--n];
    217     else
    218       ++i;
    219 
    220   /* Sort the (real) optabs.  Better than forcing the optabs.def file to
    221      remain sorted by kind.  We also scrogged any real ordering with the
    222      purging of the X patterns above.  */
    223   qsort (optabs, n, sizeof (optab_def), optab_kind_cmp);
    224 
    225   fprintf (h_file, "#ifndef GCC_INSN_OPINIT_H\n");
    226   fprintf (h_file, "#define GCC_INSN_OPINIT_H 1\n");
    227 
    228   /* Emit the optab enumeration for the header file.  */
    229   fprintf (h_file, "enum optab_tag {\n");
    230   for (i = j = 0; i < n; ++i)
    231     {
    232       optabs[i].op = i;
    233       fprintf (h_file, "  %s,\n", optabs[i].name);
    234       if (optabs[i].kind != j)
    235 	last_kind[j++] = i - 1;
    236     }
    237   fprintf (h_file, "  FIRST_CONV_OPTAB = %s,\n", optabs[last_kind[0]+1].name);
    238   fprintf (h_file, "  LAST_CONVLIB_OPTAB = %s,\n", optabs[last_kind[1]].name);
    239   fprintf (h_file, "  LAST_CONV_OPTAB = %s,\n", optabs[last_kind[2]].name);
    240   fprintf (h_file, "  FIRST_NORM_OPTAB = %s,\n", optabs[last_kind[2]+1].name);
    241   fprintf (h_file, "  LAST_NORMLIB_OPTAB = %s,\n", optabs[last_kind[3]].name);
    242   fprintf (h_file, "  LAST_NORM_OPTAB = %s\n", optabs[i-1].name);
    243   fprintf (h_file, "};\n\n");
    244 
    245   fprintf (h_file, "#define NUM_OPTABS          %u\n", n);
    246   fprintf (h_file, "#define NUM_CONVLIB_OPTABS  %u\n",
    247 	   last_kind[1] - last_kind[0]);
    248   fprintf (h_file, "#define NUM_NORMLIB_OPTABS  %u\n",
    249 	   last_kind[3] - last_kind[2]);
    250   fprintf (h_file, "#define NUM_OPTAB_PATTERNS  %u\n",
    251 	   (unsigned) patterns.length ());
    252 
    253   fprintf (h_file,
    254 	   "typedef enum optab_tag optab;\n"
    255 	   "typedef enum optab_tag convert_optab;\n"
    256 	   "typedef enum optab_tag direct_optab;\n"
    257 	   "\n"
    258 	   "struct optab_libcall_d\n"
    259 	   "{\n"
    260 	   "  char libcall_suffix;\n"
    261 	   "  const char *libcall_basename;\n"
    262 	   "  void (*libcall_gen) (optab, const char *name,\n"
    263 	   "		       char suffix, machine_mode);\n"
    264 	   "};\n"
    265 	   "\n"
    266 	   "struct convert_optab_libcall_d\n"
    267 	   "{\n"
    268 	   "  const char *libcall_basename;\n"
    269 	   "  void (*libcall_gen) (convert_optab, const char *name,\n"
    270 	   "		       machine_mode, machine_mode);\n"
    271 	   "};\n"
    272 	   "\n"
    273 	   "/* Given an enum insn_code, access the function to construct\n"
    274 	   "   the body of that kind of insn.  */\n"
    275 	   "#define GEN_FCN(CODE) (insn_data[CODE].genfun)\n"
    276 	   "\n"
    277 	   "#ifdef NUM_RTX_CODE\n"
    278 	   "/* Contains the optab used for each rtx code, and vice-versa.  */\n"
    279 	   "extern const optab code_to_optab_[NUM_RTX_CODE];\n"
    280 	   "extern const enum rtx_code optab_to_code_[NUM_OPTABS];\n"
    281 	   "\n"
    282 	   "static inline optab\n"
    283 	   "code_to_optab (enum rtx_code code)\n"
    284 	   "{\n"
    285 	   "  return code_to_optab_[code];\n"
    286 	   "}\n"
    287 	   "\n"
    288 	   "static inline enum rtx_code\n"
    289 	   "optab_to_code (optab op)\n"
    290 	   "{\n"
    291 	   "  return optab_to_code_[op];\n"
    292 	   "}\n");
    293 
    294   for (overloaded_name *oname = rtx_reader_ptr->get_overloads ();
    295        oname; oname = oname->next)
    296     {
    297       handle_overloaded_code_for (h_file, oname);
    298       handle_overloaded_gen (h_file, oname);
    299     }
    300 
    301   fprintf (h_file,
    302 	   "#endif\n"
    303 	   "\n"
    304 	   "extern const struct convert_optab_libcall_d convlib_def[NUM_CONVLIB_OPTABS];\n"
    305 	   "extern const struct optab_libcall_d normlib_def[NUM_NORMLIB_OPTABS];\n"
    306 	   "\n"
    307 	   "/* Returns the active icode for the given (encoded) optab.  */\n"
    308 	   "extern enum insn_code raw_optab_handler (unsigned);\n"
    309 	   "extern bool swap_optab_enable (optab, machine_mode, bool);\n"
    310 	   "\n"
    311 	   "/* Target-dependent globals.  */\n"
    312 	   "struct target_optabs {\n"
    313 	   "  /* Patterns that are used by optabs that are enabled for this target.  */\n"
    314 	   "  bool pat_enable[NUM_OPTAB_PATTERNS];\n"
    315 	   "\n"
    316 	   "  /* Index VOIDmode caches if the target supports vec_gather_load for any\n"
    317 	   "     vector mode.  Every other index X caches specifically for mode X.\n"
    318 	   "     1 means yes, -1 means no.  */\n"
    319 	   "  signed char supports_vec_gather_load[NUM_MACHINE_MODES];\n"
    320 	   "  signed char supports_vec_scatter_store[NUM_MACHINE_MODES];\n"
    321 	   "};\n"
    322 	   "extern void init_all_optabs (struct target_optabs *);\n"
    323 	   "extern bool partial_vectors_supported_p (void);\n"
    324 	   "\n"
    325 	   "extern struct target_optabs default_target_optabs;\n"
    326 	   "extern struct target_optabs *this_fn_optabs;\n"
    327 	   "#if SWITCHABLE_TARGET\n"
    328 	   "extern struct target_optabs *this_target_optabs;\n"
    329 	   "#else\n"
    330 	   "#define this_target_optabs (&default_target_optabs)\n"
    331 	   "#endif\n");
    332 
    333   fprintf (s_file,
    334 	   "#define IN_TARGET_CODE 1\n"
    335 	   "#include \"config.h\"\n"
    336 	   "#include \"system.h\"\n"
    337 	   "#include \"coretypes.h\"\n"
    338 	   "#include \"backend.h\"\n"
    339 	   "#include \"predict.h\"\n"
    340 	   "#include \"tree.h\"\n"
    341 	   "#include \"rtl.h\"\n"
    342 	   "#include \"alias.h\"\n"
    343 	   "#include \"varasm.h\"\n"
    344 	   "#include \"stor-layout.h\"\n"
    345 	   "#include \"calls.h\"\n"
    346 	   "#include \"memmodel.h\"\n"
    347 	   "#include \"tm_p.h\"\n"
    348 	   "#include \"flags.h\"\n"
    349 	   "#include \"insn-config.h\"\n"
    350 	   "#include \"expmed.h\"\n"
    351 	   "#include \"dojump.h\"\n"
    352 	   "#include \"explow.h\"\n"
    353 	   "#include \"emit-rtl.h\"\n"
    354 	   "#include \"stmt.h\"\n"
    355 	   "#include \"expr.h\"\n"
    356 	   "#include \"insn-codes.h\"\n"
    357 	   "#include \"optabs.h\"\n"
    358 	   "\n"
    359 	   "struct optab_pat {\n"
    360 	   "  unsigned scode;\n"
    361 	   "  enum insn_code icode;\n"
    362 	   "};\n\n");
    363 
    364   fprintf (s_file,
    365 	   "static const struct optab_pat pats[NUM_OPTAB_PATTERNS] = {\n");
    366   for (i = 0; patterns.iterate (i, &p); ++i)
    367     fprintf (s_file, "  { %#08x, CODE_FOR_%s },\n", p->sort_num, p->name);
    368   fprintf (s_file, "};\n\n");
    369 
    370   fprintf (s_file, "void\ninit_all_optabs (struct target_optabs *optabs)\n{\n");
    371   fprintf (s_file, "  bool *ena = optabs->pat_enable;\n");
    372   for (i = 0; patterns.iterate (i, &p); ++i)
    373     fprintf (s_file, "  ena[%u] = HAVE_%s;\n", i, p->name);
    374   fprintf (s_file, "}\n\n");
    375 
    376   fprintf (s_file,
    377 	   "/* Returns TRUE if the target supports any of the partial vector\n"
    378 	   "   optabs: while_ult_optab, len_load_optab or len_store_optab,\n"
    379 	   "   for any mode.  */\n"
    380 	   "bool\npartial_vectors_supported_p (void)\n{\n");
    381   bool any_match = false;
    382   fprintf (s_file, "\treturn");
    383   bool first = true;
    384   for (i = 0; patterns.iterate (i, &p); ++i)
    385     {
    386 #define CMP_NAME(N) !strncmp (p->name, (N), strlen ((N)))
    387       if (CMP_NAME("while_ult") || CMP_NAME ("len_load")
    388 	  || CMP_NAME ("len_store"))
    389 	{
    390 	  if (first)
    391 	    fprintf (s_file, " HAVE_%s", p->name);
    392 	  else
    393 	    fprintf (s_file, " || HAVE_%s", p->name);
    394 	  first = false;
    395 	  any_match = true;
    396 	}
    397     }
    398   if (!any_match)
    399     fprintf (s_file, " false");
    400   fprintf (s_file, ";\n}\n");
    401 
    402 
    403   /* Perform a binary search on a pre-encoded optab+mode*2.  */
    404   /* ??? Perhaps even better to generate a minimal perfect hash.
    405      Using gperf directly is awkward since it's so geared to working
    406      with strings.  Plus we have no visibility into the ordering of
    407      the hash entries, which complicates the pat_enable array.  */
    408   fprintf (s_file,
    409 	   "static int\n"
    410 	   "lookup_handler (unsigned scode)\n"
    411 	   "{\n"
    412 	   "  int l = 0, h = ARRAY_SIZE (pats), m;\n"
    413 	   "  while (h > l)\n"
    414 	   "    {\n"
    415 	   "      m = (h + l) / 2;\n"
    416 	   "      if (scode == pats[m].scode)\n"
    417 	   "        return m;\n"
    418 	   "      else if (scode < pats[m].scode)\n"
    419 	   "        h = m;\n"
    420 	   "      else\n"
    421 	   "        l = m + 1;\n"
    422 	   "    }\n"
    423 	   "  return -1;\n"
    424 	   "}\n\n");
    425 
    426   fprintf (s_file,
    427 	   "enum insn_code\n"
    428 	   "raw_optab_handler (unsigned scode)\n"
    429 	   "{\n"
    430 	   "  int i = lookup_handler (scode);\n"
    431 	   "  return (i >= 0 && this_fn_optabs->pat_enable[i]\n"
    432 	   "          ? pats[i].icode : CODE_FOR_nothing);\n"
    433 	   "}\n\n");
    434 
    435   fprintf (s_file,
    436 	   "bool\n"
    437 	   "swap_optab_enable (optab op, machine_mode m, bool set)\n"
    438 	   "{\n"
    439 	   "  unsigned scode = (op << 16) | m;\n"
    440 	   "  int i = lookup_handler (scode);\n"
    441 	   "  if (i >= 0)\n"
    442 	   "    {\n"
    443 	   "      bool ret = this_fn_optabs->pat_enable[i];\n"
    444 	   "      this_fn_optabs->pat_enable[i] = set;\n"
    445 	   "      return ret;\n"
    446 	   "    }\n"
    447 	   "  else\n"
    448 	   "    {\n"
    449 	   "      gcc_assert (!set);\n"
    450 	   "      return false;\n"
    451 	   "    }\n"
    452 	   "}\n\n");
    453 
    454   /* C++ (even G++) does not support (non-trivial) designated initializers.
    455      To work around that, generate these arrays programatically rather than
    456      by our traditional multiple inclusion of def files.  */
    457 
    458   fprintf (s_file,
    459 	   "const struct convert_optab_libcall_d "
    460 	   "convlib_def[NUM_CONVLIB_OPTABS] = {\n");
    461   for (i = last_kind[0] + 1; i <= last_kind[1]; ++i)
    462     fprintf (s_file, "  { %s, %s },\n", optabs[i].base, optabs[i].libcall);
    463   fprintf (s_file, "};\n\n");
    464 
    465   fprintf (s_file,
    466 	   "const struct optab_libcall_d "
    467 	   "normlib_def[NUM_NORMLIB_OPTABS] = {\n");
    468   for (i = last_kind[2] + 1; i <= last_kind[3]; ++i)
    469     fprintf (s_file, "  { %s, %s, %s },\n",
    470 	     optabs[i].suffix, optabs[i].base, optabs[i].libcall);
    471   fprintf (s_file, "};\n\n");
    472 
    473   fprintf (s_file, "enum rtx_code const optab_to_code_[NUM_OPTABS] = {\n");
    474   for (i = 0; i < n; ++i)
    475     fprintf (s_file, "  %s,\n", rtx_upname[optabs[i].fcode]);
    476   fprintf (s_file, "};\n\n");
    477 
    478   qsort (optabs, n, sizeof (optab_def), optab_rcode_cmp);
    479 
    480   fprintf (s_file, "const optab code_to_optab_[NUM_RTX_CODE] = {\n");
    481   for (j = 0; optabs[j].rcode == UNKNOWN; ++j)
    482     continue;
    483   for (i = 0; i < NON_GENERATOR_NUM_RTX_CODE; ++i)
    484     {
    485       if (j < n && optabs[j].rcode == i)
    486 	fprintf (s_file, "  %s,\n", optabs[j++].name);
    487       else
    488 	fprintf (s_file, "  unknown_optab,\n");
    489     }
    490   fprintf (s_file, "};\n\n");
    491 
    492   fprintf (h_file, "#endif\n");
    493   return (fclose (h_file) == 0 && fclose (s_file) == 0
    494 	  ? SUCCESS_EXIT_CODE : FATAL_EXIT_CODE);
    495 }
    496