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