1 | /* Print RTL for GCC. |
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 | /* This file is compiled twice: once for the generator programs, |
21 | once for the compiler. */ |
22 | #ifdef GENERATOR_FILE |
23 | #include "bconfig.h" |
24 | #else |
25 | #include "config.h" |
26 | #endif |
27 | |
28 | #include "system.h" |
29 | #include "coretypes.h" |
30 | #include "tm.h" |
31 | #include "rtl.h" |
32 | |
33 | /* These headers all define things which are not available in |
34 | generator programs. */ |
35 | #ifndef GENERATOR_FILE |
36 | #include "alias.h" |
37 | #include "tree.h" |
38 | #include "basic-block.h" |
39 | #include "print-tree.h" |
40 | #include "flags.h" |
41 | #include "predict.h" |
42 | #include "function.h" |
43 | #include "cfg.h" |
44 | #include "basic-block.h" |
45 | #include "diagnostic.h" |
46 | #include "tree-pretty-print.h" |
47 | #include "alloc-pool.h" |
48 | #include "cselib.h" |
49 | #include "dumpfile.h" /* for dump_flags */ |
50 | #include "dwarf2out.h" |
51 | #include "pretty-print.h" |
52 | #endif |
53 | |
54 | #include "print-rtl.h" |
55 | #include "rtl-iter.h" |
56 | |
57 | /* Disable warnings about quoting issues in the pp_xxx calls below |
58 | that (intentionally) don't follow GCC diagnostic conventions. */ |
59 | #if __GNUC__ >= 10 |
60 | # pragma GCC diagnostic push |
61 | # pragma GCC diagnostic ignored "-Wformat-diag" |
62 | #endif |
63 | |
64 | /* String printed at beginning of each RTL when it is dumped. |
65 | This string is set to ASM_COMMENT_START when the RTL is dumped in |
66 | the assembly output file. */ |
67 | const char *print_rtx_head = "" ; |
68 | |
69 | #ifdef GENERATOR_FILE |
70 | /* These are defined from the .opt file when not used in generator |
71 | programs. */ |
72 | |
73 | /* Nonzero means suppress output of instruction numbers |
74 | in debugging dumps. |
75 | This must be defined here so that programs like gencodes can be linked. */ |
76 | int flag_dump_unnumbered = 0; |
77 | |
78 | /* Nonzero means suppress output of instruction numbers for previous |
79 | and next insns in debugging dumps. |
80 | This must be defined here so that programs like gencodes can be linked. */ |
81 | int flag_dump_unnumbered_links = 0; |
82 | #endif |
83 | |
84 | /* Constructor for rtx_writer. */ |
85 | |
86 | rtx_writer::rtx_writer (FILE *outf, int ind, bool simple, bool compact, |
87 | rtx_reuse_manager *reuse_manager ATTRIBUTE_UNUSED) |
88 | : m_outfile (outf), m_indent (ind), m_sawclose (false), |
89 | m_in_call_function_usage (false), m_simple (simple), m_compact (compact) |
90 | #ifndef GENERATOR_FILE |
91 | , m_rtx_reuse_manager (reuse_manager) |
92 | #endif |
93 | { |
94 | } |
95 | |
96 | #ifndef GENERATOR_FILE |
97 | |
98 | /* rtx_reuse_manager's ctor. */ |
99 | |
100 | rtx_reuse_manager::rtx_reuse_manager () |
101 | : m_next_id (0) |
102 | { |
103 | } |
104 | |
105 | /* Determine if X is of a kind suitable for dumping via reuse_rtx. */ |
106 | |
107 | static bool |
108 | uses_rtx_reuse_p (const_rtx x) |
109 | { |
110 | if (x == NULL) |
111 | return false; |
112 | |
113 | switch (GET_CODE (x)) |
114 | { |
115 | case DEBUG_EXPR: |
116 | case VALUE: |
117 | case SCRATCH: |
118 | return true; |
119 | |
120 | /* We don't use reuse_rtx for consts. */ |
121 | CASE_CONST_UNIQUE: |
122 | default: |
123 | return false; |
124 | } |
125 | } |
126 | |
127 | /* Traverse X and its descendents, determining if we see any rtx more than |
128 | once. Any rtx suitable for "reuse_rtx" that is seen more than once is |
129 | assigned an ID. */ |
130 | |
131 | void |
132 | rtx_reuse_manager::preprocess (const_rtx x) |
133 | { |
134 | subrtx_iterator::array_type array; |
135 | FOR_EACH_SUBRTX (iter, array, x, NONCONST) |
136 | if (uses_rtx_reuse_p (*iter)) |
137 | { |
138 | if (int *count = m_rtx_occurrence_count.get (*iter)) |
139 | { |
140 | if (*(count++) == 1) |
141 | m_rtx_reuse_ids.put (*iter, m_next_id++); |
142 | } |
143 | else |
144 | m_rtx_occurrence_count.put (*iter, 1); |
145 | } |
146 | } |
147 | |
148 | /* Return true iff X has been assigned a reuse ID. If it has, |
149 | and OUT is non-NULL, then write the reuse ID to *OUT. */ |
150 | |
151 | bool |
152 | rtx_reuse_manager::has_reuse_id (const_rtx x, int *out) |
153 | { |
154 | int *id = m_rtx_reuse_ids.get (x); |
155 | if (id) |
156 | { |
157 | if (out) |
158 | *out = *id; |
159 | return true; |
160 | } |
161 | else |
162 | return false; |
163 | } |
164 | |
165 | /* Determine if set_seen_def has been called for the given reuse ID. */ |
166 | |
167 | bool |
168 | rtx_reuse_manager::seen_def_p (int reuse_id) |
169 | { |
170 | return bitmap_bit_p (m_defs_seen, reuse_id); |
171 | } |
172 | |
173 | /* Record that the definition of the given reuse ID has been seen. */ |
174 | |
175 | void |
176 | rtx_reuse_manager::set_seen_def (int reuse_id) |
177 | { |
178 | bitmap_set_bit (m_defs_seen, reuse_id); |
179 | } |
180 | |
181 | #endif /* #ifndef GENERATOR_FILE */ |
182 | |
183 | #ifndef GENERATOR_FILE |
184 | void |
185 | print_mem_expr (FILE *outfile, const_tree expr) |
186 | { |
187 | fputc (' ', outfile); |
188 | print_generic_expr (outfile, CONST_CAST_TREE (expr), |
189 | dump_flags | TDF_SLIM); |
190 | } |
191 | #endif |
192 | |
193 | /* Print X to FILE. */ |
194 | |
195 | static void |
196 | print_poly_int (FILE *file, poly_int64 x) |
197 | { |
198 | HOST_WIDE_INT const_x; |
199 | if (x.is_constant (const_value: &const_x)) |
200 | fprintf (stream: file, HOST_WIDE_INT_PRINT_DEC, const_x); |
201 | else |
202 | { |
203 | fprintf (stream: file, format: "[" HOST_WIDE_INT_PRINT_DEC, x.coeffs[0]); |
204 | for (int i = 1; i < NUM_POLY_INT_COEFFS; ++i) |
205 | fprintf (stream: file, format: ", " HOST_WIDE_INT_PRINT_DEC, x.coeffs[i]); |
206 | fprintf (stream: file, format: "]" ); |
207 | } |
208 | } |
209 | |
210 | /* Subroutine of print_rtx_operand for handling code '0'. |
211 | 0 indicates a field for internal use that should not be printed. |
212 | However there are various special cases, such as the third field |
213 | of a NOTE, where it indicates that the field has several different |
214 | valid contents. */ |
215 | |
216 | void |
217 | rtx_writer::print_rtx_operand_code_0 (const_rtx in_rtx ATTRIBUTE_UNUSED, |
218 | int idx ATTRIBUTE_UNUSED) |
219 | { |
220 | #ifndef GENERATOR_FILE |
221 | if (idx == 1 && GET_CODE (in_rtx) == SYMBOL_REF) |
222 | { |
223 | int flags = SYMBOL_REF_FLAGS (in_rtx); |
224 | if (flags) |
225 | fprintf (m_outfile, " [flags %#x]" , flags); |
226 | tree decl = SYMBOL_REF_DECL (in_rtx); |
227 | if (decl) |
228 | print_node_brief (m_outfile, "" , decl, dump_flags); |
229 | } |
230 | else if (idx == 3 && NOTE_P (in_rtx)) |
231 | { |
232 | switch (NOTE_KIND (in_rtx)) |
233 | { |
234 | case NOTE_INSN_EH_REGION_BEG: |
235 | case NOTE_INSN_EH_REGION_END: |
236 | if (flag_dump_unnumbered) |
237 | fprintf (m_outfile, " #" ); |
238 | else |
239 | fprintf (m_outfile, " %d" , NOTE_EH_HANDLER (in_rtx)); |
240 | m_sawclose = true; |
241 | break; |
242 | |
243 | case NOTE_INSN_BLOCK_BEG: |
244 | case NOTE_INSN_BLOCK_END: |
245 | dump_addr (m_outfile, " " , NOTE_BLOCK (in_rtx)); |
246 | m_sawclose = true; |
247 | break; |
248 | |
249 | case NOTE_INSN_BASIC_BLOCK: |
250 | { |
251 | basic_block bb = NOTE_BASIC_BLOCK (in_rtx); |
252 | if (bb != 0) |
253 | fprintf (m_outfile, " [bb %d]" , bb->index); |
254 | break; |
255 | } |
256 | |
257 | case NOTE_INSN_DELETED_LABEL: |
258 | case NOTE_INSN_DELETED_DEBUG_LABEL: |
259 | { |
260 | const char *label = NOTE_DELETED_LABEL_NAME (in_rtx); |
261 | if (label) |
262 | fprintf (m_outfile, " (\"%s\")" , label); |
263 | else |
264 | fprintf (m_outfile, " \"\"" ); |
265 | } |
266 | break; |
267 | |
268 | case NOTE_INSN_SWITCH_TEXT_SECTIONS: |
269 | { |
270 | basic_block bb = NOTE_BASIC_BLOCK (in_rtx); |
271 | if (bb != 0) |
272 | fprintf (m_outfile, " [bb %d]" , bb->index); |
273 | break; |
274 | } |
275 | |
276 | case NOTE_INSN_VAR_LOCATION: |
277 | fputc (' ', m_outfile); |
278 | print_rtx (NOTE_VAR_LOCATION (in_rtx)); |
279 | break; |
280 | |
281 | case NOTE_INSN_CFI: |
282 | fputc ('\n', m_outfile); |
283 | output_cfi_directive (m_outfile, NOTE_CFI (in_rtx)); |
284 | fputc ('\t', m_outfile); |
285 | break; |
286 | |
287 | case NOTE_INSN_BEGIN_STMT: |
288 | case NOTE_INSN_INLINE_ENTRY: |
289 | #ifndef GENERATOR_FILE |
290 | { |
291 | expanded_location xloc |
292 | = expand_location (NOTE_MARKER_LOCATION (in_rtx)); |
293 | fprintf (m_outfile, " %s:%i" , xloc.file, xloc.line); |
294 | } |
295 | #endif |
296 | break; |
297 | |
298 | default: |
299 | break; |
300 | } |
301 | } |
302 | else if (idx == 7 && JUMP_P (in_rtx) && JUMP_LABEL (in_rtx) != NULL |
303 | && !m_compact) |
304 | { |
305 | /* Output the JUMP_LABEL reference. */ |
306 | fprintf (m_outfile, "\n%s%*s -> " , print_rtx_head, m_indent * 2, "" ); |
307 | if (GET_CODE (JUMP_LABEL (in_rtx)) == RETURN) |
308 | fprintf (m_outfile, "return" ); |
309 | else if (GET_CODE (JUMP_LABEL (in_rtx)) == SIMPLE_RETURN) |
310 | fprintf (m_outfile, "simple_return" ); |
311 | else |
312 | fprintf (m_outfile, "%d" , INSN_UID (JUMP_LABEL (in_rtx))); |
313 | } |
314 | else if (idx == 0 && GET_CODE (in_rtx) == VALUE) |
315 | { |
316 | cselib_val *val = CSELIB_VAL_PTR (in_rtx); |
317 | |
318 | fprintf (m_outfile, " %u:%u" , val->uid, val->hash); |
319 | dump_addr (m_outfile, " @" , in_rtx); |
320 | dump_addr (m_outfile, "/" , (void*)val); |
321 | } |
322 | else if (idx == 0 && GET_CODE (in_rtx) == DEBUG_EXPR) |
323 | { |
324 | fprintf (m_outfile, " D#%i" , |
325 | DEBUG_TEMP_UID (DEBUG_EXPR_TREE_DECL (in_rtx))); |
326 | } |
327 | else if (idx == 0 && GET_CODE (in_rtx) == ENTRY_VALUE) |
328 | { |
329 | m_indent += 2; |
330 | if (!m_sawclose) |
331 | fprintf (m_outfile, " " ); |
332 | print_rtx (ENTRY_VALUE_EXP (in_rtx)); |
333 | m_indent -= 2; |
334 | } |
335 | #endif |
336 | } |
337 | |
338 | /* Subroutine of print_rtx_operand for handling code 'e'. |
339 | Also called by print_rtx_operand_code_u for handling code 'u' |
340 | for LABEL_REFs when they don't reference a CODE_LABEL. */ |
341 | |
342 | void |
343 | rtx_writer::print_rtx_operand_code_e (const_rtx in_rtx, int idx) |
344 | { |
345 | m_indent += 2; |
346 | if (idx == 6 && INSN_P (in_rtx)) |
347 | /* Put REG_NOTES on their own line. */ |
348 | fprintf (stream: m_outfile, format: "\n%s%*s" , |
349 | print_rtx_head, m_indent * 2, "" ); |
350 | if (!m_sawclose) |
351 | fprintf (stream: m_outfile, format: " " ); |
352 | if (idx == 7 && CALL_P (in_rtx)) |
353 | { |
354 | m_in_call_function_usage = true; |
355 | print_rtx (XEXP (in_rtx, idx)); |
356 | m_in_call_function_usage = false; |
357 | } |
358 | else |
359 | print_rtx (XEXP (in_rtx, idx)); |
360 | m_indent -= 2; |
361 | } |
362 | |
363 | /* Subroutine of print_rtx_operand for handling codes 'E' and 'V'. */ |
364 | |
365 | void |
366 | rtx_writer::print_rtx_operand_codes_E_and_V (const_rtx in_rtx, int idx) |
367 | { |
368 | m_indent += 2; |
369 | if (m_sawclose) |
370 | { |
371 | fprintf (stream: m_outfile, format: "\n%s%*s" , |
372 | print_rtx_head, m_indent * 2, "" ); |
373 | m_sawclose = false; |
374 | } |
375 | if (GET_CODE (in_rtx) == CONST_VECTOR |
376 | && !GET_MODE_NUNITS (GET_MODE (in_rtx)).is_constant () |
377 | && CONST_VECTOR_DUPLICATE_P (in_rtx)) |
378 | fprintf (stream: m_outfile, format: " repeat" ); |
379 | fputs (" [" , m_outfile); |
380 | if (XVEC (in_rtx, idx) != NULL) |
381 | { |
382 | m_indent += 2; |
383 | if (XVECLEN (in_rtx, idx)) |
384 | m_sawclose = true; |
385 | |
386 | int barrier = XVECLEN (in_rtx, idx); |
387 | if (GET_CODE (in_rtx) == CONST_VECTOR |
388 | && !GET_MODE_NUNITS (GET_MODE (in_rtx)).is_constant ()) |
389 | barrier = CONST_VECTOR_NPATTERNS (in_rtx); |
390 | |
391 | for (int j = 0; j < XVECLEN (in_rtx, idx); j++) |
392 | { |
393 | int j1; |
394 | |
395 | if (j == barrier) |
396 | { |
397 | fprintf (stream: m_outfile, format: "\n%s%*s" , |
398 | print_rtx_head, m_indent * 2, "" ); |
399 | if (!CONST_VECTOR_STEPPED_P (in_rtx)) |
400 | fprintf (stream: m_outfile, format: "repeat [" ); |
401 | else if (CONST_VECTOR_NPATTERNS (in_rtx) == 1) |
402 | fprintf (stream: m_outfile, format: "stepped [" ); |
403 | else |
404 | fprintf (stream: m_outfile, format: "stepped (interleave %d) [" , |
405 | CONST_VECTOR_NPATTERNS (in_rtx)); |
406 | m_indent += 2; |
407 | } |
408 | |
409 | print_rtx (XVECEXP (in_rtx, idx, j)); |
410 | int limit = MIN (barrier, XVECLEN (in_rtx, idx)); |
411 | for (j1 = j + 1; j1 < limit; j1++) |
412 | if (XVECEXP (in_rtx, idx, j) != XVECEXP (in_rtx, idx, j1)) |
413 | break; |
414 | |
415 | if (j1 != j + 1) |
416 | { |
417 | fprintf (stream: m_outfile, format: " repeated x%i" , j1 - j); |
418 | j = j1 - 1; |
419 | } |
420 | } |
421 | |
422 | if (barrier < XVECLEN (in_rtx, idx)) |
423 | { |
424 | m_indent -= 2; |
425 | fprintf (stream: m_outfile, format: "\n%s%*s]" , print_rtx_head, m_indent * 2, "" ); |
426 | } |
427 | |
428 | m_indent -= 2; |
429 | } |
430 | if (m_sawclose) |
431 | fprintf (stream: m_outfile, format: "\n%s%*s" , print_rtx_head, m_indent * 2, "" ); |
432 | |
433 | fputs ("]" , m_outfile); |
434 | m_sawclose = true; |
435 | m_indent -= 2; |
436 | } |
437 | |
438 | /* Subroutine of print_rtx_operand for handling code 'i'. */ |
439 | |
440 | void |
441 | rtx_writer::print_rtx_operand_code_i (const_rtx in_rtx, int idx) |
442 | { |
443 | if (idx == 4 && INSN_P (in_rtx)) |
444 | { |
445 | #ifndef GENERATOR_FILE |
446 | const rtx_insn *in_insn = as_a <const rtx_insn *> (in_rtx); |
447 | |
448 | /* Pretty-print insn locations. Ignore scoping as it is mostly |
449 | redundant with line number information and do not print anything |
450 | when there is no location information available. */ |
451 | if (INSN_HAS_LOCATION (in_insn)) |
452 | { |
453 | expanded_location xloc = insn_location (in_insn); |
454 | fprintf (m_outfile, " \"%s\":%i:%i" , xloc.file, xloc.line, |
455 | xloc.column); |
456 | int discriminator = insn_discriminator (in_insn); |
457 | if (discriminator) |
458 | fprintf (m_outfile, " discrim %d" , discriminator); |
459 | |
460 | } |
461 | #endif |
462 | } |
463 | else if (idx == 6 && GET_CODE (in_rtx) == ASM_OPERANDS) |
464 | { |
465 | #ifndef GENERATOR_FILE |
466 | if (ASM_OPERANDS_SOURCE_LOCATION (in_rtx) != UNKNOWN_LOCATION) |
467 | fprintf (m_outfile, " %s:%i" , |
468 | LOCATION_FILE (ASM_OPERANDS_SOURCE_LOCATION (in_rtx)), |
469 | LOCATION_LINE (ASM_OPERANDS_SOURCE_LOCATION (in_rtx))); |
470 | #endif |
471 | } |
472 | else if (idx == 1 && GET_CODE (in_rtx) == ASM_INPUT) |
473 | { |
474 | #ifndef GENERATOR_FILE |
475 | if (ASM_INPUT_SOURCE_LOCATION (in_rtx) != UNKNOWN_LOCATION) |
476 | fprintf (m_outfile, " %s:%i" , |
477 | LOCATION_FILE (ASM_INPUT_SOURCE_LOCATION (in_rtx)), |
478 | LOCATION_LINE (ASM_INPUT_SOURCE_LOCATION (in_rtx))); |
479 | #endif |
480 | } |
481 | else if (idx == 5 && NOTE_P (in_rtx)) |
482 | { |
483 | /* This field is only used for NOTE_INSN_DELETED_LABEL, and |
484 | other times often contains garbage from INSN->NOTE death. */ |
485 | if (NOTE_KIND (in_rtx) == NOTE_INSN_DELETED_LABEL |
486 | || NOTE_KIND (in_rtx) == NOTE_INSN_DELETED_DEBUG_LABEL) |
487 | fprintf (stream: m_outfile, format: " %d" , XINT (in_rtx, idx)); |
488 | } |
489 | #if !defined(GENERATOR_FILE) && NUM_UNSPECV_VALUES > 0 |
490 | else if (idx == 1 |
491 | && GET_CODE (in_rtx) == UNSPEC_VOLATILE |
492 | && XINT (in_rtx, 1) >= 0 |
493 | && XINT (in_rtx, 1) < NUM_UNSPECV_VALUES) |
494 | fprintf (m_outfile, " %s" , unspecv_strings[XINT (in_rtx, 1)]); |
495 | #endif |
496 | #if !defined(GENERATOR_FILE) && NUM_UNSPEC_VALUES > 0 |
497 | else if (idx == 1 |
498 | && (GET_CODE (in_rtx) == UNSPEC |
499 | || GET_CODE (in_rtx) == UNSPEC_VOLATILE) |
500 | && XINT (in_rtx, 1) >= 0 |
501 | && XINT (in_rtx, 1) < NUM_UNSPEC_VALUES) |
502 | fprintf (m_outfile, " %s" , unspec_strings[XINT (in_rtx, 1)]); |
503 | #endif |
504 | else |
505 | { |
506 | int value = XINT (in_rtx, idx); |
507 | const char *name; |
508 | int is_insn = INSN_P (in_rtx); |
509 | |
510 | /* Don't print INSN_CODEs in compact mode. */ |
511 | if (m_compact && is_insn && &INSN_CODE (in_rtx) == &XINT (in_rtx, idx)) |
512 | { |
513 | m_sawclose = false; |
514 | return; |
515 | } |
516 | |
517 | if (flag_dump_unnumbered |
518 | && (is_insn || NOTE_P (in_rtx))) |
519 | fputc ('#', m_outfile); |
520 | else |
521 | fprintf (stream: m_outfile, format: " %d" , value); |
522 | |
523 | if (is_insn && &INSN_CODE (in_rtx) == &XINT (in_rtx, idx) |
524 | && XINT (in_rtx, idx) >= 0 |
525 | && (name = get_insn_name (XINT (in_rtx, idx))) != NULL) |
526 | fprintf (stream: m_outfile, format: " {%s}" , name); |
527 | m_sawclose = false; |
528 | } |
529 | } |
530 | |
531 | /* Subroutine of print_rtx_operand for handling code 'r'. */ |
532 | |
533 | void |
534 | rtx_writer::print_rtx_operand_code_r (const_rtx in_rtx) |
535 | { |
536 | int is_insn = INSN_P (in_rtx); |
537 | unsigned int regno = REGNO (in_rtx); |
538 | |
539 | #ifndef GENERATOR_FILE |
540 | /* For hard registers and virtuals, always print the |
541 | regno, except in compact mode. */ |
542 | if (regno <= LAST_VIRTUAL_REGISTER && !m_compact) |
543 | fprintf (m_outfile, " %d" , regno); |
544 | if (regno < FIRST_PSEUDO_REGISTER) |
545 | fprintf (m_outfile, " %s" , reg_names[regno]); |
546 | else if (regno <= LAST_VIRTUAL_REGISTER) |
547 | { |
548 | if (regno == VIRTUAL_INCOMING_ARGS_REGNUM) |
549 | fprintf (m_outfile, " virtual-incoming-args" ); |
550 | else if (regno == VIRTUAL_STACK_VARS_REGNUM) |
551 | fprintf (m_outfile, " virtual-stack-vars" ); |
552 | else if (regno == VIRTUAL_STACK_DYNAMIC_REGNUM) |
553 | fprintf (m_outfile, " virtual-stack-dynamic" ); |
554 | else if (regno == VIRTUAL_OUTGOING_ARGS_REGNUM) |
555 | fprintf (m_outfile, " virtual-outgoing-args" ); |
556 | else if (regno == VIRTUAL_CFA_REGNUM) |
557 | fprintf (m_outfile, " virtual-cfa" ); |
558 | else if (regno == VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM) |
559 | fprintf (m_outfile, " virtual-preferred-stack-boundary" ); |
560 | else |
561 | fprintf (m_outfile, " virtual-reg-%d" , regno-FIRST_VIRTUAL_REGISTER); |
562 | } |
563 | else |
564 | #endif |
565 | if (flag_dump_unnumbered && is_insn) |
566 | fputc ('#', m_outfile); |
567 | else if (m_compact) |
568 | { |
569 | /* In compact mode, print pseudos with '< and '>' wrapping the regno, |
570 | offseting it by (LAST_VIRTUAL_REGISTER + 1), so that the |
571 | first non-virtual pseudo is dumped as "<0>". */ |
572 | gcc_assert (regno > LAST_VIRTUAL_REGISTER); |
573 | fprintf (stream: m_outfile, format: " <%d>" , regno - (LAST_VIRTUAL_REGISTER + 1)); |
574 | } |
575 | else |
576 | fprintf (stream: m_outfile, format: " %d" , regno); |
577 | |
578 | #ifndef GENERATOR_FILE |
579 | if (REG_ATTRS (in_rtx)) |
580 | { |
581 | fputs (" [" , m_outfile); |
582 | if (regno != ORIGINAL_REGNO (in_rtx)) |
583 | fprintf (m_outfile, "orig:%i" , ORIGINAL_REGNO (in_rtx)); |
584 | if (REG_EXPR (in_rtx)) |
585 | print_mem_expr (m_outfile, REG_EXPR (in_rtx)); |
586 | |
587 | if (maybe_ne (REG_OFFSET (in_rtx), 0)) |
588 | { |
589 | fprintf (m_outfile, "+" ); |
590 | print_poly_int (m_outfile, REG_OFFSET (in_rtx)); |
591 | } |
592 | fputs (" ]" , m_outfile); |
593 | } |
594 | if (regno != ORIGINAL_REGNO (in_rtx)) |
595 | fprintf (m_outfile, " [%d]" , ORIGINAL_REGNO (in_rtx)); |
596 | #endif |
597 | } |
598 | |
599 | /* Subroutine of print_rtx_operand for handling code 'u'. */ |
600 | |
601 | void |
602 | rtx_writer::print_rtx_operand_code_u (const_rtx in_rtx, int idx) |
603 | { |
604 | /* Don't print insn UIDs for PREV/NEXT_INSN in compact mode. */ |
605 | if (m_compact && INSN_CHAIN_CODE_P (GET_CODE (in_rtx)) && idx < 2) |
606 | return; |
607 | |
608 | if (XEXP (in_rtx, idx) != NULL) |
609 | { |
610 | rtx sub = XEXP (in_rtx, idx); |
611 | enum rtx_code subc = GET_CODE (sub); |
612 | |
613 | if (GET_CODE (in_rtx) == LABEL_REF) |
614 | { |
615 | if (subc == NOTE |
616 | && NOTE_KIND (sub) == NOTE_INSN_DELETED_LABEL) |
617 | { |
618 | if (flag_dump_unnumbered) |
619 | fprintf (stream: m_outfile, format: " [# deleted]" ); |
620 | else |
621 | fprintf (stream: m_outfile, format: " [%d deleted]" , INSN_UID (insn: sub)); |
622 | m_sawclose = false; |
623 | return; |
624 | } |
625 | |
626 | if (subc != CODE_LABEL) |
627 | { |
628 | print_rtx_operand_code_e (in_rtx, idx); |
629 | return; |
630 | } |
631 | } |
632 | |
633 | if (flag_dump_unnumbered |
634 | || (flag_dump_unnumbered_links && idx <= 1 |
635 | && (INSN_P (in_rtx) || NOTE_P (in_rtx) |
636 | || LABEL_P (in_rtx) || BARRIER_P (in_rtx)))) |
637 | fputs (" #" , m_outfile); |
638 | else |
639 | fprintf (stream: m_outfile, format: " %d" , INSN_UID (insn: sub)); |
640 | } |
641 | else |
642 | fputs (" 0" , m_outfile); |
643 | m_sawclose = false; |
644 | } |
645 | |
646 | /* Subroutine of print_rtx. Print operand IDX of IN_RTX. */ |
647 | |
648 | void |
649 | rtx_writer::print_rtx_operand (const_rtx in_rtx, int idx) |
650 | { |
651 | const char *format_ptr = GET_RTX_FORMAT (GET_CODE (in_rtx)); |
652 | |
653 | switch (format_ptr[idx]) |
654 | { |
655 | const char *str; |
656 | |
657 | case 'T': |
658 | str = XTMPL (in_rtx, idx); |
659 | goto string; |
660 | |
661 | case 'S': |
662 | case 's': |
663 | str = XSTR (in_rtx, idx); |
664 | string: |
665 | |
666 | if (str == 0) |
667 | fputs (" (nil)" , m_outfile); |
668 | else |
669 | fprintf (stream: m_outfile, format: " (\"%s\")" , str); |
670 | m_sawclose = true; |
671 | break; |
672 | |
673 | case '0': |
674 | print_rtx_operand_code_0 (in_rtx, idx); |
675 | break; |
676 | |
677 | case 'e': |
678 | print_rtx_operand_code_e (in_rtx, idx); |
679 | break; |
680 | |
681 | case 'E': |
682 | case 'V': |
683 | print_rtx_operand_codes_E_and_V (in_rtx, idx); |
684 | break; |
685 | |
686 | case 'w': |
687 | if (! m_simple) |
688 | fprintf (stream: m_outfile, format: " " ); |
689 | fprintf (stream: m_outfile, HOST_WIDE_INT_PRINT_DEC, XWINT (in_rtx, idx)); |
690 | if (! m_simple && !m_compact) |
691 | fprintf (stream: m_outfile, format: " [" HOST_WIDE_INT_PRINT_HEX "]" , |
692 | (unsigned HOST_WIDE_INT) XWINT (in_rtx, idx)); |
693 | break; |
694 | |
695 | case 'i': |
696 | print_rtx_operand_code_i (in_rtx, idx); |
697 | break; |
698 | |
699 | case 'p': |
700 | fprintf (stream: m_outfile, format: " " ); |
701 | print_poly_int (file: m_outfile, SUBREG_BYTE (in_rtx)); |
702 | break; |
703 | |
704 | case 'r': |
705 | print_rtx_operand_code_r (in_rtx); |
706 | break; |
707 | |
708 | /* Print NOTE_INSN names rather than integer codes. */ |
709 | |
710 | case 'n': |
711 | fprintf (stream: m_outfile, format: " %s" , GET_NOTE_INSN_NAME (XINT (in_rtx, idx))); |
712 | m_sawclose = false; |
713 | break; |
714 | |
715 | case 'u': |
716 | print_rtx_operand_code_u (in_rtx, idx); |
717 | break; |
718 | |
719 | case 't': |
720 | #ifndef GENERATOR_FILE |
721 | if (idx == 0 && GET_CODE (in_rtx) == DEBUG_IMPLICIT_PTR) |
722 | print_mem_expr (m_outfile, DEBUG_IMPLICIT_PTR_DECL (in_rtx)); |
723 | else if (idx == 0 && GET_CODE (in_rtx) == DEBUG_PARAMETER_REF) |
724 | print_mem_expr (m_outfile, DEBUG_PARAMETER_REF_DECL (in_rtx)); |
725 | else |
726 | dump_addr (m_outfile, " " , XTREE (in_rtx, idx)); |
727 | #endif |
728 | break; |
729 | |
730 | case '*': |
731 | fputs (" Unknown" , m_outfile); |
732 | m_sawclose = false; |
733 | break; |
734 | |
735 | case 'B': |
736 | /* Don't print basic block ids in compact mode. */ |
737 | if (m_compact) |
738 | break; |
739 | #ifndef GENERATOR_FILE |
740 | if (XBBDEF (in_rtx, idx)) |
741 | fprintf (m_outfile, " %i" , XBBDEF (in_rtx, idx)->index); |
742 | #endif |
743 | break; |
744 | |
745 | default: |
746 | gcc_unreachable (); |
747 | } |
748 | } |
749 | |
750 | /* Subroutine of rtx_writer::print_rtx. |
751 | In compact mode, determine if operand IDX of IN_RTX is interesting |
752 | to dump, or (if in a trailing position) it can be omitted. */ |
753 | |
754 | bool |
755 | rtx_writer::operand_has_default_value_p (const_rtx in_rtx, int idx) |
756 | { |
757 | const char *format_ptr = GET_RTX_FORMAT (GET_CODE (in_rtx)); |
758 | |
759 | switch (format_ptr[idx]) |
760 | { |
761 | case 'e': |
762 | case 'u': |
763 | return XEXP (in_rtx, idx) == NULL_RTX; |
764 | |
765 | case 's': |
766 | return XSTR (in_rtx, idx) == NULL; |
767 | |
768 | case '0': |
769 | switch (GET_CODE (in_rtx)) |
770 | { |
771 | case JUMP_INSN: |
772 | /* JUMP_LABELs are always omitted in compact mode, so treat |
773 | any value here as omittable, so that earlier operands can |
774 | potentially be omitted also. */ |
775 | return m_compact; |
776 | |
777 | default: |
778 | return false; |
779 | |
780 | } |
781 | |
782 | default: |
783 | return false; |
784 | } |
785 | } |
786 | |
787 | /* Print IN_RTX onto m_outfile. This is the recursive part of printing. */ |
788 | |
789 | void |
790 | rtx_writer::print_rtx (const_rtx in_rtx) |
791 | { |
792 | int idx = 0; |
793 | |
794 | if (m_sawclose) |
795 | { |
796 | if (m_simple) |
797 | fputc (' ', m_outfile); |
798 | else |
799 | fprintf (stream: m_outfile, format: "\n%s%*s" , print_rtx_head, m_indent * 2, "" ); |
800 | m_sawclose = false; |
801 | } |
802 | |
803 | if (in_rtx == 0) |
804 | { |
805 | fputs ("(nil)" , m_outfile); |
806 | m_sawclose = true; |
807 | return; |
808 | } |
809 | else if (GET_CODE (in_rtx) > NUM_RTX_CODE) |
810 | { |
811 | fprintf (stream: m_outfile, format: "(??? bad code %d\n%s%*s)" , GET_CODE (in_rtx), |
812 | print_rtx_head, m_indent * 2, "" ); |
813 | m_sawclose = true; |
814 | return; |
815 | } |
816 | |
817 | fputc ('(', m_outfile); |
818 | |
819 | /* Print name of expression code. */ |
820 | |
821 | /* Handle reuse. */ |
822 | #ifndef GENERATOR_FILE |
823 | if (m_rtx_reuse_manager) |
824 | { |
825 | int reuse_id; |
826 | if (m_rtx_reuse_manager->has_reuse_id (in_rtx, &reuse_id)) |
827 | { |
828 | /* Have we already seen the defn of this rtx? */ |
829 | if (m_rtx_reuse_manager->seen_def_p (reuse_id)) |
830 | { |
831 | fprintf (m_outfile, "reuse_rtx %i)" , reuse_id); |
832 | m_sawclose = true; |
833 | return; |
834 | } |
835 | else |
836 | { |
837 | /* First time we've seen this reused-rtx. */ |
838 | fprintf (m_outfile, "%i|" , reuse_id); |
839 | m_rtx_reuse_manager->set_seen_def (reuse_id); |
840 | } |
841 | } |
842 | } |
843 | #endif /* #ifndef GENERATOR_FILE */ |
844 | |
845 | /* In compact mode, prefix the code of insns with "c", |
846 | giving "cinsn", "cnote" etc. */ |
847 | if (m_compact && is_a <const rtx_insn *, const struct rtx_def> (p: in_rtx)) |
848 | { |
849 | /* "ccode_label" is slightly awkward, so special-case it as |
850 | just "clabel". */ |
851 | rtx_code code = GET_CODE (in_rtx); |
852 | if (code == CODE_LABEL) |
853 | fprintf (stream: m_outfile, format: "clabel" ); |
854 | else |
855 | fprintf (stream: m_outfile, format: "c%s" , GET_RTX_NAME (code)); |
856 | } |
857 | else if (m_simple && CONST_INT_P (in_rtx)) |
858 | ; /* no code. */ |
859 | else |
860 | fprintf (stream: m_outfile, format: "%s" , GET_RTX_NAME (GET_CODE (in_rtx))); |
861 | |
862 | if (! m_simple) |
863 | { |
864 | if (RTX_FLAG (in_rtx, in_struct)) |
865 | fputs ("/s" , m_outfile); |
866 | |
867 | if (RTX_FLAG (in_rtx, volatil)) |
868 | fputs ("/v" , m_outfile); |
869 | |
870 | if (RTX_FLAG (in_rtx, unchanging)) |
871 | fputs ("/u" , m_outfile); |
872 | |
873 | if (RTX_FLAG (in_rtx, frame_related)) |
874 | fputs ("/f" , m_outfile); |
875 | |
876 | if (RTX_FLAG (in_rtx, jump)) |
877 | fputs ("/j" , m_outfile); |
878 | |
879 | if (RTX_FLAG (in_rtx, call)) |
880 | fputs ("/c" , m_outfile); |
881 | |
882 | if (RTX_FLAG (in_rtx, return_val)) |
883 | fputs ("/i" , m_outfile); |
884 | |
885 | /* Print REG_NOTE names for EXPR_LIST and INSN_LIST. */ |
886 | if ((GET_CODE (in_rtx) == EXPR_LIST |
887 | || GET_CODE (in_rtx) == INSN_LIST |
888 | || GET_CODE (in_rtx) == INT_LIST) |
889 | && (int)GET_MODE (in_rtx) < REG_NOTE_MAX |
890 | && !m_in_call_function_usage) |
891 | fprintf (stream: m_outfile, format: ":%s" , |
892 | GET_REG_NOTE_NAME (GET_MODE (in_rtx))); |
893 | |
894 | /* For other rtl, print the mode if it's not VOID. */ |
895 | else if (GET_MODE (in_rtx) != VOIDmode) |
896 | fprintf (stream: m_outfile, format: ":%s" , GET_MODE_NAME (GET_MODE (in_rtx))); |
897 | |
898 | #ifndef GENERATOR_FILE |
899 | if (GET_CODE (in_rtx) == VAR_LOCATION) |
900 | { |
901 | if (TREE_CODE (PAT_VAR_LOCATION_DECL (in_rtx)) == STRING_CST) |
902 | fputs (" <debug string placeholder>" , m_outfile); |
903 | else |
904 | print_mem_expr (m_outfile, PAT_VAR_LOCATION_DECL (in_rtx)); |
905 | fputc (' ', m_outfile); |
906 | print_rtx (PAT_VAR_LOCATION_LOC (in_rtx)); |
907 | if (PAT_VAR_LOCATION_STATUS (in_rtx) |
908 | == VAR_INIT_STATUS_UNINITIALIZED) |
909 | fprintf (m_outfile, " [uninit]" ); |
910 | m_sawclose = true; |
911 | idx = GET_RTX_LENGTH (VAR_LOCATION); |
912 | } |
913 | #endif |
914 | } |
915 | |
916 | #ifndef GENERATOR_FILE |
917 | if (CONST_DOUBLE_AS_FLOAT_P (in_rtx)) |
918 | idx = 5; |
919 | #endif |
920 | |
921 | /* For insns, print the INSN_UID. */ |
922 | if (INSN_CHAIN_CODE_P (GET_CODE (in_rtx))) |
923 | { |
924 | if (flag_dump_unnumbered) |
925 | fprintf (stream: m_outfile, format: " #" ); |
926 | else |
927 | fprintf (stream: m_outfile, format: " %d" , INSN_UID (insn: in_rtx)); |
928 | } |
929 | |
930 | /* Determine which is the final operand to print. |
931 | In compact mode, skip trailing operands that have the default values |
932 | e.g. trailing "(nil)" values. */ |
933 | int limit = GET_RTX_LENGTH (GET_CODE (in_rtx)); |
934 | if (m_compact) |
935 | while (limit > idx && operand_has_default_value_p (in_rtx, idx: limit - 1)) |
936 | limit--; |
937 | |
938 | /* Get the format string and skip the first elements if we have handled |
939 | them already. */ |
940 | |
941 | for (; idx < limit; idx++) |
942 | print_rtx_operand (in_rtx, idx); |
943 | |
944 | switch (GET_CODE (in_rtx)) |
945 | { |
946 | #ifndef GENERATOR_FILE |
947 | case MEM: |
948 | if (UNLIKELY (final_insns_dump_p)) |
949 | fprintf (m_outfile, " [" ); |
950 | else |
951 | fprintf (m_outfile, " [" HOST_WIDE_INT_PRINT_DEC, |
952 | (HOST_WIDE_INT) MEM_ALIAS_SET (in_rtx)); |
953 | |
954 | if (MEM_EXPR (in_rtx)) |
955 | print_mem_expr (m_outfile, MEM_EXPR (in_rtx)); |
956 | else |
957 | fputc (' ', m_outfile); |
958 | |
959 | if (MEM_OFFSET_KNOWN_P (in_rtx)) |
960 | { |
961 | fprintf (m_outfile, "+" ); |
962 | print_poly_int (m_outfile, MEM_OFFSET (in_rtx)); |
963 | } |
964 | |
965 | if (MEM_SIZE_KNOWN_P (in_rtx)) |
966 | { |
967 | fprintf (m_outfile, " S" ); |
968 | print_poly_int (m_outfile, MEM_SIZE (in_rtx)); |
969 | } |
970 | |
971 | if (MEM_ALIGN (in_rtx) != 1) |
972 | fprintf (m_outfile, " A%u" , MEM_ALIGN (in_rtx)); |
973 | |
974 | if (!ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (in_rtx))) |
975 | fprintf (m_outfile, " AS%u" , MEM_ADDR_SPACE (in_rtx)); |
976 | |
977 | fputc (']', m_outfile); |
978 | break; |
979 | |
980 | case CONST_DOUBLE: |
981 | if (FLOAT_MODE_P (GET_MODE (in_rtx))) |
982 | { |
983 | char s[60]; |
984 | |
985 | real_to_decimal (s, CONST_DOUBLE_REAL_VALUE (in_rtx), |
986 | sizeof (s), 0, 1); |
987 | fprintf (m_outfile, " %s" , s); |
988 | |
989 | real_to_hexadecimal (s, CONST_DOUBLE_REAL_VALUE (in_rtx), |
990 | sizeof (s), 0, 1); |
991 | fprintf (m_outfile, " [%s]" , s); |
992 | } |
993 | break; |
994 | |
995 | case CONST_WIDE_INT: |
996 | fprintf (m_outfile, " " ); |
997 | cwi_output_hex (m_outfile, in_rtx); |
998 | break; |
999 | |
1000 | case CONST_POLY_INT: |
1001 | fprintf (m_outfile, " [" ); |
1002 | print_dec (CONST_POLY_INT_COEFFS (in_rtx)[0], m_outfile, SIGNED); |
1003 | for (unsigned int i = 1; i < NUM_POLY_INT_COEFFS; ++i) |
1004 | { |
1005 | fprintf (m_outfile, ", " ); |
1006 | print_dec (CONST_POLY_INT_COEFFS (in_rtx)[i], m_outfile, SIGNED); |
1007 | } |
1008 | fprintf (m_outfile, "]" ); |
1009 | break; |
1010 | #endif |
1011 | |
1012 | case CODE_LABEL: |
1013 | if (!m_compact) |
1014 | fprintf (stream: m_outfile, format: " [%d uses]" , LABEL_NUSES (in_rtx)); |
1015 | switch (LABEL_KIND (in_rtx)) |
1016 | { |
1017 | case LABEL_NORMAL: break; |
1018 | case LABEL_STATIC_ENTRY: fputs (" [entry]" , m_outfile); break; |
1019 | case LABEL_GLOBAL_ENTRY: fputs (" [global entry]" , m_outfile); break; |
1020 | case LABEL_WEAK_ENTRY: fputs (" [weak entry]" , m_outfile); break; |
1021 | default: gcc_unreachable (); |
1022 | } |
1023 | break; |
1024 | |
1025 | default: |
1026 | break; |
1027 | } |
1028 | |
1029 | fputc (')', m_outfile); |
1030 | m_sawclose = true; |
1031 | } |
1032 | |
1033 | /* Emit a closing parenthesis and newline. */ |
1034 | |
1035 | void |
1036 | rtx_writer::finish_directive () |
1037 | { |
1038 | fprintf (stream: m_outfile, format: ")\n" ); |
1039 | m_sawclose = false; |
1040 | } |
1041 | |
1042 | /* Print an rtx on the current line of FILE. Initially indent IND |
1043 | characters. */ |
1044 | |
1045 | void |
1046 | print_inline_rtx (FILE *outf, const_rtx x, int ind) |
1047 | { |
1048 | rtx_writer w (outf, ind, false, false, NULL); |
1049 | w.print_rtx (in_rtx: x); |
1050 | } |
1051 | |
1052 | /* Call this function from the debugger to see what X looks like. */ |
1053 | |
1054 | DEBUG_FUNCTION void |
1055 | debug_rtx (const_rtx x) |
1056 | { |
1057 | rtx_writer w (stderr, 0, false, false, NULL); |
1058 | w.print_rtx (in_rtx: x); |
1059 | fprintf (stderr, format: "\n" ); |
1060 | } |
1061 | |
1062 | /* Dump rtx REF. */ |
1063 | |
1064 | DEBUG_FUNCTION void |
1065 | debug (const rtx_def &ref) |
1066 | { |
1067 | debug_rtx (x: &ref); |
1068 | } |
1069 | |
1070 | DEBUG_FUNCTION void |
1071 | debug (const rtx_def *ptr) |
1072 | { |
1073 | if (ptr) |
1074 | debug (ref: *ptr); |
1075 | else |
1076 | fprintf (stderr, format: "<nil>\n" ); |
1077 | } |
1078 | |
1079 | /* Like debug_rtx but with no newline, as debug_helper will add one. |
1080 | |
1081 | Note: No debug_slim(rtx_insn *) variant implemented, as this |
1082 | function can serve for both rtx and rtx_insn. */ |
1083 | |
1084 | static void |
1085 | debug_slim (const_rtx x) |
1086 | { |
1087 | rtx_writer w (stderr, 0, false, false, NULL); |
1088 | w.print_rtx (in_rtx: x); |
1089 | } |
1090 | |
1091 | DEFINE_DEBUG_VEC (rtx_def *) |
1092 | DEFINE_DEBUG_VEC (rtx_insn *) |
1093 | DEFINE_DEBUG_HASH_SET (rtx_def *) |
1094 | DEFINE_DEBUG_HASH_SET (rtx_insn *) |
1095 | |
1096 | /* Count of rtx's to print with debug_rtx_list. |
1097 | This global exists because gdb user defined commands have no arguments. */ |
1098 | |
1099 | DEBUG_VARIABLE int debug_rtx_count = 0; /* 0 is treated as equivalent to 1 */ |
1100 | |
1101 | /* Call this function to print list from X on. |
1102 | |
1103 | N is a count of the rtx's to print. Positive values print from the specified |
1104 | rtx_insn on. Negative values print a window around the rtx_insn. |
1105 | EG: -5 prints 2 rtx_insn's on either side (in addition to the specified |
1106 | rtx_insn). */ |
1107 | |
1108 | DEBUG_FUNCTION void |
1109 | debug_rtx_list (const rtx_insn *x, int n) |
1110 | { |
1111 | int i,count; |
1112 | const rtx_insn *insn; |
1113 | |
1114 | count = n == 0 ? 1 : n < 0 ? -n : n; |
1115 | |
1116 | /* If we are printing a window, back up to the start. */ |
1117 | |
1118 | if (n < 0) |
1119 | for (i = count / 2; i > 0; i--) |
1120 | { |
1121 | if (PREV_INSN (insn: x) == 0) |
1122 | break; |
1123 | x = PREV_INSN (insn: x); |
1124 | } |
1125 | |
1126 | for (i = count, insn = x; i > 0 && insn != 0; i--, insn = NEXT_INSN (insn)) |
1127 | { |
1128 | debug_rtx (x: insn); |
1129 | fprintf (stderr, format: "\n" ); |
1130 | } |
1131 | } |
1132 | |
1133 | /* Call this function to print an rtx_insn list from START to END |
1134 | inclusive. */ |
1135 | |
1136 | DEBUG_FUNCTION void |
1137 | debug_rtx_range (const rtx_insn *start, const rtx_insn *end) |
1138 | { |
1139 | while (1) |
1140 | { |
1141 | debug_rtx (x: start); |
1142 | fprintf (stderr, format: "\n" ); |
1143 | if (!start || start == end) |
1144 | break; |
1145 | start = NEXT_INSN (insn: start); |
1146 | } |
1147 | } |
1148 | |
1149 | /* Call this function to search an rtx_insn list to find one with insn uid UID, |
1150 | and then call debug_rtx_list to print it, using DEBUG_RTX_COUNT. |
1151 | The found insn is returned to enable further debugging analysis. */ |
1152 | |
1153 | DEBUG_FUNCTION const rtx_insn * |
1154 | debug_rtx_find (const rtx_insn *x, int uid) |
1155 | { |
1156 | while (x != 0 && INSN_UID (insn: x) != uid) |
1157 | x = NEXT_INSN (insn: x); |
1158 | if (x != 0) |
1159 | { |
1160 | debug_rtx_list (x, n: debug_rtx_count); |
1161 | return x; |
1162 | } |
1163 | else |
1164 | { |
1165 | fprintf (stderr, format: "insn uid %d not found\n" , uid); |
1166 | return 0; |
1167 | } |
1168 | } |
1169 | |
1170 | /* External entry point for printing a chain of insns |
1171 | starting with RTX_FIRST. |
1172 | A blank line separates insns. |
1173 | |
1174 | If RTX_FIRST is not an insn, then it alone is printed, with no newline. */ |
1175 | |
1176 | void |
1177 | rtx_writer::print_rtl (const_rtx rtx_first) |
1178 | { |
1179 | const rtx_insn *tmp_rtx; |
1180 | |
1181 | if (rtx_first == 0) |
1182 | { |
1183 | fputs (print_rtx_head, m_outfile); |
1184 | fputs ("(nil)\n" , m_outfile); |
1185 | } |
1186 | else |
1187 | switch (GET_CODE (rtx_first)) |
1188 | { |
1189 | case INSN: |
1190 | case JUMP_INSN: |
1191 | case CALL_INSN: |
1192 | case NOTE: |
1193 | case CODE_LABEL: |
1194 | case JUMP_TABLE_DATA: |
1195 | case BARRIER: |
1196 | for (tmp_rtx = as_a <const rtx_insn *> (p: rtx_first); |
1197 | tmp_rtx != 0; |
1198 | tmp_rtx = NEXT_INSN (insn: tmp_rtx)) |
1199 | { |
1200 | fputs (print_rtx_head, m_outfile); |
1201 | print_rtx (in_rtx: tmp_rtx); |
1202 | fprintf (stream: m_outfile, format: "\n" ); |
1203 | } |
1204 | break; |
1205 | |
1206 | default: |
1207 | fputs (print_rtx_head, m_outfile); |
1208 | print_rtx (in_rtx: rtx_first); |
1209 | } |
1210 | } |
1211 | |
1212 | /* External entry point for printing a chain of insns |
1213 | starting with RTX_FIRST onto file OUTF. |
1214 | A blank line separates insns. |
1215 | |
1216 | If RTX_FIRST is not an insn, then it alone is printed, with no newline. */ |
1217 | |
1218 | void |
1219 | print_rtl (FILE *outf, const_rtx rtx_first) |
1220 | { |
1221 | rtx_writer w (outf, 0, false, false, NULL); |
1222 | w.print_rtl (rtx_first); |
1223 | } |
1224 | |
1225 | /* Like print_rtx, except specify a file. */ |
1226 | |
1227 | void |
1228 | print_rtl_single (FILE *outf, const_rtx x) |
1229 | { |
1230 | rtx_writer w (outf, 0, false, false, NULL); |
1231 | w.print_rtl_single_with_indent (x, ind: 0); |
1232 | } |
1233 | |
1234 | /* Like print_rtl_single, except specify an indentation. */ |
1235 | |
1236 | void |
1237 | rtx_writer::print_rtl_single_with_indent (const_rtx x, int ind) |
1238 | { |
1239 | char *s_indent = (char *) alloca ((size_t) ind + 1); |
1240 | memset (s: (void *) s_indent, c: ' ', n: (size_t) ind); |
1241 | s_indent[ind] = '\0'; |
1242 | fputs (s_indent, m_outfile); |
1243 | fputs (print_rtx_head, m_outfile); |
1244 | |
1245 | int old_indent = m_indent; |
1246 | m_indent = ind; |
1247 | m_sawclose = false; |
1248 | print_rtx (in_rtx: x); |
1249 | putc ('\n', m_outfile); |
1250 | m_indent = old_indent; |
1251 | } |
1252 | |
1253 | |
1254 | /* Like print_rtl except without all the detail; for example, |
1255 | if RTX is a CONST_INT then print in decimal format. */ |
1256 | |
1257 | void |
1258 | print_simple_rtl (FILE *outf, const_rtx x) |
1259 | { |
1260 | rtx_writer w (outf, 0, true, false, NULL); |
1261 | w.print_rtl (rtx_first: x); |
1262 | } |
1263 | |
1264 | /* Print the elements of VEC to FILE. */ |
1265 | |
1266 | void |
1267 | print_rtx_insn_vec (FILE *file, const vec<rtx_insn *> &vec) |
1268 | { |
1269 | fputc('{', file); |
1270 | |
1271 | unsigned int len = vec.length (); |
1272 | for (unsigned int i = 0; i < len; i++) |
1273 | { |
1274 | print_rtl_single (outf: file, x: vec[i]); |
1275 | if (i < len - 1) |
1276 | fputs (", " , file); |
1277 | } |
1278 | |
1279 | fputc ('}', file); |
1280 | } |
1281 | |
1282 | #ifndef GENERATOR_FILE |
1283 | /* The functions below try to print RTL in a form resembling assembler |
1284 | mnemonics. Because this form is more concise than the "traditional" form |
1285 | of RTL printing in Lisp-style, the form printed by this file is called |
1286 | "slim". RTL dumps in slim format can be obtained by appending the "-slim" |
1287 | option to -fdump-rtl-<pass>. Control flow graph output as a DOT file is |
1288 | always printed in slim form. |
1289 | |
1290 | The normal interface to the functionality provided in this pretty-printer |
1291 | is through the dump_*_slim functions to print to a stream, or via the |
1292 | print_*_slim functions to print into a user's pretty-printer. |
1293 | |
1294 | It is also possible to obtain a string for a single pattern as a string |
1295 | pointer, via str_pattern_slim, but this usage is discouraged. */ |
1296 | |
1297 | /* This recognizes rtx'en classified as expressions. These are always |
1298 | represent some action on values or results of other expression, that |
1299 | may be stored in objects representing values. */ |
1300 | |
1301 | static void |
1302 | print_exp (pretty_printer *pp, const_rtx x, int verbose) |
1303 | { |
1304 | const char *st[4]; |
1305 | const char *fun; |
1306 | rtx op[4]; |
1307 | int i; |
1308 | |
1309 | fun = (char *) 0; |
1310 | for (i = 0; i < 4; i++) |
1311 | { |
1312 | st[i] = (char *) 0; |
1313 | op[i] = NULL_RTX; |
1314 | } |
1315 | |
1316 | switch (GET_CODE (x)) |
1317 | { |
1318 | case PLUS: |
1319 | op[0] = XEXP (x, 0); |
1320 | if (CONST_INT_P (XEXP (x, 1)) |
1321 | && INTVAL (XEXP (x, 1)) < 0) |
1322 | { |
1323 | st[1] = "-" ; |
1324 | op[1] = GEN_INT (-INTVAL (XEXP (x, 1))); |
1325 | } |
1326 | else |
1327 | { |
1328 | st[1] = "+" ; |
1329 | op[1] = XEXP (x, 1); |
1330 | } |
1331 | break; |
1332 | case LO_SUM: |
1333 | op[0] = XEXP (x, 0); |
1334 | st[1] = "+low(" ; |
1335 | op[1] = XEXP (x, 1); |
1336 | st[2] = ")" ; |
1337 | break; |
1338 | case MINUS: |
1339 | op[0] = XEXP (x, 0); |
1340 | st[1] = "-" ; |
1341 | op[1] = XEXP (x, 1); |
1342 | break; |
1343 | case COMPARE: |
1344 | fun = "cmp" ; |
1345 | op[0] = XEXP (x, 0); |
1346 | op[1] = XEXP (x, 1); |
1347 | break; |
1348 | case NEG: |
1349 | st[0] = "-" ; |
1350 | op[0] = XEXP (x, 0); |
1351 | break; |
1352 | case FMA: |
1353 | st[0] = "{" ; |
1354 | op[0] = XEXP (x, 0); |
1355 | st[1] = "*" ; |
1356 | op[1] = XEXP (x, 1); |
1357 | st[2] = "+" ; |
1358 | op[2] = XEXP (x, 2); |
1359 | st[3] = "}" ; |
1360 | break; |
1361 | case MULT: |
1362 | op[0] = XEXP (x, 0); |
1363 | st[1] = "*" ; |
1364 | op[1] = XEXP (x, 1); |
1365 | break; |
1366 | case DIV: |
1367 | op[0] = XEXP (x, 0); |
1368 | st[1] = "/" ; |
1369 | op[1] = XEXP (x, 1); |
1370 | break; |
1371 | case UDIV: |
1372 | fun = "udiv" ; |
1373 | op[0] = XEXP (x, 0); |
1374 | op[1] = XEXP (x, 1); |
1375 | break; |
1376 | case MOD: |
1377 | op[0] = XEXP (x, 0); |
1378 | st[1] = "%" ; |
1379 | op[1] = XEXP (x, 1); |
1380 | break; |
1381 | case UMOD: |
1382 | fun = "umod" ; |
1383 | op[0] = XEXP (x, 0); |
1384 | op[1] = XEXP (x, 1); |
1385 | break; |
1386 | case SMIN: |
1387 | fun = "smin" ; |
1388 | op[0] = XEXP (x, 0); |
1389 | op[1] = XEXP (x, 1); |
1390 | break; |
1391 | case SMAX: |
1392 | fun = "smax" ; |
1393 | op[0] = XEXP (x, 0); |
1394 | op[1] = XEXP (x, 1); |
1395 | break; |
1396 | case UMIN: |
1397 | fun = "umin" ; |
1398 | op[0] = XEXP (x, 0); |
1399 | op[1] = XEXP (x, 1); |
1400 | break; |
1401 | case UMAX: |
1402 | fun = "umax" ; |
1403 | op[0] = XEXP (x, 0); |
1404 | op[1] = XEXP (x, 1); |
1405 | break; |
1406 | case NOT: |
1407 | st[0] = "~" ; |
1408 | op[0] = XEXP (x, 0); |
1409 | break; |
1410 | case AND: |
1411 | op[0] = XEXP (x, 0); |
1412 | st[1] = "&" ; |
1413 | op[1] = XEXP (x, 1); |
1414 | break; |
1415 | case IOR: |
1416 | op[0] = XEXP (x, 0); |
1417 | st[1] = "|" ; |
1418 | op[1] = XEXP (x, 1); |
1419 | break; |
1420 | case XOR: |
1421 | op[0] = XEXP (x, 0); |
1422 | st[1] = "^" ; |
1423 | op[1] = XEXP (x, 1); |
1424 | break; |
1425 | case ASHIFT: |
1426 | op[0] = XEXP (x, 0); |
1427 | st[1] = "<<" ; |
1428 | op[1] = XEXP (x, 1); |
1429 | break; |
1430 | case LSHIFTRT: |
1431 | op[0] = XEXP (x, 0); |
1432 | st[1] = " 0>>" ; |
1433 | op[1] = XEXP (x, 1); |
1434 | break; |
1435 | case ASHIFTRT: |
1436 | op[0] = XEXP (x, 0); |
1437 | st[1] = ">>" ; |
1438 | op[1] = XEXP (x, 1); |
1439 | break; |
1440 | case ROTATE: |
1441 | op[0] = XEXP (x, 0); |
1442 | st[1] = "<-<" ; |
1443 | op[1] = XEXP (x, 1); |
1444 | break; |
1445 | case ROTATERT: |
1446 | op[0] = XEXP (x, 0); |
1447 | st[1] = ">->" ; |
1448 | op[1] = XEXP (x, 1); |
1449 | break; |
1450 | case NE: |
1451 | op[0] = XEXP (x, 0); |
1452 | st[1] = "!=" ; |
1453 | op[1] = XEXP (x, 1); |
1454 | break; |
1455 | case EQ: |
1456 | op[0] = XEXP (x, 0); |
1457 | st[1] = "==" ; |
1458 | op[1] = XEXP (x, 1); |
1459 | break; |
1460 | case GE: |
1461 | op[0] = XEXP (x, 0); |
1462 | st[1] = ">=" ; |
1463 | op[1] = XEXP (x, 1); |
1464 | break; |
1465 | case GT: |
1466 | op[0] = XEXP (x, 0); |
1467 | st[1] = ">" ; |
1468 | op[1] = XEXP (x, 1); |
1469 | break; |
1470 | case LE: |
1471 | op[0] = XEXP (x, 0); |
1472 | st[1] = "<=" ; |
1473 | op[1] = XEXP (x, 1); |
1474 | break; |
1475 | case LT: |
1476 | op[0] = XEXP (x, 0); |
1477 | st[1] = "<" ; |
1478 | op[1] = XEXP (x, 1); |
1479 | break; |
1480 | case SIGN_EXTRACT: |
1481 | fun = (verbose) ? "sign_extract" : "sxt" ; |
1482 | op[0] = XEXP (x, 0); |
1483 | op[1] = XEXP (x, 1); |
1484 | op[2] = XEXP (x, 2); |
1485 | break; |
1486 | case ZERO_EXTRACT: |
1487 | fun = (verbose) ? "zero_extract" : "zxt" ; |
1488 | op[0] = XEXP (x, 0); |
1489 | op[1] = XEXP (x, 1); |
1490 | op[2] = XEXP (x, 2); |
1491 | break; |
1492 | case SIGN_EXTEND: |
1493 | fun = (verbose) ? "sign_extend" : "sxn" ; |
1494 | op[0] = XEXP (x, 0); |
1495 | break; |
1496 | case ZERO_EXTEND: |
1497 | fun = (verbose) ? "zero_extend" : "zxn" ; |
1498 | op[0] = XEXP (x, 0); |
1499 | break; |
1500 | case FLOAT_EXTEND: |
1501 | fun = (verbose) ? "float_extend" : "fxn" ; |
1502 | op[0] = XEXP (x, 0); |
1503 | break; |
1504 | case TRUNCATE: |
1505 | fun = (verbose) ? "trunc" : "trn" ; |
1506 | op[0] = XEXP (x, 0); |
1507 | break; |
1508 | case FLOAT_TRUNCATE: |
1509 | fun = (verbose) ? "float_trunc" : "ftr" ; |
1510 | op[0] = XEXP (x, 0); |
1511 | break; |
1512 | case FLOAT: |
1513 | fun = (verbose) ? "float" : "flt" ; |
1514 | op[0] = XEXP (x, 0); |
1515 | break; |
1516 | case UNSIGNED_FLOAT: |
1517 | fun = (verbose) ? "uns_float" : "ufl" ; |
1518 | op[0] = XEXP (x, 0); |
1519 | break; |
1520 | case FIX: |
1521 | fun = "fix" ; |
1522 | op[0] = XEXP (x, 0); |
1523 | break; |
1524 | case UNSIGNED_FIX: |
1525 | fun = (verbose) ? "uns_fix" : "ufx" ; |
1526 | op[0] = XEXP (x, 0); |
1527 | break; |
1528 | case PRE_DEC: |
1529 | st[0] = "--" ; |
1530 | op[0] = XEXP (x, 0); |
1531 | break; |
1532 | case PRE_INC: |
1533 | st[0] = "++" ; |
1534 | op[0] = XEXP (x, 0); |
1535 | break; |
1536 | case POST_DEC: |
1537 | op[0] = XEXP (x, 0); |
1538 | st[1] = "--" ; |
1539 | break; |
1540 | case POST_INC: |
1541 | op[0] = XEXP (x, 0); |
1542 | st[1] = "++" ; |
1543 | break; |
1544 | case PRE_MODIFY: |
1545 | st[0] = "pre " ; |
1546 | op[0] = XEXP (XEXP (x, 1), 0); |
1547 | st[1] = "+=" ; |
1548 | op[1] = XEXP (XEXP (x, 1), 1); |
1549 | break; |
1550 | case POST_MODIFY: |
1551 | st[0] = "post " ; |
1552 | op[0] = XEXP (XEXP (x, 1), 0); |
1553 | st[1] = "+=" ; |
1554 | op[1] = XEXP (XEXP (x, 1), 1); |
1555 | break; |
1556 | case CALL: |
1557 | st[0] = "call " ; |
1558 | op[0] = XEXP (x, 0); |
1559 | if (verbose) |
1560 | { |
1561 | st[1] = " argc:" ; |
1562 | op[1] = XEXP (x, 1); |
1563 | } |
1564 | break; |
1565 | case IF_THEN_ELSE: |
1566 | st[0] = "{(" ; |
1567 | op[0] = XEXP (x, 0); |
1568 | st[1] = ")?" ; |
1569 | op[1] = XEXP (x, 1); |
1570 | st[2] = ":" ; |
1571 | op[2] = XEXP (x, 2); |
1572 | st[3] = "}" ; |
1573 | break; |
1574 | case TRAP_IF: |
1575 | fun = "trap_if" ; |
1576 | op[0] = TRAP_CONDITION (x); |
1577 | break; |
1578 | case PREFETCH: |
1579 | fun = "prefetch" ; |
1580 | op[0] = XEXP (x, 0); |
1581 | op[1] = XEXP (x, 1); |
1582 | op[2] = XEXP (x, 2); |
1583 | break; |
1584 | case UNSPEC: |
1585 | case UNSPEC_VOLATILE: |
1586 | { |
1587 | pp_string (pp, "unspec" ); |
1588 | if (GET_CODE (x) == UNSPEC_VOLATILE) |
1589 | pp_string (pp, "/v" ); |
1590 | pp_left_bracket (pp); |
1591 | for (i = 0; i < XVECLEN (x, 0); i++) |
1592 | { |
1593 | if (i != 0) |
1594 | pp_comma (pp); |
1595 | print_pattern (pp, XVECEXP (x, 0, i), verbose); |
1596 | } |
1597 | pp_string (pp, "] " ); |
1598 | pp_decimal_int (pp, XINT (x, 1)); |
1599 | } |
1600 | break; |
1601 | default: |
1602 | { |
1603 | /* Most unhandled codes can be printed as pseudo-functions. */ |
1604 | if (GET_RTX_CLASS (GET_CODE (x)) == RTX_UNARY) |
1605 | { |
1606 | fun = GET_RTX_NAME (GET_CODE (x)); |
1607 | op[0] = XEXP (x, 0); |
1608 | } |
1609 | else if (GET_RTX_CLASS (GET_CODE (x)) == RTX_COMPARE |
1610 | || GET_RTX_CLASS (GET_CODE (x)) == RTX_COMM_COMPARE |
1611 | || GET_RTX_CLASS (GET_CODE (x)) == RTX_BIN_ARITH |
1612 | || GET_RTX_CLASS (GET_CODE (x)) == RTX_COMM_ARITH) |
1613 | { |
1614 | fun = GET_RTX_NAME (GET_CODE (x)); |
1615 | op[0] = XEXP (x, 0); |
1616 | op[1] = XEXP (x, 1); |
1617 | } |
1618 | else if (GET_RTX_CLASS (GET_CODE (x)) == RTX_TERNARY) |
1619 | { |
1620 | fun = GET_RTX_NAME (GET_CODE (x)); |
1621 | op[0] = XEXP (x, 0); |
1622 | op[1] = XEXP (x, 1); |
1623 | op[2] = XEXP (x, 2); |
1624 | } |
1625 | else |
1626 | /* Give up, just print the RTX name. */ |
1627 | st[0] = GET_RTX_NAME (GET_CODE (x)); |
1628 | } |
1629 | break; |
1630 | } |
1631 | |
1632 | /* Print this as a function? */ |
1633 | if (fun) |
1634 | { |
1635 | pp_string (pp, fun); |
1636 | pp_left_paren (pp); |
1637 | } |
1638 | |
1639 | for (i = 0; i < 4; i++) |
1640 | { |
1641 | if (st[i]) |
1642 | pp_string (pp, st[i]); |
1643 | |
1644 | if (op[i]) |
1645 | { |
1646 | if (fun && i != 0) |
1647 | pp_comma (pp); |
1648 | print_value (pp, op[i], verbose); |
1649 | } |
1650 | } |
1651 | |
1652 | if (fun) |
1653 | pp_right_paren (pp); |
1654 | } /* print_exp */ |
1655 | |
1656 | /* Prints rtxes, I customarily classified as values. They're constants, |
1657 | registers, labels, symbols and memory accesses. */ |
1658 | |
1659 | void |
1660 | print_value (pretty_printer *pp, const_rtx x, int verbose) |
1661 | { |
1662 | char tmp[1024]; |
1663 | |
1664 | if (!x) |
1665 | { |
1666 | pp_string (pp, "(nil)" ); |
1667 | return; |
1668 | } |
1669 | switch (GET_CODE (x)) |
1670 | { |
1671 | case CONST_INT: |
1672 | pp_scalar (pp, HOST_WIDE_INT_PRINT_HEX, |
1673 | (unsigned HOST_WIDE_INT) INTVAL (x)); |
1674 | break; |
1675 | |
1676 | case CONST_WIDE_INT: |
1677 | { |
1678 | const char *sep = "<" ; |
1679 | int i; |
1680 | for (i = CONST_WIDE_INT_NUNITS (x) - 1; i >= 0; i--) |
1681 | { |
1682 | pp_string (pp, sep); |
1683 | sep = "," ; |
1684 | sprintf (tmp, HOST_WIDE_INT_PRINT_HEX, |
1685 | (unsigned HOST_WIDE_INT) CONST_WIDE_INT_ELT (x, i)); |
1686 | pp_string (pp, tmp); |
1687 | } |
1688 | pp_greater (pp); |
1689 | } |
1690 | break; |
1691 | |
1692 | case CONST_POLY_INT: |
1693 | pp_left_bracket (pp); |
1694 | pp_wide_int (pp, CONST_POLY_INT_COEFFS (x)[0], SIGNED); |
1695 | for (unsigned int i = 1; i < NUM_POLY_INT_COEFFS; ++i) |
1696 | { |
1697 | pp_string (pp, ", " ); |
1698 | pp_wide_int (pp, CONST_POLY_INT_COEFFS (x)[i], SIGNED); |
1699 | } |
1700 | pp_right_bracket (pp); |
1701 | break; |
1702 | |
1703 | case CONST_DOUBLE: |
1704 | if (FLOAT_MODE_P (GET_MODE (x))) |
1705 | { |
1706 | real_to_decimal (tmp, CONST_DOUBLE_REAL_VALUE (x), |
1707 | sizeof (tmp), 0, 1); |
1708 | pp_string (pp, tmp); |
1709 | } |
1710 | else |
1711 | pp_printf (pp, "<%wx,%wx>" , |
1712 | (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (x), |
1713 | (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (x)); |
1714 | break; |
1715 | case CONST_FIXED: |
1716 | fixed_to_decimal (tmp, CONST_FIXED_VALUE (x), sizeof (tmp)); |
1717 | pp_string (pp, tmp); |
1718 | break; |
1719 | case CONST_STRING: |
1720 | pp_string (pp, "\"" ); |
1721 | pretty_print_string (pp, XSTR (x, 0), strlen (XSTR (x, 0))); |
1722 | pp_string (pp, "\"" ); |
1723 | break; |
1724 | case SYMBOL_REF: |
1725 | pp_printf (pp, "`%s'" , XSTR (x, 0)); |
1726 | break; |
1727 | case LABEL_REF: |
1728 | pp_printf (pp, "L%d" , INSN_UID (label_ref_label (x))); |
1729 | break; |
1730 | case CONST: |
1731 | case HIGH: |
1732 | case STRICT_LOW_PART: |
1733 | pp_printf (pp, "%s(" , GET_RTX_NAME (GET_CODE (x))); |
1734 | print_value (pp, XEXP (x, 0), verbose); |
1735 | pp_right_paren (pp); |
1736 | break; |
1737 | case REG: |
1738 | if (REGNO (x) < FIRST_PSEUDO_REGISTER) |
1739 | { |
1740 | if (ISDIGIT (reg_names[REGNO (x)][0])) |
1741 | pp_modulo (pp); |
1742 | pp_string (pp, reg_names[REGNO (x)]); |
1743 | } |
1744 | else |
1745 | pp_printf (pp, "r%d" , REGNO (x)); |
1746 | if (verbose) |
1747 | pp_printf (pp, ":%s" , GET_MODE_NAME (GET_MODE (x))); |
1748 | break; |
1749 | case SUBREG: |
1750 | print_value (pp, SUBREG_REG (x), verbose); |
1751 | pp_printf (pp, "#" ); |
1752 | pp_wide_integer (pp, SUBREG_BYTE (x)); |
1753 | break; |
1754 | case SCRATCH: |
1755 | case PC: |
1756 | pp_string (pp, GET_RTX_NAME (GET_CODE (x))); |
1757 | break; |
1758 | case MEM: |
1759 | pp_left_bracket (pp); |
1760 | print_value (pp, XEXP (x, 0), verbose); |
1761 | pp_right_bracket (pp); |
1762 | break; |
1763 | case DEBUG_EXPR: |
1764 | pp_printf (pp, "D#%i" , DEBUG_TEMP_UID (DEBUG_EXPR_TREE_DECL (x))); |
1765 | break; |
1766 | default: |
1767 | print_exp (pp, x, verbose); |
1768 | break; |
1769 | } |
1770 | } /* print_value */ |
1771 | |
1772 | /* The next step in insn detalization, its pattern recognition. */ |
1773 | |
1774 | void |
1775 | print_pattern (pretty_printer *pp, const_rtx x, int verbose) |
1776 | { |
1777 | if (! x) |
1778 | { |
1779 | pp_string (pp, "(nil)" ); |
1780 | return; |
1781 | } |
1782 | |
1783 | switch (GET_CODE (x)) |
1784 | { |
1785 | case SET: |
1786 | print_value (pp, SET_DEST (x), verbose); |
1787 | pp_equal (pp); |
1788 | print_value (pp, SET_SRC (x), verbose); |
1789 | break; |
1790 | case RETURN: |
1791 | case SIMPLE_RETURN: |
1792 | case EH_RETURN: |
1793 | pp_string (pp, GET_RTX_NAME (GET_CODE (x))); |
1794 | break; |
1795 | case CALL: |
1796 | print_exp (pp, x, verbose); |
1797 | break; |
1798 | case CLOBBER: |
1799 | case USE: |
1800 | pp_printf (pp, "%s " , GET_RTX_NAME (GET_CODE (x))); |
1801 | print_value (pp, XEXP (x, 0), verbose); |
1802 | break; |
1803 | case VAR_LOCATION: |
1804 | pp_string (pp, "loc " ); |
1805 | print_value (pp, PAT_VAR_LOCATION_LOC (x), verbose); |
1806 | break; |
1807 | case COND_EXEC: |
1808 | pp_left_paren (pp); |
1809 | if (GET_CODE (COND_EXEC_TEST (x)) == NE |
1810 | && XEXP (COND_EXEC_TEST (x), 1) == const0_rtx) |
1811 | print_value (pp, XEXP (COND_EXEC_TEST (x), 0), verbose); |
1812 | else if (GET_CODE (COND_EXEC_TEST (x)) == EQ |
1813 | && XEXP (COND_EXEC_TEST (x), 1) == const0_rtx) |
1814 | { |
1815 | pp_exclamation (pp); |
1816 | print_value (pp, XEXP (COND_EXEC_TEST (x), 0), verbose); |
1817 | } |
1818 | else |
1819 | print_value (pp, COND_EXEC_TEST (x), verbose); |
1820 | pp_string (pp, ") " ); |
1821 | print_pattern (pp, COND_EXEC_CODE (x), verbose); |
1822 | break; |
1823 | case PARALLEL: |
1824 | { |
1825 | int i; |
1826 | |
1827 | pp_left_brace (pp); |
1828 | for (i = 0; i < XVECLEN (x, 0); i++) |
1829 | { |
1830 | print_pattern (pp, XVECEXP (x, 0, i), verbose); |
1831 | pp_semicolon (pp); |
1832 | } |
1833 | pp_right_brace (pp); |
1834 | } |
1835 | break; |
1836 | case SEQUENCE: |
1837 | { |
1838 | const rtx_sequence *seq = as_a <const rtx_sequence *> (x); |
1839 | pp_string (pp, "sequence{" ); |
1840 | if (INSN_P (seq->element (0))) |
1841 | { |
1842 | /* Print the sequence insns indented. */ |
1843 | const char * save_print_rtx_head = print_rtx_head; |
1844 | char indented_print_rtx_head[32]; |
1845 | |
1846 | pp_newline (pp); |
1847 | gcc_assert (strlen (print_rtx_head) < sizeof (indented_print_rtx_head) - 4); |
1848 | snprintf (indented_print_rtx_head, |
1849 | sizeof (indented_print_rtx_head), |
1850 | "%s " , print_rtx_head); |
1851 | print_rtx_head = indented_print_rtx_head; |
1852 | for (int i = 0; i < seq->len (); i++) |
1853 | print_insn_with_notes (pp, seq->insn (i)); |
1854 | pp_printf (pp, "%s " , save_print_rtx_head); |
1855 | print_rtx_head = save_print_rtx_head; |
1856 | } |
1857 | else |
1858 | { |
1859 | for (int i = 0; i < seq->len (); i++) |
1860 | { |
1861 | print_pattern (pp, seq->element (i), verbose); |
1862 | pp_semicolon (pp); |
1863 | } |
1864 | } |
1865 | pp_right_brace (pp); |
1866 | } |
1867 | break; |
1868 | case ASM_INPUT: |
1869 | pp_printf (pp, "asm {%s}" , XSTR (x, 0)); |
1870 | break; |
1871 | case ADDR_VEC: |
1872 | for (int i = 0; i < XVECLEN (x, 0); i++) |
1873 | { |
1874 | print_value (pp, XVECEXP (x, 0, i), verbose); |
1875 | pp_semicolon (pp); |
1876 | } |
1877 | break; |
1878 | case ADDR_DIFF_VEC: |
1879 | for (int i = 0; i < XVECLEN (x, 1); i++) |
1880 | { |
1881 | print_value (pp, XVECEXP (x, 1, i), verbose); |
1882 | pp_semicolon (pp); |
1883 | } |
1884 | break; |
1885 | case TRAP_IF: |
1886 | pp_string (pp, "trap_if " ); |
1887 | print_value (pp, TRAP_CONDITION (x), verbose); |
1888 | break; |
1889 | case UNSPEC: |
1890 | case UNSPEC_VOLATILE: |
1891 | /* Fallthru -- leave UNSPECs to print_exp. */ |
1892 | default: |
1893 | print_value (pp, x, verbose); |
1894 | } |
1895 | } /* print_pattern */ |
1896 | |
1897 | /* This is the main function in slim rtl visualization mechanism. |
1898 | |
1899 | X is an insn, to be printed into PP. |
1900 | |
1901 | This function tries to print it properly in human-readable form, |
1902 | resembling assembler mnemonics (instead of the older Lisp-style |
1903 | form). |
1904 | |
1905 | If VERBOSE is TRUE, insns are printed with more complete (but |
1906 | longer) pattern names and with extra information, and prefixed |
1907 | with their INSN_UIDs. */ |
1908 | |
1909 | void |
1910 | print_insn (pretty_printer *pp, const rtx_insn *x, int verbose) |
1911 | { |
1912 | if (verbose) |
1913 | { |
1914 | /* Blech, pretty-print can't print integers with a specified width. */ |
1915 | char uid_prefix[32]; |
1916 | snprintf (uid_prefix, sizeof uid_prefix, " %4d: " , INSN_UID (x)); |
1917 | pp_string (pp, uid_prefix); |
1918 | } |
1919 | |
1920 | switch (GET_CODE (x)) |
1921 | { |
1922 | case INSN: |
1923 | print_pattern (pp, PATTERN (x), verbose); |
1924 | break; |
1925 | |
1926 | case DEBUG_INSN: |
1927 | { |
1928 | if (DEBUG_MARKER_INSN_P (x)) |
1929 | { |
1930 | switch (INSN_DEBUG_MARKER_KIND (x)) |
1931 | { |
1932 | case NOTE_INSN_BEGIN_STMT: |
1933 | pp_string (pp, "debug begin stmt marker" ); |
1934 | break; |
1935 | |
1936 | case NOTE_INSN_INLINE_ENTRY: |
1937 | pp_string (pp, "debug inline entry marker" ); |
1938 | break; |
1939 | |
1940 | default: |
1941 | gcc_unreachable (); |
1942 | } |
1943 | break; |
1944 | } |
1945 | |
1946 | const char *name = "?" ; |
1947 | char idbuf[32]; |
1948 | |
1949 | if (DECL_P (INSN_VAR_LOCATION_DECL (x))) |
1950 | { |
1951 | tree id = DECL_NAME (INSN_VAR_LOCATION_DECL (x)); |
1952 | if (id) |
1953 | name = IDENTIFIER_POINTER (id); |
1954 | else if (TREE_CODE (INSN_VAR_LOCATION_DECL (x)) |
1955 | == DEBUG_EXPR_DECL) |
1956 | { |
1957 | sprintf (idbuf, "D#%i" , |
1958 | DEBUG_TEMP_UID (INSN_VAR_LOCATION_DECL (x))); |
1959 | name = idbuf; |
1960 | } |
1961 | else |
1962 | { |
1963 | sprintf (idbuf, "D.%i" , |
1964 | DECL_UID (INSN_VAR_LOCATION_DECL (x))); |
1965 | name = idbuf; |
1966 | } |
1967 | } |
1968 | pp_printf (pp, "debug %s => " , name); |
1969 | if (VAR_LOC_UNKNOWN_P (INSN_VAR_LOCATION_LOC (x))) |
1970 | pp_string (pp, "optimized away" ); |
1971 | else |
1972 | print_pattern (pp, INSN_VAR_LOCATION_LOC (x), verbose); |
1973 | } |
1974 | break; |
1975 | |
1976 | case JUMP_INSN: |
1977 | print_pattern (pp, PATTERN (x), verbose); |
1978 | break; |
1979 | case CALL_INSN: |
1980 | if (GET_CODE (PATTERN (x)) == PARALLEL) |
1981 | print_pattern (pp, XVECEXP (PATTERN (x), 0, 0), verbose); |
1982 | else |
1983 | print_pattern (pp, PATTERN (x), verbose); |
1984 | break; |
1985 | case CODE_LABEL: |
1986 | pp_printf (pp, "L%d:" , INSN_UID (x)); |
1987 | break; |
1988 | case JUMP_TABLE_DATA: |
1989 | pp_string (pp, "jump_table_data{\n" ); |
1990 | print_pattern (pp, PATTERN (x), verbose); |
1991 | pp_right_brace (pp); |
1992 | break; |
1993 | case BARRIER: |
1994 | pp_string (pp, "barrier" ); |
1995 | break; |
1996 | case NOTE: |
1997 | { |
1998 | pp_string (pp, GET_NOTE_INSN_NAME (NOTE_KIND (x))); |
1999 | switch (NOTE_KIND (x)) |
2000 | { |
2001 | case NOTE_INSN_EH_REGION_BEG: |
2002 | case NOTE_INSN_EH_REGION_END: |
2003 | pp_printf (pp, " %d" , NOTE_EH_HANDLER (x)); |
2004 | break; |
2005 | |
2006 | case NOTE_INSN_BLOCK_BEG: |
2007 | case NOTE_INSN_BLOCK_END: |
2008 | pp_printf (pp, " %d" , BLOCK_NUMBER (NOTE_BLOCK (x))); |
2009 | break; |
2010 | |
2011 | case NOTE_INSN_BASIC_BLOCK: |
2012 | pp_printf (pp, " %d" , NOTE_BASIC_BLOCK (x)->index); |
2013 | break; |
2014 | |
2015 | case NOTE_INSN_DELETED_LABEL: |
2016 | case NOTE_INSN_DELETED_DEBUG_LABEL: |
2017 | { |
2018 | const char *label = NOTE_DELETED_LABEL_NAME (x); |
2019 | if (label == NULL) |
2020 | label = "" ; |
2021 | pp_printf (pp, " (\"%s\")" , label); |
2022 | } |
2023 | break; |
2024 | |
2025 | case NOTE_INSN_VAR_LOCATION: |
2026 | pp_left_brace (pp); |
2027 | print_pattern (pp, NOTE_VAR_LOCATION (x), verbose); |
2028 | pp_right_brace (pp); |
2029 | break; |
2030 | |
2031 | default: |
2032 | break; |
2033 | } |
2034 | break; |
2035 | } |
2036 | default: |
2037 | gcc_unreachable (); |
2038 | } |
2039 | } /* print_insn */ |
2040 | |
2041 | /* Pretty-print a slim dump of X (an insn) to PP, including any register |
2042 | note attached to the instruction. */ |
2043 | |
2044 | void |
2045 | print_insn_with_notes (pretty_printer *pp, const rtx_insn *x) |
2046 | { |
2047 | pp_string (pp, print_rtx_head); |
2048 | print_insn (pp, x, 1); |
2049 | pp_newline (pp); |
2050 | if (INSN_P (x) && REG_NOTES (x)) |
2051 | for (rtx note = REG_NOTES (x); note; note = XEXP (note, 1)) |
2052 | { |
2053 | pp_printf (pp, "%s %s " , print_rtx_head, |
2054 | GET_REG_NOTE_NAME (REG_NOTE_KIND (note))); |
2055 | if (GET_CODE (note) == INT_LIST) |
2056 | pp_printf (pp, "%d" , XINT (note, 0)); |
2057 | else |
2058 | print_pattern (pp, XEXP (note, 0), 1); |
2059 | pp_newline (pp); |
2060 | } |
2061 | } |
2062 | |
2063 | /* Print X, an RTL value node, to file F in slim format. Include |
2064 | additional information if VERBOSE is nonzero. |
2065 | |
2066 | Value nodes are constants, registers, labels, symbols and |
2067 | memory. */ |
2068 | |
2069 | void |
2070 | dump_value_slim (FILE *f, const_rtx x, int verbose) |
2071 | { |
2072 | pretty_printer rtl_slim_pp; |
2073 | rtl_slim_pp.buffer->stream = f; |
2074 | print_value (&rtl_slim_pp, x, verbose); |
2075 | pp_flush (&rtl_slim_pp); |
2076 | } |
2077 | |
2078 | /* Emit a slim dump of X (an insn) to the file F, including any register |
2079 | note attached to the instruction. */ |
2080 | void |
2081 | dump_insn_slim (FILE *f, const rtx_insn *x) |
2082 | { |
2083 | pretty_printer rtl_slim_pp; |
2084 | rtl_slim_pp.buffer->stream = f; |
2085 | print_insn_with_notes (&rtl_slim_pp, x); |
2086 | pp_flush (&rtl_slim_pp); |
2087 | } |
2088 | |
2089 | /* Same as above, but stop at LAST or when COUNT == 0. |
2090 | If COUNT < 0 it will stop only at LAST or NULL rtx. */ |
2091 | |
2092 | void |
2093 | dump_rtl_slim (FILE *f, const rtx_insn *first, const rtx_insn *last, |
2094 | int count, int flags ATTRIBUTE_UNUSED) |
2095 | { |
2096 | const rtx_insn *insn, *tail; |
2097 | pretty_printer rtl_slim_pp; |
2098 | rtl_slim_pp.buffer->stream = f; |
2099 | |
2100 | tail = last ? NEXT_INSN (last) : NULL; |
2101 | for (insn = first; |
2102 | (insn != NULL) && (insn != tail) && (count != 0); |
2103 | insn = NEXT_INSN (insn)) |
2104 | { |
2105 | print_insn_with_notes (&rtl_slim_pp, insn); |
2106 | if (count > 0) |
2107 | count--; |
2108 | } |
2109 | |
2110 | pp_flush (&rtl_slim_pp); |
2111 | } |
2112 | |
2113 | /* Dumps basic block BB to pretty-printer PP in slim form and without and |
2114 | no indentation, for use as a label of a DOT graph record-node. */ |
2115 | |
2116 | void |
2117 | rtl_dump_bb_for_graph (pretty_printer *pp, basic_block bb) |
2118 | { |
2119 | rtx_insn *insn; |
2120 | bool first = true; |
2121 | |
2122 | /* TODO: inter-bb stuff. */ |
2123 | FOR_BB_INSNS (bb, insn) |
2124 | { |
2125 | if (! first) |
2126 | { |
2127 | pp_bar (pp); |
2128 | pp_write_text_to_stream (pp); |
2129 | } |
2130 | first = false; |
2131 | print_insn_with_notes (pp, insn); |
2132 | pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/true); |
2133 | } |
2134 | } |
2135 | |
2136 | /* Pretty-print pattern X of some insn in non-verbose mode. |
2137 | Return a string pointer to the pretty-printer buffer. |
2138 | |
2139 | This function is only exported exists only to accommodate some older users |
2140 | of the slim RTL pretty printers. Please do not use it for new code. */ |
2141 | |
2142 | const char * |
2143 | str_pattern_slim (const_rtx x) |
2144 | { |
2145 | pretty_printer rtl_slim_pp; |
2146 | print_pattern (&rtl_slim_pp, x, 0); |
2147 | return ggc_strdup (pp_formatted_text (&rtl_slim_pp)); |
2148 | } |
2149 | |
2150 | /* Emit a slim dump of X (an insn) to stderr. */ |
2151 | extern void debug_insn_slim (const rtx_insn *); |
2152 | DEBUG_FUNCTION void |
2153 | debug_insn_slim (const rtx_insn *x) |
2154 | { |
2155 | dump_insn_slim (stderr, x); |
2156 | } |
2157 | |
2158 | /* Same as above, but using dump_rtl_slim. */ |
2159 | extern void debug_rtl_slim (FILE *, const rtx_insn *, const rtx_insn *, |
2160 | int, int); |
2161 | DEBUG_FUNCTION void |
2162 | debug_rtl_slim (const rtx_insn *first, const rtx_insn *last, int count, |
2163 | int flags) |
2164 | { |
2165 | dump_rtl_slim (stderr, first, last, count, flags); |
2166 | } |
2167 | |
2168 | extern void debug_bb_slim (basic_block); |
2169 | DEBUG_FUNCTION void |
2170 | debug_bb_slim (basic_block bb) |
2171 | { |
2172 | debug_bb (bb, TDF_SLIM | TDF_BLOCKS); |
2173 | } |
2174 | |
2175 | extern void debug_bb_n_slim (int); |
2176 | DEBUG_FUNCTION void |
2177 | debug_bb_n_slim (int n) |
2178 | { |
2179 | basic_block bb = BASIC_BLOCK_FOR_FN (cfun, n); |
2180 | debug_bb_slim (bb); |
2181 | } |
2182 | |
2183 | #endif |
2184 | |
2185 | #if __GNUC__ >= 10 |
2186 | # pragma GCC diagnostic pop |
2187 | #endif |
2188 | |