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