Line data Source code
1 : /* Print RTL functions for GCC.
2 : Copyright (C) 2016-2026 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 : #include "config.h"
21 : #include "system.h"
22 : #include "coretypes.h"
23 : #include "tm.h"
24 : #include "rtl.h"
25 : #include "alias.h"
26 : #include "tree.h"
27 : #include "flags.h"
28 : #include "predict.h"
29 : #include "function.h"
30 : #include "basic-block.h"
31 : #include "print-rtl.h"
32 : #include "langhooks.h"
33 : #include "memmodel.h"
34 : #include "emit-rtl.h"
35 : #include "varasm.h"
36 :
37 : /* Print an "(edge-from)" or "(edge-to)" directive describing E
38 : to OUTFILE. */
39 :
40 : static void
41 8 : print_edge (FILE *outfile, edge e, bool from)
42 : {
43 12 : fprintf (outfile, " (%s ", from ? "edge-from" : "edge-to");
44 8 : basic_block bb = from ? e->src : e->dest;
45 8 : gcc_assert (bb);
46 8 : switch (bb->index)
47 : {
48 4 : case ENTRY_BLOCK:
49 4 : fprintf (outfile, "entry");
50 4 : break;
51 4 : case EXIT_BLOCK:
52 4 : fprintf (outfile, "exit");
53 4 : break;
54 0 : default:
55 0 : fprintf (outfile, "%i", bb->index);
56 0 : break;
57 : }
58 :
59 : /* Express edge flags as a string with " | " separator.
60 : e.g. (flags "FALLTHRU | DFS_BACK"). */
61 8 : if (e->flags)
62 : {
63 8 : fprintf (outfile, " (flags \"");
64 8 : bool seen_flag = false;
65 : #define DEF_EDGE_FLAG(NAME,IDX) \
66 : do { \
67 : if (e->flags & EDGE_##NAME) \
68 : { \
69 : if (seen_flag) \
70 : fprintf (outfile, " | "); \
71 : fprintf (outfile, "%s", (#NAME)); \
72 : seen_flag = true; \
73 : } \
74 : } while (0);
75 : #include "cfg-flags.def"
76 : #undef DEF_EDGE_FLAG
77 :
78 8 : fprintf (outfile, "\")");
79 : }
80 :
81 8 : fprintf (outfile, ")\n");
82 8 : }
83 :
84 : /* If BB is non-NULL, print the start of a "(block)" directive for it
85 : to OUTFILE, otherwise do nothing. */
86 :
87 : static void
88 4 : begin_any_block (FILE *outfile, basic_block bb)
89 : {
90 4 : if (!bb)
91 0 : return;
92 :
93 4 : edge e;
94 4 : edge_iterator ei;
95 :
96 4 : fprintf (outfile, " (block %i\n", bb->index);
97 8 : FOR_EACH_EDGE (e, ei, bb->preds)
98 4 : print_edge (outfile, e, true);
99 : }
100 :
101 : /* If BB is non-NULL, print the end of a "(block)" directive for it
102 : to OUTFILE, otherwise do nothing. */
103 :
104 : static void
105 8 : end_any_block (FILE *outfile, basic_block bb)
106 : {
107 8 : if (!bb)
108 4 : return;
109 :
110 4 : edge e;
111 4 : edge_iterator ei;
112 :
113 8 : FOR_EACH_EDGE (e, ei, bb->succs)
114 4 : print_edge (outfile, e, false);
115 4 : fprintf (outfile, " ) ;; block %i\n", bb->index);
116 : }
117 :
118 : /* Determine if INSN is of a kind that can have a basic block. */
119 :
120 : static bool
121 28 : can_have_basic_block_p (const rtx_insn *insn)
122 : {
123 28 : rtx_code code = GET_CODE (insn);
124 28 : if (code == BARRIER)
125 : return false;
126 28 : gcc_assert (GET_RTX_FORMAT (code)[2] == 'B');
127 : return true;
128 : }
129 :
130 : /* Subroutine of print_param. Write the name of ARG, if any, to OUTFILE. */
131 :
132 : static void
133 0 : print_any_param_name (FILE *outfile, tree arg)
134 : {
135 0 : if (DECL_NAME (arg))
136 0 : fprintf (outfile, " \"%s\"", IDENTIFIER_POINTER (DECL_NAME (arg)));
137 0 : }
138 :
139 : /* Print a "(param)" directive for ARG to OUTFILE. */
140 :
141 : static void
142 0 : print_param (FILE *outfile, rtx_writer &w, tree arg)
143 : {
144 0 : fprintf (outfile, " (param");
145 0 : print_any_param_name (outfile, arg);
146 0 : fprintf (outfile, "\n");
147 :
148 : /* Print the value of DECL_RTL (without lazy-evaluation). */
149 0 : fprintf (outfile, " (DECL_RTL ");
150 0 : w.print_rtx (DECL_RTL_IF_SET (arg));
151 0 : w.finish_directive ();
152 :
153 : /* Print DECL_INCOMING_RTL. */
154 0 : fprintf (outfile, " (DECL_RTL_INCOMING ");
155 0 : w.print_rtx (DECL_INCOMING_RTL (arg));
156 0 : fprintf (outfile, ")");
157 :
158 0 : w.finish_directive ();
159 0 : }
160 :
161 : /* Write FN to OUTFILE in a form suitable for parsing, with indentation
162 : and comments to make the structure easy for a human to grok. Track
163 : the basic blocks of insns in the chain, wrapping those that are within
164 : blocks within "(block)" directives.
165 :
166 : If COMPACT, then instructions are printed in a compact form:
167 : - INSN_UIDs are omitted, except for jumps and CODE_LABELs,
168 : - INSN_CODEs are omitted,
169 : - register numbers are omitted for hard and virtual regs, and
170 : non-virtual pseudos are offset relative to the first such reg, and
171 : printed with a '%' sigil e.g. "%0" for (LAST_VIRTUAL_REGISTER + 1),
172 : - insn names are prefixed with "c" (e.g. "cinsn", "cnote", etc)
173 :
174 : Example output (with COMPACT==true):
175 :
176 : (function "times_two"
177 : (param "i"
178 : (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
179 : (const_int -4)) [1 i+0 S4 A32]))
180 : (DECL_RTL_INCOMING (reg:SI di [ i ])))
181 : (insn-chain
182 : (cnote 1 NOTE_INSN_DELETED)
183 : (block 2
184 : (edge-from entry (flags "FALLTHRU"))
185 : (cnote 4 [bb 2] NOTE_INSN_BASIC_BLOCK)
186 : (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
187 : (const_int -4)) [1 i+0 S4 A32])
188 : (reg:SI di [ i ])) "t.c":2)
189 : (cnote 3 NOTE_INSN_FUNCTION_BEG)
190 : (cinsn 6 (set (reg:SI <2>)
191 : (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
192 : (const_int -4)) [1 i+0 S4 A32])) "t.c":3)
193 : (cinsn 7 (parallel [
194 : (set (reg:SI <0> [ _2 ])
195 : (ashift:SI (reg:SI <2>)
196 : (const_int 1)))
197 : (clobber (reg:CC flags))
198 : ]) "t.c":3
199 : (expr_list:REG_EQUAL (ashift:SI (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
200 : (const_int -4)) [1 i+0 S4 A32])
201 : (const_int 1))))
202 : (cinsn 10 (set (reg:SI <1> [ <retval> ])
203 : (reg:SI <0> [ _2 ])) "t.c":3)
204 : (cinsn 14 (set (reg/i:SI ax)
205 : (reg:SI <1> [ <retval> ])) "t.c":4)
206 : (cinsn 15 (use (reg/i:SI ax)) "t.c":4)
207 : (edge-to exit (flags "FALLTHRU"))
208 : ) ;; block 2
209 : ) ;; insn-chain
210 : (crtl
211 : (return_rtx
212 : (reg/i:SI ax)
213 : ) ;; return_rtx
214 : ) ;; crtl
215 : ) ;; function "times_two"
216 : */
217 :
218 : DEBUG_FUNCTION void
219 4 : print_rtx_function (FILE *outfile, function *fn, bool compact)
220 : {
221 4 : rtx_reuse_manager r;
222 4 : rtx_writer w (outfile, 0, false, compact, &r);
223 :
224 : /* Support "reuse_rtx" in the dump. */
225 32 : for (rtx_insn *insn = get_insns (); insn; insn = NEXT_INSN (insn))
226 28 : r.preprocess (insn);
227 :
228 4 : tree fdecl = fn->decl;
229 :
230 4 : const char *dname = lang_hooks.decl_printable_name (fdecl, 1);
231 :
232 4 : fprintf (outfile, "(function \"%s\"\n", dname);
233 :
234 : /* Params. */
235 4 : for (tree arg = DECL_ARGUMENTS (fdecl); arg; arg = DECL_CHAIN (arg))
236 0 : print_param (outfile, w, arg);
237 :
238 : /* The instruction chain. */
239 4 : fprintf (outfile, " (insn-chain\n");
240 4 : basic_block curr_bb = NULL;
241 32 : for (rtx_insn *insn = get_insns (); insn; insn = NEXT_INSN (insn))
242 : {
243 28 : basic_block insn_bb;
244 28 : if (can_have_basic_block_p (insn))
245 28 : insn_bb = BLOCK_FOR_INSN (insn);
246 : else
247 : insn_bb = NULL;
248 28 : if (curr_bb != insn_bb)
249 : {
250 4 : end_any_block (outfile, curr_bb);
251 4 : curr_bb = insn_bb;
252 4 : begin_any_block (outfile, curr_bb);
253 : }
254 32 : w.print_rtl_single_with_indent (insn, curr_bb ? 6 : 4);
255 : }
256 4 : end_any_block (outfile, curr_bb);
257 4 : fprintf (outfile, " ) ;; insn-chain\n");
258 :
259 : /* Additional RTL state. */
260 4 : fprintf (outfile, " (crtl\n");
261 4 : fprintf (outfile, " (return_rtx \n");
262 4 : w.print_rtl_single_with_indent (crtl->return_rtx, 6);
263 4 : fprintf (outfile, " ) ;; return_rtx\n");
264 4 : fprintf (outfile, " ) ;; crtl\n");
265 :
266 4 : fprintf (outfile, ") ;; function \"%s\"\n", dname);
267 4 : }
|