1/* Generate code from machine description to emit insns as rtl.
2 Copyright (C) 1987-2025 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
21#include "bconfig.h"
22#include "system.h"
23#include "coretypes.h"
24#include "tm.h"
25#include "rtl.h"
26#include "errors.h"
27#include "read-md.h"
28#include "gensupport.h"
29
30
31/* Data structure for recording the patterns of insns that have CLOBBERs.
32 We use this to output a function that adds these CLOBBERs to a
33 previously-allocated PARALLEL expression. */
34
35struct clobber_pat
36{
37 struct clobber_ent *insns;
38 rtvec pattern;
39 int first_clobber;
40 struct clobber_pat *next;
41 int has_hard_reg;
42} *clobber_list;
43
44/* Records one insn that uses the clobber list. */
45
46struct clobber_ent
47{
48 int code_number; /* Counts only insns. */
49 struct clobber_ent *next;
50};
51
52static void output_peephole2_scratches (rtx, FILE*);
53
54/* True for <X>_optab if that optab isn't allowed to fail. */
55static bool nofail_optabs[NUM_OPTABS];
56
57/* A list of the md constructs that need a gen_* function. */
58static vec<md_rtx_info> queue;
59
60unsigned FIRST_CODE = (unsigned) expand_opcode::FIRST_CODE;
61
62/* A structure used to generate code for a particular expansion. */
63struct generator
64{
65 generator (const md_rtx_info &info) : info (info) {}
66
67 void add_uint (uint64_t);
68 void add_opcode (expand_opcode opcode) { add_uint ((unsigned) opcode); }
69 void add_code (rtx_code code) { add_uint (FIRST_CODE + (unsigned) code); }
70 void add_match_operator (machine_mode, int, rtvec);
71 void add_exp (rtx);
72 void add_vec (rtvec);
73
74 const char *gen_table (FILE *, const char *);
75 const char *gen_exp (FILE *, rtx);
76 const char *gen_emit_seq (FILE *, rtvec);
77
78 /* The construct that we're expanding. */
79 const md_rtx_info info;
80
81 /* Used to build up the encoding of the expanded rtx sequence. */
82 auto_vec<uint8_t> bytes;
83};
84
85/* Add VALUE to the encoding using "BEB128" (big-endian version of LEB128).
86 This is slightly easier for the consumer. */
87
88void
89generator::add_uint (uint64_t value)
90{
91 int shift = 0;
92 while ((value >> shift >> 7) > 0)
93 shift += 7;
94 do
95 {
96 bytes.safe_push (obj: ((value >> shift) & 127) | (shift > 0 ? 128 : 0));
97 shift -= 7;
98 }
99 while (shift >= 0);
100}
101
102/* Add the rtx expansion of a MATCH_OPERATOR or MATCH_OP_DUP. OPNO is the
103 number of the matched operand. MODE is the mode that the rtx should have,
104 or NUM_MACHINE_MODES if the operand's original mode should be retained.
105 VEC is the vector of suboperands, which replace those of the original
106 operand. */
107
108void
109generator::add_match_operator (machine_mode mode, int opno, rtvec vec)
110{
111 if (mode != NUM_MACHINE_MODES)
112 {
113 add_opcode (opcode: expand_opcode::MATCH_OPERATOR_WITH_MODE);
114 add_uint (value: mode);
115 }
116 else
117 add_opcode (opcode: expand_opcode::MATCH_OPERATOR);
118 add_uint (value: opno);
119 for (int i = 0; i < GET_NUM_ELEM (vec); i++)
120 add_exp (RTVEC_ELT (vec, i));
121}
122
123/* Add the expansion of X to the encoding. */
124
125void
126generator::add_exp (rtx x)
127{
128 if (x == 0)
129 {
130 add_opcode (opcode: expand_opcode::NO_RTX);
131 return;
132 }
133
134 auto code = GET_CODE (x);
135 switch (code)
136 {
137 case MATCH_OPERAND:
138 case MATCH_DUP:
139 add_opcode (opcode: expand_opcode::MATCH_OPERAND);
140 add_uint (XINT (x, 0));
141 return;
142
143 case MATCH_OP_DUP:
144 if (GET_MODE (x) == VOIDmode)
145 add_match_operator (mode: NUM_MACHINE_MODES, XINT (x, 0), XVEC (x, 1));
146 else
147 add_match_operator (GET_MODE (x), XINT (x, 0), XVEC (x, 1));
148 return;
149
150 case MATCH_OPERATOR:
151 add_match_operator (GET_MODE (x), XINT (x, 0), XVEC (x, 2));
152 return;
153
154 case MATCH_PARALLEL:
155 case MATCH_PAR_DUP:
156 add_opcode (opcode: expand_opcode::MATCH_PARALLEL);
157 add_uint (XINT (x, 0));
158 return;
159
160 case MATCH_SCRATCH:
161 add_code (code: SCRATCH);
162 add_uint (GET_MODE (x));
163 return;
164
165 case CLOBBER:
166 if (REG_P (XEXP (x, 0)))
167 {
168 add_opcode (opcode: expand_opcode::CLOBBER_REG);
169 add_uint (GET_MODE (XEXP (x, 0)));
170 add_uint (REGNO (XEXP (x, 0)));
171 return;
172 }
173 break;
174
175 case CONST_INT:
176 add_code (code: CONST_INT);
177 add_uint (UINTVAL (x));
178 return;
179
180 case CONST_DOUBLE:
181 /* Handle `const_double_zero' rtx. */
182 if (CONST_DOUBLE_REAL_VALUE (x)->cl == rvc_zero)
183 {
184 add_code (code: CONST_DOUBLE);
185 add_uint (GET_MODE (x));
186 return;
187 }
188 /* Fall through. */
189 case CONST_FIXED:
190 case CONST_WIDE_INT:
191 /* These shouldn't be written in MD files. Instead, the appropriate
192 routines in varasm.cc should be called. */
193 gcc_unreachable ();
194
195 default:
196 break;
197 }
198
199 add_code (code);
200 if (!always_void_p (code))
201 add_uint (GET_MODE (x));
202
203 auto fmt = GET_RTX_FORMAT (code);
204 unsigned int len = GET_RTX_LENGTH (code);
205 for (unsigned int i = 0; i < len; i++)
206 {
207 if (fmt[i] == '0')
208 break;
209 switch (fmt[i])
210 {
211 case 'e': case 'u':
212 add_exp (XEXP (x, i));
213 break;
214
215 case 'i':
216 add_uint (XUINT (x, i));
217 break;
218
219 case 'L':
220 case 's':
221 fatal_at (info.loc, "'%s' rtxes are not supported in this context",
222 GET_RTX_NAME (code));
223 break;
224
225 case 'r':
226 add_uint (REGNO (x));
227 break;
228
229 case 'p':
230 /* We don't have a way of parsing polynomial offsets yet,
231 and hopefully never will. */
232 add_uint (SUBREG_BYTE (x).to_constant ());
233 break;
234
235 case 'E':
236 add_vec (XVEC (x, i));
237 break;
238
239 default:
240 gcc_unreachable ();
241 }
242 }
243}
244
245/* Add the expansion of rtx vector VEC to the encoding. */
246
247void
248generator::add_vec (rtvec vec)
249{
250 add_uint (GET_NUM_ELEM (vec));
251 for (int i = 0; i < GET_NUM_ELEM (vec); ++i)
252 add_exp (RTVEC_ELT (vec, i));
253}
254
255/* Emit the encoding as a static C++ array called NAME. Return NAME. */
256
257const char *
258generator::gen_table (FILE *file, const char *name)
259{
260 fprintf (stream: file, format: " static const uint8_t %s[] = {", name);
261 for (size_t i = 0; i < bytes.length (); ++i)
262 fprintf (stream: file, format: "%s%s 0x%02x",
263 i == 0 ? "" : ",",
264 i % 8 == 0 ? "\n " : "",
265 bytes[i]);
266 fprintf (stream: file, format: "\n };\n");
267 return name;
268}
269
270/* Output the code necessary for generating rtx X and return the name
271 of the C++ array that contains the encoding. */
272
273const char *
274generator::gen_exp (FILE *file, rtx x)
275{
276 add_exp (x);
277 return gen_table (file, name: "expand_encoding");
278}
279
280/* Output the code necessary for emitting each element of VEC as a separate
281 instruction. Return the name of the C++ array that contains the
282 encoding. */
283
284const char *
285generator::gen_emit_seq (FILE *file, rtvec vec)
286{
287 add_vec (vec);
288 return gen_table (file, name: "expand_encoding");
289}
290
291/* Emit the given C code to the output file. The code is allowed to
292 fail if CAN_FAIL_P. NAME describes what we're generating,
293 for use in error messages. */
294
295static void
296emit_c_code (const char *code, bool can_fail_p, const char *name, FILE *file)
297{
298 if (can_fail_p)
299 fprintf (stream: file, format: "#define FAIL return (end_sequence (), nullptr)\n");
300 else
301 fprintf (stream: file, format: "#define FAIL _Pragma (\"GCC error \\\"%s cannot FAIL\\\"\")"
302 " (void)0\n", name);
303 fprintf (stream: file, format: "#define DONE return end_sequence ()\n");
304
305 rtx_reader_ptr->print_md_ptr_loc (ptr: code, file);
306 fprintf (stream: file, format: "%s\n", code);
307
308 fprintf (stream: file, format: "#undef DONE\n");
309 fprintf (stream: file, format: "#undef FAIL\n");
310}
311
312/* Process the DEFINE_INSN in LOC, and queue it if it needs a gen_*
313 function. */
314
315static void
316maybe_queue_insn (const md_rtx_info &info)
317{
318 /* See if the pattern for this insn ends with a group of CLOBBERs of (hard)
319 registers or MATCH_SCRATCHes. If so, store away the information for
320 later. */
321
322 rtx insn = info.def;
323 if (XVEC (insn, 1))
324 {
325 int has_hard_reg = 0;
326 rtvec pattern = XVEC (insn, 1);
327
328 /* Look though an explicit parallel. */
329 if (GET_NUM_ELEM (pattern) == 1
330 && GET_CODE (RTVEC_ELT (pattern, 0)) == PARALLEL)
331 pattern = XVEC (RTVEC_ELT (pattern, 0), 0);
332
333 int i;
334 for (i = GET_NUM_ELEM (pattern) - 1; i > 0; i--)
335 {
336 if (GET_CODE (RTVEC_ELT (pattern, i)) != CLOBBER)
337 break;
338
339 if (REG_P (XEXP (RTVEC_ELT (pattern, i), 0)))
340 has_hard_reg = 1;
341 else if (GET_CODE (XEXP (RTVEC_ELT (pattern, i), 0)) != MATCH_SCRATCH)
342 break;
343 }
344
345 if (i != GET_NUM_ELEM (pattern) - 1)
346 {
347 struct clobber_pat *p;
348 struct clobber_ent *link = XNEW (struct clobber_ent);
349 int j;
350
351 link->code_number = info.index;
352
353 /* See if any previous CLOBBER_LIST entry is the same as this
354 one. */
355
356 for (p = clobber_list; p; p = p->next)
357 {
358 if (p->first_clobber != i + 1
359 || GET_NUM_ELEM (p->pattern) != GET_NUM_ELEM (pattern))
360 continue;
361
362 for (j = i + 1; j < GET_NUM_ELEM (pattern); j++)
363 {
364 rtx old_rtx = XEXP (RTVEC_ELT (p->pattern, j), 0);
365 rtx new_rtx = XEXP (RTVEC_ELT (pattern, j), 0);
366
367 /* OLD and NEW_INSN are the same if both are to be a SCRATCH
368 of the same mode,
369 or if both are registers of the same mode and number. */
370 if (! (GET_CODE (old_rtx) == GET_CODE (new_rtx)
371 && GET_MODE (old_rtx) == GET_MODE (new_rtx)
372 && ((GET_CODE (old_rtx) == MATCH_SCRATCH
373 && GET_CODE (new_rtx) == MATCH_SCRATCH)
374 || (REG_P (old_rtx) && REG_P (new_rtx)
375 && REGNO (old_rtx) == REGNO (new_rtx)))))
376 break;
377 }
378
379 if (j == GET_NUM_ELEM (pattern))
380 break;
381 }
382
383 if (p == 0)
384 {
385 p = XNEW (struct clobber_pat);
386
387 p->insns = 0;
388 p->pattern = pattern;
389 p->first_clobber = i + 1;
390 p->next = clobber_list;
391 p->has_hard_reg = has_hard_reg;
392 clobber_list = p;
393 }
394
395 link->next = p->insns;
396 p->insns = link;
397 }
398 }
399
400 /* Don't mention instructions whose names are the null string
401 or begin with '*'. They are in the machine description just
402 to be recognized. */
403 if (XSTR (insn, 0)[0] == 0 || XSTR (insn, 0)[0] == '*')
404 return;
405
406 queue.safe_push (obj: info);
407}
408
409/* Output the function name, argument declarations, and initial function
410 body for a pattern called NAME, given that it has the properties
411 in STATS. Return the C++ expression for the operands array. */
412
413static const char *
414start_gen_insn (FILE *file, const char *name, const pattern_stats &stats)
415{
416 fprintf (stream: file, format: "rtx\ngen_%s (", name);
417 if (stats.num_generator_args)
418 for (int i = 0; i < stats.num_generator_args; i++)
419 fprintf (stream: file, format: "%sconst rtx operand%d", i == 0 ? "" : ", ", i);
420 else
421 fprintf (stream: file, format: "void");
422 fprintf (stream: file, format: ")\n");
423 fprintf (stream: file, format: "{\n");
424 if (stats.num_generator_args)
425 {
426 fprintf (stream: file, format: " rtx operands[%d] ATTRIBUTE_UNUSED = {",
427 stats.num_operand_vars);
428 for (int i = 0; i < stats.num_generator_args; i++)
429 fprintf (stream: file, format: "%s operand%d", i == 0 ? "" : ",", i);
430 fprintf (stream: file, format: " };\n");
431 return "operands";
432 }
433
434 if (stats.num_operand_vars != 0)
435 {
436 fprintf (stream: file, format: " rtx operands[%d] ATTRIBUTE_UNUSED;\n",
437 stats.num_operand_vars);
438 return "operands";
439 }
440
441 return "nullptr";
442}
443
444/* Generate the `gen_...' function for a DEFINE_INSN. */
445
446static void
447gen_insn (const md_rtx_info &info, FILE *file)
448{
449 struct pattern_stats stats;
450
451 /* Find out how many operands this function has. */
452 rtx insn = info.def;
453 get_pattern_stats (ranges: &stats, XVEC (insn, 1));
454 if (stats.max_dup_opno > stats.max_opno)
455 fatal_at (info.loc, "match_dup operand number has no match_operand");
456
457 /* Output the function name and argument declarations. */
458 const char *operands = start_gen_insn (file, XSTR (insn, 0), stats);
459
460 /* Output code to construct and return the rtl for the instruction body. */
461
462 rtx pattern = add_implicit_parallel (XVEC (insn, 1));
463 const char *table = generator (info).gen_exp (file, x: pattern);
464 fprintf (stream: file, format: " return expand_rtx (%s, %s);\n}\n\n", table, operands);
465}
466
467/* Process and queue the DEFINE_EXPAND in INFO. */
468
469static void
470queue_expand (const md_rtx_info &info)
471{
472 rtx expand = info.def;
473 if (strlen (XSTR (expand, 0)) == 0)
474 fatal_at (info.loc, "define_expand lacks a name");
475 if (XVEC (expand, 1) == 0)
476 fatal_at (info.loc, "define_expand for %s lacks a pattern",
477 XSTR (expand, 0));
478 queue.safe_push (obj: info);
479}
480
481/* Generate the `gen_...' function for a DEFINE_EXPAND. */
482
483static void
484gen_expand (const md_rtx_info &info, FILE *file)
485{
486 struct pattern_stats stats;
487
488 /* Find out how many operands this function has. */
489 rtx expand = info.def;
490 get_pattern_stats (ranges: &stats, XVEC (expand, 1));
491 if (stats.min_scratch_opno != -1
492 && stats.min_scratch_opno <= MAX (stats.max_opno, stats.max_dup_opno))
493 fatal_at (info.loc, "define_expand for %s needs to have match_scratch "
494 "numbers above all other operands", XSTR (expand, 0));
495
496 /* Output the function name and argument declarations. */
497 const char *operands = start_gen_insn (file, XSTR (expand, 0), stats);
498
499 /* If we don't have any C code to write, only one insn is being written,
500 and no MATCH_DUPs are present, we can just return the desired insn
501 like we do for a DEFINE_INSN. This saves memory. */
502 if ((XSTR (expand, 3) == 0 || *XSTR (expand, 3) == '\0')
503 && stats.max_opno >= stats.max_dup_opno
504 && XVECLEN (expand, 1) == 1)
505 {
506 rtx pattern = XVECEXP (expand, 1, 0);
507 const char *table = generator (info).gen_exp (file, x: pattern);
508 fprintf (stream: file, format: " return expand_rtx (%s, %s);\n}\n\n", table, operands);
509 return;
510 }
511
512 fprintf (stream: file, format: " start_sequence ();\n");
513
514 /* The fourth operand of DEFINE_EXPAND is some code to be executed
515 before the actual construction.
516 This code expects to refer to `operands'
517 just as the output-code in a DEFINE_INSN does,
518 but here `operands' is an automatic array.
519 So copy the operand values there before executing it. */
520 if (XSTR (expand, 3) && *XSTR (expand, 3))
521 {
522 fprintf (stream: file, format: " {\n");
523
524 /* Output the special code to be executed before the sequence
525 is generated. */
526 optab_pattern p;
527 bool can_fail_p = true;
528 if (find_optab (&p, XSTR (expand, 0)))
529 {
530 gcc_assert (p.op < NUM_OPTABS);
531 if (nofail_optabs[p.op])
532 can_fail_p = false;
533 }
534 emit_c_code (XSTR (expand, 3), can_fail_p, XSTR (expand, 0), file);
535
536 fprintf (stream: file, format: " }\n");
537 }
538
539 const char *table = generator (info).gen_emit_seq (file, XVEC (expand, 1));
540 fprintf (stream: file, format: " return complete_seq (%s, %s);\n}\n\n", table, operands);
541}
542
543/* Process and queue the DEFINE_SPLIT or DEFINE_PEEPHOLE2 in INFO. */
544
545static void
546queue_split (const md_rtx_info &info)
547{
548 rtx split = info.def;
549
550 if (XVEC (split, 0) == 0)
551 fatal_at (info.loc, "%s lacks a pattern",
552 GET_RTX_NAME (GET_CODE (split)));
553 if (XVEC (split, 2) == 0)
554 fatal_at (info.loc, "%s lacks a replacement pattern",
555 GET_RTX_NAME (GET_CODE (split)));
556
557 queue.safe_push (obj: info);
558}
559
560/* Generate the `gen_...' function for a DEFINE_SPLIT or DEFINE_PEEPHOLE2. */
561
562static void
563gen_split (const md_rtx_info &info, FILE *file)
564{
565 struct pattern_stats stats;
566 rtx split = info.def;
567 const char *const name =
568 ((GET_CODE (split) == DEFINE_PEEPHOLE2) ? "peephole2" : "split");
569 const char *unused;
570
571 /* Find out how many operands this function has. */
572
573 get_pattern_stats (ranges: &stats, XVEC (split, 2));
574 unused = (stats.num_operand_vars == 0 ? " ATTRIBUTE_UNUSED" : "");
575
576 /* Output the prototype, function name and argument declarations. */
577 if (GET_CODE (split) == DEFINE_PEEPHOLE2)
578 {
579 fprintf (stream: file, format: "extern rtx_insn *gen_%s_%d (rtx_insn *, rtx *);\n",
580 name, info.index);
581 fprintf (stream: file, format: "rtx_insn *\ngen_%s_%d (rtx_insn *curr_insn ATTRIBUTE_UNUSED,"
582 " rtx *operands%s)\n",
583 name, info.index, unused);
584 }
585 else
586 {
587 fprintf (stream: file, format: "extern rtx_insn *gen_split_%d (rtx_insn *, rtx *);\n",
588 info.index);
589 fprintf (stream: file, format: "rtx_insn *\ngen_split_%d "
590 "(rtx_insn *curr_insn ATTRIBUTE_UNUSED, rtx *operands%s)\n",
591 info.index, unused);
592 }
593 fprintf (stream: file, format: "{\n");
594
595 if (GET_CODE (split) == DEFINE_PEEPHOLE2)
596 output_peephole2_scratches (split, file);
597
598 const char *fn = info.loc.filename;
599 for (const char *p = fn; *p; p++)
600 if (*p == '/')
601 fn = p + 1;
602
603 fprintf (stream: file, format: " if (dump_file)\n");
604 fprintf (stream: file, format: " fprintf (dump_file, \"Splitting with gen_%s_%d (%s:%d)\\n\");\n",
605 name, info.index, fn, info.loc.lineno);
606
607 fprintf (stream: file, format: " start_sequence ();\n");
608
609 /* The fourth operand of DEFINE_SPLIT is some code to be executed
610 before the actual construction. */
611
612 if (XSTR (split, 3))
613 emit_c_code (XSTR (split, 3), can_fail_p: true, name, file);
614
615 const char *table = generator (info).gen_emit_seq (file, XVEC (split, 2));
616 fprintf (stream: file, format: " return complete_seq (%s, %s);\n}\n\n", table, "operands");
617}
618
619/* Write a function, `add_clobbers', that is given a PARALLEL of sufficient
620 size for the insn and an INSN_CODE, and inserts the required CLOBBERs at
621 the end of the vector. */
622
623static void
624output_add_clobbers (FILE *file)
625{
626 struct clobber_pat *clobber;
627 struct clobber_ent *ent;
628 int i;
629
630 fprintf (stream: file, format: "\n\nvoid\nadd_clobbers (rtx pattern ATTRIBUTE_UNUSED, int insn_code_number)\n");
631 fprintf (stream: file, format: "{\n");
632 fprintf (stream: file, format: " switch (insn_code_number)\n");
633 fprintf (stream: file, format: " {\n");
634
635 for (clobber = clobber_list; clobber; clobber = clobber->next)
636 {
637 for (ent = clobber->insns; ent; ent = ent->next)
638 fprintf (stream: file, format: " case %d:\n", ent->code_number);
639
640 for (i = clobber->first_clobber; i < GET_NUM_ELEM (clobber->pattern); i++)
641 {
642 fprintf (stream: file, format: " XVECEXP (pattern, 0, %d) ="
643 " gen_rtx_CLOBBER (VOIDmode, ", i);
644 rtx x = XEXP (RTVEC_ELT (clobber->pattern, i), 0);
645 if (REG_P (x))
646 fprintf (stream: file, format: "gen_rtx_REG (%smode, %d)",
647 GET_MODE_NAME (GET_MODE (x)), REGNO (x));
648 else
649 fprintf (stream: file, format: "gen_rtx_SCRATCH (%smode)",
650 GET_MODE_NAME (GET_MODE (x)));
651 fprintf (stream: file, format: ");\n");
652 }
653
654 fprintf (stream: file, format: " break;\n\n");
655 }
656
657 fprintf (stream: file, format: " default:\n");
658 fprintf (stream: file, format: " gcc_unreachable ();\n");
659 fprintf (stream: file, format: " }\n");
660 fprintf (stream: file, format: "}\n");
661}
662
663/* Write a function, `added_clobbers_hard_reg_p' that is given an insn_code
664 number that will have clobbers added (as indicated by `recog') and returns
665 1 if those include a clobber of a hard reg or 0 if all of them just clobber
666 SCRATCH. */
667
668static void
669output_added_clobbers_hard_reg_p (FILE *file)
670{
671 struct clobber_pat *clobber;
672 struct clobber_ent *ent;
673 int clobber_p;
674 bool used;
675
676 fprintf (stream: file, format: "\n\nbool\nadded_clobbers_hard_reg_p (int insn_code_number)\n");
677 fprintf (stream: file, format: "{\n");
678 fprintf (stream: file, format: " switch (insn_code_number)\n");
679 fprintf (stream: file, format: " {\n");
680
681 for (clobber_p = 0; clobber_p <= 1; clobber_p++)
682 {
683 used = false;
684 for (clobber = clobber_list; clobber; clobber = clobber->next)
685 if (clobber->has_hard_reg == clobber_p)
686 for (ent = clobber->insns; ent; ent = ent->next)
687 {
688 fprintf (stream: file, format: " case %d:\n", ent->code_number);
689 used = true;
690 }
691
692 if (used)
693 fprintf (stream: file, format: " return %s;\n\n", clobber_p ? "true" : "false");
694 }
695
696 fprintf (stream: file, format: " default:\n");
697 fprintf (stream: file, format: " gcc_unreachable ();\n");
698 fprintf (stream: file, format: " }\n");
699 fprintf (stream: file, format: "}\n");
700}
701
702/* Generate code to invoke find_free_register () as needed for the
703 scratch registers used by the peephole2 pattern in SPLIT. */
704
705static void
706output_peephole2_scratches (rtx split, FILE *file)
707{
708 int i;
709 int insn_nr = 0;
710 bool first = true;
711
712 for (i = 0; i < XVECLEN (split, 0); i++)
713 {
714 rtx elt = XVECEXP (split, 0, i);
715 if (GET_CODE (elt) == MATCH_SCRATCH)
716 {
717 int last_insn_nr = insn_nr;
718 int cur_insn_nr = insn_nr;
719 int j;
720 for (j = i + 1; j < XVECLEN (split, 0); j++)
721 if (GET_CODE (XVECEXP (split, 0, j)) == MATCH_DUP)
722 {
723 if (XINT (XVECEXP (split, 0, j), 0) == XINT (elt, 0))
724 last_insn_nr = cur_insn_nr;
725 }
726 else if (GET_CODE (XVECEXP (split, 0, j)) != MATCH_SCRATCH)
727 cur_insn_nr++;
728
729 if (first)
730 {
731 fprintf (stream: file, format: " HARD_REG_SET _regs_allocated;\n");
732 fprintf (stream: file, format: " CLEAR_HARD_REG_SET (_regs_allocated);\n");
733 first = false;
734 }
735
736 fprintf (stream: file, format: " if ((operands[%d] = peep2_find_free_register (%d, %d, \"%s\", %smode, &_regs_allocated)) == NULL_RTX)\n\
737 return NULL;\n",
738 XINT (elt, 0),
739 insn_nr, last_insn_nr,
740 XSTR (elt, 1),
741 GET_MODE_NAME (GET_MODE (elt)));
742
743 }
744 else if (GET_CODE (elt) != MATCH_DUP)
745 insn_nr++;
746 }
747}
748
749/* Print "arg<N>" parameter declarations for each argument N of ONAME. */
750
751static void
752print_overload_arguments (overloaded_name *oname, FILE *file)
753{
754 for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
755 fprintf (stream: file, format: "%s%s arg%d", i == 0 ? "" : ", ", oname->arg_types[i], i);
756}
757
758/* Print code to test whether INSTANCE should be chosen, given that
759 argument N of the overload is available as "arg<N>". */
760
761static void
762print_overload_test (overloaded_instance *instance, FILE *file)
763{
764 for (unsigned int i = 0; i < instance->arg_values.length (); ++i)
765 fprintf (stream: file, format: "%sarg%d == %s", i == 0 ? " if (" : "\n && ",
766 i, instance->arg_values[i]);
767 fprintf (stream: file, format: ")\n");
768}
769
770/* Emit a maybe_code_for_* function for ONAME. */
771
772static void
773handle_overloaded_code_for (overloaded_name *oname, FILE *file)
774{
775 /* Print the function prototype. */
776 fprintf (stream: file, format: "\ninsn_code\nmaybe_code_for_%s (", oname->name);
777 print_overload_arguments (oname, file);
778 fprintf (stream: file, format: ")\n{\n");
779
780 /* Use a sequence of "if" statements for each instance. */
781 for (overloaded_instance *instance = oname->first_instance;
782 instance; instance = instance->next)
783 {
784 print_overload_test (instance, file);
785 fprintf (stream: file, format: " return CODE_FOR_%s;\n", instance->name);
786 }
787
788 /* Return null if no match was found. */
789 fprintf (stream: file, format: " return CODE_FOR_nothing;\n}\n");
790}
791
792/* Emit a maybe_gen_* function for ONAME. */
793
794static void
795handle_overloaded_gen (overloaded_name *oname, FILE *file)
796{
797 unsigned HOST_WIDE_INT seen = 0;
798 /* All patterns must have the same number of operands. */
799 for (overloaded_instance *instance = oname->first_instance->next;
800 instance; instance = instance->next)
801 {
802 pattern_stats stats;
803 get_pattern_stats (ranges: &stats, XVEC (instance->insn, 1));
804 unsigned HOST_WIDE_INT mask
805 = HOST_WIDE_INT_1U << stats.num_generator_args;
806 if (seen & mask)
807 continue;
808
809 seen |= mask;
810
811 /* Print the function prototype. */
812 fprintf (stream: file, format: "\nrtx\nmaybe_gen_%s (", oname->name);
813 print_overload_arguments (oname, file);
814 for (int i = 0; i < stats.num_generator_args; ++i)
815 fprintf (stream: file, format: ", rtx x%d", i);
816 fprintf (stream: file, format: ")\n{\n");
817
818 /* Use maybe_code_for_*, instead of duplicating the selection
819 logic here. */
820 fprintf (stream: file, format: " insn_code code = maybe_code_for_%s (", oname->name);
821 for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
822 fprintf (stream: file, format: "%sarg%d", i == 0 ? "" : ", ", i);
823 fprintf (stream: file, format: ");\n"
824 " if (code != CODE_FOR_nothing)\n"
825 " {\n"
826 " gcc_assert (insn_data[code].n_generator_args == %d);\n"
827 " return GEN_FCN (code) (", stats.num_generator_args);
828 for (int i = 0; i < stats.num_generator_args; ++i)
829 fprintf (stream: file, format: "%sx%d", i == 0 ? "" : ", ", i);
830 fprintf (stream: file, format: ");\n"
831 " }\n"
832 " else\n"
833 " return NULL_RTX;\n"
834 "}\n");
835 }
836}
837
838void
839print_header (FILE *file)
840{
841 fprintf (stream: file, format: "/* Generated automatically by the program `genemit'\n\
842from the machine description file `md'. */\n\n");
843
844 fprintf (stream: file, format: "#define IN_TARGET_CODE 1\n");
845 fprintf (stream: file, format: "#include \"config.h\"\n");
846 fprintf (stream: file, format: "#include \"system.h\"\n");
847 fprintf (stream: file, format: "#include \"coretypes.h\"\n");
848 fprintf (stream: file, format: "#include \"backend.h\"\n");
849 fprintf (stream: file, format: "#include \"predict.h\"\n");
850 fprintf (stream: file, format: "#include \"tree.h\"\n");
851 fprintf (stream: file, format: "#include \"rtl.h\"\n");
852 fprintf (stream: file, format: "#include \"alias.h\"\n");
853 fprintf (stream: file, format: "#include \"varasm.h\"\n");
854 fprintf (stream: file, format: "#include \"stor-layout.h\"\n");
855 fprintf (stream: file, format: "#include \"calls.h\"\n");
856 fprintf (stream: file, format: "#include \"memmodel.h\"\n");
857 fprintf (stream: file, format: "#include \"tm_p.h\"\n");
858 fprintf (stream: file, format: "#include \"flags.h\"\n");
859 fprintf (stream: file, format: "#include \"insn-config.h\"\n");
860 fprintf (stream: file, format: "#include \"expmed.h\"\n");
861 fprintf (stream: file, format: "#include \"dojump.h\"\n");
862 fprintf (stream: file, format: "#include \"explow.h\"\n");
863 fprintf (stream: file, format: "#include \"emit-rtl.h\"\n");
864 fprintf (stream: file, format: "#include \"stmt.h\"\n");
865 fprintf (stream: file, format: "#include \"expr.h\"\n");
866 fprintf (stream: file, format: "#include \"insn-codes.h\"\n");
867 fprintf (stream: file, format: "#include \"optabs.h\"\n");
868 fprintf (stream: file, format: "#include \"dfp.h\"\n");
869 fprintf (stream: file, format: "#include \"output.h\"\n");
870 fprintf (stream: file, format: "#include \"recog.h\"\n");
871 fprintf (stream: file, format: "#include \"df.h\"\n");
872 fprintf (stream: file, format: "#include \"resource.h\"\n");
873 fprintf (stream: file, format: "#include \"reload.h\"\n");
874 fprintf (stream: file, format: "#include \"diagnostic-core.h\"\n");
875 fprintf (stream: file, format: "#include \"regs.h\"\n");
876 fprintf (stream: file, format: "#include \"tm-constrs.h\"\n");
877 fprintf (stream: file, format: "#include \"ggc.h\"\n");
878 fprintf (stream: file, format: "#include \"target.h\"\n\n");
879}
880
881auto_vec<FILE *, 10> output_files;
882
883static bool
884handle_arg (const char *arg)
885{
886 if (arg[1] == 'O')
887 {
888 FILE *file = fopen (&arg[2], "w");
889 output_files.safe_push (obj: file);
890 return true;
891 }
892 return false;
893}
894
895int
896main (int argc, const char **argv)
897{
898 progname = "genemit";
899
900 if (!init_rtx_reader_args_cb (argc, argv, handle_arg))
901 return (FATAL_EXIT_CODE);
902
903#define DEF_INTERNAL_OPTAB_FN(NAME, FLAGS, OPTAB, TYPE) \
904 nofail_optabs[OPTAB##_optab] = true;
905#include "internal-fn.def"
906
907 /* Assign sequential codes to all entries in the machine description
908 in parallel with the tables in insn-output.cc. */
909
910 md_rtx_info info;
911
912 if (output_files.is_empty ())
913 output_files.safe_push (stdout);
914
915 for (auto f : output_files)
916 print_header (file: f);
917
918 FILE *file = NULL;
919 unsigned file_idx;
920
921 /* Read the machine description. */
922 while (read_md_rtx (&info))
923 switch (GET_CODE (info.def))
924 {
925 case DEFINE_INSN:
926 maybe_queue_insn (info);
927 break;
928
929 case DEFINE_EXPAND:
930 queue_expand (info);
931 break;
932
933 case DEFINE_SPLIT:
934 case DEFINE_PEEPHOLE2:
935 queue_split (info);
936 break;
937
938 default:
939 break;
940 }
941
942 for (auto &info : queue)
943 {
944 file = choose_output (output_files, file_idx);
945
946 fprintf (stream: file, format: "/* %s:%d */\n", info.loc.filename, info.loc.lineno);
947 switch (GET_CODE (info.def))
948 {
949 case DEFINE_INSN:
950 gen_insn (info, file);
951 break;
952
953 case DEFINE_EXPAND:
954 gen_expand (info, file);
955 break;
956
957 case DEFINE_SPLIT:
958 case DEFINE_PEEPHOLE2:
959 gen_split (info, file);
960 break;
961
962 default:
963 break;
964 }
965 }
966
967 file = choose_output (output_files, file_idx);
968
969 /* Write out the routines to add CLOBBERs to a pattern and say whether they
970 clobber a hard reg. */
971 output_add_clobbers (file);
972 output_added_clobbers_hard_reg_p (file);
973
974 for (overloaded_name *oname = rtx_reader_ptr->get_overloads ();
975 oname; oname = oname->next)
976 {
977 handle_overloaded_code_for (oname, file);
978 handle_overloaded_gen (oname, file);
979 }
980
981 int ret = SUCCESS_EXIT_CODE;
982 for (FILE *f : output_files)
983 if (fclose (stream: f) != 0)
984 ret = FATAL_EXIT_CODE;
985
986 return ret;
987}
988

source code of gcc/genemit.cc