1/* Generate code to initialize optabs from machine description.
2   Copyright (C) 1993-2022 Free Software Foundation, Inc.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free
8Software Foundation; either version 3, or (at your option) any later
9version.
10
11GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or
13FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14for more details.
15
16You should have received a copy of the GNU General Public License
17along 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
32static 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.  */
39static vec<optab_pattern> patterns;
40
41static void
42gen_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
49static int
50pattern_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
57static int
58optab_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
68static int
69optab_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
76static const char *header_file_name = "init-opinit.h";
77static const char *source_file_name = "init-opinit.c";
78
79static bool
80handle_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
95static FILE *
96open_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
110static void
111handle_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
134static void
135handle_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
176int
177main (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