]>
Commit | Line | Data |
---|---|---|
5079aa9a | 1 | /* Generate code to initialize optabs from machine description. |
fbd26352 | 2 | Copyright (C) 1993-2019 Free Software Foundation, Inc. |
5079aa9a | 3 | |
f12b58b3 | 4 | This file is part of GCC. |
5079aa9a | 5 | |
f12b58b3 | 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 | |
8c4c00c1 | 8 | Software Foundation; either version 3, or (at your option) any later |
f12b58b3 | 9 | version. |
5079aa9a | 10 | |
f12b58b3 | 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. | |
5079aa9a | 15 | |
16 | You should have received a copy of the GNU General Public License | |
8c4c00c1 | 17 | along with GCC; see the file COPYING3. If not see |
18 | <http://www.gnu.org/licenses/>. */ | |
5079aa9a | 19 | |
20 | ||
805e22b2 | 21 | #include "bconfig.h" |
5ce88198 | 22 | #include "system.h" |
805e22b2 | 23 | #include "coretypes.h" |
24 | #include "tm.h" | |
5079aa9a | 25 | #include "rtl.h" |
04b58880 | 26 | #include "errors.h" |
c5ddd6b5 | 27 | #include "gensupport.h" |
3ef9782d | 28 | |
5079aa9a | 29 | |
ee65118b | 30 | #define DEF_RTL_EXPR(V, N, X, C) #V, |
5079aa9a | 31 | |
ee65118b | 32 | static const char * const rtx_upname[] = { |
33 | #include "rtl.def" | |
34 | }; | |
35 | ||
36 | #undef DEF_RTL_EXPR | |
37 | ||
ee65118b | 38 | /* Vector in which to collect insns that match. */ |
592e7d69 | 39 | static vec<optab_pattern> patterns; |
12693c81 | 40 | |
5079aa9a | 41 | static void |
c04601c1 | 42 | gen_insn (md_rtx_info *info) |
5079aa9a | 43 | { |
592e7d69 | 44 | optab_pattern p; |
45 | if (find_optab (&p, XSTR (info->def, 0))) | |
46 | patterns.safe_push (p); | |
ee65118b | 47 | } |
5079aa9a | 48 | |
ee65118b | 49 | static int |
50 | pattern_cmp (const void *va, const void *vb) | |
51 | { | |
592e7d69 | 52 | const optab_pattern *a = (const optab_pattern *)va; |
53 | const optab_pattern *b = (const optab_pattern *)vb; | |
ee65118b | 54 | return a->sort_num - b->sort_num; |
55 | } | |
5079aa9a | 56 | |
ee65118b | 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 | } | |
5079aa9a | 67 | |
ee65118b | 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 | } | |
5079aa9a | 75 | |
ee65118b | 76 | static const char *header_file_name = "init-opinit.h"; |
77 | static const char *source_file_name = "init-opinit.c"; | |
5079aa9a | 78 | |
ee65118b | 79 | static bool |
80 | handle_arg (const char *arg) | |
81 | { | |
82 | switch (arg[1]) | |
5079aa9a | 83 | { |
ee65118b | 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; | |
5079aa9a | 92 | } |
5079aa9a | 93 | } |
5079aa9a | 94 | |
ee65118b | 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 | } | |
947491b7 | 106 | |
60eea7fb | 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 | { | |
f8533207 | 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 | } | |
60eea7fb | 174 | } |
175 | ||
5079aa9a | 176 | int |
16570c04 | 177 | main (int argc, const char **argv) |
5079aa9a | 178 | { |
ee65118b | 179 | FILE *h_file, *s_file; |
180 | unsigned int i, j, n, last_kind[5]; | |
592e7d69 | 181 | optab_pattern *p; |
5079aa9a | 182 | |
04b58880 | 183 | progname = "genopinit"; |
5079aa9a | 184 | |
ee65118b | 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)) | |
c5ddd6b5 | 189 | return (FATAL_EXIT_CODE); |
5079aa9a | 190 | |
ee65118b | 191 | h_file = open_outfile (header_file_name); |
192 | s_file = open_outfile (source_file_name); | |
0beae642 | 193 | |
5079aa9a | 194 | /* Read the machine description. */ |
c04601c1 | 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); | |
5079aa9a | 202 | break; |
c04601c1 | 203 | |
204 | default: | |
205 | break; | |
206 | } | |
5079aa9a | 207 | |
ee65118b | 208 | /* Sort the collected patterns. */ |
90a2d741 | 209 | patterns.qsort (pattern_cmp); |
ee65118b | 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. */ | |
592e7d69 | 213 | n = num_optabs; |
ee65118b | 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. */ | |
9af5ce0c | 223 | qsort (optabs, n, sizeof (optab_def), optab_kind_cmp); |
ee65118b | 224 | |
947ed59a | 225 | fprintf (h_file, "#ifndef GCC_INSN_OPINIT_H\n"); |
226 | fprintf (h_file, "#define GCC_INSN_OPINIT_H 1\n"); | |
227 | ||
ee65118b | 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", | |
f1f41a6c | 251 | (unsigned) patterns.length ()); |
ee65118b | 252 | |
34517c64 | 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" | |
947ed59a | 277 | "#ifdef NUM_RTX_CODE\n" |
34517c64 | 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" | |
60eea7fb | 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, | |
947ed59a | 302 | "#endif\n" |
34517c64 | 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" | |
1619606c | 315 | "\n" |
316 | " /* Cache if the target supports vec_gather_load for at least one vector\n" | |
317 | " mode. */\n" | |
318 | " bool supports_vec_gather_load;\n" | |
319 | " bool supports_vec_gather_load_cached;\n" | |
0bf8b382 | 320 | " bool supports_vec_scatter_store;\n" |
321 | " bool supports_vec_scatter_store_cached;\n" | |
34517c64 | 322 | "};\n" |
323 | "extern void init_all_optabs (struct target_optabs *);\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 | ||
ee65118b | 333 | fprintf (s_file, |
785790dc | 334 | "#define IN_TARGET_CODE 1\n" |
ee65118b | 335 | "#include \"config.h\"\n" |
336 | "#include \"system.h\"\n" | |
337 | "#include \"coretypes.h\"\n" | |
9ef16211 | 338 | "#include \"backend.h\"\n" |
d040a5b0 | 339 | "#include \"predict.h\"\n" |
41a8aa41 | 340 | "#include \"tree.h\"\n" |
9ef16211 | 341 | "#include \"rtl.h\"\n" |
342 | "#include \"alias.h\"\n" | |
9ed99284 | 343 | "#include \"varasm.h\"\n" |
344 | "#include \"stor-layout.h\"\n" | |
345 | "#include \"calls.h\"\n" | |
ad7b10a2 | 346 | "#include \"memmodel.h\"\n" |
ee65118b | 347 | "#include \"tm_p.h\"\n" |
348 | "#include \"flags.h\"\n" | |
349 | "#include \"insn-config.h\"\n" | |
d53441c8 | 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" | |
ee65118b | 355 | "#include \"expr.h\"\n" |
34517c64 | 356 | "#include \"insn-codes.h\"\n" |
ee65118b | 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"); | |
f1f41a6c | 366 | for (i = 0; patterns.iterate (i, &p); ++i) |
ee65118b | 367 | fprintf (s_file, " { %#08x, CODE_FOR_%s },\n", p->sort_num, p->name); |
368 | fprintf (s_file, "};\n\n"); | |
369 | ||
08c7d04b | 370 | fprintf (s_file, "void\ninit_all_optabs (struct target_optabs *optabs)\n{\n"); |
371 | fprintf (s_file, " bool *ena = optabs->pat_enable;\n"); | |
f1f41a6c | 372 | for (i = 0; patterns.iterate (i, &p); ++i) |
ee65118b | 373 | fprintf (s_file, " ena[%u] = HAVE_%s;\n", i, p->name); |
374 | fprintf (s_file, "}\n\n"); | |
375 | ||
376 | /* Perform a binary search on a pre-encoded optab+mode*2. */ | |
377 | /* ??? Perhaps even better to generate a minimal perfect hash. | |
378 | Using gperf directly is awkward since it's so geared to working | |
379 | with strings. Plus we have no visibility into the ordering of | |
380 | the hash entries, which complicates the pat_enable array. */ | |
381 | fprintf (s_file, | |
382 | "static int\n" | |
383 | "lookup_handler (unsigned scode)\n" | |
384 | "{\n" | |
385 | " int l = 0, h = ARRAY_SIZE (pats), m;\n" | |
386 | " while (h > l)\n" | |
387 | " {\n" | |
388 | " m = (h + l) / 2;\n" | |
389 | " if (scode == pats[m].scode)\n" | |
390 | " return m;\n" | |
391 | " else if (scode < pats[m].scode)\n" | |
392 | " h = m;\n" | |
393 | " else\n" | |
394 | " l = m + 1;\n" | |
395 | " }\n" | |
396 | " return -1;\n" | |
397 | "}\n\n"); | |
398 | ||
399 | fprintf (s_file, | |
400 | "enum insn_code\n" | |
401 | "raw_optab_handler (unsigned scode)\n" | |
402 | "{\n" | |
403 | " int i = lookup_handler (scode);\n" | |
08c7d04b | 404 | " return (i >= 0 && this_fn_optabs->pat_enable[i]\n" |
ee65118b | 405 | " ? pats[i].icode : CODE_FOR_nothing);\n" |
406 | "}\n\n"); | |
407 | ||
408 | fprintf (s_file, | |
409 | "bool\n" | |
3754d046 | 410 | "swap_optab_enable (optab op, machine_mode m, bool set)\n" |
ee65118b | 411 | "{\n" |
412 | " unsigned scode = (op << 16) | m;\n" | |
413 | " int i = lookup_handler (scode);\n" | |
414 | " if (i >= 0)\n" | |
415 | " {\n" | |
08c7d04b | 416 | " bool ret = this_fn_optabs->pat_enable[i];\n" |
417 | " this_fn_optabs->pat_enable[i] = set;\n" | |
ee65118b | 418 | " return ret;\n" |
419 | " }\n" | |
420 | " else\n" | |
421 | " {\n" | |
422 | " gcc_assert (!set);\n" | |
423 | " return false;\n" | |
424 | " }\n" | |
425 | "}\n\n"); | |
426 | ||
427 | /* C++ (even G++) does not support (non-trivial) designated initializers. | |
428 | To work around that, generate these arrays programatically rather than | |
429 | by our traditional multiple inclusion of def files. */ | |
430 | ||
431 | fprintf (s_file, | |
432 | "const struct convert_optab_libcall_d " | |
433 | "convlib_def[NUM_CONVLIB_OPTABS] = {\n"); | |
434 | for (i = last_kind[0] + 1; i <= last_kind[1]; ++i) | |
435 | fprintf (s_file, " { %s, %s },\n", optabs[i].base, optabs[i].libcall); | |
436 | fprintf (s_file, "};\n\n"); | |
437 | ||
438 | fprintf (s_file, | |
439 | "const struct optab_libcall_d " | |
440 | "normlib_def[NUM_NORMLIB_OPTABS] = {\n"); | |
441 | for (i = last_kind[2] + 1; i <= last_kind[3]; ++i) | |
442 | fprintf (s_file, " { %s, %s, %s },\n", | |
443 | optabs[i].suffix, optabs[i].base, optabs[i].libcall); | |
444 | fprintf (s_file, "};\n\n"); | |
445 | ||
446 | fprintf (s_file, "enum rtx_code const optab_to_code_[NUM_OPTABS] = {\n"); | |
447 | for (i = 0; i < n; ++i) | |
448 | fprintf (s_file, " %s,\n", rtx_upname[optabs[i].fcode]); | |
449 | fprintf (s_file, "};\n\n"); | |
450 | ||
451 | qsort (optabs, n, sizeof (optab_def), optab_rcode_cmp); | |
452 | ||
453 | fprintf (s_file, "const optab code_to_optab_[NUM_RTX_CODE] = {\n"); | |
454 | for (j = 0; optabs[j].rcode == UNKNOWN; ++j) | |
455 | continue; | |
456 | for (i = 0; i < NON_GENERATOR_NUM_RTX_CODE; ++i) | |
457 | { | |
458 | if (j < n && optabs[j].rcode == i) | |
459 | fprintf (s_file, " %s,\n", optabs[j++].name); | |
460 | else | |
461 | fprintf (s_file, " unknown_optab,\n"); | |
462 | } | |
463 | fprintf (s_file, "};\n\n"); | |
464 | ||
947ed59a | 465 | fprintf (h_file, "#endif\n"); |
ee65118b | 466 | return (fclose (h_file) == 0 && fclose (s_file) == 0 |
467 | ? SUCCESS_EXIT_CODE : FATAL_EXIT_CODE); | |
5079aa9a | 468 | } |