1 /* Print RTL functions for GCC.
2    Copyright (C) 2016-2018 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
print_edge(FILE * outfile,edge e,bool from)41 print_edge (FILE *outfile, edge e, bool from)
42 {
43   fprintf (outfile, "      (%s ", from ? "edge-from" : "edge-to");
44   basic_block bb = from ? e->src : e->dest;
45   gcc_assert (bb);
46   switch (bb->index)
47     {
48     case ENTRY_BLOCK:
49       fprintf (outfile, "entry");
50       break;
51     case EXIT_BLOCK:
52       fprintf (outfile, "exit");
53       break;
54     default:
55       fprintf (outfile, "%i", bb->index);
56       break;
57     }
58 
59   /* Express edge flags as a string with " | " separator.
60      e.g. (flags "FALLTHRU | DFS_BACK").  */
61   if (e->flags)
62     {
63       fprintf (outfile, " (flags \"");
64       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       fprintf (outfile, "\")");
79     }
80 
81   fprintf (outfile, ")\n");
82 }
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
begin_any_block(FILE * outfile,basic_block bb)88 begin_any_block (FILE *outfile, basic_block bb)
89 {
90   if (!bb)
91     return;
92 
93   edge e;
94   edge_iterator ei;
95 
96   fprintf (outfile, "    (block %i\n", bb->index);
97   FOR_EACH_EDGE (e, ei, bb->preds)
98     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
end_any_block(FILE * outfile,basic_block bb)105 end_any_block (FILE *outfile, basic_block bb)
106 {
107   if (!bb)
108     return;
109 
110   edge e;
111   edge_iterator ei;
112 
113   FOR_EACH_EDGE (e, ei, bb->succs)
114     print_edge (outfile, e, false);
115   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
can_have_basic_block_p(const rtx_insn * insn)121 can_have_basic_block_p (const rtx_insn *insn)
122 {
123   rtx_code code = GET_CODE (insn);
124   if (code == BARRIER)
125     return false;
126   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
print_any_param_name(FILE * outfile,tree arg)133 print_any_param_name (FILE *outfile, tree arg)
134 {
135   if (DECL_NAME (arg))
136     fprintf (outfile, " \"%s\"", IDENTIFIER_POINTER (DECL_NAME (arg)));
137 }
138 
139 /* Print a "(param)" directive for ARG to OUTFILE.  */
140 
141 static void
print_param(FILE * outfile,rtx_writer & w,tree arg)142 print_param (FILE *outfile, rtx_writer &w, tree arg)
143 {
144   fprintf (outfile, "  (param");
145   print_any_param_name (outfile, arg);
146   fprintf (outfile, "\n");
147 
148   /* Print the value of DECL_RTL (without lazy-evaluation).  */
149   fprintf (outfile, "    (DECL_RTL ");
150   w.print_rtx (DECL_RTL_IF_SET (arg));
151   w.finish_directive ();
152 
153   /* Print DECL_INCOMING_RTL.  */
154   fprintf (outfile, "    (DECL_RTL_INCOMING ");
155   w.print_rtx (DECL_INCOMING_RTL (arg));
156   fprintf (outfile, ")");
157 
158   w.finish_directive ();
159 }
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
print_rtx_function(FILE * outfile,function * fn,bool compact)219 print_rtx_function (FILE *outfile, function *fn, bool compact)
220 {
221   rtx_reuse_manager r;
222   rtx_writer w (outfile, 0, false, compact, &r);
223 
224   /* Support "reuse_rtx" in the dump.  */
225   for (rtx_insn *insn = get_insns (); insn; insn = NEXT_INSN (insn))
226     r.preprocess (insn);
227 
228   tree fdecl = fn->decl;
229 
230   const char *dname = lang_hooks.decl_printable_name (fdecl, 1);
231 
232   fprintf (outfile, "(function \"%s\"\n", dname);
233 
234   /* Params.  */
235   for (tree arg = DECL_ARGUMENTS (fdecl); arg; arg = DECL_CHAIN (arg))
236     print_param (outfile, w, arg);
237 
238   /* The instruction chain.  */
239   fprintf (outfile, "  (insn-chain\n");
240   basic_block curr_bb = NULL;
241   for (rtx_insn *insn = get_insns (); insn; insn = NEXT_INSN (insn))
242     {
243       basic_block insn_bb;
244       if (can_have_basic_block_p (insn))
245 	insn_bb = BLOCK_FOR_INSN (insn);
246       else
247 	insn_bb = NULL;
248       if (curr_bb != insn_bb)
249 	{
250 	  end_any_block (outfile, curr_bb);
251 	  curr_bb = insn_bb;
252 	  begin_any_block (outfile, curr_bb);
253 	}
254       w.print_rtl_single_with_indent (insn, curr_bb ? 6 : 4);
255     }
256   end_any_block (outfile, curr_bb);
257   fprintf (outfile, "  ) ;; insn-chain\n");
258 
259   /* Additional RTL state.  */
260   fprintf (outfile, "  (crtl\n");
261   fprintf (outfile, "    (return_rtx \n");
262   w.print_rtl_single_with_indent (crtl->return_rtx, 6);
263   fprintf (outfile, "    ) ;; return_rtx\n");
264   fprintf (outfile, "  ) ;; crtl\n");
265 
266   fprintf (outfile, ") ;; function \"%s\"\n", dname);
267 }
268