]>
Commit | Line | Data |
---|---|---|
5079aa9a | 1 | /* Generate code to initialize optabs from machine description. |
f1717362 | 2 | Copyright (C) 1993-2016 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 | |
5079aa9a | 107 | int |
1a97be37 | 108 | main (int argc, char **argv) |
5079aa9a | 109 | { |
ee65118b | 110 | FILE *h_file, *s_file; |
111 | unsigned int i, j, n, last_kind[5]; | |
592e7d69 | 112 | optab_pattern *p; |
5079aa9a | 113 | |
04b58880 | 114 | progname = "genopinit"; |
5079aa9a | 115 | |
ee65118b | 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)) | |
c5ddd6b5 | 120 | return (FATAL_EXIT_CODE); |
5079aa9a | 121 | |
ee65118b | 122 | h_file = open_outfile (header_file_name); |
123 | s_file = open_outfile (source_file_name); | |
0beae642 | 124 | |
5079aa9a | 125 | /* Read the machine description. */ |
c04601c1 | 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); | |
5079aa9a | 133 | break; |
c04601c1 | 134 | |
135 | default: | |
136 | break; | |
137 | } | |
5079aa9a | 138 | |
ee65118b | 139 | /* Sort the collected patterns. */ |
90a2d741 | 140 | patterns.qsort (pattern_cmp); |
ee65118b | 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. */ | |
592e7d69 | 144 | n = num_optabs; |
ee65118b | 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. */ | |
9af5ce0c | 154 | qsort (optabs, n, sizeof (optab_def), optab_kind_cmp); |
ee65118b | 155 | |
947ed59a | 156 | fprintf (h_file, "#ifndef GCC_INSN_OPINIT_H\n"); |
157 | fprintf (h_file, "#define GCC_INSN_OPINIT_H 1\n"); | |
158 | ||
ee65118b | 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", | |
f1f41a6c | 182 | (unsigned) patterns.length ()); |
ee65118b | 183 | |
34517c64 | 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" | |
947ed59a | 208 | "#ifdef NUM_RTX_CODE\n" |
34517c64 | 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" | |
947ed59a | 224 | "#endif\n" |
34517c64 | 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 | "extern void init_all_optabs (struct target_optabs *);\n" | |
239 | "\n" | |
240 | "extern struct target_optabs default_target_optabs;\n" | |
241 | "extern struct target_optabs *this_fn_optabs;\n" | |
242 | "#if SWITCHABLE_TARGET\n" | |
243 | "extern struct target_optabs *this_target_optabs;\n" | |
244 | "#else\n" | |
245 | "#define this_target_optabs (&default_target_optabs)\n" | |
246 | "#endif\n"); | |
247 | ||
ee65118b | 248 | fprintf (s_file, |
249 | "#include \"config.h\"\n" | |
250 | "#include \"system.h\"\n" | |
251 | "#include \"coretypes.h\"\n" | |
9ef16211 | 252 | "#include \"backend.h\"\n" |
d040a5b0 | 253 | "#include \"predict.h\"\n" |
41a8aa41 | 254 | "#include \"tree.h\"\n" |
9ef16211 | 255 | "#include \"rtl.h\"\n" |
256 | "#include \"alias.h\"\n" | |
9ed99284 | 257 | "#include \"varasm.h\"\n" |
258 | "#include \"stor-layout.h\"\n" | |
259 | "#include \"calls.h\"\n" | |
ee65118b | 260 | "#include \"tm_p.h\"\n" |
261 | "#include \"flags.h\"\n" | |
262 | "#include \"insn-config.h\"\n" | |
d53441c8 | 263 | "#include \"expmed.h\"\n" |
264 | "#include \"dojump.h\"\n" | |
265 | "#include \"explow.h\"\n" | |
266 | "#include \"emit-rtl.h\"\n" | |
267 | "#include \"stmt.h\"\n" | |
ee65118b | 268 | "#include \"expr.h\"\n" |
34517c64 | 269 | "#include \"insn-codes.h\"\n" |
ee65118b | 270 | "#include \"optabs.h\"\n" |
271 | "\n" | |
272 | "struct optab_pat {\n" | |
273 | " unsigned scode;\n" | |
274 | " enum insn_code icode;\n" | |
275 | "};\n\n"); | |
276 | ||
277 | fprintf (s_file, | |
278 | "static const struct optab_pat pats[NUM_OPTAB_PATTERNS] = {\n"); | |
f1f41a6c | 279 | for (i = 0; patterns.iterate (i, &p); ++i) |
ee65118b | 280 | fprintf (s_file, " { %#08x, CODE_FOR_%s },\n", p->sort_num, p->name); |
281 | fprintf (s_file, "};\n\n"); | |
282 | ||
08c7d04b | 283 | fprintf (s_file, "void\ninit_all_optabs (struct target_optabs *optabs)\n{\n"); |
284 | fprintf (s_file, " bool *ena = optabs->pat_enable;\n"); | |
f1f41a6c | 285 | for (i = 0; patterns.iterate (i, &p); ++i) |
ee65118b | 286 | fprintf (s_file, " ena[%u] = HAVE_%s;\n", i, p->name); |
287 | fprintf (s_file, "}\n\n"); | |
288 | ||
289 | /* Perform a binary search on a pre-encoded optab+mode*2. */ | |
290 | /* ??? Perhaps even better to generate a minimal perfect hash. | |
291 | Using gperf directly is awkward since it's so geared to working | |
292 | with strings. Plus we have no visibility into the ordering of | |
293 | the hash entries, which complicates the pat_enable array. */ | |
294 | fprintf (s_file, | |
295 | "static int\n" | |
296 | "lookup_handler (unsigned scode)\n" | |
297 | "{\n" | |
298 | " int l = 0, h = ARRAY_SIZE (pats), m;\n" | |
299 | " while (h > l)\n" | |
300 | " {\n" | |
301 | " m = (h + l) / 2;\n" | |
302 | " if (scode == pats[m].scode)\n" | |
303 | " return m;\n" | |
304 | " else if (scode < pats[m].scode)\n" | |
305 | " h = m;\n" | |
306 | " else\n" | |
307 | " l = m + 1;\n" | |
308 | " }\n" | |
309 | " return -1;\n" | |
310 | "}\n\n"); | |
311 | ||
312 | fprintf (s_file, | |
313 | "enum insn_code\n" | |
314 | "raw_optab_handler (unsigned scode)\n" | |
315 | "{\n" | |
316 | " int i = lookup_handler (scode);\n" | |
08c7d04b | 317 | " return (i >= 0 && this_fn_optabs->pat_enable[i]\n" |
ee65118b | 318 | " ? pats[i].icode : CODE_FOR_nothing);\n" |
319 | "}\n\n"); | |
320 | ||
321 | fprintf (s_file, | |
322 | "bool\n" | |
3754d046 | 323 | "swap_optab_enable (optab op, machine_mode m, bool set)\n" |
ee65118b | 324 | "{\n" |
325 | " unsigned scode = (op << 16) | m;\n" | |
326 | " int i = lookup_handler (scode);\n" | |
327 | " if (i >= 0)\n" | |
328 | " {\n" | |
08c7d04b | 329 | " bool ret = this_fn_optabs->pat_enable[i];\n" |
330 | " this_fn_optabs->pat_enable[i] = set;\n" | |
ee65118b | 331 | " return ret;\n" |
332 | " }\n" | |
333 | " else\n" | |
334 | " {\n" | |
335 | " gcc_assert (!set);\n" | |
336 | " return false;\n" | |
337 | " }\n" | |
338 | "}\n\n"); | |
339 | ||
340 | /* C++ (even G++) does not support (non-trivial) designated initializers. | |
341 | To work around that, generate these arrays programatically rather than | |
342 | by our traditional multiple inclusion of def files. */ | |
343 | ||
344 | fprintf (s_file, | |
345 | "const struct convert_optab_libcall_d " | |
346 | "convlib_def[NUM_CONVLIB_OPTABS] = {\n"); | |
347 | for (i = last_kind[0] + 1; i <= last_kind[1]; ++i) | |
348 | fprintf (s_file, " { %s, %s },\n", optabs[i].base, optabs[i].libcall); | |
349 | fprintf (s_file, "};\n\n"); | |
350 | ||
351 | fprintf (s_file, | |
352 | "const struct optab_libcall_d " | |
353 | "normlib_def[NUM_NORMLIB_OPTABS] = {\n"); | |
354 | for (i = last_kind[2] + 1; i <= last_kind[3]; ++i) | |
355 | fprintf (s_file, " { %s, %s, %s },\n", | |
356 | optabs[i].suffix, optabs[i].base, optabs[i].libcall); | |
357 | fprintf (s_file, "};\n\n"); | |
358 | ||
359 | fprintf (s_file, "enum rtx_code const optab_to_code_[NUM_OPTABS] = {\n"); | |
360 | for (i = 0; i < n; ++i) | |
361 | fprintf (s_file, " %s,\n", rtx_upname[optabs[i].fcode]); | |
362 | fprintf (s_file, "};\n\n"); | |
363 | ||
364 | qsort (optabs, n, sizeof (optab_def), optab_rcode_cmp); | |
365 | ||
366 | fprintf (s_file, "const optab code_to_optab_[NUM_RTX_CODE] = {\n"); | |
367 | for (j = 0; optabs[j].rcode == UNKNOWN; ++j) | |
368 | continue; | |
369 | for (i = 0; i < NON_GENERATOR_NUM_RTX_CODE; ++i) | |
370 | { | |
371 | if (j < n && optabs[j].rcode == i) | |
372 | fprintf (s_file, " %s,\n", optabs[j++].name); | |
373 | else | |
374 | fprintf (s_file, " unknown_optab,\n"); | |
375 | } | |
376 | fprintf (s_file, "};\n\n"); | |
377 | ||
947ed59a | 378 | fprintf (h_file, "#endif\n"); |
ee65118b | 379 | return (fclose (h_file) == 0 && fclose (s_file) == 0 |
380 | ? SUCCESS_EXIT_CODE : FATAL_EXIT_CODE); | |
5079aa9a | 381 | } |