/* Subroutines for log output for Atmel AVR back end. Copyright (C) 2011-2014 Free Software Foundation, Inc. Contributed by Georg-Johann Lay (avr@gjlay.de) This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #include "config.h" #include "system.h" #include "coretypes.h" #include "tm.h" #include "rtl.h" #include "tree.h" #include "print-tree.h" #include "output.h" #include "input.h" #include "function.h" #include "tm_p.h" #include "tree-pass.h" /* for current_pass */ /* This file supplies some functions for AVR back-end developers with a printf-like interface. The functions are called through macros avr_edump or avr_fdump from avr-protos.h: avr_edump (const char *fmt, ...); avr_fdump (FILE *stream, const char *fmt, ...); avr_edump (fmt, ...) is a shortcut for avr_fdump (stderr, fmt, ...) == known %-codes == b: bool r: rtx t: tree T: tree (brief) C: enum rtx_code m: enum machine_mode R: enum reg_class L: insn list H: location_t == no arguments == A: call abort() f: current_function_name() F: caller (via __FUNCTION__) P: Pass name and number ?: Print caller, current function and pass info !: Ditto, but only print if in a pass with static pass number, else return. == same as printf == %: % c: char s: string d: int (decimal) x: int (hex) */ /* Set according to -mlog= option. */ avr_log_t avr_log; /* The caller as of __FUNCTION__ */ static const char *avr_log_caller = "?"; /* The worker function implementing the %-codes */ static void avr_log_vadump (FILE*, const char*, va_list); /* As we have no variadic macros, avr_edump maps to a call to avr_log_set_caller_e which saves __FUNCTION__ to avr_log_caller and returns a function pointer to avr_log_fdump_e. avr_log_fdump_e gets the printf-like arguments and calls avr_log_vadump, the worker function. avr_fdump works the same way. */ /* Provide avr_log_fdump_e/f so that avr_log_set_caller_e/_f can return their address. */ static int avr_log_fdump_e (const char *fmt, ...) { va_list ap; va_start (ap, fmt); avr_log_vadump (stderr, fmt, ap); va_end (ap); return 1; } static int avr_log_fdump_f (FILE *stream, const char *fmt, ...) { va_list ap; va_start (ap, fmt); if (stream) avr_log_vadump (stream, fmt, ap); va_end (ap); return 1; } /* Macros avr_edump/avr_fdump map to calls of the following two functions, respectively. You don't need to call them directly. */ int (* avr_log_set_caller_e (const char *caller) )(const char*, ...) { avr_log_caller = caller; return avr_log_fdump_e; } int (* avr_log_set_caller_f (const char *caller) )(FILE*, const char*, ...) { avr_log_caller = caller; return avr_log_fdump_f; } /* Worker function implementing the %-codes and forwarding to respective print/dump function. */ static void avr_log_vadump (FILE *file, const char *fmt, va_list ap) { char bs[3] = {'\\', '?', '\0'}; while (*fmt) { switch (*fmt++) { default: fputc (*(fmt-1), file); break; case '\\': bs[1] = *fmt++; fputs (bs, file); break; case '%': switch (*fmt++) { case '%': fputc ('%', file); break; case 't': { tree t = va_arg (ap, tree); if (NULL_TREE == t) fprintf (file, ""); else { if (stderr == file) debug_tree (t); else { print_node (file, "", t, 0); putc ('\n', file); } } break; } case 'T': print_node_brief (file, "", va_arg (ap, tree), 3); break; case 'd': fprintf (file, "%d", va_arg (ap, int)); break; case 'x': fprintf (file, "%x", va_arg (ap, int)); break; case 'b': fprintf (file, "%s", va_arg (ap, int) ? "true" : "false"); break; case 'c': fputc (va_arg (ap, int), file); break; case 'r': print_inline_rtx (file, va_arg (ap, rtx), 0); break; case 'L': { rtx insn = va_arg (ap, rtx); while (insn) { print_inline_rtx (file, insn, 0); fprintf (file, "\n"); insn = NEXT_INSN (insn); } break; } case 'f': if (cfun && cfun->decl) fputs (current_function_name(), file); break; case 's': { const char *str = va_arg (ap, char*); fputs (str ? str : "(null)", file); } break; case 'm': fputs (GET_MODE_NAME ((enum machine_mode) va_arg (ap, int)), file); break; case 'C': fputs (rtx_name[va_arg (ap, int)], file); break; case 'R': fputs (reg_class_names[va_arg (ap, int)], file); break; case 'F': fputs (avr_log_caller, file); break; case 'H': { location_t loc = va_arg (ap, location_t); if (BUILTINS_LOCATION == loc) fprintf (file, ""); else if (UNKNOWN_LOCATION == loc) fprintf (file, ""); else fprintf (file, "%s:%d", LOCATION_FILE (loc), LOCATION_LINE (loc)); break; } case '!': if (!current_pass) return; /* FALLTHRU */ case '?': avr_log_fdump_f (file, "%F[%f:%P]"); break; case 'P': if (current_pass) fprintf (file, "%s(%d)", current_pass->name, current_pass->static_pass_number); else fprintf (file, "pass=?"); break; case 'A': fflush (file); abort(); default: /* Unknown %-code: Stop printing */ fprintf (file, "??? %%%c ???%s\n", *(fmt-1), fmt); fmt = ""; break; } break; /* % */ } } fflush (file); } /* Called from avr.c:avr_option_override(). Parse argument of -mlog= and set respective fields in avr_log. */ void avr_log_set_avr_log (void) { bool all = TARGET_ALL_DEBUG != 0; if (all || avr_log_details) { /* Adding , at beginning and end of string makes searching easier. */ char *str = (char*) alloca (3 + strlen (avr_log_details)); bool info; str[0] = ','; strcat (stpcpy (str+1, avr_log_details), ","); all |= NULL != strstr (str, ",all,"); info = NULL != strstr (str, ",?,"); if (info) fprintf (stderr, "\n-mlog="); #define SET_DUMP_DETAIL(S) \ do { \ avr_log.S = (all || NULL != strstr (str, "," #S ",")); \ if (info) \ fprintf (stderr, #S ","); \ } while (0) SET_DUMP_DETAIL (address_cost); SET_DUMP_DETAIL (builtin); SET_DUMP_DETAIL (constraints); SET_DUMP_DETAIL (legitimate_address_p); SET_DUMP_DETAIL (legitimize_address); SET_DUMP_DETAIL (legitimize_reload_address); SET_DUMP_DETAIL (progmem); SET_DUMP_DETAIL (rtx_costs); #undef SET_DUMP_DETAIL if (info) fprintf (stderr, "?\n\n"); } }