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