1/* Print RTL functions for GCC.
2   Copyright (C) 2016-2020 Free Software Foundation, Inc.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free
8Software Foundation; either version 3, or (at your option) any later
9version.
10
11GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or
13FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14for more details.
15
16You should have received a copy of the GNU General Public License
17along 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
40static void
41print_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
87static void
88begin_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
104static void
105end_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
120static bool
121can_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
132static void
133print_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
141static void
142print_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
218DEBUG_FUNCTION void
219print_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