1/* Subroutines for log output for Atmel AVR back end. 2 Copyright (C) 2011-2022 Free Software Foundation, Inc. 3 Contributed by Georg-Johann Lay (avr@gjlay.de) 4 5 This file is part of GCC. 6 7 GCC is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3, or (at your option) 10 any later version. 11 12 GCC is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with GCC; see the file COPYING3. If not see 19 <http://www.gnu.org/licenses/>. */ 20 21#define IN_TARGET_CODE 1 22 23#include "config.h" 24#include "system.h" 25#include "coretypes.h" 26#include "tm.h" 27#include "function.h" 28#include "rtl.h" 29#include "tree.h" 30#include "tree-pass.h" /* for current_pass */ 31#include "memmodel.h" 32#include "tm_p.h" 33#include "print-tree.h" 34 35/* This file supplies some functions for AVR back-end developers 36 with a printf-like interface. The functions are called through 37 macros `avr_dump', `avr_edump' or `avr_fdump' from avr-protos.h: 38 39 avr_fdump (FILE *stream, const char *fmt, ...); 40 avr_edump (fmt, ...) is a shortcut for avr_fdump (stderr, fmt, ...) 41 avr_dump (fmt, ...) is a shortcut for avr_fdump (dump_file, fmt, ...) 42 43 == known %-codes == 44 45 b: bool 46 r: rtx 47 t: tree 48 T: tree (brief) 49 C: enum rtx_code 50 m: machine_mode 51 R: enum reg_class 52 L: insn list 53 H: location_t 54 55 == no arguments == 56 57 A: call abort() 58 f: current_function_name() 59 F: caller (via __FUNCTION__) 60 P: Pass name and number 61 ?: Print caller, current function and pass info 62 !: Ditto, but only print if in a pass with static pass number, 63 else return. 64 65 == same as printf == 66 67 %: % 68 c: char 69 s: string 70 d: int (decimal) 71 x: int (hex) 72*/ 73 74/* Set according to -mlog= option. */ 75avr_log_t avr_log; 76 77/* The worker function implementing the %-codes */ 78static void avr_log_vadump (FILE*, const char*, va_list); 79 80/* Wrapper for avr_log_vadump. If STREAM is NULL we are called by avr_dump, 81 i.e. output to dump_file if available. The 2nd argument is __FUNCTION__. 82 The 3rd argument is the format string. */ 83 84int 85avr_vdump (FILE *stream, const char *caller, ...) 86{ 87 va_list ap; 88 89 if (stream == NULL && dump_file) 90 stream = dump_file; 91 92 va_start (ap, caller); 93 if (stream) 94 avr_log_vadump (stream, caller, ap); 95 va_end (ap); 96 97 return 1; 98} 99 100 101/* Worker function implementing the %-codes and forwarding to 102 respective print/dump function. */ 103 104static void 105avr_log_vadump (FILE *file, const char *caller, va_list ap) 106{ 107 char bs[3] = {'\\', '?', '\0'}; 108 109 /* 3rd proper argument is always the format string. */ 110 const char *fmt = va_arg (ap, const char*); 111 112 while (*fmt) 113 { 114 switch (*fmt++) 115 { 116 default: 117 fputc (*(fmt-1), file); 118 break; 119 120 case '\\': 121 bs[1] = *fmt++; 122 fputs (bs, file); 123 break; 124 125 case '%': 126 switch (*fmt++) 127 { 128 case '%': 129 fputc ('%', file); 130 break; 131 132 case 't': 133 { 134 tree t = va_arg (ap, tree); 135 if (NULL_TREE == t) 136 fprintf (file, "<NULL-TREE>"); 137 else 138 { 139 if (stderr == file) 140 debug_tree (t); 141 else 142 { 143 print_node (file, "", t, 0); 144 putc ('\n', file); 145 } 146 } 147 break; 148 } 149 150 case 'T': 151 { 152 tree t = va_arg (ap, tree); 153 if (NULL_TREE == t) 154 fprintf (file, "<NULL-TREE>"); 155 else 156 print_node_brief (file, "", t, 3); 157 } 158 break; 159 160 case 'd': 161 fprintf (file, "%d", va_arg (ap, int)); 162 break; 163 164 case 'x': 165 fprintf (file, "%x", va_arg (ap, int)); 166 break; 167 168 case 'b': 169 fprintf (file, "%s", va_arg (ap, int) ? "true" : "false"); 170 break; 171 172 case 'c': 173 fputc (va_arg (ap, int), file); 174 break; 175 176 case 'r': 177 print_inline_rtx (file, va_arg (ap, rtx), 0); 178 break; 179 180 case 'L': 181 { 182 rtx_insn *insn = safe_as_a <rtx_insn *> (va_arg (ap, rtx)); 183 184 while (insn) 185 { 186 print_inline_rtx (file, insn, 0); 187 fprintf (file, "\n"); 188 insn = NEXT_INSN (insn); 189 } 190 break; 191 } 192 193 case 'f': 194 if (cfun && cfun->decl) 195 fputs (current_function_name(), file); 196 break; 197 198 case 's': 199 { 200 const char *str = va_arg (ap, char*); 201 fputs (str ? str : "(null)", file); 202 } 203 break; 204 205 case 'm': 206 fputs (GET_MODE_NAME ((machine_mode) va_arg (ap, int)), 207 file); 208 break; 209 210 case 'C': 211 fputs (rtx_name[va_arg (ap, int)], file); 212 break; 213 214 case 'R': 215 fputs (reg_class_names[va_arg (ap, int)], file); 216 break; 217 218 case 'F': 219 fputs (caller, file); 220 break; 221 222 case 'H': 223 { 224 location_t loc = va_arg (ap, location_t); 225 226 if (BUILTINS_LOCATION == loc) 227 fprintf (file, "<BUILTIN-LOCATION>"); 228 else if (UNKNOWN_LOCATION == loc) 229 fprintf (file, "<UNKNOWN-LOCATION>"); 230 else 231 fprintf (file, "%s:%d", 232 LOCATION_FILE (loc), LOCATION_LINE (loc)); 233 234 break; 235 } 236 237 case '!': 238 if (!current_pass) 239 return; 240 /* FALLTHRU */ 241 242 case '?': 243 avr_vdump (file, caller, "%F[%f:%P]"); 244 break; 245 246 case 'P': 247 if (current_pass) 248 fprintf (file, "%s(%d)", 249 current_pass->name, 250 current_pass->static_pass_number); 251 else 252 fprintf (file, "pass=?"); 253 254 break; 255 256 case 'A': 257 fflush (file); 258 abort(); 259 260 default: 261 /* Unknown %-code: Stop printing */ 262 263 fprintf (file, "??? %%%c ???%s\n", *(fmt-1), fmt); 264 fmt = ""; 265 266 break; 267 } 268 break; /* % */ 269 } 270 } 271 272 fflush (file); 273} 274 275 276/* Called from avr.cc:avr_option_override(). 277 Parse argument of -mlog= and set respective fields in avr_log. */ 278 279void 280avr_log_set_avr_log (void) 281{ 282 bool all = TARGET_ALL_DEBUG != 0; 283 284 if (all) 285 avr_log_details = "all"; 286 287 if (all || avr_log_details) 288 { 289 /* Adding , at beginning and end of string makes searching easier. */ 290 291 char *str = (char*) alloca (3 + strlen (avr_log_details)); 292 bool info; 293 294 str[0] = ','; 295 strcat (stpcpy (str+1, avr_log_details), ","); 296 297 all |= strstr (str, ",all,") != NULL; 298 info = strstr (str, ",?,") != NULL; 299 300 if (info) 301 fprintf (stderr, "\n-mlog="); 302 303#define SET_DUMP_DETAIL(S) \ 304 do { \ 305 avr_log.S = (all || strstr (str, "," #S ",") != NULL); \ 306 if (info) \ 307 fprintf (stderr, #S ","); \ 308 } while (0) 309 310 SET_DUMP_DETAIL (address_cost); 311 SET_DUMP_DETAIL (builtin); 312 SET_DUMP_DETAIL (constraints); 313 SET_DUMP_DETAIL (insn_addresses); 314 SET_DUMP_DETAIL (legitimate_address_p); 315 SET_DUMP_DETAIL (legitimize_address); 316 SET_DUMP_DETAIL (legitimize_reload_address); 317 SET_DUMP_DETAIL (progmem); 318 SET_DUMP_DETAIL (rtx_costs); 319 320#undef SET_DUMP_DETAIL 321 322 if (info) 323 fprintf (stderr, "?\n\n"); 324 } 325} 326