Imported Upstream version 4.8.1
[platform/upstream/gcc48.git] / gcc / config / avr / avr-log.c
1 /* Subroutines for log output for Atmel AVR back end.
2    Copyright (C) 2011-2013 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 "rtl.h"
26 #include "tree.h"
27 #include "output.h"
28 #include "input.h"
29 #include "function.h"
30 #include "tm_p.h"
31 #include "tree-pass.h"  /* for current_pass */
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_edump or avr_fdump from avr-protos.h:
36
37       avr_edump (const char *fmt, ...);
38
39       avr_fdump (FILE *stream, const char *fmt, ...);
40
41    avr_edump (fmt, ...) is a shortcut for avr_fdump (stderr, 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: enum machine_mode
51   R: enum reg_class
52   D: double_int (signed decimal)
53   X: double_int (unsigned hex)
54   L: insn list
55   H: location_t
56
57   == no arguments ==
58
59   A: call abort()
60   f: current_function_name()
61   F: caller (via __FUNCTION__)
62   P: Pass name and number
63   ?: Print caller, current function and pass info
64   !: Ditto, but only print if in a pass with static pass number,
65      else return.
66
67   == same as printf ==
68
69   %: %
70   c: char
71   s: string
72   d: int (decimal)
73   x: int (hex)
74 */
75
76 /* Set according to -mlog= option.  */
77 avr_log_t avr_log;
78
79 /* The caller as of __FUNCTION__ */
80 static const char *avr_log_caller = "?";
81
82 /* The worker function implementing the %-codes */
83 static void avr_log_vadump (FILE*, const char*, va_list);
84
85 /* As we have no variadic macros, avr_edump maps to a call to
86    avr_log_set_caller_e which saves __FUNCTION__ to avr_log_caller and
87    returns a function pointer to avr_log_fdump_e.  avr_log_fdump_e
88    gets the printf-like arguments and calls avr_log_vadump, the
89    worker function.  avr_fdump works the same way.  */
90
91 /* Provide avr_log_fdump_e/f so that avr_log_set_caller_e/_f can return
92    their address.  */
93
94 static int
95 avr_log_fdump_e (const char *fmt, ...)
96 {
97   va_list ap;
98
99   va_start (ap, fmt);
100   avr_log_vadump (stderr, fmt, ap);
101   va_end (ap);
102
103   return 1;
104 }
105
106 static int
107 avr_log_fdump_f (FILE *stream, const char *fmt, ...)
108 {
109   va_list ap;
110
111   va_start (ap, fmt);
112   if (stream)
113     avr_log_vadump (stream, fmt, ap);
114   va_end (ap);
115
116   return 1;
117 }
118
119 /* Macros avr_edump/avr_fdump map to calls of the following two functions,
120    respectively.  You don't need to call them directly.  */
121
122 int (*
123 avr_log_set_caller_e (const char *caller)
124      )(const char*, ...)
125 {
126   avr_log_caller = caller;
127
128   return avr_log_fdump_e;
129 }
130
131 int (*
132 avr_log_set_caller_f (const char *caller)
133      )(FILE*, const char*, ...)
134 {
135   avr_log_caller = caller;
136
137   return avr_log_fdump_f;
138 }
139
140
141 /* Copy-paste from double-int.c:double_int_split_digit (it's static there).
142    Splits last digit of *CST (taken as unsigned) in BASE and returns it.  */
143
144 static unsigned
145 avr_double_int_pop_digit (double_int *cst, unsigned base)
146 {
147   double_int drem;
148
149   *cst = cst->udivmod (double_int::from_uhwi (base), (int) FLOOR_DIV_EXPR,
150                        &drem);
151
152   return (unsigned) drem.to_uhwi();
153 }
154
155
156 /* Dump VAL as hex value to FILE.  */
157
158 static void
159 avr_dump_double_int_hex (FILE *file, double_int val)
160 {
161   unsigned digit[4];
162
163   digit[0] = avr_double_int_pop_digit (&val, 1 << 16);
164   digit[1] = avr_double_int_pop_digit (&val, 1 << 16);
165   digit[2] = avr_double_int_pop_digit (&val, 1 << 16);
166   digit[3] = avr_double_int_pop_digit (&val, 1 << 16);
167
168   fprintf (file, "0x");
169
170   if (digit[3] | digit[2])
171     fprintf (file, "%04x%04x", digit[3], digit[2]);
172
173   if (digit[3] | digit[2] | digit[1] | digit[0])
174     fprintf (file, "%04x%04x", digit[1], digit[0]);
175   else
176     fprintf (file, "0");
177 }
178
179
180 /* Worker function implementing the %-codes and forwarding to
181    respective print/dump function.  */
182
183 static void
184 avr_log_vadump (FILE *file, const char *fmt, va_list ap)
185 {
186   char bs[3] = {'\\', '?', '\0'};
187
188   while (*fmt)
189     {
190       switch (*fmt++)
191         {
192         default:
193           fputc (*(fmt-1), file);
194           break;
195
196         case '\\':
197           bs[1] = *fmt++;
198           fputs (bs, file);
199           break;
200
201         case '%':
202           switch (*fmt++)
203             {
204             case '%':
205               fputc ('%', file);
206               break;
207
208             case 't':
209               {
210                 tree t = va_arg (ap, tree);
211                 if (NULL_TREE == t)
212                   fprintf (file, "<NULL-TREE>");
213                 else
214                   {
215                     if (stderr == file)
216                       debug_tree (t);
217                     else
218                       {
219                         print_node (file, "", t, 0);
220                         putc ('\n', file);
221                       }
222                   }
223                 break;
224               }
225
226             case 'T':
227               print_node_brief (file, "", va_arg (ap, tree), 3);
228               break;
229
230             case 'd':
231               fprintf (file, "%d", va_arg (ap, int));
232               break;
233
234             case 'D':
235               dump_double_int (file, va_arg (ap, double_int), false);
236               break;
237
238             case 'X':
239               avr_dump_double_int_hex (file, va_arg (ap, double_int));
240               break;
241
242             case 'x':
243               fprintf (file, "%x", va_arg (ap, int));
244               break;
245
246             case 'b':
247               fprintf (file, "%s", va_arg (ap, int) ? "true" : "false");
248               break;
249
250             case 'c':
251               fputc (va_arg (ap, int), file);
252               break;
253
254             case 'r':
255               print_inline_rtx (file, va_arg (ap, rtx), 0);
256               break;
257
258             case 'L':
259               {
260                 rtx insn = va_arg (ap, rtx);
261
262                 while (insn)
263                   {
264                     print_inline_rtx (file, insn, 0);
265                     fprintf (file, "\n");
266                     insn = NEXT_INSN (insn);
267                   }
268                 break;
269               }
270
271             case 'f':
272               if (cfun && cfun->decl)
273                 fputs (current_function_name(), file);
274               break;
275
276             case 's':
277               {
278                 const char *str = va_arg (ap, char*);
279                 fputs (str ? str : "(null)", file);
280               }
281               break;
282
283             case 'm':
284               fputs (GET_MODE_NAME ((enum machine_mode) va_arg (ap, int)),
285                      file);
286               break;
287
288             case 'C':
289               fputs (rtx_name[va_arg (ap, int)], file);
290               break;
291
292             case 'R':
293               fputs (reg_class_names[va_arg (ap, int)], file);
294               break;
295
296             case 'F':
297               fputs (avr_log_caller, file);
298               break;
299
300             case 'H':
301               {
302                 location_t loc = va_arg (ap, location_t);
303
304                 if (BUILTINS_LOCATION == loc)
305                   fprintf (file, "<BUILTIN-LOCATION>");
306                 else if (UNKNOWN_LOCATION == loc)
307                   fprintf (file, "<UNKNOWN-LOCATION>");
308                 else
309                   fprintf (file, "%s:%d",
310                            LOCATION_FILE (loc), LOCATION_LINE (loc));
311
312                 break;
313               }
314
315             case '!':
316               if (!current_pass)
317                 return;
318               /* FALLTHRU */
319
320             case '?':
321               avr_log_fdump_f (file, "%F[%f:%P]");
322               break;
323
324             case 'P':
325               if (current_pass)
326                 fprintf (file, "%s(%d)",
327                          current_pass->name,
328                          current_pass->static_pass_number);
329               else
330                 fprintf (file, "pass=?");
331
332               break;
333
334             case 'A':
335               fflush (file);
336               abort();
337
338             default:
339               /* Unknown %-code: Stop printing */
340
341               fprintf (file, "??? %%%c ???%s\n", *(fmt-1), fmt);
342               fmt = "";
343
344               break;
345             }
346           break; /* % */
347         }
348     }
349
350   fflush (file);
351 }
352
353
354 /* Called from avr.c:avr_option_override().
355    Parse argument of -mlog= and set respective fields in avr_log.  */
356
357 void
358 avr_log_set_avr_log (void)
359 {
360   bool all = TARGET_ALL_DEBUG != 0;
361
362   if (all || avr_log_details)
363     {
364       /* Adding , at beginning and end of string makes searching easier.  */
365
366       char *str = (char*) alloca (3 + strlen (avr_log_details));
367       bool info;
368
369       str[0] = ',';
370       strcat (stpcpy (str+1, avr_log_details), ",");
371
372       all |= NULL != strstr (str, ",all,");
373       info = NULL != strstr (str, ",?,");
374
375       if (info)
376         fprintf (stderr, "\n-mlog=");
377
378 #define SET_DUMP_DETAIL(S)                                       \
379       do {                                                       \
380         avr_log.S = (all || NULL != strstr (str, "," #S ","));   \
381         if (info)                                                \
382           fprintf (stderr, #S ",");                              \
383       } while (0)
384
385       SET_DUMP_DETAIL (address_cost);
386       SET_DUMP_DETAIL (builtin);
387       SET_DUMP_DETAIL (constraints);
388       SET_DUMP_DETAIL (legitimate_address_p);
389       SET_DUMP_DETAIL (legitimize_address);
390       SET_DUMP_DETAIL (legitimize_reload_address);
391       SET_DUMP_DETAIL (progmem);
392       SET_DUMP_DETAIL (rtx_costs);
393
394 #undef SET_DUMP_DETAIL
395
396       if (info)
397         fprintf (stderr, "?\n\n");
398     }
399 }