aboutsummaryrefslogtreecommitdiff
path: root/gcc/dump-context.h
blob: e90c4ee1d6aeee9e8b4c30ead09854b493c61554 (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
/* Support code for handling the various dump_* calls in dumpfile.h
   Copyright (C) 2018-2024 Free Software Foundation, Inc.
   Contributed by David Malcolm <dmalcolm@redhat.com>.

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/>.  */


#ifndef GCC_DUMP_CONTEXT_H
#define GCC_DUMP_CONTEXT_H 1

#include "dumpfile.h"
#include "pretty-print.h"
#include "selftest.h"
#include "optinfo.h"

class optrecord_json_writer;
namespace selftest { class temp_dump_context; }
class debug_dump_context;

/* A class for handling the various dump_* calls.

   In particular, this class has responsibility for consolidating
   the "dump_*" calls into optinfo instances (delimited by "dump_*_loc"
   calls), and emitting them.

   Putting this in a class (rather than as global state) allows
   for selftesting of this code.  */

class dump_context
{
  friend class selftest::temp_dump_context;
  friend class debug_dump_context;

 public:
  static dump_context &get () { return *s_current; }

  ~dump_context ();

  void refresh_dumps_are_enabled ();

  void dump_loc (const dump_metadata_t &metadata,
		 const dump_user_location_t &loc);
  void dump_loc_immediate (dump_flags_t dump_kind,
			   const dump_user_location_t &loc);

  void dump_gimple_stmt (const dump_metadata_t &metadata,
			 dump_flags_t extra_dump_flags,
			 gimple *gs, int spc);

  void dump_gimple_stmt_loc (const dump_metadata_t &metadata,
			     const dump_user_location_t &loc,
			     dump_flags_t extra_dump_flags,
			     gimple *gs, int spc);

  void dump_gimple_expr (const dump_metadata_t &metadata,
			 dump_flags_t extra_dump_flags,
			 gimple *gs, int spc);

  void dump_gimple_expr_loc (const dump_metadata_t &metadata,
			     const dump_user_location_t &loc,
			     dump_flags_t extra_dump_flags,
			     gimple *gs,
			     int spc);

  void dump_generic_expr (const dump_metadata_t &metadata,
			  dump_flags_t extra_dump_flags,
			  tree t);

  void dump_generic_expr_loc (const dump_metadata_t &metadata,
			      const dump_user_location_t &loc,
			      dump_flags_t extra_dump_flags,
			      tree t);

  void dump_printf_va (const dump_metadata_t &metadata, const char *format,
		       va_list *ap) ATTRIBUTE_GCC_DUMP_PRINTF (3, 0);

  void dump_printf_loc_va (const dump_metadata_t &metadata,
			   const dump_user_location_t &loc,
			   const char *format, va_list *ap)
    ATTRIBUTE_GCC_DUMP_PRINTF (4, 0);

  template<unsigned int N, typename C>
  void dump_dec (const dump_metadata_t &metadata, const poly_int<N, C> &value);

  void dump_symtab_node (const dump_metadata_t &metadata, symtab_node *node);

  /* Managing nested scopes.  */
  unsigned int get_scope_depth () const;
  void begin_scope (const char *name,
		    const dump_user_location_t &user_location,
		    const dump_impl_location_t &impl_location);
  void end_scope ();

  /* Should optinfo instances be created?
     All creation of optinfos should be guarded by this predicate.
     Return true if any optinfo destinations are active.  */
  bool optinfo_enabled_p () const;

  bool optimization_records_enabled_p () const
  {
    return m_json_writer != NULL;
  }
  void set_json_writer (optrecord_json_writer *writer);
  void finish_any_json_writer ();

  void end_any_optinfo ();

  void emit_optinfo (const optinfo *info);
  void emit_item (const optinfo_item &item, dump_flags_t dump_kind);

  bool apply_dump_filter_p (dump_flags_t dump_kind, dump_flags_t filter) const;

 private:
  optinfo &ensure_pending_optinfo (const dump_metadata_t &metadata);
  optinfo &begin_next_optinfo (const dump_metadata_t &metadata,
			       const dump_user_location_t &loc);

  /* The current nesting depth of dump scopes, for showing nesting
     via indentation).  */
  unsigned int m_scope_depth;

  /* The optinfo currently being accumulated since the last dump_*_loc call,
     if any.  */
  optinfo *m_pending;

  /* If -fsave-optimization-record is enabled, the heap-allocated JSON writer
     instance, otherwise NULL.  */
  optrecord_json_writer *m_json_writer;

  /* For use in selftests: if non-NULL, then items are to be printed
     to this, using the given flags.  */
  pretty_printer *m_test_pp;
  dump_flags_t m_test_pp_flags;

  /* The currently active dump_context, for use by the dump_* API calls.  */
  static dump_context *s_current;

  /* The default active context.  */
  static dump_context s_default;
};

/* A subclass of pretty_printer for implementing dump_context::dump_printf_va.
   In particular, the formatted chunks are captured as optinfo_item instances
   as pp_token_custom_data, thus retaining metadata about the entities being
   dumped (e.g. source locations), rather than just as plain text.
   These custom items are retained through to the end of stage 3 of formatted
   printing; the printer uses a custom token_printer subclass to emit them to
   the active optinfo (if any).  */

class dump_pretty_printer : public pretty_printer
{
public:
  dump_pretty_printer (dump_context *context, dump_flags_t dump_kind);

  void set_optinfo (optinfo *info) { m_token_printer.m_optinfo = info; }

private:
  struct custom_token_printer : public token_printer
  {
    custom_token_printer (dump_pretty_printer &dump_pp)
    : m_dump_pp (dump_pp),
      m_optinfo (nullptr)
    {}
    void print_tokens (pretty_printer *pp,
		       const pp_token_list &tokens) final override;
    void emit_any_pending_textual_chunks ();

    dump_pretty_printer &m_dump_pp;
    optinfo *m_optinfo;
  };

  static bool format_decoder_cb (pretty_printer *pp, text_info *text,
				 const char *spec, int /*precision*/,
				 bool /*wide*/, bool /*set_locus*/,
				 bool /*verbose*/, bool */*quoted*/,
				 pp_token_list &formatted_tok_list);

  bool decode_format (text_info *text, const char *spec,
		      pp_token_list &formatted_tok_list);

  void stash_item (pp_token_list &formatted_tok_list,
		   std::unique_ptr<optinfo_item> item);

  void emit_item (std::unique_ptr<optinfo_item> item, optinfo *dest);

  dump_context *m_context;
  dump_flags_t m_dump_kind;
  custom_token_printer m_token_printer;
};

/* An RAII-style class for use in debug dumpers for temporarily using a
   different dump_context.  It enables full details and outputs to
   stderr instead of the currently active dump_file.  */

class debug_dump_context
{
 public:
  debug_dump_context (FILE *f = stderr);
  ~debug_dump_context ();

 private:
  dump_context m_context;
  dump_context *m_saved;
  dump_flags_t m_saved_flags;
  dump_flags_t m_saved_pflags;
  FILE *m_saved_file;
};


#if CHECKING_P

namespace selftest {

/* An RAII-style class for use in selftests for temporarily using a different
   dump_context.  */

class temp_dump_context
{
 public:
  temp_dump_context (bool forcibly_enable_optinfo,
		     bool forcibly_enable_dumping,
		     dump_flags_t test_pp_flags);
  ~temp_dump_context ();

  /* Support for selftests.  */
  optinfo *get_pending_optinfo () const { return m_context.m_pending; }
  const char *get_dumped_text ();

 private:
  pretty_printer m_pp;
  dump_context m_context;
  dump_context *m_saved;
};

/* Implementation detail of ASSERT_DUMPED_TEXT_EQ.  */

extern void verify_dumped_text (const location &loc,
				temp_dump_context *context,
				const char *expected_text);

/* Verify that the text dumped so far in CONTEXT equals
   EXPECTED_TEXT.
   As a side-effect, the internal buffer is 0-terminated.  */

#define ASSERT_DUMPED_TEXT_EQ(CONTEXT, EXPECTED_TEXT)			\
  SELFTEST_BEGIN_STMT							\
    verify_dumped_text (SELFTEST_LOCATION, &(CONTEXT), (EXPECTED_TEXT)); \
  SELFTEST_END_STMT


/* Verify that ITEM has the expected values.  */

void
verify_item (const location &loc,
	     const optinfo_item *item,
	     enum optinfo_item_kind expected_kind,
	     location_t expected_location,
	     const char *expected_text);

/* Verify that ITEM is a text item, with EXPECTED_TEXT.  */

#define ASSERT_IS_TEXT(ITEM, EXPECTED_TEXT) \
  SELFTEST_BEGIN_STMT						    \
    verify_item (SELFTEST_LOCATION, (ITEM), OPTINFO_ITEM_KIND_TEXT, \
		 UNKNOWN_LOCATION, (EXPECTED_TEXT));		    \
  SELFTEST_END_STMT

/* Verify that ITEM is a tree item, with the expected values.  */

#define ASSERT_IS_TREE(ITEM, EXPECTED_LOCATION, EXPECTED_TEXT) \
  SELFTEST_BEGIN_STMT						    \
    verify_item (SELFTEST_LOCATION, (ITEM), OPTINFO_ITEM_KIND_TREE, \
		 (EXPECTED_LOCATION), (EXPECTED_TEXT));	    \
  SELFTEST_END_STMT

/* Verify that ITEM is a gimple item, with the expected values.  */

#define ASSERT_IS_GIMPLE(ITEM, EXPECTED_LOCATION, EXPECTED_TEXT) \
  SELFTEST_BEGIN_STMT						    \
    verify_item (SELFTEST_LOCATION, (ITEM), OPTINFO_ITEM_KIND_GIMPLE, \
		 (EXPECTED_LOCATION), (EXPECTED_TEXT));	    \
  SELFTEST_END_STMT

/* Verify that ITEM is a symtab node, with the expected values.  */

#define ASSERT_IS_SYMTAB_NODE(ITEM, EXPECTED_LOCATION, EXPECTED_TEXT) \
  SELFTEST_BEGIN_STMT						    \
    verify_item (SELFTEST_LOCATION, (ITEM), OPTINFO_ITEM_KIND_SYMTAB_NODE, \
		 (EXPECTED_LOCATION), (EXPECTED_TEXT));	    \
  SELFTEST_END_STMT

} // namespace selftest

#endif /* CHECKING_P */

#endif /* GCC_DUMP_CONTEXT_H */