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