aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/avr/avr-log.c
blob: edb1cbda1ec01fff9501aae810f65a9911ad4514 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
/* Subroutines for log output for Atmel AVR back end.
   Copyright (C) 2011 Free Software Foundation, Inc.
   Contributed by Georg-Johann Lay (avr@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"	/* for current_pass */

/* 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 ==
  
  b: bool  
  r: rtx
  t: tree
  T: tree (brief)
  C: enum rtx_code
  m: enum machine_mode
  R: enum reg_class
  D: double_int (signed decimal)
  X: double_int (unsigned hex)
  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
  !: Ditto, but only print if in a pass with static pass number,
     else return.

  == 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_log_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;
}


/* Copy-paste from double-int.c:double_int_split_digit (it's static there).
   Splits last digit of *CST (taken as unsigned) in BASE and returns it.  */

static unsigned
avr_double_int_pop_digit (double_int *cst, unsigned base)
{
  double_int drem;

  *cst = cst->udivmod (double_int::from_uhwi (base), (int) FLOOR_DIV_EXPR,
                       &drem);

  return (unsigned) drem.to_uhwi();
}


/* Dump VAL as hex value to FILE.  */

static void
avr_dump_double_int_hex (FILE *file, double_int val)
{
  unsigned digit[4];

  digit[0] = avr_double_int_pop_digit (&val, 1 << 16);
  digit[1] = avr_double_int_pop_digit (&val, 1 << 16);
  digit[2] = avr_double_int_pop_digit (&val, 1 << 16);
  digit[3] = avr_double_int_pop_digit (&val, 1 << 16);

  fprintf (file, "0x");

  if (digit[3] | digit[2])
    fprintf (file, "%04x%04x", digit[3], digit[2]);

  if (digit[3] | digit[2] | digit[1] | digit[0])
    fprintf (file, "%04x%04x", digit[1], digit[0]);
  else
    fprintf (file, "0");
}


/* Worker function implementing the %-codes and forwarding 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);
                    else
                      {
                        print_node (file, "", t, 0);
                        putc ('\n', file);
                      }
                  }
                break;
              }
              
            case 'T':
              print_node_brief (file, "", va_arg (ap, tree), 3);
              break;
              
            case 'd':
              fprintf (file, "%d", va_arg (ap, int));
              break;
              
            case 'D':
              dump_double_int (file, va_arg (ap, double_int), false);
              break;

            case 'X':
              avr_dump_double_int_hex (file, va_arg (ap, double_int));
              break;
              
            case 'x':
              fprintf (file, "%x", va_arg (ap, int));
              break;
                        
            case 'b':
              fprintf (file, "%s", va_arg (ap, int) ? "true" : "false");
              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 ((enum machine_mode) va_arg (ap, int)), file);
              break;
              
            case 'C':
              fputs (rtx_name[va_arg (ap, int)], file);
              break;
              
            case 'R':
              fputs (reg_class_names[va_arg (ap, int)], 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:
              /* Unknown %-code: Stop printing */
              
              fprintf (file, "??? %%%c ???%s\n", *(fmt-1), fmt);
              fmt = "";
              
              break;
            }
          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)
{
  bool all = TARGET_ALL_DEBUG != 0;
  
  if (all || avr_log_details)
    {
      /* Adding , at beginning and end of string makes searching easier.  */
      
      char *str = (char*) alloca (3 + strlen (avr_log_details));
      bool info;
      
      str[0] = ',';
      strcat (stpcpy (str+1, avr_log_details), ",");

      all |= NULL != strstr (str, ",all,");
      info = NULL != strstr (str, ",?,");

      if (info)
        fprintf (stderr, "\n-mlog=");

#define SET_DUMP_DETAIL(S)                                       \
      do {                                                       \
        avr_log.S = (all || NULL != strstr (str, "," #S ","));   \
        if (info)                                                \
          fprintf (stderr, #S ",");                              \
      } while (0)

      SET_DUMP_DETAIL (address_cost);
      SET_DUMP_DETAIL (builtin);
      SET_DUMP_DETAIL (constraints);
      SET_DUMP_DETAIL (legitimate_address_p);
      SET_DUMP_DETAIL (legitimize_address);
      SET_DUMP_DETAIL (legitimize_reload_address);
      SET_DUMP_DETAIL (progmem);
      SET_DUMP_DETAIL (rtx_costs);

#undef SET_DUMP_DETAIL

      if (info)
        fprintf (stderr, "?\n\n");
    }
}