1 | /* Generate code from to output assembler insns as recognized from rtl. |
2 | Copyright (C) 1987-2023 Free Software Foundation, Inc. |
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 | |
21 | /* This program reads the machine description for the compiler target machine |
22 | and produces a file containing these things: |
23 | |
24 | 1. An array of `struct insn_data_d', which is indexed by insn code number, |
25 | which contains: |
26 | |
27 | a. `name' is the name for that pattern. Nameless patterns are |
28 | given a name. |
29 | |
30 | b. `output' hold either the output template, an array of output |
31 | templates, or an output function. |
32 | |
33 | c. `genfun' is the function to generate a body for that pattern, |
34 | given operands as arguments. |
35 | |
36 | d. `n_operands' is the number of distinct operands in the pattern |
37 | for that insn, |
38 | |
39 | e. `n_dups' is the number of match_dup's that appear in the insn's |
40 | pattern. This says how many elements of `recog_data.dup_loc' are |
41 | significant after an insn has been recognized. |
42 | |
43 | f. `n_alternatives' is the number of alternatives in the constraints |
44 | of each pattern. |
45 | |
46 | g. `output_format' tells what type of thing `output' is. |
47 | |
48 | h. `operand' is the base of an array of operand data for the insn. |
49 | |
50 | 2. An array of `struct insn_operand data', used by `operand' above. |
51 | |
52 | a. `predicate', an int-valued function, is the match_operand predicate |
53 | for this operand. |
54 | |
55 | b. `constraint' is the constraint for this operand. |
56 | |
57 | c. `address_p' indicates that the operand appears within ADDRESS |
58 | rtx's. |
59 | |
60 | d. `mode' is the machine mode that that operand is supposed to have. |
61 | |
62 | e. `strict_low', is nonzero for operands contained in a STRICT_LOW_PART. |
63 | |
64 | f. `eliminable', is nonzero for operands that are matched normally by |
65 | MATCH_OPERAND; it is zero for operands that should not be changed during |
66 | register elimination such as MATCH_OPERATORs. |
67 | |
68 | g. `allows_mem', is true for operands that accept MEM rtxes. |
69 | |
70 | The code number of an insn is simply its position in the machine |
71 | description; code numbers are assigned sequentially to entries in |
72 | the description, starting with code number 0. |
73 | |
74 | Thus, the following entry in the machine description |
75 | |
76 | (define_insn "clrdf" |
77 | [(set (match_operand:DF 0 "general_operand" "") |
78 | (const_int 0))] |
79 | "" |
80 | "clrd %0") |
81 | |
82 | assuming it is the 25th entry present, would cause |
83 | insn_data[24].template to be "clrd %0", and |
84 | insn_data[24].n_operands to be 1. */ |
85 | |
86 | #include "bconfig.h" |
87 | #include "system.h" |
88 | #include "coretypes.h" |
89 | #include "tm.h" |
90 | #include "rtl.h" |
91 | #include "errors.h" |
92 | #include "read-md.h" |
93 | #include "gensupport.h" |
94 | |
95 | /* No instruction can have more operands than this. Sorry for this |
96 | arbitrary limit, but what machine will have an instruction with |
97 | this many operands? */ |
98 | |
99 | #define MAX_MAX_OPERANDS 40 |
100 | |
101 | static char general_mem[] = { TARGET_MEM_CONSTRAINT, 0 }; |
102 | |
103 | static int n_occurrences (int, const char *); |
104 | static const char *strip_whitespace (const char *); |
105 | |
106 | /* This counts all operands used in the md file. The first is null. */ |
107 | |
108 | static int next_operand_number = 1; |
109 | |
110 | /* Record in this chain all information about the operands we will output. */ |
111 | |
112 | struct operand_data |
113 | { |
114 | struct operand_data *next; |
115 | int index; |
116 | const char *predicate; |
117 | const char *constraint; |
118 | machine_mode mode; |
119 | unsigned char n_alternatives; |
120 | char address_p; |
121 | char strict_low; |
122 | char eliminable; |
123 | char seen; |
124 | }; |
125 | |
126 | /* Begin with a null operand at index 0. */ |
127 | |
128 | static struct operand_data null_operand = |
129 | { |
130 | .next: 0, .index: 0, .predicate: "" , .constraint: "" , .mode: E_VOIDmode, .n_alternatives: 0, .address_p: 0, .strict_low: 0, .eliminable: 0, .seen: 0 |
131 | }; |
132 | |
133 | static struct operand_data *odata = &null_operand; |
134 | static struct operand_data **odata_end = &null_operand.next; |
135 | |
136 | /* Must match the constants in recog.h. */ |
137 | |
138 | #define INSN_OUTPUT_FORMAT_NONE 0 /* abort */ |
139 | #define INSN_OUTPUT_FORMAT_SINGLE 1 /* const char * */ |
140 | #define INSN_OUTPUT_FORMAT_MULTI 2 /* const char * const * */ |
141 | #define INSN_OUTPUT_FORMAT_FUNCTION 3 /* const char * (*)(...) */ |
142 | |
143 | /* Record in this chain all information that we will output, |
144 | associated with the code number of the insn. */ |
145 | |
146 | class data |
147 | { |
148 | public: |
149 | class data *next; |
150 | const char *name; |
151 | const char *template_code; |
152 | file_location loc; |
153 | int code_number; |
154 | int n_generator_args; /* Number of arguments passed to generator */ |
155 | int n_operands; /* Number of operands this insn recognizes */ |
156 | int n_dups; /* Number times match_dup appears in pattern */ |
157 | int n_alternatives; /* Number of alternatives in each constraint */ |
158 | int operand_number; /* Operand index in the big array. */ |
159 | int output_format; /* INSN_OUTPUT_FORMAT_*. */ |
160 | bool compact_syntax_p; |
161 | struct operand_data operand[MAX_MAX_OPERANDS]; |
162 | }; |
163 | |
164 | /* This variable points to the first link in the insn chain. */ |
165 | static class data *idata; |
166 | |
167 | /* This variable points to the end of the insn chain. This is where |
168 | everything relevant from the machien description is appended to. */ |
169 | static class data **idata_end; |
170 | |
171 | |
172 | static void output_prologue (void); |
173 | static void output_operand_data (void); |
174 | static void output_insn_data (void); |
175 | static void output_get_insn_name (void); |
176 | static void scan_operands (class data *, rtx, int, int); |
177 | static int compare_operands (struct operand_data *, |
178 | struct operand_data *); |
179 | static void place_operands (class data *); |
180 | static void process_template (class data *, const char *); |
181 | static void validate_insn_alternatives (class data *); |
182 | static void validate_insn_operands (class data *); |
183 | |
184 | class constraint_data |
185 | { |
186 | public: |
187 | class constraint_data *next_this_letter; |
188 | file_location loc; |
189 | unsigned int namelen; |
190 | char name[1]; |
191 | }; |
192 | |
193 | /* All machine-independent constraint characters (except digits) that |
194 | are handled outside the define*_constraint mechanism. */ |
195 | static const char indep_constraints[] = ",=+%*?!^$#&g" ; |
196 | |
197 | static class constraint_data * |
198 | constraints_by_letter_table[1 << CHAR_BIT]; |
199 | |
200 | static int mdep_constraint_len (const char *, file_location, int); |
201 | static void note_constraint (md_rtx_info *); |
202 | |
203 | static void |
204 | output_prologue (void) |
205 | { |
206 | printf (format: "/* Generated automatically by the program `genoutput'\n\ |
207 | from the machine description file `md'. */\n\n" ); |
208 | |
209 | printf (format: "#define IN_TARGET_CODE 1\n" ); |
210 | printf (format: "#include \"config.h\"\n" ); |
211 | printf (format: "#include \"system.h\"\n" ); |
212 | printf (format: "#include \"coretypes.h\"\n" ); |
213 | printf (format: "#include \"backend.h\"\n" ); |
214 | printf (format: "#include \"predict.h\"\n" ); |
215 | printf (format: "#include \"tree.h\"\n" ); |
216 | printf (format: "#include \"rtl.h\"\n" ); |
217 | printf (format: "#include \"flags.h\"\n" ); |
218 | printf (format: "#include \"alias.h\"\n" ); |
219 | printf (format: "#include \"varasm.h\"\n" ); |
220 | printf (format: "#include \"stor-layout.h\"\n" ); |
221 | printf (format: "#include \"calls.h\"\n" ); |
222 | printf (format: "#include \"insn-config.h\"\n" ); |
223 | printf (format: "#include \"expmed.h\"\n" ); |
224 | printf (format: "#include \"dojump.h\"\n" ); |
225 | printf (format: "#include \"explow.h\"\n" ); |
226 | printf (format: "#include \"memmodel.h\"\n" ); |
227 | printf (format: "#include \"emit-rtl.h\"\n" ); |
228 | printf (format: "#include \"stmt.h\"\n" ); |
229 | printf (format: "#include \"expr.h\"\n" ); |
230 | printf (format: "#include \"insn-codes.h\"\n" ); |
231 | printf (format: "#include \"tm_p.h\"\n" ); |
232 | printf (format: "#include \"regs.h\"\n" ); |
233 | printf (format: "#include \"conditions.h\"\n" ); |
234 | printf (format: "#include \"insn-attr.h\"\n\n" ); |
235 | printf (format: "#include \"recog.h\"\n\n" ); |
236 | printf (format: "#include \"diagnostic-core.h\"\n" ); |
237 | printf (format: "#include \"output.h\"\n" ); |
238 | printf (format: "#include \"target.h\"\n" ); |
239 | printf (format: "#include \"tm-constrs.h\"\n" ); |
240 | } |
241 | |
242 | static void |
243 | output_operand_data (void) |
244 | { |
245 | struct operand_data *d; |
246 | |
247 | printf (format: "\nstatic const struct insn_operand_data operand_data[] = \n{\n" ); |
248 | |
249 | for (d = odata; d; d = d->next) |
250 | { |
251 | struct pred_data *pred; |
252 | |
253 | printf (format: " {\n" ); |
254 | |
255 | printf (format: " %s,\n" , |
256 | d->predicate && d->predicate[0] ? d->predicate : "0" ); |
257 | |
258 | printf (format: " \"%s\",\n" , d->constraint ? d->constraint : "" ); |
259 | |
260 | printf (format: " E_%smode,\n" , GET_MODE_NAME (d->mode)); |
261 | |
262 | printf (format: " %d,\n" , d->strict_low); |
263 | |
264 | printf (format: " %d,\n" , d->constraint == NULL ? 1 : 0); |
265 | |
266 | printf (format: " %d,\n" , d->eliminable); |
267 | |
268 | pred = NULL; |
269 | if (d->predicate) |
270 | pred = lookup_predicate (d->predicate); |
271 | printf (format: " %d\n" , pred && pred->codes[MEM]); |
272 | |
273 | printf (format: " },\n" ); |
274 | } |
275 | printf (format: "};\n\n\n" ); |
276 | } |
277 | |
278 | static void |
279 | output_insn_data (void) |
280 | { |
281 | class data *d; |
282 | int name_offset = 0; |
283 | int next_name_offset; |
284 | const char * last_name = 0; |
285 | const char * next_name = 0; |
286 | class data *n; |
287 | |
288 | for (n = idata, next_name_offset = 1; n; n = n->next, next_name_offset++) |
289 | if (n->name) |
290 | { |
291 | next_name = n->name; |
292 | break; |
293 | } |
294 | |
295 | printf (format: "#if GCC_VERSION >= 2007\n__extension__\n#endif\n" ); |
296 | printf (format: "\nconst struct insn_data_d insn_data[] = \n{\n" ); |
297 | |
298 | for (d = idata; d; d = d->next) |
299 | { |
300 | printf (format: " /* %s:%d */\n" , d->loc.filename, d->loc.lineno); |
301 | printf (format: " {\n" ); |
302 | |
303 | if (d->name) |
304 | { |
305 | printf (format: " \"%s\",\n" , d->name); |
306 | name_offset = 0; |
307 | last_name = d->name; |
308 | next_name = 0; |
309 | for (n = d->next, next_name_offset = 1; n; |
310 | n = n->next, next_name_offset++) |
311 | { |
312 | if (n->name) |
313 | { |
314 | next_name = n->name; |
315 | break; |
316 | } |
317 | } |
318 | } |
319 | else |
320 | { |
321 | name_offset++; |
322 | if (next_name && (last_name == 0 |
323 | || name_offset > next_name_offset / 2)) |
324 | printf (format: " \"%s-%d\",\n" , next_name, |
325 | next_name_offset - name_offset); |
326 | else |
327 | printf (format: " \"%s+%d\",\n" , last_name, name_offset); |
328 | } |
329 | |
330 | switch (d->output_format) |
331 | { |
332 | case INSN_OUTPUT_FORMAT_NONE: |
333 | printf (format: "#if HAVE_DESIGNATED_UNION_INITIALIZERS\n" ); |
334 | printf (format: " { 0 },\n" ); |
335 | printf (format: "#else\n" ); |
336 | printf (format: " { 0, 0, 0 },\n" ); |
337 | printf (format: "#endif\n" ); |
338 | break; |
339 | case INSN_OUTPUT_FORMAT_SINGLE: |
340 | { |
341 | const char *p = d->template_code; |
342 | char prev = 0; |
343 | |
344 | printf (format: "#if HAVE_DESIGNATED_UNION_INITIALIZERS\n" ); |
345 | printf (format: " { .single =\n" ); |
346 | printf (format: "#else\n" ); |
347 | printf (format: " {\n" ); |
348 | printf (format: "#endif\n" ); |
349 | printf (format: " \"" ); |
350 | while (*p) |
351 | { |
352 | if (IS_VSPACE (*p) && prev != '\\') |
353 | { |
354 | /* Preserve two consecutive \n's or \r's, but treat \r\n |
355 | as a single newline. */ |
356 | if (*p == '\n' && prev != '\r') |
357 | printf (format: "\\n\\\n" ); |
358 | } |
359 | else |
360 | putchar (*p); |
361 | prev = *p; |
362 | ++p; |
363 | } |
364 | printf (format: "\",\n" ); |
365 | printf (format: "#if HAVE_DESIGNATED_UNION_INITIALIZERS\n" ); |
366 | printf (format: " },\n" ); |
367 | printf (format: "#else\n" ); |
368 | printf (format: " 0, 0 },\n" ); |
369 | printf (format: "#endif\n" ); |
370 | } |
371 | break; |
372 | case INSN_OUTPUT_FORMAT_MULTI: |
373 | printf (format: "#if HAVE_DESIGNATED_UNION_INITIALIZERS\n" ); |
374 | printf (format: " { .multi = output_%d },\n" , d->code_number); |
375 | printf (format: "#else\n" ); |
376 | printf (format: " { 0, output_%d, 0 },\n" , d->code_number); |
377 | printf (format: "#endif\n" ); |
378 | break; |
379 | case INSN_OUTPUT_FORMAT_FUNCTION: |
380 | printf (format: "#if HAVE_DESIGNATED_UNION_INITIALIZERS\n" ); |
381 | printf (format: " { .function = output_%d },\n" , d->code_number); |
382 | printf (format: "#else\n" ); |
383 | printf (format: " { 0, 0, output_%d },\n" , d->code_number); |
384 | printf (format: "#endif\n" ); |
385 | break; |
386 | default: |
387 | gcc_unreachable (); |
388 | } |
389 | |
390 | if (d->name && d->name[0] != '*') |
391 | printf (format: " { (insn_gen_fn::stored_funcptr) gen_%s },\n" , d->name); |
392 | else |
393 | printf (format: " { 0 },\n" ); |
394 | |
395 | printf (format: " &operand_data[%d],\n" , d->operand_number); |
396 | printf (format: " %d,\n" , d->n_generator_args); |
397 | printf (format: " %d,\n" , d->n_operands); |
398 | printf (format: " %d,\n" , d->n_dups); |
399 | printf (format: " %d,\n" , d->n_alternatives); |
400 | printf (format: " %d\n" , d->output_format); |
401 | |
402 | printf (format: " },\n" ); |
403 | } |
404 | printf (format: "};\n\n\n" ); |
405 | } |
406 | |
407 | static void |
408 | output_get_insn_name (void) |
409 | { |
410 | printf (format: "const char *\n" ); |
411 | printf (format: "get_insn_name (int code)\n" ); |
412 | printf (format: "{\n" ); |
413 | printf (format: " if (code == NOOP_MOVE_INSN_CODE)\n" ); |
414 | printf (format: " return \"NOOP_MOVE\";\n" ); |
415 | printf (format: " else\n" ); |
416 | printf (format: " return insn_data[code].name;\n" ); |
417 | printf (format: "}\n" ); |
418 | } |
419 | |
420 | |
421 | /* Stores the operand data into `d->operand[i]'. |
422 | |
423 | THIS_ADDRESS_P is nonzero if the containing rtx was an ADDRESS. |
424 | THIS_STRICT_LOW is nonzero if the containing rtx was a STRICT_LOW_PART. */ |
425 | |
426 | static void |
427 | scan_operands (class data *d, rtx part, int this_address_p, |
428 | int this_strict_low) |
429 | { |
430 | int i, j; |
431 | const char *format_ptr; |
432 | int opno; |
433 | |
434 | if (part == 0) |
435 | return; |
436 | |
437 | switch (GET_CODE (part)) |
438 | { |
439 | case MATCH_OPERAND: |
440 | opno = XINT (part, 0); |
441 | if (opno >= MAX_MAX_OPERANDS) |
442 | { |
443 | error_at (d->loc, "maximum number of operands exceeded" ); |
444 | return; |
445 | } |
446 | if (d->operand[opno].seen) |
447 | error_at (d->loc, "repeated operand number %d\n" , opno); |
448 | |
449 | d->operand[opno].seen = 1; |
450 | d->operand[opno].mode = GET_MODE (part); |
451 | d->operand[opno].strict_low = this_strict_low; |
452 | d->operand[opno].predicate = XSTR (part, 1); |
453 | d->operand[opno].constraint = strip_whitespace (XSTR (part, 2)); |
454 | d->operand[opno].n_alternatives |
455 | = n_occurrences (',', d->operand[opno].constraint) + 1; |
456 | d->operand[opno].address_p = this_address_p; |
457 | d->operand[opno].eliminable = 1; |
458 | return; |
459 | |
460 | case MATCH_SCRATCH: |
461 | opno = XINT (part, 0); |
462 | if (opno >= MAX_MAX_OPERANDS) |
463 | { |
464 | error_at (d->loc, "maximum number of operands exceeded" ); |
465 | return; |
466 | } |
467 | if (d->operand[opno].seen) |
468 | error_at (d->loc, "repeated operand number %d\n" , opno); |
469 | |
470 | d->operand[opno].seen = 1; |
471 | d->operand[opno].mode = GET_MODE (part); |
472 | d->operand[opno].strict_low = 0; |
473 | d->operand[opno].predicate = "scratch_operand" ; |
474 | d->operand[opno].constraint = strip_whitespace (XSTR (part, 1)); |
475 | d->operand[opno].n_alternatives |
476 | = n_occurrences (',', d->operand[opno].constraint) + 1; |
477 | d->operand[opno].address_p = 0; |
478 | d->operand[opno].eliminable = 0; |
479 | return; |
480 | |
481 | case MATCH_OPERATOR: |
482 | case MATCH_PARALLEL: |
483 | opno = XINT (part, 0); |
484 | if (opno >= MAX_MAX_OPERANDS) |
485 | { |
486 | error_at (d->loc, "maximum number of operands exceeded" ); |
487 | return; |
488 | } |
489 | if (d->operand[opno].seen) |
490 | error_at (d->loc, "repeated operand number %d\n" , opno); |
491 | |
492 | d->operand[opno].seen = 1; |
493 | d->operand[opno].mode = GET_MODE (part); |
494 | d->operand[opno].strict_low = 0; |
495 | d->operand[opno].predicate = XSTR (part, 1); |
496 | d->operand[opno].constraint = 0; |
497 | d->operand[opno].address_p = 0; |
498 | d->operand[opno].eliminable = 0; |
499 | for (i = 0; i < XVECLEN (part, 2); i++) |
500 | scan_operands (d, XVECEXP (part, 2, i), this_address_p: 0, this_strict_low: 0); |
501 | return; |
502 | |
503 | case STRICT_LOW_PART: |
504 | scan_operands (d, XEXP (part, 0), this_address_p: 0, this_strict_low: 1); |
505 | return; |
506 | |
507 | default: |
508 | break; |
509 | } |
510 | |
511 | format_ptr = GET_RTX_FORMAT (GET_CODE (part)); |
512 | |
513 | for (i = 0; i < GET_RTX_LENGTH (GET_CODE (part)); i++) |
514 | switch (*format_ptr++) |
515 | { |
516 | case 'e': |
517 | case 'u': |
518 | scan_operands (d, XEXP (part, i), this_address_p: 0, this_strict_low: 0); |
519 | break; |
520 | case 'E': |
521 | if (XVEC (part, i) != NULL) |
522 | for (j = 0; j < XVECLEN (part, i); j++) |
523 | scan_operands (d, XVECEXP (part, i, j), this_address_p: 0, this_strict_low: 0); |
524 | break; |
525 | } |
526 | } |
527 | |
528 | /* Compare two operands for content equality. */ |
529 | |
530 | static int |
531 | compare_operands (struct operand_data *d0, struct operand_data *d1) |
532 | { |
533 | const char *p0, *p1; |
534 | |
535 | p0 = d0->predicate; |
536 | if (!p0) |
537 | p0 = "" ; |
538 | p1 = d1->predicate; |
539 | if (!p1) |
540 | p1 = "" ; |
541 | if (strcmp (s1: p0, s2: p1) != 0) |
542 | return 0; |
543 | |
544 | p0 = d0->constraint; |
545 | if (!p0) |
546 | p0 = "" ; |
547 | p1 = d1->constraint; |
548 | if (!p1) |
549 | p1 = "" ; |
550 | if (strcmp (s1: p0, s2: p1) != 0) |
551 | return 0; |
552 | |
553 | if (d0->mode != d1->mode) |
554 | return 0; |
555 | |
556 | if (d0->strict_low != d1->strict_low) |
557 | return 0; |
558 | |
559 | if (d0->eliminable != d1->eliminable) |
560 | return 0; |
561 | |
562 | return 1; |
563 | } |
564 | |
565 | /* Scan the list of operands we've already committed to output and either |
566 | find a subsequence that is the same, or allocate a new one at the end. */ |
567 | |
568 | static void |
569 | place_operands (class data *d) |
570 | { |
571 | struct operand_data *od, *od2; |
572 | int i; |
573 | |
574 | if (d->n_operands == 0) |
575 | { |
576 | d->operand_number = 0; |
577 | return; |
578 | } |
579 | |
580 | /* Brute force substring search. */ |
581 | for (od = odata, i = 0; od; od = od->next, i = 0) |
582 | if (compare_operands (d0: od, d1: &d->operand[0])) |
583 | { |
584 | od2 = od->next; |
585 | i = 1; |
586 | while (1) |
587 | { |
588 | if (i == d->n_operands) |
589 | goto full_match; |
590 | if (od2 == NULL) |
591 | goto partial_match; |
592 | if (! compare_operands (d0: od2, d1: &d->operand[i])) |
593 | break; |
594 | ++i, od2 = od2->next; |
595 | } |
596 | } |
597 | |
598 | /* Either partial match at the end of the list, or no match. In either |
599 | case, we tack on what operands are remaining to the end of the list. */ |
600 | partial_match: |
601 | d->operand_number = next_operand_number - i; |
602 | for (; i < d->n_operands; ++i) |
603 | { |
604 | od2 = &d->operand[i]; |
605 | *odata_end = od2; |
606 | odata_end = &od2->next; |
607 | od2->index = next_operand_number++; |
608 | } |
609 | *odata_end = NULL; |
610 | return; |
611 | |
612 | full_match: |
613 | d->operand_number = od->index; |
614 | return; |
615 | } |
616 | |
617 | |
618 | /* Process an assembler template from a define_insn or a define_peephole. |
619 | It is either the assembler code template, a list of assembler code |
620 | templates, or C code to generate the assembler code template. */ |
621 | |
622 | static void |
623 | process_template (class data *d, const char *template_code) |
624 | { |
625 | const char *cp; |
626 | int i; |
627 | |
628 | /* Templates starting with * contain straight code to be run. */ |
629 | if (template_code[0] == '*') |
630 | { |
631 | d->template_code = 0; |
632 | d->output_format = INSN_OUTPUT_FORMAT_FUNCTION; |
633 | |
634 | puts (s: "\nstatic const char *" ); |
635 | printf (format: "output_%d (rtx *operands ATTRIBUTE_UNUSED, rtx_insn *insn ATTRIBUTE_UNUSED)\n" , |
636 | d->code_number); |
637 | puts (s: "{" ); |
638 | rtx_reader_ptr->print_md_ptr_loc (ptr: template_code); |
639 | puts (s: template_code + 1); |
640 | puts (s: "}" ); |
641 | } |
642 | |
643 | /* If the assembler code template starts with a @ it is a newline-separated |
644 | list of assembler code templates, one for each alternative. */ |
645 | else if (template_code[0] == '@') |
646 | { |
647 | int found_star = 0; |
648 | |
649 | for (cp = &template_code[1]; *cp; ) |
650 | { |
651 | while (ISSPACE (*cp)) |
652 | cp++; |
653 | if (*cp == '*') |
654 | found_star = 1; |
655 | while (!IS_VSPACE (*cp) && *cp != '\0') |
656 | ++cp; |
657 | } |
658 | d->template_code = 0; |
659 | if (found_star) |
660 | { |
661 | d->output_format = INSN_OUTPUT_FORMAT_FUNCTION; |
662 | puts (s: "\nstatic const char *" ); |
663 | printf (format: "output_%d (rtx *operands ATTRIBUTE_UNUSED, " |
664 | "rtx_insn *insn ATTRIBUTE_UNUSED)\n" , d->code_number); |
665 | puts (s: "{" ); |
666 | puts (s: " switch (which_alternative)\n {" ); |
667 | } |
668 | else |
669 | { |
670 | d->output_format = INSN_OUTPUT_FORMAT_MULTI; |
671 | printf (format: "\nstatic const char * const output_%d[] = {\n" , |
672 | d->code_number); |
673 | } |
674 | |
675 | for (i = 0, cp = &template_code[1]; *cp; ) |
676 | { |
677 | const char *ep, *sp, *bp; |
678 | |
679 | while (ISSPACE (*cp)) |
680 | cp++; |
681 | |
682 | bp = cp; |
683 | if (found_star) |
684 | { |
685 | printf (format: " case %d:" , i); |
686 | if (*cp == '*') |
687 | { |
688 | printf (format: "\n " ); |
689 | cp++; |
690 | } |
691 | else |
692 | printf (format: " return \"" ); |
693 | } |
694 | else |
695 | printf (format: " \"" ); |
696 | |
697 | for (ep = sp = cp; !IS_VSPACE (*ep) && *ep != '\0'; ++ep) |
698 | if (!ISSPACE (*ep)) |
699 | sp = ep + 1; |
700 | |
701 | if (sp != ep) |
702 | message_at (d->loc, "trailing whitespace in output template" ); |
703 | |
704 | /* Check for any unexpanded iterators. */ |
705 | if (bp[0] != '*' && d->compact_syntax_p) |
706 | { |
707 | const char *p = cp; |
708 | const char *last_bracket = nullptr; |
709 | while (p < sp) |
710 | { |
711 | if (*p == '\\' && p + 1 < sp) |
712 | { |
713 | putchar (*p); |
714 | putchar (*(p+1)); |
715 | p += 2; |
716 | continue; |
717 | } |
718 | |
719 | if (*p == '>' && last_bracket && *last_bracket == '<') |
720 | { |
721 | int len = p - last_bracket; |
722 | fatal_at (d->loc, "unresolved iterator '%.*s' in '%s'" , |
723 | len - 1, last_bracket + 1, cp); |
724 | } |
725 | else if (*p == '<' || *p == '>') |
726 | last_bracket = p; |
727 | |
728 | putchar (*p); |
729 | p += 1; |
730 | } |
731 | |
732 | if (last_bracket) |
733 | { |
734 | char *nl = strchr (s: const_cast<char*> (cp), c: '\n'); |
735 | if (nl) |
736 | *nl = '\0'; |
737 | fatal_at (d->loc, "unmatched angle brackets, likely an " |
738 | "error in iterator syntax in %s" , cp); |
739 | } |
740 | } |
741 | else |
742 | { |
743 | while (cp < sp) |
744 | putchar (*(cp++)); |
745 | } |
746 | |
747 | cp = sp; |
748 | |
749 | if (!found_star) |
750 | puts (s: "\"," ); |
751 | else if (*bp != '*') |
752 | puts (s: "\";" ); |
753 | else |
754 | { |
755 | /* The usual action will end with a return. |
756 | If there is neither break or return at the end, this is |
757 | assumed to be intentional; this allows to have multiple |
758 | consecutive alternatives share some code. */ |
759 | puts (s: "" ); |
760 | } |
761 | i++; |
762 | } |
763 | if (i == 1) |
764 | message_at (d->loc, "'@' is redundant for output template with" |
765 | " single alternative" ); |
766 | if (i != d->n_alternatives) |
767 | error_at (d->loc, "wrong number of alternatives in the output" |
768 | " template" ); |
769 | |
770 | if (found_star) |
771 | puts (s: " default: gcc_unreachable ();\n }\n}" ); |
772 | else |
773 | printf (format: "};\n" ); |
774 | } |
775 | else |
776 | { |
777 | d->template_code = template_code; |
778 | d->output_format = INSN_OUTPUT_FORMAT_SINGLE; |
779 | } |
780 | } |
781 | |
782 | /* Check insn D for consistency in number of constraint alternatives. */ |
783 | |
784 | static void |
785 | validate_insn_alternatives (class data *d) |
786 | { |
787 | int n = 0, start; |
788 | |
789 | /* Make sure all the operands have the same number of alternatives |
790 | in their constraints. Let N be that number. */ |
791 | for (start = 0; start < d->n_operands; start++) |
792 | if (d->operand[start].n_alternatives > 0) |
793 | { |
794 | int len, i; |
795 | const char *p; |
796 | char c; |
797 | int which_alternative = 0; |
798 | int alternative_count_unsure = 0; |
799 | bool seen_write = false; |
800 | bool alt_mismatch = false; |
801 | |
802 | for (p = d->operand[start].constraint; (c = *p); p += len) |
803 | { |
804 | if ((c == '%' || c == '=' || c == '+') |
805 | && p != d->operand[start].constraint) |
806 | error_at (d->loc, "character '%c' can only be used at the" |
807 | " beginning of a constraint string" , c); |
808 | |
809 | if (c == '=' || c == '+') |
810 | seen_write = true; |
811 | |
812 | /* Earlyclobber operands must always be marked write-only |
813 | or read/write. */ |
814 | if (!seen_write && c == '&') |
815 | error_at (d->loc, "earlyclobber operands may not be" |
816 | " read-only in alternative %d" , which_alternative); |
817 | |
818 | if (ISSPACE (c) || strchr (s: indep_constraints, c: c)) |
819 | len = 1; |
820 | else if (ISDIGIT (c)) |
821 | { |
822 | const char *q = p; |
823 | do |
824 | q++; |
825 | while (ISDIGIT (*q)); |
826 | len = q - p; |
827 | } |
828 | else |
829 | len = mdep_constraint_len (p, d->loc, start); |
830 | |
831 | if (c == ',') |
832 | { |
833 | which_alternative++; |
834 | continue; |
835 | } |
836 | |
837 | for (i = 1; i < len; i++) |
838 | if (p[i] == '\0') |
839 | { |
840 | error_at (d->loc, "NUL in alternative %d of operand %d" , |
841 | which_alternative, start); |
842 | alternative_count_unsure = 1; |
843 | break; |
844 | } |
845 | else if (strchr (s: ",#*" , c: p[i])) |
846 | { |
847 | error_at (d->loc, "'%c' in alternative %d of operand %d" , |
848 | p[i], which_alternative, start); |
849 | alternative_count_unsure = 1; |
850 | } |
851 | } |
852 | if (!alternative_count_unsure) |
853 | { |
854 | if (n == 0) |
855 | n = d->operand[start].n_alternatives; |
856 | else if (n != d->operand[start].n_alternatives) |
857 | { |
858 | if (!alt_mismatch) |
859 | { |
860 | alt_mismatch = true; |
861 | error_at (d->loc, |
862 | "alternative number mismatch: " |
863 | "operand %d has %d, operand %d has %d" , |
864 | 0, n, start, d->operand[start].n_alternatives); |
865 | } |
866 | else |
867 | error_at (d->loc, "operand %d has %d alternatives" , |
868 | start, d->operand[start].n_alternatives); |
869 | } |
870 | } |
871 | } |
872 | |
873 | /* Record the insn's overall number of alternatives. */ |
874 | d->n_alternatives = n; |
875 | } |
876 | |
877 | /* Verify that there are no gaps in operand numbers for INSNs. */ |
878 | |
879 | static void |
880 | validate_insn_operands (class data *d) |
881 | { |
882 | int i; |
883 | |
884 | for (i = 0; i < d->n_operands; ++i) |
885 | if (d->operand[i].seen == 0) |
886 | error_at (d->loc, "missing operand %d" , i); |
887 | } |
888 | |
889 | static void |
890 | validate_optab_operands (class data *d) |
891 | { |
892 | if (!d->name || d->name[0] == '\0' || d->name[0] == '*') |
893 | return; |
894 | |
895 | /* Miscellaneous tests. */ |
896 | if (startswith (str: d->name, prefix: "cstore" ) |
897 | && d->name[strlen (s: d->name) - 1] == '4' |
898 | && d->operand[0].mode == VOIDmode) |
899 | { |
900 | message_at (d->loc, "missing mode for operand 0 of cstore" ); |
901 | have_error = 1; |
902 | } |
903 | } |
904 | |
905 | /* Look at a define_insn just read. Assign its code number. Record |
906 | on idata the template and the number of arguments. If the insn has |
907 | a hairy output action, output a function for now. */ |
908 | |
909 | static void |
910 | gen_insn (md_rtx_info *info) |
911 | { |
912 | struct pattern_stats stats; |
913 | rtx insn = info->def; |
914 | data *d = new data; |
915 | int i; |
916 | |
917 | d->code_number = info->index; |
918 | d->loc = info->loc; |
919 | if (XSTR (insn, 0)[0]) |
920 | d->name = XSTR (insn, 0); |
921 | else |
922 | d->name = 0; |
923 | |
924 | d->compact_syntax_p = compact_syntax.contains (k: insn); |
925 | |
926 | /* Build up the list in the same order as the insns are seen |
927 | in the machine description. */ |
928 | d->next = 0; |
929 | *idata_end = d; |
930 | idata_end = &d->next; |
931 | |
932 | memset (s: d->operand, c: 0, n: sizeof (d->operand)); |
933 | |
934 | for (i = 0; i < XVECLEN (insn, 1); i++) |
935 | scan_operands (d, XVECEXP (insn, 1, i), this_address_p: 0, this_strict_low: 0); |
936 | |
937 | get_pattern_stats (ranges: &stats, XVEC (insn, 1)); |
938 | d->n_generator_args = stats.num_generator_args; |
939 | d->n_operands = stats.num_insn_operands; |
940 | d->n_dups = stats.num_dups; |
941 | |
942 | validate_insn_operands (d); |
943 | validate_insn_alternatives (d); |
944 | validate_optab_operands (d); |
945 | place_operands (d); |
946 | process_template (d, XTMPL (insn, 3)); |
947 | } |
948 | |
949 | /* Look at a define_peephole just read. Assign its code number. |
950 | Record on idata the template and the number of arguments. |
951 | If the insn has a hairy output action, output it now. */ |
952 | |
953 | static void |
954 | gen_peephole (md_rtx_info *info) |
955 | { |
956 | struct pattern_stats stats; |
957 | data *d = new data; |
958 | int i; |
959 | |
960 | d->code_number = info->index; |
961 | d->loc = info->loc; |
962 | d->name = 0; |
963 | |
964 | /* Build up the list in the same order as the insns are seen |
965 | in the machine description. */ |
966 | d->next = 0; |
967 | *idata_end = d; |
968 | idata_end = &d->next; |
969 | |
970 | memset (s: d->operand, c: 0, n: sizeof (d->operand)); |
971 | |
972 | /* Get the number of operands by scanning all the patterns of the |
973 | peephole optimizer. But ignore all the rest of the information |
974 | thus obtained. */ |
975 | rtx peep = info->def; |
976 | for (i = 0; i < XVECLEN (peep, 0); i++) |
977 | scan_operands (d, XVECEXP (peep, 0, i), this_address_p: 0, this_strict_low: 0); |
978 | |
979 | get_pattern_stats (ranges: &stats, XVEC (peep, 0)); |
980 | d->n_generator_args = 0; |
981 | d->n_operands = stats.num_insn_operands; |
982 | d->n_dups = 0; |
983 | |
984 | validate_insn_alternatives (d); |
985 | place_operands (d); |
986 | process_template (d, XTMPL (peep, 2)); |
987 | } |
988 | |
989 | /* Process a define_expand just read. Assign its code number, |
990 | only for the purposes of `insn_gen_function'. */ |
991 | |
992 | static void |
993 | gen_expand (md_rtx_info *info) |
994 | { |
995 | struct pattern_stats stats; |
996 | rtx insn = info->def; |
997 | data *d = new data; |
998 | int i; |
999 | |
1000 | d->code_number = info->index; |
1001 | d->loc = info->loc; |
1002 | if (XSTR (insn, 0)[0]) |
1003 | d->name = XSTR (insn, 0); |
1004 | else |
1005 | d->name = 0; |
1006 | |
1007 | /* Build up the list in the same order as the insns are seen |
1008 | in the machine description. */ |
1009 | d->next = 0; |
1010 | *idata_end = d; |
1011 | idata_end = &d->next; |
1012 | |
1013 | memset (s: d->operand, c: 0, n: sizeof (d->operand)); |
1014 | |
1015 | /* Scan the operands to get the specified predicates and modes, |
1016 | since expand_binop needs to know them. */ |
1017 | |
1018 | if (XVEC (insn, 1)) |
1019 | for (i = 0; i < XVECLEN (insn, 1); i++) |
1020 | scan_operands (d, XVECEXP (insn, 1, i), this_address_p: 0, this_strict_low: 0); |
1021 | |
1022 | get_pattern_stats (ranges: &stats, XVEC (insn, 1)); |
1023 | d->n_generator_args = stats.num_generator_args; |
1024 | d->n_operands = stats.num_insn_operands; |
1025 | d->n_dups = stats.num_dups; |
1026 | d->template_code = 0; |
1027 | d->output_format = INSN_OUTPUT_FORMAT_NONE; |
1028 | |
1029 | validate_insn_alternatives (d); |
1030 | validate_optab_operands (d); |
1031 | place_operands (d); |
1032 | } |
1033 | |
1034 | static void |
1035 | init_insn_for_nothing (void) |
1036 | { |
1037 | idata = XCNEW (class data); |
1038 | new (idata) data (); |
1039 | idata->name = "*placeholder_for_nothing" ; |
1040 | idata->loc = file_location ("<internal>" , 0, 0); |
1041 | idata_end = &idata->next; |
1042 | } |
1043 | |
1044 | extern int main (int, const char **); |
1045 | |
1046 | int |
1047 | main (int argc, const char **argv) |
1048 | { |
1049 | progname = "genoutput" ; |
1050 | |
1051 | init_insn_for_nothing (); |
1052 | |
1053 | if (!init_rtx_reader_args (argc, argv)) |
1054 | return (FATAL_EXIT_CODE); |
1055 | |
1056 | output_prologue (); |
1057 | |
1058 | /* Read the machine description. */ |
1059 | |
1060 | md_rtx_info info; |
1061 | while (read_md_rtx (&info)) |
1062 | switch (GET_CODE (info.def)) |
1063 | { |
1064 | case DEFINE_INSN: |
1065 | gen_insn (info: &info); |
1066 | break; |
1067 | |
1068 | case DEFINE_PEEPHOLE: |
1069 | gen_peephole (info: &info); |
1070 | break; |
1071 | |
1072 | case DEFINE_EXPAND: |
1073 | gen_expand (info: &info); |
1074 | break; |
1075 | |
1076 | case DEFINE_CONSTRAINT: |
1077 | case DEFINE_REGISTER_CONSTRAINT: |
1078 | case DEFINE_ADDRESS_CONSTRAINT: |
1079 | case DEFINE_MEMORY_CONSTRAINT: |
1080 | case DEFINE_SPECIAL_MEMORY_CONSTRAINT: |
1081 | case DEFINE_RELAXED_MEMORY_CONSTRAINT: |
1082 | note_constraint (&info); |
1083 | break; |
1084 | |
1085 | default: |
1086 | break; |
1087 | } |
1088 | |
1089 | printf (format: "\n\n" ); |
1090 | output_operand_data (); |
1091 | output_insn_data (); |
1092 | output_get_insn_name (); |
1093 | |
1094 | fflush (stdout); |
1095 | return (ferror (stdout) != 0 || have_error |
1096 | ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); |
1097 | } |
1098 | |
1099 | /* Return the number of occurrences of character C in string S or |
1100 | -1 if S is the null string. */ |
1101 | |
1102 | static int |
1103 | n_occurrences (int c, const char *s) |
1104 | { |
1105 | int n = 0; |
1106 | |
1107 | if (s == 0 || *s == '\0') |
1108 | return -1; |
1109 | |
1110 | while (*s) |
1111 | n += (*s++ == c); |
1112 | |
1113 | return n; |
1114 | } |
1115 | |
1116 | /* Remove whitespace in `s' by moving up characters until the end. |
1117 | Return a new string. */ |
1118 | |
1119 | static const char * |
1120 | strip_whitespace (const char *s) |
1121 | { |
1122 | char *p, *q; |
1123 | char ch; |
1124 | |
1125 | if (s == 0) |
1126 | return 0; |
1127 | |
1128 | p = q = XNEWVEC (char, strlen (s) + 1); |
1129 | while ((ch = *s++) != '\0') |
1130 | if (! ISSPACE (ch)) |
1131 | *p++ = ch; |
1132 | |
1133 | *p = '\0'; |
1134 | return q; |
1135 | } |
1136 | |
1137 | /* Record just enough information about the constraint in *INFO to allow |
1138 | checking of operand constraint strings above, in validate_insn_alternatives. |
1139 | Does not validate most properties of the constraint itself; does enforce |
1140 | no duplicate names, no overlap with MI constraints, and no prefixes. */ |
1141 | static void |
1142 | note_constraint (md_rtx_info *info) |
1143 | { |
1144 | rtx exp = info->def; |
1145 | const char *name = XSTR (exp, 0); |
1146 | class constraint_data **iter, **slot, *new_cdata; |
1147 | |
1148 | if (strcmp (s1: name, s2: "TARGET_MEM_CONSTRAINT" ) == 0) |
1149 | name = general_mem; |
1150 | unsigned int namelen = strlen (s: name); |
1151 | |
1152 | if (strchr (s: indep_constraints, c: name[0])) |
1153 | { |
1154 | if (name[1] == '\0') |
1155 | error_at (info->loc, "constraint letter '%s' cannot be " |
1156 | "redefined by the machine description" , name); |
1157 | else |
1158 | error_at (info->loc, "constraint name '%s' cannot be defined by " |
1159 | "the machine description, as it begins with '%c'" , |
1160 | name, name[0]); |
1161 | return; |
1162 | } |
1163 | |
1164 | slot = &constraints_by_letter_table[(unsigned int)name[0]]; |
1165 | for (iter = slot; *iter; iter = &(*iter)->next_this_letter) |
1166 | { |
1167 | /* This causes slot to end up pointing to the |
1168 | next_this_letter field of the last constraint with a name |
1169 | of equal or greater length than the new constraint; hence |
1170 | the new constraint will be inserted after all previous |
1171 | constraints with names of the same length. */ |
1172 | if ((*iter)->namelen >= namelen) |
1173 | slot = iter; |
1174 | |
1175 | if (!strcmp (s1: (*iter)->name, s2: name)) |
1176 | { |
1177 | error_at (info->loc, "redefinition of constraint '%s'" , name); |
1178 | message_at ((*iter)->loc, "previous definition is here" ); |
1179 | return; |
1180 | } |
1181 | else if (!strncmp (s1: (*iter)->name, s2: name, n: (*iter)->namelen)) |
1182 | { |
1183 | error_at (info->loc, "defining constraint '%s' here" , name); |
1184 | message_at ((*iter)->loc, "renders constraint '%s' " |
1185 | "(defined here) a prefix" , (*iter)->name); |
1186 | return; |
1187 | } |
1188 | else if (!strncmp (s1: (*iter)->name, s2: name, n: namelen)) |
1189 | { |
1190 | error_at (info->loc, "constraint '%s' is a prefix" , name); |
1191 | message_at ((*iter)->loc, "of constraint '%s' " |
1192 | "(defined here)" , (*iter)->name); |
1193 | return; |
1194 | } |
1195 | } |
1196 | new_cdata = XNEWVAR (class constraint_data, |
1197 | sizeof (class constraint_data) + namelen); |
1198 | new (new_cdata) constraint_data (); |
1199 | strcpy (CONST_CAST (char *, new_cdata->name), src: name); |
1200 | new_cdata->namelen = namelen; |
1201 | new_cdata->loc = info->loc; |
1202 | new_cdata->next_this_letter = *slot; |
1203 | *slot = new_cdata; |
1204 | } |
1205 | |
1206 | /* Return the length of the constraint name beginning at position S |
1207 | of an operand constraint string, or issue an error message if there |
1208 | is no such constraint. Does not expect to be called for generic |
1209 | constraints. */ |
1210 | static int |
1211 | mdep_constraint_len (const char *s, file_location loc, int opno) |
1212 | { |
1213 | class constraint_data *p; |
1214 | |
1215 | p = constraints_by_letter_table[(unsigned int)s[0]]; |
1216 | |
1217 | if (p) |
1218 | for (; p; p = p->next_this_letter) |
1219 | if (!strncmp (s1: s, s2: p->name, n: p->namelen)) |
1220 | return p->namelen; |
1221 | |
1222 | error_at (loc, "error: undefined machine-specific constraint " |
1223 | "at this point: \"%s\"" , s); |
1224 | message_at (loc, "note: in operand %d" , opno); |
1225 | return 1; /* safe */ |
1226 | } |
1227 | |