xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/print-rtl-function.c (revision 4c3eb207d36f67d31994830c0a694161fc1ca39b)
13ad841b2Smrg /* Print RTL functions for GCC.
2*4c3eb207Smrg    Copyright (C) 2016-2020 Free Software Foundation, Inc.
33ad841b2Smrg 
43ad841b2Smrg This file is part of GCC.
53ad841b2Smrg 
63ad841b2Smrg GCC is free software; you can redistribute it and/or modify it under
73ad841b2Smrg the terms of the GNU General Public License as published by the Free
83ad841b2Smrg Software Foundation; either version 3, or (at your option) any later
93ad841b2Smrg version.
103ad841b2Smrg 
113ad841b2Smrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
123ad841b2Smrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
133ad841b2Smrg FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
143ad841b2Smrg for more details.
153ad841b2Smrg 
163ad841b2Smrg You should have received a copy of the GNU General Public License
173ad841b2Smrg along with GCC; see the file COPYING3.  If not see
183ad841b2Smrg <http://www.gnu.org/licenses/>.  */
193ad841b2Smrg 
203ad841b2Smrg #include "config.h"
213ad841b2Smrg #include "system.h"
223ad841b2Smrg #include "coretypes.h"
233ad841b2Smrg #include "tm.h"
243ad841b2Smrg #include "rtl.h"
253ad841b2Smrg #include "alias.h"
263ad841b2Smrg #include "tree.h"
273ad841b2Smrg #include "flags.h"
283ad841b2Smrg #include "predict.h"
293ad841b2Smrg #include "function.h"
303ad841b2Smrg #include "basic-block.h"
313ad841b2Smrg #include "print-rtl.h"
323ad841b2Smrg #include "langhooks.h"
333ad841b2Smrg #include "memmodel.h"
343ad841b2Smrg #include "emit-rtl.h"
353ad841b2Smrg #include "varasm.h"
363ad841b2Smrg 
373ad841b2Smrg /* Print an "(edge-from)" or "(edge-to)" directive describing E
383ad841b2Smrg    to OUTFILE.  */
393ad841b2Smrg 
403ad841b2Smrg static void
print_edge(FILE * outfile,edge e,bool from)413ad841b2Smrg print_edge (FILE *outfile, edge e, bool from)
423ad841b2Smrg {
433ad841b2Smrg   fprintf (outfile, "      (%s ", from ? "edge-from" : "edge-to");
443ad841b2Smrg   basic_block bb = from ? e->src : e->dest;
453ad841b2Smrg   gcc_assert (bb);
463ad841b2Smrg   switch (bb->index)
473ad841b2Smrg     {
483ad841b2Smrg     case ENTRY_BLOCK:
493ad841b2Smrg       fprintf (outfile, "entry");
503ad841b2Smrg       break;
513ad841b2Smrg     case EXIT_BLOCK:
523ad841b2Smrg       fprintf (outfile, "exit");
533ad841b2Smrg       break;
543ad841b2Smrg     default:
553ad841b2Smrg       fprintf (outfile, "%i", bb->index);
563ad841b2Smrg       break;
573ad841b2Smrg     }
583ad841b2Smrg 
593ad841b2Smrg   /* Express edge flags as a string with " | " separator.
603ad841b2Smrg      e.g. (flags "FALLTHRU | DFS_BACK").  */
613ad841b2Smrg   if (e->flags)
623ad841b2Smrg     {
633ad841b2Smrg       fprintf (outfile, " (flags \"");
643ad841b2Smrg       bool seen_flag = false;
653ad841b2Smrg #define DEF_EDGE_FLAG(NAME,IDX)			\
663ad841b2Smrg   do {						\
673ad841b2Smrg     if (e->flags & EDGE_##NAME)			\
683ad841b2Smrg       {						\
693ad841b2Smrg 	if (seen_flag)				\
703ad841b2Smrg 	  fprintf (outfile, " | ");		\
713ad841b2Smrg 	fprintf (outfile, "%s", (#NAME));	\
723ad841b2Smrg 	seen_flag = true;			\
733ad841b2Smrg       }						\
743ad841b2Smrg   } while (0);
753ad841b2Smrg #include "cfg-flags.def"
763ad841b2Smrg #undef DEF_EDGE_FLAG
773ad841b2Smrg 
783ad841b2Smrg       fprintf (outfile, "\")");
793ad841b2Smrg     }
803ad841b2Smrg 
813ad841b2Smrg   fprintf (outfile, ")\n");
823ad841b2Smrg }
833ad841b2Smrg 
843ad841b2Smrg /* If BB is non-NULL, print the start of a "(block)" directive for it
853ad841b2Smrg    to OUTFILE, otherwise do nothing.  */
863ad841b2Smrg 
873ad841b2Smrg static void
begin_any_block(FILE * outfile,basic_block bb)883ad841b2Smrg begin_any_block (FILE *outfile, basic_block bb)
893ad841b2Smrg {
903ad841b2Smrg   if (!bb)
913ad841b2Smrg     return;
923ad841b2Smrg 
933ad841b2Smrg   edge e;
943ad841b2Smrg   edge_iterator ei;
953ad841b2Smrg 
963ad841b2Smrg   fprintf (outfile, "    (block %i\n", bb->index);
973ad841b2Smrg   FOR_EACH_EDGE (e, ei, bb->preds)
983ad841b2Smrg     print_edge (outfile, e, true);
993ad841b2Smrg }
1003ad841b2Smrg 
1013ad841b2Smrg /* If BB is non-NULL, print the end of a "(block)" directive for it
1023ad841b2Smrg    to OUTFILE, otherwise do nothing.  */
1033ad841b2Smrg 
1043ad841b2Smrg static void
end_any_block(FILE * outfile,basic_block bb)1053ad841b2Smrg end_any_block (FILE *outfile, basic_block bb)
1063ad841b2Smrg {
1073ad841b2Smrg   if (!bb)
1083ad841b2Smrg     return;
1093ad841b2Smrg 
1103ad841b2Smrg   edge e;
1113ad841b2Smrg   edge_iterator ei;
1123ad841b2Smrg 
1133ad841b2Smrg   FOR_EACH_EDGE (e, ei, bb->succs)
1143ad841b2Smrg     print_edge (outfile, e, false);
1153ad841b2Smrg   fprintf (outfile, "    ) ;; block %i\n", bb->index);
1163ad841b2Smrg }
1173ad841b2Smrg 
1183ad841b2Smrg /* Determine if INSN is of a kind that can have a basic block.  */
1193ad841b2Smrg 
1203ad841b2Smrg static bool
can_have_basic_block_p(const rtx_insn * insn)1213ad841b2Smrg can_have_basic_block_p (const rtx_insn *insn)
1223ad841b2Smrg {
1233ad841b2Smrg   rtx_code code = GET_CODE (insn);
1243ad841b2Smrg   if (code == BARRIER)
1253ad841b2Smrg     return false;
1263ad841b2Smrg   gcc_assert (GET_RTX_FORMAT (code)[2] == 'B');
1273ad841b2Smrg   return true;
1283ad841b2Smrg }
1293ad841b2Smrg 
1303ad841b2Smrg /* Subroutine of print_param.  Write the name of ARG, if any, to OUTFILE.  */
1313ad841b2Smrg 
1323ad841b2Smrg static void
print_any_param_name(FILE * outfile,tree arg)1333ad841b2Smrg print_any_param_name (FILE *outfile, tree arg)
1343ad841b2Smrg {
1353ad841b2Smrg   if (DECL_NAME (arg))
1363ad841b2Smrg     fprintf (outfile, " \"%s\"", IDENTIFIER_POINTER (DECL_NAME (arg)));
1373ad841b2Smrg }
1383ad841b2Smrg 
1393ad841b2Smrg /* Print a "(param)" directive for ARG to OUTFILE.  */
1403ad841b2Smrg 
1413ad841b2Smrg static void
print_param(FILE * outfile,rtx_writer & w,tree arg)1423ad841b2Smrg print_param (FILE *outfile, rtx_writer &w, tree arg)
1433ad841b2Smrg {
1443ad841b2Smrg   fprintf (outfile, "  (param");
1453ad841b2Smrg   print_any_param_name (outfile, arg);
1463ad841b2Smrg   fprintf (outfile, "\n");
1473ad841b2Smrg 
1483ad841b2Smrg   /* Print the value of DECL_RTL (without lazy-evaluation).  */
1493ad841b2Smrg   fprintf (outfile, "    (DECL_RTL ");
1503ad841b2Smrg   w.print_rtx (DECL_RTL_IF_SET (arg));
1513ad841b2Smrg   w.finish_directive ();
1523ad841b2Smrg 
1533ad841b2Smrg   /* Print DECL_INCOMING_RTL.  */
1543ad841b2Smrg   fprintf (outfile, "    (DECL_RTL_INCOMING ");
1553ad841b2Smrg   w.print_rtx (DECL_INCOMING_RTL (arg));
1563ad841b2Smrg   fprintf (outfile, ")");
1573ad841b2Smrg 
1583ad841b2Smrg   w.finish_directive ();
1593ad841b2Smrg }
1603ad841b2Smrg 
1613ad841b2Smrg /* Write FN to OUTFILE in a form suitable for parsing, with indentation
1623ad841b2Smrg    and comments to make the structure easy for a human to grok.  Track
1633ad841b2Smrg    the basic blocks of insns in the chain, wrapping those that are within
1643ad841b2Smrg    blocks within "(block)" directives.
1653ad841b2Smrg 
1663ad841b2Smrg    If COMPACT, then instructions are printed in a compact form:
1673ad841b2Smrg    - INSN_UIDs are omitted, except for jumps and CODE_LABELs,
1683ad841b2Smrg    - INSN_CODEs are omitted,
1693ad841b2Smrg    - register numbers are omitted for hard and virtual regs, and
1703ad841b2Smrg      non-virtual pseudos are offset relative to the first such reg, and
1713ad841b2Smrg      printed with a '%' sigil e.g. "%0" for (LAST_VIRTUAL_REGISTER + 1),
1723ad841b2Smrg    - insn names are prefixed with "c" (e.g. "cinsn", "cnote", etc)
1733ad841b2Smrg 
1743ad841b2Smrg    Example output (with COMPACT==true):
1753ad841b2Smrg 
1763ad841b2Smrg    (function "times_two"
1773ad841b2Smrg      (param "i"
1783ad841b2Smrg        (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
1793ad841b2Smrg 	   (const_int -4)) [1 i+0 S4 A32]))
1803ad841b2Smrg        (DECL_RTL_INCOMING (reg:SI di [ i ])))
1813ad841b2Smrg      (insn-chain
1823ad841b2Smrg        (cnote 1 NOTE_INSN_DELETED)
1833ad841b2Smrg        (block 2
1843ad841b2Smrg 	 (edge-from entry (flags "FALLTHRU"))
1853ad841b2Smrg 	 (cnote 4 [bb 2] NOTE_INSN_BASIC_BLOCK)
1863ad841b2Smrg 	 (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
1873ad841b2Smrg 			       (const_int -4)) [1 i+0 S4 A32])
1883ad841b2Smrg 		       (reg:SI di [ i ])) "t.c":2)
1893ad841b2Smrg 	 (cnote 3 NOTE_INSN_FUNCTION_BEG)
1903ad841b2Smrg 	 (cinsn 6 (set (reg:SI <2>)
1913ad841b2Smrg 		       (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
1923ad841b2Smrg 			       (const_int -4)) [1 i+0 S4 A32])) "t.c":3)
1933ad841b2Smrg 	 (cinsn 7 (parallel [
1943ad841b2Smrg 			   (set (reg:SI <0> [ _2 ])
1953ad841b2Smrg 			       (ashift:SI (reg:SI <2>)
1963ad841b2Smrg 				   (const_int 1)))
1973ad841b2Smrg 			   (clobber (reg:CC flags))
1983ad841b2Smrg 		       ]) "t.c":3
1993ad841b2Smrg 		    (expr_list:REG_EQUAL (ashift:SI (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
2003ad841b2Smrg 				   (const_int -4)) [1 i+0 S4 A32])
2013ad841b2Smrg 			   (const_int 1))))
2023ad841b2Smrg 	 (cinsn 10 (set (reg:SI <1> [ <retval> ])
2033ad841b2Smrg 		       (reg:SI <0> [ _2 ])) "t.c":3)
2043ad841b2Smrg 	 (cinsn 14 (set (reg/i:SI ax)
2053ad841b2Smrg 		       (reg:SI <1> [ <retval> ])) "t.c":4)
2063ad841b2Smrg 	 (cinsn 15 (use (reg/i:SI ax)) "t.c":4)
2073ad841b2Smrg 	 (edge-to exit (flags "FALLTHRU"))
2083ad841b2Smrg        ) ;; block 2
2093ad841b2Smrg      ) ;; insn-chain
2103ad841b2Smrg      (crtl
2113ad841b2Smrg        (return_rtx
2123ad841b2Smrg 	 (reg/i:SI ax)
2133ad841b2Smrg        ) ;; return_rtx
2143ad841b2Smrg      ) ;; crtl
2153ad841b2Smrg    ) ;; function "times_two"
2163ad841b2Smrg */
2173ad841b2Smrg 
2183ad841b2Smrg DEBUG_FUNCTION void
print_rtx_function(FILE * outfile,function * fn,bool compact)2193ad841b2Smrg print_rtx_function (FILE *outfile, function *fn, bool compact)
2203ad841b2Smrg {
2213ad841b2Smrg   rtx_reuse_manager r;
2223ad841b2Smrg   rtx_writer w (outfile, 0, false, compact, &r);
2233ad841b2Smrg 
2243ad841b2Smrg   /* Support "reuse_rtx" in the dump.  */
2253ad841b2Smrg   for (rtx_insn *insn = get_insns (); insn; insn = NEXT_INSN (insn))
2263ad841b2Smrg     r.preprocess (insn);
2273ad841b2Smrg 
2283ad841b2Smrg   tree fdecl = fn->decl;
2293ad841b2Smrg 
230cef8759bSmrg   const char *dname = lang_hooks.decl_printable_name (fdecl, 1);
2313ad841b2Smrg 
2323ad841b2Smrg   fprintf (outfile, "(function \"%s\"\n", dname);
2333ad841b2Smrg 
2343ad841b2Smrg   /* Params.  */
2353ad841b2Smrg   for (tree arg = DECL_ARGUMENTS (fdecl); arg; arg = DECL_CHAIN (arg))
2363ad841b2Smrg     print_param (outfile, w, arg);
2373ad841b2Smrg 
2383ad841b2Smrg   /* The instruction chain.  */
2393ad841b2Smrg   fprintf (outfile, "  (insn-chain\n");
2403ad841b2Smrg   basic_block curr_bb = NULL;
2413ad841b2Smrg   for (rtx_insn *insn = get_insns (); insn; insn = NEXT_INSN (insn))
2423ad841b2Smrg     {
2433ad841b2Smrg       basic_block insn_bb;
2443ad841b2Smrg       if (can_have_basic_block_p (insn))
2453ad841b2Smrg 	insn_bb = BLOCK_FOR_INSN (insn);
2463ad841b2Smrg       else
2473ad841b2Smrg 	insn_bb = NULL;
2483ad841b2Smrg       if (curr_bb != insn_bb)
2493ad841b2Smrg 	{
2503ad841b2Smrg 	  end_any_block (outfile, curr_bb);
2513ad841b2Smrg 	  curr_bb = insn_bb;
2523ad841b2Smrg 	  begin_any_block (outfile, curr_bb);
2533ad841b2Smrg 	}
2543ad841b2Smrg       w.print_rtl_single_with_indent (insn, curr_bb ? 6 : 4);
2553ad841b2Smrg     }
2563ad841b2Smrg   end_any_block (outfile, curr_bb);
2573ad841b2Smrg   fprintf (outfile, "  ) ;; insn-chain\n");
2583ad841b2Smrg 
2593ad841b2Smrg   /* Additional RTL state.  */
2603ad841b2Smrg   fprintf (outfile, "  (crtl\n");
2613ad841b2Smrg   fprintf (outfile, "    (return_rtx \n");
2623ad841b2Smrg   w.print_rtl_single_with_indent (crtl->return_rtx, 6);
2633ad841b2Smrg   fprintf (outfile, "    ) ;; return_rtx\n");
2643ad841b2Smrg   fprintf (outfile, "  ) ;; crtl\n");
2653ad841b2Smrg 
2663ad841b2Smrg   fprintf (outfile, ") ;; function \"%s\"\n", dname);
2673ad841b2Smrg }
268