1 /* Subroutines for log output for Atmel AVR back end. 2 Copyright (C) 2011-2013 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 "tree.h" 27 #include "output.h" 28 #include "input.h" 29 #include "function.h" 30 #include "tm_p.h" 31 #include "tree-pass.h" /* for current_pass */ 32 33 /* This file supplies some functions for AVR back-end developers 34 with a printf-like interface. The functions are called through 35 macros avr_edump or avr_fdump from avr-protos.h: 36 37 avr_edump (const char *fmt, ...); 38 39 avr_fdump (FILE *stream, const char *fmt, ...); 40 41 avr_edump (fmt, ...) is a shortcut for avr_fdump (stderr, 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: enum machine_mode 51 R: enum reg_class 52 D: double_int (signed decimal) 53 X: double_int (unsigned hex) 54 L: insn list 55 H: location_t 56 57 == no arguments == 58 59 A: call abort() 60 f: current_function_name() 61 F: caller (via __FUNCTION__) 62 P: Pass name and number 63 ?: Print caller, current function and pass info 64 !: Ditto, but only print if in a pass with static pass number, 65 else return. 66 67 == same as printf == 68 69 %: % 70 c: char 71 s: string 72 d: int (decimal) 73 x: int (hex) 74 */ 75 76 /* Set according to -mlog= option. */ 77 avr_log_t avr_log; 78 79 /* The caller as of __FUNCTION__ */ 80 static const char *avr_log_caller = "?"; 81 82 /* The worker function implementing the %-codes */ 83 static void avr_log_vadump (FILE*, const char*, va_list); 84 85 /* As we have no variadic macros, avr_edump maps to a call to 86 avr_log_set_caller_e which saves __FUNCTION__ to avr_log_caller and 87 returns a function pointer to avr_log_fdump_e. avr_log_fdump_e 88 gets the printf-like arguments and calls avr_log_vadump, the 89 worker function. avr_fdump works the same way. */ 90 91 /* Provide avr_log_fdump_e/f so that avr_log_set_caller_e/_f can return 92 their address. */ 93 94 static int 95 avr_log_fdump_e (const char *fmt, ...) 96 { 97 va_list ap; 98 99 va_start (ap, fmt); 100 avr_log_vadump (stderr, fmt, ap); 101 va_end (ap); 102 103 return 1; 104 } 105 106 static int 107 avr_log_fdump_f (FILE *stream, const char *fmt, ...) 108 { 109 va_list ap; 110 111 va_start (ap, fmt); 112 if (stream) 113 avr_log_vadump (stream, fmt, ap); 114 va_end (ap); 115 116 return 1; 117 } 118 119 /* Macros avr_edump/avr_fdump map to calls of the following two functions, 120 respectively. You don't need to call them directly. */ 121 122 int (* 123 avr_log_set_caller_e (const char *caller) 124 )(const char*, ...) 125 { 126 avr_log_caller = caller; 127 128 return avr_log_fdump_e; 129 } 130 131 int (* 132 avr_log_set_caller_f (const char *caller) 133 )(FILE*, const char*, ...) 134 { 135 avr_log_caller = caller; 136 137 return avr_log_fdump_f; 138 } 139 140 141 /* Copy-paste from double-int.c:double_int_split_digit (it's static there). 142 Splits last digit of *CST (taken as unsigned) in BASE and returns it. */ 143 144 static unsigned 145 avr_double_int_pop_digit (double_int *cst, unsigned base) 146 { 147 double_int drem; 148 149 *cst = cst->udivmod (double_int::from_uhwi (base), (int) FLOOR_DIV_EXPR, 150 &drem); 151 152 return (unsigned) drem.to_uhwi(); 153 } 154 155 156 /* Dump VAL as hex value to FILE. */ 157 158 static void 159 avr_dump_double_int_hex (FILE *file, double_int val) 160 { 161 unsigned digit[4]; 162 163 digit[0] = avr_double_int_pop_digit (&val, 1 << 16); 164 digit[1] = avr_double_int_pop_digit (&val, 1 << 16); 165 digit[2] = avr_double_int_pop_digit (&val, 1 << 16); 166 digit[3] = avr_double_int_pop_digit (&val, 1 << 16); 167 168 fprintf (file, "0x"); 169 170 if (digit[3] | digit[2]) 171 fprintf (file, "%04x%04x", digit[3], digit[2]); 172 173 if (digit[3] | digit[2] | digit[1] | digit[0]) 174 fprintf (file, "%04x%04x", digit[1], digit[0]); 175 else 176 fprintf (file, "0"); 177 } 178 179 180 /* Worker function implementing the %-codes and forwarding to 181 respective print/dump function. */ 182 183 static void 184 avr_log_vadump (FILE *file, const char *fmt, va_list ap) 185 { 186 char bs[3] = {'\\', '?', '\0'}; 187 188 while (*fmt) 189 { 190 switch (*fmt++) 191 { 192 default: 193 fputc (*(fmt-1), file); 194 break; 195 196 case '\\': 197 bs[1] = *fmt++; 198 fputs (bs, file); 199 break; 200 201 case '%': 202 switch (*fmt++) 203 { 204 case '%': 205 fputc ('%', file); 206 break; 207 208 case 't': 209 { 210 tree t = va_arg (ap, tree); 211 if (NULL_TREE == t) 212 fprintf (file, "<NULL-TREE>"); 213 else 214 { 215 if (stderr == file) 216 debug_tree (t); 217 else 218 { 219 print_node (file, "", t, 0); 220 putc ('\n', file); 221 } 222 } 223 break; 224 } 225 226 case 'T': 227 print_node_brief (file, "", va_arg (ap, tree), 3); 228 break; 229 230 case 'd': 231 fprintf (file, "%d", va_arg (ap, int)); 232 break; 233 234 case 'D': 235 dump_double_int (file, va_arg (ap, double_int), false); 236 break; 237 238 case 'X': 239 avr_dump_double_int_hex (file, va_arg (ap, double_int)); 240 break; 241 242 case 'x': 243 fprintf (file, "%x", va_arg (ap, int)); 244 break; 245 246 case 'b': 247 fprintf (file, "%s", va_arg (ap, int) ? "true" : "false"); 248 break; 249 250 case 'c': 251 fputc (va_arg (ap, int), file); 252 break; 253 254 case 'r': 255 print_inline_rtx (file, va_arg (ap, rtx), 0); 256 break; 257 258 case 'L': 259 { 260 rtx insn = va_arg (ap, rtx); 261 262 while (insn) 263 { 264 print_inline_rtx (file, insn, 0); 265 fprintf (file, "\n"); 266 insn = NEXT_INSN (insn); 267 } 268 break; 269 } 270 271 case 'f': 272 if (cfun && cfun->decl) 273 fputs (current_function_name(), file); 274 break; 275 276 case 's': 277 { 278 const char *str = va_arg (ap, char*); 279 fputs (str ? str : "(null)", file); 280 } 281 break; 282 283 case 'm': 284 fputs (GET_MODE_NAME ((enum machine_mode) va_arg (ap, int)), 285 file); 286 break; 287 288 case 'C': 289 fputs (rtx_name[va_arg (ap, int)], file); 290 break; 291 292 case 'R': 293 fputs (reg_class_names[va_arg (ap, int)], file); 294 break; 295 296 case 'F': 297 fputs (avr_log_caller, file); 298 break; 299 300 case 'H': 301 { 302 location_t loc = va_arg (ap, location_t); 303 304 if (BUILTINS_LOCATION == loc) 305 fprintf (file, "<BUILTIN-LOCATION>"); 306 else if (UNKNOWN_LOCATION == loc) 307 fprintf (file, "<UNKNOWN-LOCATION>"); 308 else 309 fprintf (file, "%s:%d", 310 LOCATION_FILE (loc), LOCATION_LINE (loc)); 311 312 break; 313 } 314 315 case '!': 316 if (!current_pass) 317 return; 318 /* FALLTHRU */ 319 320 case '?': 321 avr_log_fdump_f (file, "%F[%f:%P]"); 322 break; 323 324 case 'P': 325 if (current_pass) 326 fprintf (file, "%s(%d)", 327 current_pass->name, 328 current_pass->static_pass_number); 329 else 330 fprintf (file, "pass=?"); 331 332 break; 333 334 case 'A': 335 fflush (file); 336 abort(); 337 338 default: 339 /* Unknown %-code: Stop printing */ 340 341 fprintf (file, "??? %%%c ???%s\n", *(fmt-1), fmt); 342 fmt = ""; 343 344 break; 345 } 346 break; /* % */ 347 } 348 } 349 350 fflush (file); 351 } 352 353 354 /* Called from avr.c:avr_option_override(). 355 Parse argument of -mlog= and set respective fields in avr_log. */ 356 357 void 358 avr_log_set_avr_log (void) 359 { 360 bool all = TARGET_ALL_DEBUG != 0; 361 362 if (all || avr_log_details) 363 { 364 /* Adding , at beginning and end of string makes searching easier. */ 365 366 char *str = (char*) alloca (3 + strlen (avr_log_details)); 367 bool info; 368 369 str[0] = ','; 370 strcat (stpcpy (str+1, avr_log_details), ","); 371 372 all |= NULL != strstr (str, ",all,"); 373 info = NULL != strstr (str, ",?,"); 374 375 if (info) 376 fprintf (stderr, "\n-mlog="); 377 378 #define SET_DUMP_DETAIL(S) \ 379 do { \ 380 avr_log.S = (all || NULL != strstr (str, "," #S ",")); \ 381 if (info) \ 382 fprintf (stderr, #S ","); \ 383 } while (0) 384 385 SET_DUMP_DETAIL (address_cost); 386 SET_DUMP_DETAIL (builtin); 387 SET_DUMP_DETAIL (constraints); 388 SET_DUMP_DETAIL (legitimate_address_p); 389 SET_DUMP_DETAIL (legitimize_address); 390 SET_DUMP_DETAIL (legitimize_reload_address); 391 SET_DUMP_DETAIL (progmem); 392 SET_DUMP_DETAIL (rtx_costs); 393 394 #undef SET_DUMP_DETAIL 395 396 if (info) 397 fprintf (stderr, "?\n\n"); 398 } 399 } 400