Branch data Line data Source code
1 : : /* Print RTL functions for GCC.
2 : : Copyright (C) 2016-2025 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 : }
|