1 /* Generate code to initialize optabs from machine description.
2 Copyright (C) 1993-2025 Free Software Foundation, Inc.
4 This file is part of GCC.
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
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
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/>. */
23 #include "coretypes.h"
27 #include "gensupport.h"
30 #define DEF_RTL_EXPR(V, N, X, C) #V,
32 static const char * const rtx_upname
[] = {
38 /* Vector in which to collect insns that match. */
39 static vec
<optab_pattern
> patterns
;
42 gen_insn (md_rtx_info
*info
)
45 if (find_optab (&p
, XSTR (info
->def
, 0)))
46 patterns
.safe_push (p
);
50 pattern_cmp (const void *va
, const void *vb
)
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
;
58 optab_kind_cmp (const void *va
, const void *vb
)
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
;
69 optab_rcode_cmp (const void *va
, const void *vb
)
71 const optab_def
*a
= (const optab_def
*)va
;
72 const optab_def
*b
= (const optab_def
*)vb
;
73 return a
->rcode
- b
->rcode
;
76 static const char *header_file_name
= "init-opinit.h";
77 static const char *source_file_name
= "init-opinit.c";
80 handle_arg (const char *arg
)
85 header_file_name
= &arg
[2];
88 source_file_name
= &arg
[2];
96 open_outfile (const char *file_name
)
98 FILE *f
= fopen (file_name
, "w");
100 fatal ("cannot open file %s: %s", file_name
, xstrerror (errno
));
102 "/* Generated automatically by the program `genopinit'\n"
103 " from the machine description file `md'. */\n\n");
107 /* Declare the maybe_code_for_* function for ONAME, and provide
108 an inline definition of the assserting code_for_* wrapper. */
111 handle_overloaded_code_for (FILE *file
, overloaded_name
*oname
)
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");
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
);
126 " gcc_assert (code != CODE_FOR_nothing);\n"
131 /* Declare the maybe_gen_* function for ONAME, and provide
132 an inline definition of the assserting gen_* wrapper. */
135 handle_overloaded_gen (FILE *file
, overloaded_name
*oname
)
137 unsigned HOST_WIDE_INT seen
= 0;
138 for (overloaded_instance
*instance
= oname
->first_instance
->next
;
139 instance
; instance
= instance
->next
)
142 get_pattern_stats (&stats
, XVEC (instance
->insn
, 1));
143 unsigned HOST_WIDE_INT mask
144 = HOST_WIDE_INT_1U
<< stats
.num_generator_args
;
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");
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
);
170 " gcc_assert (res);\n"
177 main (int argc
, const char **argv
)
179 FILE *h_file
, *s_file
;
180 unsigned int i
, j
, n
, last_kind
[5];
183 progname
= "genopinit";
185 if (NUM_OPTABS
> 0xfff || NUM_MACHINE_MODES
> 0x3ff)
186 fatal ("genopinit range assumptions invalid");
188 if (!init_rtx_reader_args_cb (argc
, argv
, handle_arg
))
189 return (FATAL_EXIT_CODE
);
191 h_file
= open_outfile (header_file_name
);
192 s_file
= open_outfile (source_file_name
);
194 /* Read the machine description. */
196 while (read_md_rtx (&info
))
197 switch (GET_CODE (info
.def
))
208 /* Sort the collected patterns. */
209 patterns
.qsort (pattern_cmp
);
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. */
215 if (optabs
[i
].base
== NULL
)
216 optabs
[i
] = optabs
[--n
];
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
);
225 fprintf (h_file
, "#ifndef GCC_INSN_OPINIT_H\n");
226 fprintf (h_file
, "#define GCC_INSN_OPINIT_H 1\n");
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
)
233 fprintf (h_file
, " %s,\n", optabs
[i
].name
);
234 if (optabs
[i
].kind
!= j
)
235 last_kind
[j
++] = i
- 1;
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");
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 ());
254 "typedef enum optab_tag optab;\n"
255 "typedef enum optab_tag convert_optab;\n"
256 "typedef enum optab_tag direct_optab;\n"
258 "struct optab_libcall_d\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"
266 "struct convert_optab_libcall_d\n"
268 " const char *libcall_basename;\n"
269 " void (*libcall_gen) (convert_optab, const char *name,\n"
270 " machine_mode, machine_mode);\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"
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"
282 "static inline optab\n"
283 "code_to_optab (enum rtx_code code)\n"
285 " return code_to_optab_[code];\n"
288 "static inline enum rtx_code\n"
289 "optab_to_code (optab op)\n"
291 " return optab_to_code_[op];\n"
294 for (overloaded_name
*oname
= rtx_reader_ptr
->get_overloads ();
295 oname
; oname
= oname
->next
)
297 handle_overloaded_code_for (h_file
, oname
);
298 handle_overloaded_gen (h_file
, oname
);
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"
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"
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"
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"
322 "extern void init_all_optabs (struct target_optabs *);\n"
323 "extern bool partial_vectors_supported_p (void);\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"
330 "#define this_target_optabs (&default_target_optabs)\n"
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"
359 "struct optab_pat {\n"
361 " enum insn_code icode;\n"
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");
370 /* Some targets like riscv have a large number of patterns. In order to
371 prevent pathological situations in dataflow analysis split the init
372 function into separate ones that initialize 1000 patterns each. */
374 const int patterns_per_function
= 1000;
376 if (patterns
.length () > patterns_per_function
)
378 unsigned num_init_functions
379 = patterns
.length () / patterns_per_function
+ 1;
380 for (i
= 0; i
< num_init_functions
; i
++)
382 fprintf (s_file
, "static void\ninit_optabs_%02d "
383 "(struct target_optabs *optabs)\n{\n", i
);
384 fprintf (s_file
, " bool *ena = optabs->pat_enable;\n");
385 unsigned start
= i
* patterns_per_function
;
386 unsigned end
= MIN (patterns
.length (),
387 (i
+ 1) * patterns_per_function
);
388 for (j
= start
; j
< end
; ++j
)
389 fprintf (s_file
, " ena[%u] = HAVE_%s;\n", j
, patterns
[j
].name
);
390 fprintf (s_file
, "}\n\n");
393 fprintf (s_file
, "void\ninit_all_optabs "
394 "(struct target_optabs *optabs)\n{\n");
395 for (i
= 0; i
< num_init_functions
; ++i
)
396 fprintf (s_file
, " init_optabs_%02d (optabs);\n", i
);
397 fprintf (s_file
, "}\n\n");
401 fprintf (s_file
, "void\ninit_all_optabs "
402 "(struct target_optabs *optabs)\n{\n");
403 fprintf (s_file
, " bool *ena = optabs->pat_enable;\n");
404 for (i
= 0; patterns
.iterate (i
, &p
); ++i
)
405 fprintf (s_file
, " ena[%u] = HAVE_%s;\n", i
, p
->name
);
406 fprintf (s_file
, "}\n\n");
410 "/* Returns TRUE if the target supports any of the partial vector\n"
411 " optabs: while_ult_optab, len_load_optab, len_store_optab,\n"
412 " mask_len_load_optab or mask_len_store_optab,\n"
413 " for any mode. */\n"
414 "bool\npartial_vectors_supported_p (void)\n{\n");
415 bool any_match
= false;
416 fprintf (s_file
, "\treturn");
418 for (i
= 0; patterns
.iterate (i
, &p
); ++i
)
420 #define CMP_NAME(N) !strncmp (p->name, (N), strlen ((N)))
421 if (CMP_NAME("while_ult") || CMP_NAME ("len_load")
422 || CMP_NAME ("len_store")|| CMP_NAME ("mask_len_load")
423 || CMP_NAME ("mask_len_store"))
426 fprintf (s_file
, " HAVE_%s", p
->name
);
428 fprintf (s_file
, " || HAVE_%s", p
->name
);
434 fprintf (s_file
, " false");
435 fprintf (s_file
, ";\n}\n");
438 /* Perform a binary search on a pre-encoded optab+mode*2. */
439 /* ??? Perhaps even better to generate a minimal perfect hash.
440 Using gperf directly is awkward since it's so geared to working
441 with strings. Plus we have no visibility into the ordering of
442 the hash entries, which complicates the pat_enable array. */
445 "lookup_handler (unsigned scode)\n"
447 " int l = 0, h = ARRAY_SIZE (pats), m;\n"
450 " m = (h + l) / 2;\n"
451 " if (scode == pats[m].scode)\n"
453 " else if (scode < pats[m].scode)\n"
463 "raw_optab_handler (unsigned scode)\n"
465 " int i = lookup_handler (scode);\n"
466 " return (i >= 0 && this_fn_optabs->pat_enable[i]\n"
467 " ? pats[i].icode : CODE_FOR_nothing);\n"
472 "swap_optab_enable (optab op, machine_mode m, bool set)\n"
474 " unsigned scode = (op << 20) | m;\n"
475 " int i = lookup_handler (scode);\n"
478 " bool ret = this_fn_optabs->pat_enable[i];\n"
479 " this_fn_optabs->pat_enable[i] = set;\n"
484 " gcc_assert (!set);\n"
489 /* C++ (even G++) does not support (non-trivial) designated initializers.
490 To work around that, generate these arrays programatically rather than
491 by our traditional multiple inclusion of def files. */
494 "const struct convert_optab_libcall_d "
495 "convlib_def[NUM_CONVLIB_OPTABS] = {\n");
496 for (i
= last_kind
[0] + 1; i
<= last_kind
[1]; ++i
)
497 fprintf (s_file
, " { %s, %s },\n", optabs
[i
].base
, optabs
[i
].libcall
);
498 fprintf (s_file
, "};\n\n");
501 "const struct optab_libcall_d "
502 "normlib_def[NUM_NORMLIB_OPTABS] = {\n");
503 for (i
= last_kind
[2] + 1; i
<= last_kind
[3]; ++i
)
504 fprintf (s_file
, " { %s, %s, %s },\n",
505 optabs
[i
].suffix
, optabs
[i
].base
, optabs
[i
].libcall
);
506 fprintf (s_file
, "};\n\n");
508 fprintf (s_file
, "enum rtx_code const optab_to_code_[NUM_OPTABS] = {\n");
509 for (i
= 0; i
< n
; ++i
)
510 fprintf (s_file
, " %s,\n", rtx_upname
[optabs
[i
].fcode
]);
511 fprintf (s_file
, "};\n\n");
513 qsort (optabs
, n
, sizeof (optab_def
), optab_rcode_cmp
);
515 fprintf (s_file
, "const optab code_to_optab_[NUM_RTX_CODE] = {\n");
516 for (j
= 0; optabs
[j
].rcode
== UNKNOWN
; ++j
)
518 for (i
= 0; i
< NON_GENERATOR_NUM_RTX_CODE
; ++i
)
520 if (j
< n
&& optabs
[j
].rcode
== i
)
521 fprintf (s_file
, " %s,\n", optabs
[j
++].name
);
523 fprintf (s_file
, " unknown_optab,\n");
525 fprintf (s_file
, "};\n\n");
527 fprintf (h_file
, "#endif\n");
528 return (fclose (h_file
) == 0 && fclose (s_file
) == 0
529 ? SUCCESS_EXIT_CODE
: FATAL_EXIT_CODE
);