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