]>
Commit | Line | Data |
---|---|---|
4bccb39e | 1 | /* Generate insn-target-def.h, an automatically-generated part of targetm. |
99dee823 | 2 | Copyright (C) 1987-2021 Free Software Foundation, Inc. |
4bccb39e RS |
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 | #include "bconfig.h" | |
21 | #include "system.h" | |
22 | #include "coretypes.h" | |
23 | #include "tm.h" | |
24 | #include "rtl.h" | |
25 | #include "errors.h" | |
26 | #include "read-md.h" | |
27 | #include "gensupport.h" | |
28 | #include "hash-table.h" | |
29 | ||
30 | /* This class hashes define_insns and define_expands by name. */ | |
31 | struct insn_hasher : nofree_ptr_hash <rtx_def> | |
32 | { | |
33 | typedef rtx value_type; | |
34 | typedef const char *compare_type; | |
35 | ||
36 | static inline hashval_t hash (rtx); | |
37 | static inline bool equal (rtx, const char *); | |
38 | }; | |
39 | ||
40 | hashval_t | |
41 | insn_hasher::hash (rtx x) | |
42 | { | |
43 | return htab_hash_string (XSTR (x, 0)); | |
44 | } | |
45 | ||
46 | bool | |
47 | insn_hasher::equal (rtx x, const char *y) | |
48 | { | |
49 | return strcmp (XSTR (x, 0), y) == 0; | |
50 | } | |
51 | ||
52 | /* All define_insns and define_expands, hashed by name. */ | |
53 | static hash_table <insn_hasher> *insns; | |
54 | ||
55 | /* Records the prototype suffix X for each invalid_X stub that has been | |
56 | generated. */ | |
57 | static hash_table <nofree_string_hash> *stubs; | |
58 | ||
59 | /* Records which C conditions have been wrapped in functions, as a mapping | |
60 | from the C condition to the function name. */ | |
61 | static hash_map <nofree_string_hash, const char *> *have_funcs; | |
62 | ||
58d745ec RS |
63 | /* Return true if the part of the prototype at P is for an argument |
64 | name. If so, point *END_OUT to the first character after the name. | |
65 | If OPNO_OUT is nonnull, set *OPNO_OUT to the number of the associated | |
66 | operand. If REQUIRED_OUT is nonnull, set *REQUIRED_OUT to whether the | |
67 | .md pattern is required to match the operand. */ | |
68 | ||
69 | static bool | |
70 | parse_argument (const char *p, const char **end_out, | |
71 | unsigned int *opno_out = 0, | |
72 | bool *required_out = 0) | |
73 | { | |
74 | while (ISSPACE (*p)) | |
75 | p++; | |
76 | if (p[0] == 'x' && ISDIGIT (p[1])) | |
77 | { | |
78 | p += 1; | |
79 | if (required_out) | |
80 | *required_out = true; | |
81 | } | |
82 | else if (p[0] == 'o' && p[1] == 'p' && p[2] == 't' && ISDIGIT (p[3])) | |
83 | { | |
84 | p += 3; | |
85 | if (required_out) | |
86 | *required_out = false; | |
87 | } | |
88 | else | |
89 | return false; | |
90 | ||
91 | char *endptr; | |
92 | unsigned int opno = strtol (p, &endptr, 10); | |
93 | if (opno_out) | |
94 | *opno_out = opno; | |
95 | *end_out = endptr; | |
96 | return true; | |
97 | } | |
98 | ||
99 | ||
4bccb39e RS |
100 | /* Output hook definitions for pattern NAME, which has target-insns.def |
101 | prototype PROTOTYPE. */ | |
102 | ||
103 | static void | |
104 | def_target_insn (const char *name, const char *prototype) | |
105 | { | |
106 | /* Get an upper-case form of NAME. */ | |
107 | unsigned int i; | |
108 | char *upper_name = XALLOCAVEC (char, strlen (name) + 1); | |
109 | for (i = 0; name[i]; ++i) | |
110 | upper_name[i] = TOUPPER (name[i]); | |
111 | upper_name[i] = 0; | |
112 | ||
113 | /* Check that the prototype is valid and concatenate the types | |
114 | together to get a suffix. */ | |
115 | char *suffix = XALLOCAVEC (char, strlen (prototype) + 1); | |
116 | i = 0; | |
117 | unsigned int opno = 0; | |
58d745ec RS |
118 | unsigned int required_ops = 0; |
119 | unsigned int this_opno; | |
120 | bool required_p; | |
4bccb39e | 121 | for (const char *p = prototype; *p; ++p) |
58d745ec | 122 | if (parse_argument (p, &p, &this_opno, &required_p)) |
4bccb39e | 123 | { |
58d745ec | 124 | if (this_opno != opno || (*p != ',' && *p != ')')) |
4bccb39e RS |
125 | { |
126 | error ("invalid prototype for '%s'", name); | |
127 | exit (FATAL_EXIT_CODE); | |
128 | } | |
58d745ec RS |
129 | if (required_p && required_ops < opno) |
130 | { | |
131 | error ("prototype for '%s' has required operands after" | |
132 | " optional operands", name); | |
133 | exit (FATAL_EXIT_CODE); | |
134 | } | |
4bccb39e | 135 | opno += 1; |
58d745ec RS |
136 | if (required_p) |
137 | required_ops = opno; | |
138 | /* Skip over ')'s. */ | |
4bccb39e RS |
139 | if (*p == ',') |
140 | suffix[i++] = '_'; | |
141 | } | |
142 | else if (*p == ')' || *p == ',') | |
143 | { | |
144 | /* We found the end of a parameter without finding a | |
145 | parameter name. */ | |
146 | if (strcmp (prototype, "(void)") != 0) | |
147 | { | |
148 | error ("argument %d of '%s' did not have the expected name", | |
149 | opno, name); | |
150 | exit (FATAL_EXIT_CODE); | |
151 | } | |
152 | } | |
153 | else if (*p != '(' && !ISSPACE (*p)) | |
154 | suffix[i++] = *p; | |
155 | suffix[i] = 0; | |
156 | ||
157 | /* See whether we have an implementation of this pattern. */ | |
158 | hashval_t hash = htab_hash_string (name); | |
159 | int truth = 0; | |
160 | const char *have_name = name; | |
161 | if (rtx insn = insns->find_with_hash (name, hash)) | |
162 | { | |
58d745ec RS |
163 | pattern_stats stats; |
164 | get_pattern_stats (&stats, XVEC (insn, 1)); | |
165 | unsigned int actual_ops = stats.num_generator_args; | |
166 | if (opno == required_ops && opno != actual_ops) | |
167 | error_at (get_file_location (insn), | |
168 | "'%s' must have %d operands (excluding match_dups)", | |
169 | name, required_ops); | |
170 | else if (actual_ops < required_ops) | |
171 | error_at (get_file_location (insn), | |
172 | "'%s' must have at least %d operands (excluding match_dups)", | |
173 | name, required_ops); | |
174 | else if (actual_ops > opno) | |
175 | error_at (get_file_location (insn), | |
176 | "'%s' must have no more than %d operands" | |
177 | " (excluding match_dups)", name, opno); | |
178 | ||
4bccb39e RS |
179 | const char *test = XSTR (insn, 2); |
180 | truth = maybe_eval_c_test (test); | |
181 | gcc_assert (truth != 0); | |
182 | if (truth < 0) | |
183 | { | |
184 | /* Try to reuse an existing function that performs the same test. */ | |
185 | bool existed; | |
186 | const char *&entry = have_funcs->get_or_insert (test, &existed); | |
187 | if (!existed) | |
188 | { | |
189 | entry = name; | |
190 | printf ("\nstatic bool\n"); | |
191 | printf ("target_have_%s (void)\n", name); | |
192 | printf ("{\n"); | |
193 | printf (" return "); | |
b78027d1 | 194 | rtx_reader_ptr->print_c_condition (test); |
4bccb39e RS |
195 | printf (";\n"); |
196 | printf ("}\n"); | |
197 | } | |
198 | have_name = entry; | |
199 | } | |
200 | printf ("\nstatic rtx_insn *\n"); | |
58d745ec RS |
201 | printf ("target_gen_%s ", name); |
202 | /* Print the prototype with the argument names after ACTUAL_OPS | |
203 | removed. */ | |
204 | const char *p = prototype, *end; | |
205 | while (*p) | |
206 | if (parse_argument (p, &end, &this_opno) && this_opno >= actual_ops) | |
207 | p = end; | |
208 | else | |
209 | fputc (*p++, stdout); | |
210 | ||
211 | printf ("\n{\n"); | |
4bccb39e RS |
212 | if (truth < 0) |
213 | printf (" gcc_checking_assert (targetm.have_%s ());\n", name); | |
214 | printf (" return insnify (gen_%s (", name); | |
58d745ec RS |
215 | for (i = 0; i < actual_ops; ++i) |
216 | printf ("%s%s%d", i == 0 ? "" : ", ", | |
217 | i < required_ops ? "x" : "opt", i); | |
4bccb39e RS |
218 | printf ("));\n"); |
219 | printf ("}\n"); | |
220 | } | |
221 | else | |
222 | { | |
223 | const char **slot = stubs->find_slot (suffix, INSERT); | |
224 | if (!*slot) | |
225 | { | |
226 | *slot = xstrdup (suffix); | |
227 | printf ("\nstatic rtx_insn *\n"); | |
228 | printf ("invalid_%s ", suffix); | |
58d745ec | 229 | /* Print the prototype with the argument names removed. */ |
4bccb39e RS |
230 | const char *p = prototype; |
231 | while (*p) | |
58d745ec RS |
232 | if (!parse_argument (p, &p)) |
233 | fputc (*p++, stdout); | |
4bccb39e RS |
234 | printf ("\n{\n"); |
235 | printf (" gcc_unreachable ();\n"); | |
236 | printf ("}\n"); | |
237 | } | |
238 | } | |
239 | printf ("\n#undef TARGET_HAVE_%s\n", upper_name); | |
240 | printf ("#define TARGET_HAVE_%s ", upper_name); | |
241 | if (truth == 0) | |
242 | printf ("hook_bool_void_false\n"); | |
243 | else if (truth == 1) | |
244 | printf ("hook_bool_void_true\n"); | |
245 | else | |
246 | printf ("target_have_%s\n", have_name); | |
247 | ||
248 | printf ("#undef TARGET_GEN_%s\n", upper_name); | |
249 | printf ("#define TARGET_GEN_%s ", upper_name); | |
250 | if (truth == 0) | |
251 | printf ("invalid_%s\n", suffix); | |
252 | else | |
253 | printf ("target_gen_%s\n", name); | |
8684d89d RS |
254 | |
255 | printf ("#undef TARGET_CODE_FOR_%s\n", upper_name); | |
256 | printf ("#define TARGET_CODE_FOR_%s ", upper_name); | |
257 | if (truth == 0) | |
258 | printf ("CODE_FOR_nothing\n"); | |
259 | else | |
260 | printf ("CODE_FOR_%s\n", name); | |
4bccb39e RS |
261 | } |
262 | ||
5d2d3e43 RS |
263 | /* Record the DEFINE_INSN or DEFINE_EXPAND described by INFO. */ |
264 | ||
265 | static void | |
266 | add_insn (md_rtx_info *info) | |
267 | { | |
268 | rtx def = info->def; | |
269 | const char *name = XSTR (def, 0); | |
270 | if (name[0] == 0 || name[0] == '*') | |
271 | return; | |
272 | ||
273 | hashval_t hash = htab_hash_string (name); | |
274 | rtx *slot = insns->find_slot_with_hash (name, hash, INSERT); | |
275 | if (*slot) | |
276 | error_at (info->loc, "duplicate definition of '%s'", name); | |
277 | else | |
278 | *slot = def; | |
279 | } | |
280 | ||
4bccb39e | 281 | int |
66b0fe8f | 282 | main (int argc, const char **argv) |
4bccb39e | 283 | { |
4bccb39e RS |
284 | progname = "gentarget-def"; |
285 | ||
286 | if (!init_rtx_reader_args (argc, argv)) | |
287 | return (FATAL_EXIT_CODE); | |
288 | ||
289 | insns = new hash_table <insn_hasher> (31); | |
290 | stubs = new hash_table <nofree_string_hash> (31); | |
291 | have_funcs = new hash_map <nofree_string_hash, const char *>; | |
292 | ||
5d2d3e43 RS |
293 | md_rtx_info info; |
294 | while (read_md_rtx (&info)) | |
295 | switch (GET_CODE (info.def)) | |
296 | { | |
297 | case DEFINE_INSN: | |
298 | case DEFINE_EXPAND: | |
299 | add_insn (&info); | |
4bccb39e | 300 | break; |
5d2d3e43 RS |
301 | |
302 | default: | |
303 | break; | |
304 | } | |
4bccb39e RS |
305 | |
306 | printf ("/* Generated automatically by the program `gentarget-def'. */\n"); | |
307 | printf ("#ifndef GCC_INSN_TARGET_DEF_H\n"); | |
308 | printf ("#define GCC_INSN_TARGET_DEF_H\n"); | |
309 | ||
310 | /* Output a routine to convert an rtx to an rtx_insn sequence. | |
311 | ??? At some point the gen_* functions themselves should return | |
312 | rtx_insns. */ | |
313 | printf ("\nstatic inline rtx_insn *\n"); | |
314 | printf ("insnify (rtx x)\n"); | |
315 | printf ("{\n"); | |
316 | printf (" if (!x)\n"); | |
317 | printf (" return NULL;\n"); | |
318 | printf (" if (rtx_insn *insn = dyn_cast <rtx_insn *> (x))\n"); | |
319 | printf (" return insn;\n"); | |
320 | printf (" start_sequence ();\n"); | |
9d8895c9 | 321 | printf (" emit (x, false);\n"); |
4bccb39e RS |
322 | printf (" rtx_insn *res = get_insns ();\n"); |
323 | printf (" end_sequence ();\n"); | |
324 | printf (" return res;\n"); | |
325 | printf ("}\n"); | |
326 | ||
327 | #define DEF_TARGET_INSN(INSN, ARGS) \ | |
328 | def_target_insn (#INSN, #ARGS); | |
329 | #include "target-insns.def" | |
330 | #undef DEF_TARGET_INSN | |
331 | ||
332 | printf ("\n#endif /* GCC_INSN_TARGET_DEF_H */\n"); | |
333 | ||
334 | if (have_error || ferror (stdout) || fflush (stdout) || fclose (stdout)) | |
335 | return FATAL_EXIT_CODE; | |
336 | ||
337 | return SUCCESS_EXIT_CODE; | |
338 | } |