Georg-Johann Lay wrote: > This is a tentative patch for better support of logging information for avr BE > developers. > > There are situations where it is more convenient to let the compiler produce > information than to debug into the compiler. One example are -da dumps. > > This patch proposes a better support to print information by means of a > printf-like function via %-codes. > > The current debug output with avr-gcc's option -mdeb produces bulk of > information that is very hard to read because > - there is much output > - there is no information on current_function_decl > - there is no information on current pass name/number > - there is no print-like function so the trees, rtxes so that it is > tedious to get formatted output. > > For example, the following call to avr_edump > > static int > avr_OS_main_function_p (tree func) > { > avr_edump ("%?: %t\n", func); > return avr_lookup_function_attribute1 (func, "OS_main"); > } > > prints additional information in a convenient way (foo is function to be > compiled): > > avr_OS_main_function_p[foo:pro_and_epilogue(202)]: <function_decl # foo > type <function_type # > type <void_type # void VOID > ... > > Wondering that similar functionality is not provided by GCC itself, I wrote > this patch. GCC's diagnostic seems to be overwhelmingly complicated and not > intended for the purpose mentioned above. > > The code is dead code at the moment. No function in the BE uses the new > functions. This patch just adds them. > > Moreover; I don't know if avr port maintainers or global reviewers like such > stuff in the compiler... Therefore it's just tentative draft. > > Supported %-codes are: > > 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 args -- > A: call abort() > f: current_function_name() > F: caller (via __FUNCTION__) > P: Pass name and number > ?: Print caller, current function and pass info > > -- same as printf -- > %: % > c: char > s: string > d: int (decimal) > x: int (hex) > > These codes cover great deal of BE developers needs and if something is > missing > it can be added easily.
Here is now the patch for review. As Denis proposed in http://gcc.gnu.org/ml/gcc/2011-09/msg00357.html all additional functions are put in the new file avr-log.c. -mdebug= is a new command line option that takes a string argument to filter specific log messages. The purpose of -mdebug=all is to be similar to -mdeb and, e.g, -mdebug=rtx_costs,legitimate_address_p is intended to print information from respective named hooks. avr.c:avr_option_override calls avr-log.c:avr__set_avr_debug to parse -mdebug and set bitfield avr_debug accordingly, but using the log functions and avr_debug is still to come. This patch just supplies the basis. I opened PR50566 to collect changes for better logging. Ok for trunk? Johann PR target/50566 * config.gcc (extra_objs): Add avr-log.o for $target in: avr-*-rtems*, avr-*-*. * config/avr/t-avr (avr-log.o): New rule to compile... * config/avr/avr-log.c: ...this new file. * config/avr/avr.opt (mlog=): New option. * config/avr/avr-protos.h (avr_edump, avr_fdump): New macros. (avr_log_set_caller_e, avr_log_set_caller_f): New prototypes. (avr_log_set_avr_log): New prototype. (avr_log_t): New typedef. (avr_log): New declaration. * config/avr/avr.c (avr_option_override): Call avr_log_set_avr_log.
Index: config.gcc =================================================================== --- config.gcc (revision 179334) +++ config.gcc (working copy) @@ -939,14 +939,14 @@ avr-*-rtems*) libgcc_tm_file="$libgcc_tm_file avr/avr-lib.h" tmake_file="avr/t-avr t-rtems avr/t-rtems" extra_gcc_objs="driver-avr.o avr-devices.o" - extra_objs="avr-devices.o" + extra_objs="avr-devices.o avr-log.o" ;; avr-*-*) tm_file="elfos.h avr/elf.h avr/avr.h dbxelf.h newlib-stdint.h" libgcc_tm_file="$libgcc_tm_file avr/avr-lib.h" use_gcc_stdint=wrap extra_gcc_objs="driver-avr.o avr-devices.o" - extra_objs="avr-devices.o" + extra_objs="avr-devices.o avr-log.o" ;; bfin*-elf*) tm_file="${tm_file} dbxelf.h elfos.h newlib-stdint.h bfin/elf.h" Index: config/avr/avr-log.c =================================================================== --- config/avr/avr-log.c (revision 0) +++ config/avr/avr-log.c (revision 0) @@ -0,0 +1,314 @@ +/* Subroutines for log output for Atmel AVR back end. + Copyright (C) 2011 Free Software Foundation, Inc. + Contributed by Georg-Johann Lay (a...@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 + <http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "rtl.h" +#include "tree.h" +#include "output.h" +#include "input.h" +#include "function.h" +#include "tm_p.h" +#include "tree-pass.h" + +/* 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 == + + 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 + + == 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_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 forwarning 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, "<NULL-TREE>"); + else + { + if (stderr == file) + debug_tree (t); + } + 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 '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 (va_arg (ap, enum machine_mode)), file); + break; + + case 'C': + fputs (rtx_name[va_arg (ap, enum rtx_code)], file); + break; + + case 'R': + fputs (reg_class_names[va_arg (ap, enum reg_class)], 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, "<BUILTIN-LOCATION"); + else if (UNKNOWN_LOCATION == loc) + fprintf (file, "<UNKNOWN-LOCATION>"); + 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: + fputc (*(fmt-1), file); + } + 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) +{ + if (avr_log_details) + { + /* Adding , at beginning and end of string makes searching easier. */ + + char *str = (char*) alloca (3 + strlen (avr_log_details)); + + str[0] = ','; + strcat (stpcpy (str+1, avr_log_details), ","); + +#define SET_DUMP_DETAIL(S) \ + avr_log.S = (TARGET_ALL_DEBUG \ + || NULL != strstr (str, "," #S ",") \ + || NULL != strstr (str, ",all,")) + + SET_DUMP_DETAIL (rtx_costs); + SET_DUMP_DETAIL (legitimate_address_p); + SET_DUMP_DETAIL (legitimize_address); + SET_DUMP_DETAIL (legitimize_reload_address); + SET_DUMP_DETAIL (constraints); + +#undef SET_DUMP_DETAIL + } +} Index: config/avr/avr.opt =================================================================== --- config/avr/avr.opt (revision 179316) +++ config/avr/avr.opt (working copy) @@ -29,6 +29,9 @@ Target RejectNegative Joined Var(avr_mcu mdeb Target Report Undocumented Mask(ALL_DEBUG) +mlog= +Target RejectNegative Joined Undocumented Var(avr_log_details) + mint8 Target Report Mask(INT8) Use an 8-bit 'int' type Index: config/avr/t-avr =================================================================== --- config/avr/t-avr (revision 179316) +++ config/avr/t-avr (working copy) @@ -30,6 +30,10 @@ avr-c.o: $(srcdir)/config/avr/avr-c.c \ $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(C_COMMON_H) $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< +avr-log.o: $(srcdir)/config/avr/avr-log.c \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(INPUT_H) + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< + $(srcdir)/config/avr/avr-tables.opt: $(srcdir)/config/avr/genopt.sh \ $(srcdir)/config/avr/avr-mcus.def $(SHELL) $(srcdir)/config/avr/genopt.sh $(srcdir)/config/avr > \ Index: config/avr/avr-protos.h =================================================================== --- config/avr/avr-protos.h (revision 179316) +++ config/avr/avr-protos.h (working copy) @@ -111,3 +111,24 @@ extern rtx avr_incoming_return_addr_rtx #ifdef REAL_VALUE_TYPE extern void asm_output_float (FILE *file, REAL_VALUE_TYPE n); #endif + +/* From avr-log.c */ + +#define avr_edump (avr_log_set_caller_e (__FUNCTION__)) +#define avr_fdump (avr_log_set_caller_f (__FUNCTION__)) + +extern int (*avr_log_set_caller_e (const char*))(const char*, ...); +extern int (*avr_log_set_caller_f (const char*))(FILE*, const char*, ...); + +extern void avr_log_set_avr_log (void); + +typedef struct +{ + unsigned rtx_costs :1; + unsigned legitimate_address_p :1; + unsigned legitimize_address :1; + unsigned legitimize_reload_address :1; + unsigned constraints :1; +} avr_log_t; + +extern avr_log_t avr_log; Index: config/avr/avr.c =================================================================== --- config/avr/avr.c (revision 179316) +++ config/avr/avr.c (working copy) @@ -359,6 +359,8 @@ avr_option_override (void) zero_reg_rtx = gen_rtx_REG (QImode, ZERO_REGNO); init_machine_status = avr_init_machine_status; + + avr_log_set_avr_log(); } /* Function to set up the backend function structure. */