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