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