1/* Generate insn-target-def.h, an automatically-generated part of targetm.
2 Copyright (C) 1987-2023 Free Software Foundation, Inc.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free
8Software Foundation; either version 3, or (at your option) any later
9version.
10
11GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or
13FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14for more details.
15
16You should have received a copy of the GNU General Public License
17along 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. */
31struct 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
40hashval_t
41insn_hasher::hash (rtx x)
42{
43 return htab_hash_string (XSTR (x, 0));
44}
45
46bool
47insn_hasher::equal (rtx x, const char *y)
48{
49 return strcmp (XSTR (x, 0), s2: y) == 0;
50}
51
52/* All define_insns and define_expands, hashed by name. */
53static hash_table <insn_hasher> *insns;
54
55/* Records the prototype suffix X for each invalid_X stub that has been
56 generated. */
57static 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. */
61static hash_map <nofree_string_hash, const char *> *have_funcs;
62
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
69static bool
70parse_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 (nptr: p, endptr: &endptr, base: 10);
93 if (opno_out)
94 *opno_out = opno;
95 *end_out = endptr;
96 return true;
97}
98
99
100/* Output hook definitions for pattern NAME, which has target-insns.def
101 prototype PROTOTYPE. */
102
103static void
104def_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;
118 unsigned int required_ops = 0;
119 unsigned int this_opno;
120 bool required_p;
121 for (const char *p = prototype; *p; ++p)
122 if (parse_argument (p, end_out: &p, opno_out: &this_opno, required_out: &required_p))
123 {
124 if (this_opno != opno || (*p != ',' && *p != ')'))
125 {
126 error ("invalid prototype for '%s'", name);
127 exit (FATAL_EXIT_CODE);
128 }
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 }
135 opno += 1;
136 if (required_p)
137 required_ops = opno;
138 /* Skip over ')'s. */
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 (s1: prototype, s2: "(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 (comparable: name, hash))
162 {
163 pattern_stats stats;
164 get_pattern_stats (ranges: &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
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 (k: test, existed: &existed);
187 if (!existed)
188 {
189 entry = name;
190 printf (format: "\nstatic bool\n");
191 printf (format: "target_have_%s (void)\n", name);
192 printf (format: "{\n");
193 printf (format: " return ");
194 rtx_reader_ptr->print_c_condition (cond: test);
195 printf (format: ";\n");
196 printf (format: "}\n");
197 }
198 have_name = entry;
199 }
200 printf (format: "\nstatic rtx_insn *\n");
201 printf (format: "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_out: &end, opno_out: &this_opno) && this_opno >= actual_ops)
207 p = end;
208 else
209 fputc (*p++, stdout);
210
211 printf (format: "\n{\n");
212 if (truth < 0)
213 printf (format: " gcc_checking_assert (targetm.have_%s ());\n", name);
214 printf (format: " return insnify (gen_%s (", name);
215 for (i = 0; i < actual_ops; ++i)
216 printf (format: "%s%s%d", i == 0 ? "" : ", ",
217 i < required_ops ? "x" : "opt", i);
218 printf (format: "));\n");
219 printf (format: "}\n");
220 }
221 else
222 {
223 const char **slot = stubs->find_slot (value: suffix, insert: INSERT);
224 if (!*slot)
225 {
226 *slot = xstrdup (suffix);
227 printf (format: "\nstatic rtx_insn *\n");
228 printf (format: "invalid_%s ", suffix);
229 /* Print the prototype with the argument names removed. */
230 const char *p = prototype;
231 while (*p)
232 if (!parse_argument (p, end_out: &p))
233 fputc (*p++, stdout);
234 printf (format: "\n{\n");
235 printf (format: " gcc_unreachable ();\n");
236 printf (format: "}\n");
237 }
238 }
239 printf (format: "\n#undef TARGET_HAVE_%s\n", upper_name);
240 printf (format: "#define TARGET_HAVE_%s ", upper_name);
241 if (truth == 0)
242 printf (format: "hook_bool_void_false\n");
243 else if (truth == 1)
244 printf (format: "hook_bool_void_true\n");
245 else
246 printf (format: "target_have_%s\n", have_name);
247
248 printf (format: "#undef TARGET_GEN_%s\n", upper_name);
249 printf (format: "#define TARGET_GEN_%s ", upper_name);
250 if (truth == 0)
251 printf (format: "invalid_%s\n", suffix);
252 else
253 printf (format: "target_gen_%s\n", name);
254
255 printf (format: "#undef TARGET_CODE_FOR_%s\n", upper_name);
256 printf (format: "#define TARGET_CODE_FOR_%s ", upper_name);
257 if (truth == 0)
258 printf (format: "CODE_FOR_nothing\n");
259 else
260 printf (format: "CODE_FOR_%s\n", name);
261}
262
263/* Record the DEFINE_INSN or DEFINE_EXPAND described by INFO. */
264
265static void
266add_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 (comparable: name, hash, insert: INSERT);
275 if (*slot)
276 error_at (info->loc, "duplicate definition of '%s'", name);
277 else
278 *slot = def;
279}
280
281int
282main (int argc, const char **argv)
283{
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
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: &info);
300 break;
301
302 default:
303 break;
304 }
305
306 printf (format: "/* Generated automatically by the program `gentarget-def'. */\n");
307 printf (format: "#ifndef GCC_INSN_TARGET_DEF_H\n");
308 printf (format: "#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 (format: "\nstatic inline rtx_insn *\n");
314 printf (format: "insnify (rtx x)\n");
315 printf (format: "{\n");
316 printf (format: " if (!x)\n");
317 printf (format: " return NULL;\n");
318 printf (format: " if (rtx_insn *insn = dyn_cast <rtx_insn *> (x))\n");
319 printf (format: " return insn;\n");
320 printf (format: " start_sequence ();\n");
321 printf (format: " emit (x, false);\n");
322 printf (format: " rtx_insn *res = get_insns ();\n");
323 printf (format: " end_sequence ();\n");
324 printf (format: " return res;\n");
325 printf (format: "}\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 (format: "\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}
339

source code of gcc/gentarget-def.cc