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