xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/genopinit.c (revision a04395531661c5e8d314125d5ae77d4cbedd5d73)
1 /* Generate code to initialize optabs from machine description.
2    Copyright (C) 1993-2019 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   pattern_stats stats;
138   get_pattern_stats (&stats, XVEC (oname->first_instance->insn, 1));
139 
140   fprintf (file, "\nextern rtx maybe_gen_%s (", oname->name);
141   for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
142     fprintf (file, "%s%s", i == 0 ? "" : ", ", oname->arg_types[i]);
143   for (int i = 0; i < stats.num_generator_args; ++i)
144     fprintf (file, ", rtx");
145   fprintf (file, ");\n");
146 
147   fprintf (file, "inline rtx\ngen_%s (", oname->name);
148   for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
149     fprintf (file, "%s%s arg%d", i == 0 ? "" : ", ", oname->arg_types[i], i);
150   for (int i = 0; i < stats.num_generator_args; ++i)
151     fprintf (file, ", rtx x%d", i);
152   fprintf (file, ")\n{\n  rtx res = maybe_gen_%s (", oname->name);
153   for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
154     fprintf (file, "%sarg%d", i == 0 ? "" : ", ", i);
155   for (int i = 0; i < stats.num_generator_args; ++i)
156     fprintf (file, ", x%d", i);
157   fprintf (file,
158 	   ");\n"
159 	   "  gcc_assert (res);\n"
160 	   "  return res;\n"
161 	   "}\n");
162 }
163 
164 int
165 main (int argc, const char **argv)
166 {
167   FILE *h_file, *s_file;
168   unsigned int i, j, n, last_kind[5];
169   optab_pattern *p;
170 
171   progname = "genopinit";
172 
173   if (NUM_OPTABS > 0xffff || MAX_MACHINE_MODE >= 0xff)
174     fatal ("genopinit range assumptions invalid");
175 
176   if (!init_rtx_reader_args_cb (argc, argv, handle_arg))
177     return (FATAL_EXIT_CODE);
178 
179   h_file = open_outfile (header_file_name);
180   s_file = open_outfile (source_file_name);
181 
182   /* Read the machine description.  */
183   md_rtx_info info;
184   while (read_md_rtx (&info))
185     switch (GET_CODE (info.def))
186       {
187       case DEFINE_INSN:
188       case DEFINE_EXPAND:
189 	gen_insn (&info);
190 	break;
191 
192       default:
193 	break;
194       }
195 
196   /* Sort the collected patterns.  */
197   patterns.qsort (pattern_cmp);
198 
199   /* Now that we've handled the "extra" patterns, eliminate them from
200      the optabs array.  That way they don't get in the way below.  */
201   n = num_optabs;
202   for (i = 0; i < n; )
203     if (optabs[i].base == NULL)
204       optabs[i] = optabs[--n];
205     else
206       ++i;
207 
208   /* Sort the (real) optabs.  Better than forcing the optabs.def file to
209      remain sorted by kind.  We also scrogged any real ordering with the
210      purging of the X patterns above.  */
211   qsort (optabs, n, sizeof (optab_def), optab_kind_cmp);
212 
213   fprintf (h_file, "#ifndef GCC_INSN_OPINIT_H\n");
214   fprintf (h_file, "#define GCC_INSN_OPINIT_H 1\n");
215 
216   /* Emit the optab enumeration for the header file.  */
217   fprintf (h_file, "enum optab_tag {\n");
218   for (i = j = 0; i < n; ++i)
219     {
220       optabs[i].op = i;
221       fprintf (h_file, "  %s,\n", optabs[i].name);
222       if (optabs[i].kind != j)
223 	last_kind[j++] = i - 1;
224     }
225   fprintf (h_file, "  FIRST_CONV_OPTAB = %s,\n", optabs[last_kind[0]+1].name);
226   fprintf (h_file, "  LAST_CONVLIB_OPTAB = %s,\n", optabs[last_kind[1]].name);
227   fprintf (h_file, "  LAST_CONV_OPTAB = %s,\n", optabs[last_kind[2]].name);
228   fprintf (h_file, "  FIRST_NORM_OPTAB = %s,\n", optabs[last_kind[2]+1].name);
229   fprintf (h_file, "  LAST_NORMLIB_OPTAB = %s,\n", optabs[last_kind[3]].name);
230   fprintf (h_file, "  LAST_NORM_OPTAB = %s\n", optabs[i-1].name);
231   fprintf (h_file, "};\n\n");
232 
233   fprintf (h_file, "#define NUM_OPTABS          %u\n", n);
234   fprintf (h_file, "#define NUM_CONVLIB_OPTABS  %u\n",
235 	   last_kind[1] - last_kind[0]);
236   fprintf (h_file, "#define NUM_NORMLIB_OPTABS  %u\n",
237 	   last_kind[3] - last_kind[2]);
238   fprintf (h_file, "#define NUM_OPTAB_PATTERNS  %u\n",
239 	   (unsigned) patterns.length ());
240 
241   fprintf (h_file,
242 	   "typedef enum optab_tag optab;\n"
243 	   "typedef enum optab_tag convert_optab;\n"
244 	   "typedef enum optab_tag direct_optab;\n"
245 	   "\n"
246 	   "struct optab_libcall_d\n"
247 	   "{\n"
248 	   "  char libcall_suffix;\n"
249 	   "  const char *libcall_basename;\n"
250 	   "  void (*libcall_gen) (optab, const char *name,\n"
251 	   "		       char suffix, machine_mode);\n"
252 	   "};\n"
253 	   "\n"
254 	   "struct convert_optab_libcall_d\n"
255 	   "{\n"
256 	   "  const char *libcall_basename;\n"
257 	   "  void (*libcall_gen) (convert_optab, const char *name,\n"
258 	   "		       machine_mode, machine_mode);\n"
259 	   "};\n"
260 	   "\n"
261 	   "/* Given an enum insn_code, access the function to construct\n"
262 	   "   the body of that kind of insn.  */\n"
263 	   "#define GEN_FCN(CODE) (insn_data[CODE].genfun)\n"
264 	   "\n"
265 	   "#ifdef NUM_RTX_CODE\n"
266 	   "/* Contains the optab used for each rtx code, and vice-versa.  */\n"
267 	   "extern const optab code_to_optab_[NUM_RTX_CODE];\n"
268 	   "extern const enum rtx_code optab_to_code_[NUM_OPTABS];\n"
269 	   "\n"
270 	   "static inline optab\n"
271 	   "code_to_optab (enum rtx_code code)\n"
272 	   "{\n"
273 	   "  return code_to_optab_[code];\n"
274 	   "}\n"
275 	   "\n"
276 	   "static inline enum rtx_code\n"
277 	   "optab_to_code (optab op)\n"
278 	   "{\n"
279 	   "  return optab_to_code_[op];\n"
280 	   "}\n");
281 
282   for (overloaded_name *oname = rtx_reader_ptr->get_overloads ();
283        oname; oname = oname->next)
284     {
285       handle_overloaded_code_for (h_file, oname);
286       handle_overloaded_gen (h_file, oname);
287     }
288 
289   fprintf (h_file,
290 	   "#endif\n"
291 	   "\n"
292 	   "extern const struct convert_optab_libcall_d convlib_def[NUM_CONVLIB_OPTABS];\n"
293 	   "extern const struct optab_libcall_d normlib_def[NUM_NORMLIB_OPTABS];\n"
294 	   "\n"
295 	   "/* Returns the active icode for the given (encoded) optab.  */\n"
296 	   "extern enum insn_code raw_optab_handler (unsigned);\n"
297 	   "extern bool swap_optab_enable (optab, machine_mode, bool);\n"
298 	   "\n"
299 	   "/* Target-dependent globals.  */\n"
300 	   "struct target_optabs {\n"
301 	   "  /* Patterns that are used by optabs that are enabled for this target.  */\n"
302 	   "  bool pat_enable[NUM_OPTAB_PATTERNS];\n"
303 	   "\n"
304 	   "  /* Cache if the target supports vec_gather_load for at least one vector\n"
305 	   "     mode.  */\n"
306 	   "  bool supports_vec_gather_load;\n"
307 	   "  bool supports_vec_gather_load_cached;\n"
308 	   "  bool supports_vec_scatter_store;\n"
309 	   "  bool supports_vec_scatter_store_cached;\n"
310 	   "};\n"
311 	   "extern void init_all_optabs (struct target_optabs *);\n"
312 	   "\n"
313 	   "extern struct target_optabs default_target_optabs;\n"
314 	   "extern struct target_optabs *this_fn_optabs;\n"
315 	   "#if SWITCHABLE_TARGET\n"
316 	   "extern struct target_optabs *this_target_optabs;\n"
317 	   "#else\n"
318 	   "#define this_target_optabs (&default_target_optabs)\n"
319 	   "#endif\n");
320 
321   fprintf (s_file,
322 	   "#define IN_TARGET_CODE 1\n"
323 	   "#include \"config.h\"\n"
324 	   "#include \"system.h\"\n"
325 	   "#include \"coretypes.h\"\n"
326 	   "#include \"backend.h\"\n"
327 	   "#include \"predict.h\"\n"
328 	   "#include \"tree.h\"\n"
329 	   "#include \"rtl.h\"\n"
330 	   "#include \"alias.h\"\n"
331 	   "#include \"varasm.h\"\n"
332 	   "#include \"stor-layout.h\"\n"
333 	   "#include \"calls.h\"\n"
334 	   "#include \"memmodel.h\"\n"
335 	   "#include \"tm_p.h\"\n"
336 	   "#include \"flags.h\"\n"
337 	   "#include \"insn-config.h\"\n"
338 	   "#include \"expmed.h\"\n"
339 	   "#include \"dojump.h\"\n"
340 	   "#include \"explow.h\"\n"
341 	   "#include \"emit-rtl.h\"\n"
342 	   "#include \"stmt.h\"\n"
343 	   "#include \"expr.h\"\n"
344 	   "#include \"insn-codes.h\"\n"
345 	   "#include \"optabs.h\"\n"
346 	   "\n"
347 	   "struct optab_pat {\n"
348 	   "  unsigned scode;\n"
349 	   "  enum insn_code icode;\n"
350 	   "};\n\n");
351 
352   fprintf (s_file,
353 	   "static const struct optab_pat pats[NUM_OPTAB_PATTERNS] = {\n");
354   for (i = 0; patterns.iterate (i, &p); ++i)
355     fprintf (s_file, "  { %#08x, CODE_FOR_%s },\n", p->sort_num, p->name);
356   fprintf (s_file, "};\n\n");
357 
358   fprintf (s_file, "void\ninit_all_optabs (struct target_optabs *optabs)\n{\n");
359   fprintf (s_file, "  bool *ena = optabs->pat_enable;\n");
360   for (i = 0; patterns.iterate (i, &p); ++i)
361     fprintf (s_file, "  ena[%u] = HAVE_%s;\n", i, p->name);
362   fprintf (s_file, "}\n\n");
363 
364   /* Perform a binary search on a pre-encoded optab+mode*2.  */
365   /* ??? Perhaps even better to generate a minimal perfect hash.
366      Using gperf directly is awkward since it's so geared to working
367      with strings.  Plus we have no visibility into the ordering of
368      the hash entries, which complicates the pat_enable array.  */
369   fprintf (s_file,
370 	   "static int\n"
371 	   "lookup_handler (unsigned scode)\n"
372 	   "{\n"
373 	   "  int l = 0, h = ARRAY_SIZE (pats), m;\n"
374 	   "  while (h > l)\n"
375 	   "    {\n"
376 	   "      m = (h + l) / 2;\n"
377 	   "      if (scode == pats[m].scode)\n"
378 	   "        return m;\n"
379 	   "      else if (scode < pats[m].scode)\n"
380 	   "        h = m;\n"
381 	   "      else\n"
382 	   "        l = m + 1;\n"
383 	   "    }\n"
384 	   "  return -1;\n"
385 	   "}\n\n");
386 
387   fprintf (s_file,
388 	   "enum insn_code\n"
389 	   "raw_optab_handler (unsigned scode)\n"
390 	   "{\n"
391 	   "  int i = lookup_handler (scode);\n"
392 	   "  return (i >= 0 && this_fn_optabs->pat_enable[i]\n"
393 	   "          ? pats[i].icode : CODE_FOR_nothing);\n"
394 	   "}\n\n");
395 
396   fprintf (s_file,
397 	   "bool\n"
398 	   "swap_optab_enable (optab op, machine_mode m, bool set)\n"
399 	   "{\n"
400 	   "  unsigned scode = (op << 16) | m;\n"
401 	   "  int i = lookup_handler (scode);\n"
402 	   "  if (i >= 0)\n"
403 	   "    {\n"
404 	   "      bool ret = this_fn_optabs->pat_enable[i];\n"
405 	   "      this_fn_optabs->pat_enable[i] = set;\n"
406 	   "      return ret;\n"
407 	   "    }\n"
408 	   "  else\n"
409 	   "    {\n"
410 	   "      gcc_assert (!set);\n"
411 	   "      return false;\n"
412 	   "    }\n"
413 	   "}\n\n");
414 
415   /* C++ (even G++) does not support (non-trivial) designated initializers.
416      To work around that, generate these arrays programatically rather than
417      by our traditional multiple inclusion of def files.  */
418 
419   fprintf (s_file,
420 	   "const struct convert_optab_libcall_d "
421 	   "convlib_def[NUM_CONVLIB_OPTABS] = {\n");
422   for (i = last_kind[0] + 1; i <= last_kind[1]; ++i)
423     fprintf (s_file, "  { %s, %s },\n", optabs[i].base, optabs[i].libcall);
424   fprintf (s_file, "};\n\n");
425 
426   fprintf (s_file,
427 	   "const struct optab_libcall_d "
428 	   "normlib_def[NUM_NORMLIB_OPTABS] = {\n");
429   for (i = last_kind[2] + 1; i <= last_kind[3]; ++i)
430     fprintf (s_file, "  { %s, %s, %s },\n",
431 	     optabs[i].suffix, optabs[i].base, optabs[i].libcall);
432   fprintf (s_file, "};\n\n");
433 
434   fprintf (s_file, "enum rtx_code const optab_to_code_[NUM_OPTABS] = {\n");
435   for (i = 0; i < n; ++i)
436     fprintf (s_file, "  %s,\n", rtx_upname[optabs[i].fcode]);
437   fprintf (s_file, "};\n\n");
438 
439   qsort (optabs, n, sizeof (optab_def), optab_rcode_cmp);
440 
441   fprintf (s_file, "const optab code_to_optab_[NUM_RTX_CODE] = {\n");
442   for (j = 0; optabs[j].rcode == UNKNOWN; ++j)
443     continue;
444   for (i = 0; i < NON_GENERATOR_NUM_RTX_CODE; ++i)
445     {
446       if (j < n && optabs[j].rcode == i)
447 	fprintf (s_file, "  %s,\n", optabs[j++].name);
448       else
449 	fprintf (s_file, "  unknown_optab,\n");
450     }
451   fprintf (s_file, "};\n\n");
452 
453   fprintf (h_file, "#endif\n");
454   return (fclose (h_file) == 0 && fclose (s_file) == 0
455 	  ? SUCCESS_EXIT_CODE : FATAL_EXIT_CODE);
456 }
457