1/* Subroutines for log output for Atmel AVR back end.
2   Copyright (C) 2011-2022 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.  */
75avr_log_t avr_log;
76
77/* The worker function implementing the %-codes */
78static 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
84int
85avr_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
104static void
105avr_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.cc:avr_option_override().
277   Parse argument of -mlog= and set respective fields in avr_log.  */
278
279void
280avr_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