111
|
1 /* read-rtl-function.c - Reader for RTL function dumps
|
145
|
2 Copyright (C) 2016-2020 Free Software Foundation, Inc.
|
111
|
3
|
|
4 This file is part of GCC.
|
|
5
|
|
6 GCC is free software; you can redistribute it and/or modify it under
|
|
7 the terms of the GNU General Public License as published by the Free
|
|
8 Software Foundation; either version 3, or (at your option) any later
|
|
9 version.
|
|
10
|
|
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
14 for more details.
|
|
15
|
|
16 You should have received a copy of the GNU General Public License
|
|
17 along with GCC; see the file COPYING3. If not see
|
|
18 <http://www.gnu.org/licenses/>. */
|
|
19
|
|
20 #include "config.h"
|
|
21 #include "system.h"
|
|
22 #include "coretypes.h"
|
|
23 #include "target.h"
|
|
24 #include "tree.h"
|
|
25 #include "diagnostic.h"
|
|
26 #include "read-md.h"
|
|
27 #include "rtl.h"
|
|
28 #include "cfghooks.h"
|
|
29 #include "stringpool.h"
|
|
30 #include "function.h"
|
|
31 #include "tree-cfg.h"
|
|
32 #include "cfg.h"
|
|
33 #include "basic-block.h"
|
|
34 #include "cfgrtl.h"
|
|
35 #include "memmodel.h"
|
|
36 #include "emit-rtl.h"
|
|
37 #include "cgraph.h"
|
|
38 #include "tree-pass.h"
|
|
39 #include "toplev.h"
|
|
40 #include "varasm.h"
|
|
41 #include "read-rtl-function.h"
|
|
42 #include "selftest.h"
|
|
43 #include "selftest-rtl.h"
|
145
|
44 #include "regs.h"
|
|
45 #include "function-abi.h"
|
111
|
46
|
|
47 /* Forward decls. */
|
|
48 class function_reader;
|
|
49 class fixup;
|
|
50
|
|
51 /* Edges are recorded when parsing the "insn-chain" directive,
|
|
52 and created at the end when all the blocks ought to exist.
|
|
53 This struct records an "edge-from" or "edge-to" directive seen
|
|
54 at LOC, which will be turned into an actual CFG edge once
|
|
55 the "insn-chain" is fully parsed. */
|
|
56
|
145
|
57 class deferred_edge
|
111
|
58 {
|
145
|
59 public:
|
111
|
60 deferred_edge (file_location loc, int src_bb_idx, int dest_bb_idx, int flags)
|
|
61 : m_loc (loc), m_src_bb_idx (src_bb_idx), m_dest_bb_idx (dest_bb_idx),
|
|
62 m_flags (flags)
|
|
63 {}
|
|
64
|
|
65 file_location m_loc;
|
|
66 int m_src_bb_idx;
|
|
67 int m_dest_bb_idx;
|
|
68 int m_flags;
|
|
69 };
|
|
70
|
|
71 /* Subclass of rtx_reader for reading function dumps. */
|
|
72
|
|
73 class function_reader : public rtx_reader
|
|
74 {
|
|
75 public:
|
|
76 function_reader ();
|
|
77 ~function_reader ();
|
|
78
|
|
79 /* Overridden vfuncs of class md_reader. */
|
|
80 void handle_unknown_directive (file_location, const char *) FINAL OVERRIDE;
|
|
81
|
|
82 /* Overridden vfuncs of class rtx_reader. */
|
|
83 rtx read_rtx_operand (rtx x, int idx) FINAL OVERRIDE;
|
|
84 void handle_any_trailing_information (rtx x) FINAL OVERRIDE;
|
|
85 rtx postprocess (rtx) FINAL OVERRIDE;
|
|
86 const char *finalize_string (char *stringbuf) FINAL OVERRIDE;
|
|
87
|
|
88 rtx_insn **get_insn_by_uid (int uid);
|
|
89 tree parse_mem_expr (const char *desc);
|
|
90
|
|
91 private:
|
|
92 void parse_function ();
|
|
93 void create_function ();
|
|
94 void parse_param ();
|
|
95 void parse_insn_chain ();
|
|
96 void parse_block ();
|
|
97 int parse_bb_idx ();
|
|
98 void parse_edge (basic_block block, bool from);
|
|
99 rtx_insn *parse_insn (file_location loc, const char *name);
|
|
100 void parse_cfg (file_location loc);
|
|
101 void parse_crtl (file_location loc);
|
|
102 void create_edges ();
|
|
103
|
|
104 int parse_enum_value (int num_values, const char *const *strings);
|
|
105
|
|
106 void read_rtx_operand_u (rtx x, int idx);
|
|
107 void read_rtx_operand_i_or_n (rtx x, int idx, char format_char);
|
|
108 rtx read_rtx_operand_r (rtx x);
|
|
109 rtx extra_parsing_for_operand_code_0 (rtx x, int idx);
|
|
110
|
|
111 void add_fixup_insn_uid (file_location loc, rtx insn, int operand_idx,
|
|
112 int insn_uid);
|
|
113
|
|
114 void add_fixup_note_insn_basic_block (file_location loc, rtx insn,
|
|
115 int operand_idx, int bb_idx);
|
|
116
|
|
117 void add_fixup_source_location (file_location loc, rtx_insn *insn,
|
145
|
118 const char *filename, int lineno, int colno);
|
111
|
119
|
|
120 void add_fixup_expr (file_location loc, rtx x,
|
|
121 const char *desc);
|
|
122
|
|
123 rtx consolidate_singletons (rtx x);
|
|
124 rtx parse_rtx ();
|
|
125 void maybe_read_location (rtx_insn *insn);
|
|
126
|
|
127 void handle_insn_uids ();
|
|
128 void apply_fixups ();
|
|
129
|
|
130 private:
|
|
131 struct uid_hash : int_hash <int, -1, -2> {};
|
|
132 hash_map<uid_hash, rtx_insn *> m_insns_by_uid;
|
|
133 auto_vec<fixup *> m_fixups;
|
|
134 rtx_insn *m_first_insn;
|
|
135 auto_vec<tree> m_fake_scope;
|
|
136 char *m_name;
|
|
137 bool m_have_crtl_directive;
|
|
138 basic_block m_bb_to_insert_after;
|
|
139 auto_vec <deferred_edge> m_deferred_edges;
|
|
140 int m_highest_bb_idx;
|
|
141 };
|
|
142
|
|
143 /* Abstract base class for recording post-processing steps that must be
|
|
144 done after reading a .rtl file. */
|
|
145
|
|
146 class fixup
|
|
147 {
|
|
148 public:
|
|
149 /* Constructor for a fixup at LOC affecting X. */
|
|
150 fixup (file_location loc, rtx x)
|
|
151 : m_loc (loc), m_rtx (x)
|
|
152 {}
|
|
153 virtual ~fixup () {}
|
|
154
|
|
155 virtual void apply (function_reader *reader) const = 0;
|
|
156
|
|
157 protected:
|
|
158 file_location m_loc;
|
|
159 rtx m_rtx;
|
|
160 };
|
|
161
|
|
162 /* An abstract subclass of fixup for post-processing steps that
|
|
163 act on a specific operand of a specific instruction. */
|
|
164
|
|
165 class operand_fixup : public fixup
|
|
166 {
|
|
167 public:
|
|
168 /* Constructor for a fixup at LOC affecting INSN's operand
|
|
169 with index OPERAND_IDX. */
|
|
170 operand_fixup (file_location loc, rtx insn, int operand_idx)
|
|
171 : fixup (loc, insn), m_operand_idx (operand_idx)
|
|
172 {}
|
|
173
|
|
174 protected:
|
|
175 int m_operand_idx;
|
|
176 };
|
|
177
|
|
178 /* A concrete subclass of operand_fixup: fixup an rtx_insn *
|
|
179 field based on an integer UID. */
|
|
180
|
|
181 class fixup_insn_uid : public operand_fixup
|
|
182 {
|
|
183 public:
|
|
184 /* Constructor for a fixup at LOC affecting INSN's operand
|
|
185 with index OPERAND_IDX. Record INSN_UID as the uid. */
|
|
186 fixup_insn_uid (file_location loc, rtx insn, int operand_idx, int insn_uid)
|
|
187 : operand_fixup (loc, insn, operand_idx),
|
|
188 m_insn_uid (insn_uid)
|
|
189 {}
|
|
190
|
|
191 void apply (function_reader *reader) const;
|
|
192
|
|
193 private:
|
|
194 int m_insn_uid;
|
|
195 };
|
|
196
|
|
197 /* A concrete subclass of operand_fixup: fix up a
|
|
198 NOTE_INSN_BASIC_BLOCK based on an integer block ID. */
|
|
199
|
|
200 class fixup_note_insn_basic_block : public operand_fixup
|
|
201 {
|
|
202 public:
|
|
203 fixup_note_insn_basic_block (file_location loc, rtx insn, int operand_idx,
|
|
204 int bb_idx)
|
|
205 : operand_fixup (loc, insn, operand_idx),
|
|
206 m_bb_idx (bb_idx)
|
|
207 {}
|
|
208
|
|
209 void apply (function_reader *reader) const;
|
|
210
|
|
211 private:
|
|
212 int m_bb_idx;
|
|
213 };
|
|
214
|
|
215 /* A concrete subclass of fixup (not operand_fixup): fix up
|
|
216 the expr of an rtx (REG or MEM) based on a textual dump. */
|
|
217
|
|
218 class fixup_expr : public fixup
|
|
219 {
|
|
220 public:
|
|
221 fixup_expr (file_location loc, rtx x, const char *desc)
|
|
222 : fixup (loc, x),
|
|
223 m_desc (xstrdup (desc))
|
|
224 {}
|
|
225
|
|
226 ~fixup_expr () { free (m_desc); }
|
|
227
|
|
228 void apply (function_reader *reader) const;
|
|
229
|
|
230 private:
|
|
231 char *m_desc;
|
|
232 };
|
|
233
|
|
234 /* Return a textual description of the operand of INSN with
|
|
235 index OPERAND_IDX. */
|
|
236
|
|
237 static const char *
|
|
238 get_operand_name (rtx insn, int operand_idx)
|
|
239 {
|
|
240 gcc_assert (is_a <rtx_insn *> (insn));
|
|
241 switch (operand_idx)
|
|
242 {
|
|
243 case 0:
|
|
244 return "PREV_INSN";
|
|
245 case 1:
|
|
246 return "NEXT_INSN";
|
|
247 default:
|
|
248 return NULL;
|
|
249 }
|
|
250 }
|
|
251
|
|
252 /* Fixup an rtx_insn * field based on an integer UID, as read by READER. */
|
|
253
|
|
254 void
|
|
255 fixup_insn_uid::apply (function_reader *reader) const
|
|
256 {
|
|
257 rtx_insn **insn_from_uid = reader->get_insn_by_uid (m_insn_uid);
|
|
258 if (insn_from_uid)
|
|
259 XEXP (m_rtx, m_operand_idx) = *insn_from_uid;
|
|
260 else
|
|
261 {
|
|
262 const char *op_name = get_operand_name (m_rtx, m_operand_idx);
|
|
263 if (op_name)
|
|
264 error_at (m_loc,
|
|
265 "insn with UID %i not found for operand %i (`%s') of insn %i",
|
|
266 m_insn_uid, m_operand_idx, op_name, INSN_UID (m_rtx));
|
|
267 else
|
|
268 error_at (m_loc,
|
|
269 "insn with UID %i not found for operand %i of insn %i",
|
|
270 m_insn_uid, m_operand_idx, INSN_UID (m_rtx));
|
|
271 }
|
|
272 }
|
|
273
|
|
274 /* Fix up a NOTE_INSN_BASIC_BLOCK based on an integer block ID. */
|
|
275
|
|
276 void
|
|
277 fixup_note_insn_basic_block::apply (function_reader *) const
|
|
278 {
|
|
279 basic_block bb = BASIC_BLOCK_FOR_FN (cfun, m_bb_idx);
|
|
280 gcc_assert (bb);
|
|
281 NOTE_BASIC_BLOCK (m_rtx) = bb;
|
|
282 }
|
|
283
|
|
284 /* Fix up the expr of an rtx (REG or MEM) based on a textual dump
|
|
285 read by READER. */
|
|
286
|
|
287 void
|
|
288 fixup_expr::apply (function_reader *reader) const
|
|
289 {
|
|
290 tree expr = reader->parse_mem_expr (m_desc);
|
|
291 switch (GET_CODE (m_rtx))
|
|
292 {
|
|
293 case REG:
|
|
294 set_reg_attrs_for_decl_rtl (expr, m_rtx);
|
|
295 break;
|
|
296 case MEM:
|
|
297 set_mem_expr (m_rtx, expr);
|
|
298 break;
|
|
299 default:
|
|
300 gcc_unreachable ();
|
|
301 }
|
|
302 }
|
|
303
|
|
304 /* Strip trailing whitespace from DESC. */
|
|
305
|
|
306 static void
|
|
307 strip_trailing_whitespace (char *desc)
|
|
308 {
|
|
309 char *terminator = desc + strlen (desc);
|
|
310 while (desc < terminator)
|
|
311 {
|
|
312 terminator--;
|
|
313 if (ISSPACE (*terminator))
|
|
314 *terminator = '\0';
|
|
315 else
|
|
316 break;
|
|
317 }
|
|
318 }
|
|
319
|
|
320 /* Return the numeric value n for GET_NOTE_INSN_NAME (n) for STRING,
|
|
321 or fail if STRING isn't recognized. */
|
|
322
|
|
323 static int
|
|
324 parse_note_insn_name (const char *string)
|
|
325 {
|
|
326 for (int i = 0; i < NOTE_INSN_MAX; i++)
|
131
|
327 if (strcmp (string, GET_NOTE_INSN_NAME (i)) == 0)
|
111
|
328 return i;
|
|
329 fatal_with_file_and_line ("unrecognized NOTE_INSN name: `%s'", string);
|
|
330 }
|
|
331
|
|
332 /* Return the register number for NAME, or return -1 if it isn't
|
|
333 recognized. */
|
|
334
|
|
335 static int
|
|
336 lookup_reg_by_dump_name (const char *name)
|
|
337 {
|
|
338 for (int i = 0; i < FIRST_PSEUDO_REGISTER; i++)
|
|
339 if (reg_names[i][0]
|
|
340 && ! strcmp (name, reg_names[i]))
|
|
341 return i;
|
|
342
|
|
343 /* Also lookup virtuals. */
|
|
344 if (!strcmp (name, "virtual-incoming-args"))
|
|
345 return VIRTUAL_INCOMING_ARGS_REGNUM;
|
|
346 if (!strcmp (name, "virtual-stack-vars"))
|
|
347 return VIRTUAL_STACK_VARS_REGNUM;
|
|
348 if (!strcmp (name, "virtual-stack-dynamic"))
|
|
349 return VIRTUAL_STACK_DYNAMIC_REGNUM;
|
|
350 if (!strcmp (name, "virtual-outgoing-args"))
|
|
351 return VIRTUAL_OUTGOING_ARGS_REGNUM;
|
|
352 if (!strcmp (name, "virtual-cfa"))
|
|
353 return VIRTUAL_CFA_REGNUM;
|
|
354 if (!strcmp (name, "virtual-preferred-stack-boundary"))
|
|
355 return VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM;
|
|
356 /* TODO: handle "virtual-reg-%d". */
|
|
357
|
|
358 /* In compact mode, pseudos are printed with '< and '>' wrapping the regno,
|
|
359 offseting it by (LAST_VIRTUAL_REGISTER + 1), so that the
|
|
360 first non-virtual pseudo is dumped as "<0>". */
|
|
361 if (name[0] == '<' && name[strlen (name) - 1] == '>')
|
|
362 {
|
|
363 int dump_num = atoi (name + 1);
|
|
364 return dump_num + LAST_VIRTUAL_REGISTER + 1;
|
|
365 }
|
|
366
|
|
367 /* Not found. */
|
|
368 return -1;
|
|
369 }
|
|
370
|
|
371 /* class function_reader : public rtx_reader */
|
|
372
|
|
373 /* function_reader's constructor. */
|
|
374
|
|
375 function_reader::function_reader ()
|
|
376 : rtx_reader (true),
|
|
377 m_first_insn (NULL),
|
|
378 m_name (NULL),
|
|
379 m_have_crtl_directive (false),
|
|
380 m_bb_to_insert_after (NULL),
|
|
381 m_highest_bb_idx (EXIT_BLOCK)
|
|
382 {
|
|
383 }
|
|
384
|
|
385 /* function_reader's destructor. */
|
|
386
|
|
387 function_reader::~function_reader ()
|
|
388 {
|
|
389 int i;
|
|
390 fixup *f;
|
|
391 FOR_EACH_VEC_ELT (m_fixups, i, f)
|
|
392 delete f;
|
|
393
|
|
394 free (m_name);
|
|
395 }
|
|
396
|
|
397 /* Implementation of rtx_reader::handle_unknown_directive,
|
|
398 for parsing the remainder of a directive with name NAME
|
|
399 seen at START_LOC.
|
|
400
|
|
401 Require a top-level "function" directive, as emitted by
|
|
402 print_rtx_function, and parse it. */
|
|
403
|
|
404 void
|
|
405 function_reader::handle_unknown_directive (file_location start_loc,
|
|
406 const char *name)
|
|
407 {
|
|
408 if (strcmp (name, "function"))
|
|
409 fatal_at (start_loc, "expected 'function'");
|
|
410
|
|
411 if (flag_lto)
|
|
412 error ("%<__RTL%> function cannot be compiled with %<-flto%>");
|
|
413
|
|
414 parse_function ();
|
|
415 }
|
|
416
|
|
417 /* Parse the output of print_rtx_function (or hand-written data in the
|
|
418 same format), having already parsed the "(function" heading, and
|
|
419 finishing immediately before the final ")".
|
|
420
|
|
421 The "param" and "crtl" clauses are optional. */
|
|
422
|
|
423 void
|
|
424 function_reader::parse_function ()
|
|
425 {
|
|
426 m_name = xstrdup (read_string (0));
|
|
427
|
|
428 create_function ();
|
|
429
|
|
430 while (1)
|
|
431 {
|
|
432 int c = read_skip_spaces ();
|
|
433 if (c == ')')
|
|
434 {
|
|
435 unread_char (c);
|
|
436 break;
|
|
437 }
|
|
438 unread_char (c);
|
|
439 require_char ('(');
|
|
440 file_location loc = get_current_location ();
|
|
441 struct md_name directive;
|
|
442 read_name (&directive);
|
|
443 if (strcmp (directive.string, "param") == 0)
|
|
444 parse_param ();
|
|
445 else if (strcmp (directive.string, "insn-chain") == 0)
|
|
446 parse_insn_chain ();
|
|
447 else if (strcmp (directive.string, "crtl") == 0)
|
|
448 parse_crtl (loc);
|
|
449 else
|
|
450 fatal_with_file_and_line ("unrecognized directive: %s",
|
|
451 directive.string);
|
|
452 }
|
|
453
|
|
454 handle_insn_uids ();
|
|
455
|
|
456 apply_fixups ();
|
|
457
|
|
458 /* Rebuild the JUMP_LABEL field of any JUMP_INSNs in the chain, and the
|
|
459 LABEL_NUSES of any CODE_LABELs.
|
|
460
|
|
461 This has to happen after apply_fixups, since only after then do
|
|
462 LABEL_REFs have their label_ref_label set up. */
|
|
463 rebuild_jump_labels (get_insns ());
|
|
464
|
|
465 crtl->init_stack_alignment ();
|
|
466 }
|
|
467
|
|
468 /* Set up state for the function *before* fixups are applied.
|
|
469
|
|
470 Create "cfun" and a decl for the function.
|
|
471 By default, every function decl is hardcoded as
|
|
472 int test_1 (int i, int j, int k);
|
|
473 Set up various other state:
|
|
474 - the cfg and basic blocks (edges are created later, *after* fixups
|
|
475 are applied).
|
|
476 - add the function to the callgraph. */
|
|
477
|
|
478 void
|
|
479 function_reader::create_function ()
|
|
480 {
|
|
481 /* We start in cfgrtl mode, rather than cfglayout mode. */
|
|
482 rtl_register_cfg_hooks ();
|
|
483
|
|
484 /* When run from selftests or "rtl1", cfun is NULL.
|
|
485 When run from "cc1" for a C function tagged with __RTL, cfun is the
|
|
486 tagged function. */
|
|
487 if (!cfun)
|
|
488 {
|
|
489 tree fn_name = get_identifier (m_name ? m_name : "test_1");
|
|
490 tree int_type = integer_type_node;
|
|
491 tree return_type = int_type;
|
|
492 tree arg_types[3] = {int_type, int_type, int_type};
|
|
493 tree fn_type = build_function_type_array (return_type, 3, arg_types);
|
|
494 tree fndecl = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL, fn_name, fn_type);
|
|
495 tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE,
|
|
496 return_type);
|
|
497 DECL_ARTIFICIAL (resdecl) = 1;
|
|
498 DECL_IGNORED_P (resdecl) = 1;
|
|
499 DECL_RESULT (fndecl) = resdecl;
|
|
500 allocate_struct_function (fndecl, false);
|
|
501 /* This sets cfun. */
|
|
502 current_function_decl = fndecl;
|
|
503 }
|
|
504
|
|
505 gcc_assert (cfun);
|
|
506 gcc_assert (current_function_decl);
|
|
507 tree fndecl = current_function_decl;
|
|
508
|
|
509 /* Mark this function as being specified as __RTL. */
|
|
510 cfun->curr_properties |= PROP_rtl;
|
|
511
|
|
512 /* cc1 normally inits DECL_INITIAL (fndecl) to be error_mark_node.
|
|
513 Create a dummy block for it. */
|
|
514 DECL_INITIAL (fndecl) = make_node (BLOCK);
|
|
515
|
|
516 cfun->curr_properties = (PROP_cfg | PROP_rtl);
|
|
517
|
|
518 /* Do we need this to force cgraphunit.c to output the function? */
|
|
519 DECL_EXTERNAL (fndecl) = 0;
|
|
520 DECL_PRESERVE_P (fndecl) = 1;
|
|
521
|
|
522 /* Add to cgraph. */
|
|
523 cgraph_node::finalize_function (fndecl, false);
|
|
524
|
|
525 /* Create bare-bones cfg. This creates the entry and exit blocks. */
|
|
526 init_empty_tree_cfg_for_function (cfun);
|
|
527 ENTRY_BLOCK_PTR_FOR_FN (cfun)->flags |= BB_RTL;
|
|
528 EXIT_BLOCK_PTR_FOR_FN (cfun)->flags |= BB_RTL;
|
|
529 init_rtl_bb_info (ENTRY_BLOCK_PTR_FOR_FN (cfun));
|
|
530 init_rtl_bb_info (EXIT_BLOCK_PTR_FOR_FN (cfun));
|
|
531 m_bb_to_insert_after = ENTRY_BLOCK_PTR_FOR_FN (cfun);
|
|
532
|
|
533 }
|
|
534
|
|
535 /* Look within the the params of FNDECL for a param named NAME.
|
|
536 Return NULL_TREE if one isn't found. */
|
|
537
|
|
538 static tree
|
|
539 find_param_by_name (tree fndecl, const char *name)
|
|
540 {
|
|
541 for (tree arg = DECL_ARGUMENTS (fndecl); arg; arg = TREE_CHAIN (arg))
|
|
542 if (id_equal (DECL_NAME (arg), name))
|
|
543 return arg;
|
|
544 return NULL_TREE;
|
|
545 }
|
|
546
|
|
547 /* Parse the content of a "param" directive, having already parsed the
|
|
548 "(param". Consume the trailing ')'. */
|
|
549
|
|
550 void
|
|
551 function_reader::parse_param ()
|
|
552 {
|
|
553 require_char_ws ('"');
|
|
554 file_location loc = get_current_location ();
|
|
555 char *name = read_quoted_string ();
|
|
556
|
|
557 /* Lookup param by name. */
|
|
558 tree t_param = find_param_by_name (cfun->decl, name);
|
|
559 if (!t_param)
|
|
560 fatal_at (loc, "param not found: %s", name);
|
|
561
|
|
562 /* Parse DECL_RTL. */
|
|
563 require_char_ws ('(');
|
|
564 require_word_ws ("DECL_RTL");
|
|
565 DECL_WRTL_CHECK (t_param)->decl_with_rtl.rtl = parse_rtx ();
|
|
566 require_char_ws (')');
|
|
567
|
|
568 /* Parse DECL_RTL_INCOMING. */
|
|
569 require_char_ws ('(');
|
|
570 require_word_ws ("DECL_RTL_INCOMING");
|
|
571 DECL_INCOMING_RTL (t_param) = parse_rtx ();
|
|
572 require_char_ws (')');
|
|
573
|
|
574 require_char_ws (')');
|
|
575 }
|
|
576
|
|
577 /* Parse zero or more child insn elements within an
|
|
578 "insn-chain" element. Consume the trailing ')'. */
|
|
579
|
|
580 void
|
|
581 function_reader::parse_insn_chain ()
|
|
582 {
|
|
583 while (1)
|
|
584 {
|
|
585 int c = read_skip_spaces ();
|
|
586 file_location loc = get_current_location ();
|
|
587 if (c == ')')
|
|
588 break;
|
|
589 else if (c == '(')
|
|
590 {
|
|
591 struct md_name directive;
|
|
592 read_name (&directive);
|
|
593 if (strcmp (directive.string, "block") == 0)
|
|
594 parse_block ();
|
|
595 else
|
|
596 parse_insn (loc, directive.string);
|
|
597 }
|
|
598 else
|
|
599 fatal_at (loc, "expected '(' or ')'");
|
|
600 }
|
|
601
|
|
602 create_edges ();
|
|
603 }
|
|
604
|
|
605 /* Parse zero or more child directives (edges and insns) within a
|
|
606 "block" directive, having already parsed the "(block " heading.
|
|
607 Consume the trailing ')'. */
|
|
608
|
|
609 void
|
|
610 function_reader::parse_block ()
|
|
611 {
|
|
612 /* Parse the index value from the dump. This will be an integer;
|
|
613 we don't support "entry" or "exit" here (unlike for edges). */
|
|
614 struct md_name name;
|
|
615 read_name (&name);
|
|
616 int bb_idx = atoi (name.string);
|
|
617
|
|
618 /* The term "index" has two meanings for basic blocks in a CFG:
|
|
619 (a) the "index" field within struct basic_block_def.
|
|
620 (b) the index of a basic_block within the cfg's x_basic_block_info
|
|
621 vector, as accessed via BASIC_BLOCK_FOR_FN.
|
|
622
|
|
623 These can get out-of-sync when basic blocks are optimized away.
|
|
624 They get back in sync by "compact_blocks".
|
|
625 We reconstruct cfun->cfg->x_basic_block_info->m_vecdata with NULL
|
|
626 values in it for any missing basic blocks, so that (a) == (b) for
|
|
627 all of the blocks we create. The doubly-linked list of basic
|
|
628 blocks (next_bb/prev_bb) skips over these "holes". */
|
|
629
|
|
630 if (m_highest_bb_idx < bb_idx)
|
|
631 m_highest_bb_idx = bb_idx;
|
|
632
|
|
633 size_t new_size = m_highest_bb_idx + 1;
|
|
634 if (basic_block_info_for_fn (cfun)->length () < new_size)
|
|
635 vec_safe_grow_cleared (basic_block_info_for_fn (cfun), new_size);
|
|
636
|
|
637 last_basic_block_for_fn (cfun) = new_size;
|
|
638
|
|
639 /* Create the basic block.
|
|
640
|
|
641 We can't call create_basic_block and use the regular RTL block-creation
|
|
642 hooks, since this creates NOTE_INSN_BASIC_BLOCK instances. We don't
|
|
643 want to do that; we want to use the notes we were provided with. */
|
|
644 basic_block bb = alloc_block ();
|
|
645 init_rtl_bb_info (bb);
|
|
646 bb->index = bb_idx;
|
|
647 bb->flags = BB_NEW | BB_RTL;
|
|
648 link_block (bb, m_bb_to_insert_after);
|
|
649 m_bb_to_insert_after = bb;
|
|
650
|
|
651 n_basic_blocks_for_fn (cfun)++;
|
|
652 SET_BASIC_BLOCK_FOR_FN (cfun, bb_idx, bb);
|
|
653 BB_SET_PARTITION (bb, BB_UNPARTITIONED);
|
|
654
|
|
655 /* Handle insns, edge-from and edge-to directives. */
|
|
656 while (1)
|
|
657 {
|
|
658 int c = read_skip_spaces ();
|
|
659 file_location loc = get_current_location ();
|
|
660 if (c == ')')
|
|
661 break;
|
|
662 else if (c == '(')
|
|
663 {
|
|
664 struct md_name directive;
|
|
665 read_name (&directive);
|
|
666 if (strcmp (directive.string, "edge-from") == 0)
|
|
667 parse_edge (bb, true);
|
|
668 else if (strcmp (directive.string, "edge-to") == 0)
|
|
669 parse_edge (bb, false);
|
|
670 else
|
|
671 {
|
|
672 rtx_insn *insn = parse_insn (loc, directive.string);
|
|
673 set_block_for_insn (insn, bb);
|
|
674 if (!BB_HEAD (bb))
|
|
675 BB_HEAD (bb) = insn;
|
|
676 BB_END (bb) = insn;
|
|
677 }
|
|
678 }
|
|
679 else
|
|
680 fatal_at (loc, "expected '(' or ')'");
|
|
681 }
|
|
682 }
|
|
683
|
|
684 /* Subroutine of function_reader::parse_edge.
|
|
685 Parse a basic block index, handling "entry" and "exit". */
|
|
686
|
|
687 int
|
|
688 function_reader::parse_bb_idx ()
|
|
689 {
|
|
690 struct md_name name;
|
|
691 read_name (&name);
|
|
692 if (strcmp (name.string, "entry") == 0)
|
|
693 return ENTRY_BLOCK;
|
|
694 if (strcmp (name.string, "exit") == 0)
|
|
695 return EXIT_BLOCK;
|
|
696 return atoi (name.string);
|
|
697 }
|
|
698
|
|
699 /* Subroutine of parse_edge_flags.
|
|
700 Parse TOK, a token such as "FALLTHRU", converting to the flag value.
|
|
701 Issue an error if the token is unrecognized. */
|
|
702
|
|
703 static int
|
|
704 parse_edge_flag_token (const char *tok)
|
|
705 {
|
|
706 #define DEF_EDGE_FLAG(NAME,IDX) \
|
|
707 do { \
|
|
708 if (strcmp (tok, #NAME) == 0) \
|
|
709 return EDGE_##NAME; \
|
|
710 } while (0);
|
|
711 #include "cfg-flags.def"
|
|
712 #undef DEF_EDGE_FLAG
|
145
|
713 error ("unrecognized edge flag: %qs", tok);
|
111
|
714 return 0;
|
|
715 }
|
|
716
|
|
717 /* Subroutine of function_reader::parse_edge.
|
|
718 Parse STR and convert to a flag value (or issue an error).
|
|
719 The parser uses strtok and hence modifiers STR in-place. */
|
|
720
|
|
721 static int
|
|
722 parse_edge_flags (char *str)
|
|
723 {
|
|
724 int result = 0;
|
|
725
|
|
726 char *tok = strtok (str, "| ");
|
|
727 while (tok)
|
|
728 {
|
|
729 result |= parse_edge_flag_token (tok);
|
|
730 tok = strtok (NULL, "| ");
|
|
731 }
|
|
732
|
|
733 return result;
|
|
734 }
|
|
735
|
|
736 /* Parse an "edge-from" or "edge-to" directive within the "block"
|
|
737 directive for BLOCK, having already parsed the "(edge" heading.
|
|
738 Consume the final ")". Record the edge within m_deferred_edges.
|
|
739 FROM is true for an "edge-from" directive, false for an "edge-to"
|
|
740 directive. */
|
|
741
|
|
742 void
|
|
743 function_reader::parse_edge (basic_block block, bool from)
|
|
744 {
|
|
745 gcc_assert (block);
|
|
746 int this_bb_idx = block->index;
|
|
747 file_location loc = get_current_location ();
|
|
748 int other_bb_idx = parse_bb_idx ();
|
|
749
|
|
750 /* "(edge-from 2)" means src = 2, dest = this_bb_idx, whereas
|
|
751 "(edge-to 3)" means src = this_bb_idx, dest = 3. */
|
|
752 int src_idx = from ? other_bb_idx : this_bb_idx;
|
|
753 int dest_idx = from ? this_bb_idx : other_bb_idx;
|
|
754
|
|
755 /* Optional "(flags)". */
|
|
756 int flags = 0;
|
|
757 int c = read_skip_spaces ();
|
|
758 if (c == '(')
|
|
759 {
|
|
760 require_word_ws ("flags");
|
|
761 require_char_ws ('"');
|
|
762 char *str = read_quoted_string ();
|
|
763 flags = parse_edge_flags (str);
|
|
764 require_char_ws (')');
|
|
765 }
|
|
766 else
|
|
767 unread_char (c);
|
|
768
|
|
769 require_char_ws (')');
|
|
770
|
|
771 /* This BB already exists, but the other BB might not yet.
|
|
772 For now, save the edges, and create them at the end of insn-chain
|
|
773 processing. */
|
|
774 /* For now, only process the (edge-from) to this BB, and (edge-to)
|
|
775 that go to the exit block.
|
|
776 FIXME: we don't yet verify that the edge-from and edge-to directives
|
|
777 are consistent. */
|
|
778 if (from || dest_idx == EXIT_BLOCK)
|
|
779 m_deferred_edges.safe_push (deferred_edge (loc, src_idx, dest_idx, flags));
|
|
780 }
|
|
781
|
|
782 /* Parse an rtx instruction, having parsed the opening and parenthesis, and
|
|
783 name NAME, seen at START_LOC, by calling read_rtx_code, calling
|
|
784 set_first_insn and set_last_insn as appropriate, and
|
|
785 adding the insn to the insn chain.
|
|
786 Consume the trailing ')'. */
|
|
787
|
|
788 rtx_insn *
|
|
789 function_reader::parse_insn (file_location start_loc, const char *name)
|
|
790 {
|
|
791 rtx x = read_rtx_code (name);
|
|
792 if (!x)
|
|
793 fatal_at (start_loc, "expected insn type; got '%s'", name);
|
|
794 rtx_insn *insn = dyn_cast <rtx_insn *> (x);
|
|
795 if (!insn)
|
|
796 fatal_at (start_loc, "expected insn type; got '%s'", name);
|
|
797
|
|
798 /* Consume the trailing ')'. */
|
|
799 require_char_ws (')');
|
|
800
|
|
801 rtx_insn *last_insn = get_last_insn ();
|
|
802
|
|
803 /* Add "insn" to the insn chain. */
|
|
804 if (last_insn)
|
|
805 {
|
|
806 gcc_assert (NEXT_INSN (last_insn) == NULL);
|
|
807 SET_NEXT_INSN (last_insn) = insn;
|
|
808 }
|
|
809 SET_PREV_INSN (insn) = last_insn;
|
|
810
|
|
811 /* Add it to the sequence. */
|
|
812 set_last_insn (insn);
|
|
813 if (!m_first_insn)
|
|
814 {
|
|
815 m_first_insn = insn;
|
|
816 set_first_insn (insn);
|
|
817 }
|
|
818
|
|
819 if (rtx_code_label *label = dyn_cast <rtx_code_label *> (insn))
|
|
820 maybe_set_max_label_num (label);
|
|
821
|
|
822 return insn;
|
|
823 }
|
|
824
|
|
825 /* Postprocessing subroutine for parse_insn_chain: all the basic blocks
|
|
826 should have been created by now; create the edges that were seen. */
|
|
827
|
|
828 void
|
|
829 function_reader::create_edges ()
|
|
830 {
|
|
831 int i;
|
|
832 deferred_edge *de;
|
|
833 FOR_EACH_VEC_ELT (m_deferred_edges, i, de)
|
|
834 {
|
|
835 /* The BBs should already have been created by parse_block. */
|
|
836 basic_block src = BASIC_BLOCK_FOR_FN (cfun, de->m_src_bb_idx);
|
|
837 if (!src)
|
|
838 fatal_at (de->m_loc, "error: block index %i not found",
|
|
839 de->m_src_bb_idx);
|
|
840 basic_block dst = BASIC_BLOCK_FOR_FN (cfun, de->m_dest_bb_idx);
|
|
841 if (!dst)
|
|
842 fatal_at (de->m_loc, "error: block with index %i not found",
|
|
843 de->m_dest_bb_idx);
|
|
844 unchecked_make_edge (src, dst, de->m_flags);
|
|
845 }
|
|
846 }
|
|
847
|
|
848 /* Parse a "crtl" directive, having already parsed the "(crtl" heading
|
|
849 at location LOC.
|
|
850 Consume the final ")". */
|
|
851
|
|
852 void
|
|
853 function_reader::parse_crtl (file_location loc)
|
|
854 {
|
|
855 if (m_have_crtl_directive)
|
|
856 error_at (loc, "more than one 'crtl' directive");
|
|
857 m_have_crtl_directive = true;
|
|
858
|
|
859 /* return_rtx. */
|
|
860 require_char_ws ('(');
|
|
861 require_word_ws ("return_rtx");
|
|
862 crtl->return_rtx = parse_rtx ();
|
|
863 require_char_ws (')');
|
|
864
|
|
865 require_char_ws (')');
|
|
866 }
|
|
867
|
|
868 /* Parse operand IDX of X, returning X, or an equivalent rtx
|
|
869 expression (for consolidating singletons).
|
|
870 This is an overridden implementation of rtx_reader::read_rtx_operand for
|
|
871 function_reader, handling various extra data printed by print_rtx,
|
|
872 and sometimes calling the base class implementation. */
|
|
873
|
|
874 rtx
|
|
875 function_reader::read_rtx_operand (rtx x, int idx)
|
|
876 {
|
|
877 RTX_CODE code = GET_CODE (x);
|
|
878 const char *format_ptr = GET_RTX_FORMAT (code);
|
|
879 const char format_char = format_ptr[idx];
|
|
880 struct md_name name;
|
|
881
|
|
882 /* Override the regular parser for some format codes. */
|
|
883 switch (format_char)
|
|
884 {
|
|
885 case 'e':
|
|
886 if (idx == 7 && CALL_P (x))
|
|
887 {
|
|
888 m_in_call_function_usage = true;
|
|
889 return rtx_reader::read_rtx_operand (x, idx);
|
|
890 m_in_call_function_usage = false;
|
|
891 }
|
|
892 else
|
|
893 return rtx_reader::read_rtx_operand (x, idx);
|
|
894 break;
|
|
895
|
|
896 case 'u':
|
|
897 read_rtx_operand_u (x, idx);
|
|
898 /* Don't run regular parser for 'u'. */
|
|
899 return x;
|
|
900
|
|
901 case 'i':
|
|
902 case 'n':
|
|
903 read_rtx_operand_i_or_n (x, idx, format_char);
|
|
904 /* Don't run regular parser for these codes. */
|
|
905 return x;
|
|
906
|
|
907 case 'B':
|
|
908 gcc_assert (is_compact ());
|
|
909 /* Compact mode doesn't store BBs. */
|
|
910 /* Don't run regular parser. */
|
|
911 return x;
|
|
912
|
|
913 case 'r':
|
|
914 /* Don't run regular parser for 'r'. */
|
|
915 return read_rtx_operand_r (x);
|
|
916
|
|
917 default:
|
|
918 break;
|
|
919 }
|
|
920
|
|
921 /* Call base class implementation. */
|
|
922 x = rtx_reader::read_rtx_operand (x, idx);
|
|
923
|
|
924 /* Handle any additional parsing needed to handle what the dump
|
|
925 could contain. */
|
|
926 switch (format_char)
|
|
927 {
|
|
928 case '0':
|
|
929 x = extra_parsing_for_operand_code_0 (x, idx);
|
|
930 break;
|
|
931
|
|
932 case 'w':
|
|
933 if (!is_compact ())
|
|
934 {
|
|
935 /* Strip away the redundant hex dump of the value. */
|
|
936 require_char_ws ('[');
|
|
937 read_name (&name);
|
|
938 require_char_ws (']');
|
|
939 }
|
|
940 break;
|
|
941
|
|
942 default:
|
|
943 break;
|
|
944 }
|
|
945
|
|
946 return x;
|
|
947 }
|
|
948
|
|
949 /* Parse operand IDX of X, of code 'u', when reading function dumps.
|
|
950
|
|
951 The RTL file recorded the ID of an insn (or 0 for NULL); we
|
|
952 must store this as a pointer, but the insn might not have
|
|
953 been loaded yet. Store the ID away for now, via a fixup. */
|
|
954
|
|
955 void
|
|
956 function_reader::read_rtx_operand_u (rtx x, int idx)
|
|
957 {
|
|
958 /* In compact mode, the PREV/NEXT insn uids are not dumped, so skip
|
|
959 the "uu" when reading. */
|
|
960 if (is_compact () && GET_CODE (x) != LABEL_REF)
|
|
961 return;
|
|
962
|
|
963 struct md_name name;
|
|
964 file_location loc = read_name (&name);
|
|
965 int insn_id = atoi (name.string);
|
|
966 if (insn_id)
|
|
967 add_fixup_insn_uid (loc, x, idx, insn_id);
|
|
968 }
|
|
969
|
|
970 /* Read a name, looking for a match against a string found in array
|
|
971 STRINGS of size NUM_VALUES.
|
|
972 Return the index of the the matched string, or emit an error. */
|
|
973
|
|
974 int
|
|
975 function_reader::parse_enum_value (int num_values, const char *const *strings)
|
|
976 {
|
|
977 struct md_name name;
|
|
978 read_name (&name);
|
|
979 for (int i = 0; i < num_values; i++)
|
|
980 {
|
|
981 if (strcmp (name.string, strings[i]) == 0)
|
|
982 return i;
|
|
983 }
|
145
|
984 error ("unrecognized enum value: %qs", name.string);
|
111
|
985 return 0;
|
|
986 }
|
|
987
|
|
988 /* Parse operand IDX of X, of code 'i' or 'n' (as specified by FORMAT_CHAR).
|
|
989 Special-cased handling of these, for reading function dumps. */
|
|
990
|
|
991 void
|
|
992 function_reader::read_rtx_operand_i_or_n (rtx x, int idx,
|
|
993 char format_char)
|
|
994 {
|
|
995 /* Handle some of the extra information that print_rtx
|
|
996 can write out for these cases. */
|
|
997 /* print_rtx only writes out operand 5 for notes
|
|
998 for NOTE_KIND values NOTE_INSN_DELETED_LABEL
|
|
999 and NOTE_INSN_DELETED_DEBUG_LABEL. */
|
|
1000 if (idx == 5 && NOTE_P (x))
|
|
1001 return;
|
|
1002
|
|
1003 if (idx == 4 && INSN_P (x))
|
|
1004 {
|
|
1005 maybe_read_location (as_a <rtx_insn *> (x));
|
|
1006 return;
|
|
1007 }
|
|
1008
|
|
1009 /* INSN_CODEs aren't printed in compact mode, so don't attempt to
|
|
1010 parse them. */
|
|
1011 if (is_compact ()
|
|
1012 && INSN_P (x)
|
|
1013 && &INSN_CODE (x) == &XINT (x, idx))
|
|
1014 {
|
|
1015 INSN_CODE (x) = -1;
|
|
1016 return;
|
|
1017 }
|
|
1018
|
|
1019 /* Handle UNSPEC and UNSPEC_VOLATILE's operand 1. */
|
|
1020 #if !defined(GENERATOR_FILE) && NUM_UNSPECV_VALUES > 0
|
|
1021 if (idx == 1
|
|
1022 && GET_CODE (x) == UNSPEC_VOLATILE)
|
|
1023 {
|
|
1024 XINT (x, 1)
|
|
1025 = parse_enum_value (NUM_UNSPECV_VALUES, unspecv_strings);
|
|
1026 return;
|
|
1027 }
|
|
1028 #endif
|
|
1029 #if !defined(GENERATOR_FILE) && NUM_UNSPEC_VALUES > 0
|
|
1030 if (idx == 1
|
|
1031 && (GET_CODE (x) == UNSPEC
|
|
1032 || GET_CODE (x) == UNSPEC_VOLATILE))
|
|
1033 {
|
|
1034 XINT (x, 1)
|
|
1035 = parse_enum_value (NUM_UNSPEC_VALUES, unspec_strings);
|
|
1036 return;
|
|
1037 }
|
|
1038 #endif
|
|
1039
|
|
1040 struct md_name name;
|
|
1041 read_name (&name);
|
|
1042 int value;
|
|
1043 if (format_char == 'n')
|
|
1044 value = parse_note_insn_name (name.string);
|
|
1045 else
|
|
1046 value = atoi (name.string);
|
|
1047 XINT (x, idx) = value;
|
|
1048 }
|
|
1049
|
|
1050 /* Parse the 'r' operand of X, returning X, or an equivalent rtx
|
|
1051 expression (for consolidating singletons).
|
|
1052 Special-cased handling of code 'r' for reading function dumps. */
|
|
1053
|
|
1054 rtx
|
|
1055 function_reader::read_rtx_operand_r (rtx x)
|
|
1056 {
|
|
1057 struct md_name name;
|
|
1058 file_location loc = read_name (&name);
|
|
1059 int regno = lookup_reg_by_dump_name (name.string);
|
|
1060 if (regno == -1)
|
|
1061 fatal_at (loc, "unrecognized register: '%s'", name.string);
|
|
1062
|
|
1063 set_regno_raw (x, regno, 1);
|
|
1064
|
|
1065 /* Consolidate singletons. */
|
|
1066 x = consolidate_singletons (x);
|
|
1067
|
|
1068 ORIGINAL_REGNO (x) = regno;
|
|
1069
|
|
1070 /* Parse extra stuff at end of 'r'.
|
|
1071 We may have zero, one, or two sections marked by square
|
|
1072 brackets. */
|
|
1073 int ch = read_skip_spaces ();
|
|
1074 bool expect_original_regno = false;
|
|
1075 if (ch == '[')
|
|
1076 {
|
|
1077 file_location loc = get_current_location ();
|
|
1078 char *desc = read_until ("]", true);
|
|
1079 strip_trailing_whitespace (desc);
|
|
1080 const char *desc_start = desc;
|
|
1081 /* If ORIGINAL_REGNO (rtx) != regno, we will have:
|
|
1082 "orig:%i", ORIGINAL_REGNO (rtx).
|
|
1083 Consume it, we don't set ORIGINAL_REGNO, since we can
|
|
1084 get that from the 2nd copy later. */
|
131
|
1085 if (strncmp (desc, "orig:", 5) == 0)
|
111
|
1086 {
|
|
1087 expect_original_regno = true;
|
|
1088 desc_start += 5;
|
|
1089 /* Skip to any whitespace following the integer. */
|
|
1090 const char *space = strchr (desc_start, ' ');
|
|
1091 if (space)
|
|
1092 desc_start = space + 1;
|
|
1093 }
|
|
1094 /* Any remaining text may be the REG_EXPR. Alternatively we have
|
|
1095 no REG_ATTRS, and instead we have ORIGINAL_REGNO. */
|
|
1096 if (ISDIGIT (*desc_start))
|
|
1097 {
|
|
1098 /* Assume we have ORIGINAL_REGNO. */
|
|
1099 ORIGINAL_REGNO (x) = atoi (desc_start);
|
|
1100 }
|
|
1101 else
|
|
1102 {
|
|
1103 /* Assume we have REG_EXPR. */
|
|
1104 add_fixup_expr (loc, x, desc_start);
|
|
1105 }
|
|
1106 free (desc);
|
|
1107 }
|
|
1108 else
|
|
1109 unread_char (ch);
|
|
1110 if (expect_original_regno)
|
|
1111 {
|
|
1112 require_char_ws ('[');
|
|
1113 char *desc = read_until ("]", true);
|
|
1114 ORIGINAL_REGNO (x) = atoi (desc);
|
|
1115 free (desc);
|
|
1116 }
|
|
1117
|
|
1118 return x;
|
|
1119 }
|
|
1120
|
|
1121 /* Additional parsing for format code '0' in dumps, handling a variety
|
|
1122 of special-cases in print_rtx, when parsing operand IDX of X.
|
|
1123 Return X, or possibly a reallocated copy of X. */
|
|
1124
|
|
1125 rtx
|
|
1126 function_reader::extra_parsing_for_operand_code_0 (rtx x, int idx)
|
|
1127 {
|
|
1128 RTX_CODE code = GET_CODE (x);
|
|
1129 int c;
|
|
1130 struct md_name name;
|
|
1131
|
|
1132 if (idx == 1 && code == SYMBOL_REF)
|
|
1133 {
|
|
1134 /* Possibly wrote " [flags %#x]", SYMBOL_REF_FLAGS (in_rtx). */
|
|
1135 c = read_skip_spaces ();
|
|
1136 if (c == '[')
|
|
1137 {
|
|
1138 file_location loc = read_name (&name);
|
|
1139 if (strcmp (name.string, "flags"))
|
|
1140 error_at (loc, "was expecting `%s'", "flags");
|
|
1141 read_name (&name);
|
|
1142 SYMBOL_REF_FLAGS (x) = strtol (name.string, NULL, 16);
|
|
1143
|
|
1144 /* The standard RTX_CODE_SIZE (SYMBOL_REF) used when allocating
|
|
1145 x doesn't have space for the block_symbol information, so
|
|
1146 we must reallocate it if this flag is set. */
|
|
1147 if (SYMBOL_REF_HAS_BLOCK_INFO_P (x))
|
|
1148 {
|
|
1149 /* Emulate the allocation normally done by
|
|
1150 varasm.c:create_block_symbol. */
|
|
1151 unsigned int size = RTX_HDR_SIZE + sizeof (struct block_symbol);
|
|
1152 rtx new_x = (rtx) ggc_internal_alloc (size);
|
|
1153
|
|
1154 /* Copy data over from the smaller SYMBOL_REF. */
|
|
1155 memcpy (new_x, x, RTX_CODE_SIZE (SYMBOL_REF));
|
|
1156 x = new_x;
|
|
1157
|
|
1158 /* We can't reconstruct SYMBOL_REF_BLOCK; set it to NULL. */
|
|
1159 SYMBOL_REF_BLOCK (x) = NULL;
|
|
1160
|
|
1161 /* Zero the offset. */
|
|
1162 SYMBOL_REF_BLOCK_OFFSET (x) = 0;
|
|
1163 }
|
|
1164
|
|
1165 require_char (']');
|
|
1166 }
|
|
1167 else
|
|
1168 unread_char (c);
|
|
1169
|
|
1170 /* If X had a non-NULL SYMBOL_REF_DECL,
|
|
1171 rtx_writer::print_rtx_operand_code_0 would have dumped it
|
|
1172 using print_node_brief.
|
|
1173 Skip the content for now. */
|
|
1174 c = read_skip_spaces ();
|
|
1175 if (c == '<')
|
|
1176 {
|
|
1177 while (1)
|
|
1178 {
|
|
1179 char ch = read_char ();
|
|
1180 if (ch == '>')
|
|
1181 break;
|
|
1182 }
|
|
1183 }
|
|
1184 else
|
|
1185 unread_char (c);
|
|
1186 }
|
|
1187 else if (idx == 3 && code == NOTE)
|
|
1188 {
|
|
1189 /* Note-specific data appears for operand 3, which annoyingly
|
|
1190 is before the enum specifying which kind of note we have
|
|
1191 (operand 4). */
|
|
1192 c = read_skip_spaces ();
|
|
1193 if (c == '[')
|
|
1194 {
|
|
1195 /* Possibly data for a NOTE_INSN_BASIC_BLOCK, of the form:
|
|
1196 [bb %d]. */
|
|
1197 file_location bb_loc = read_name (&name);
|
|
1198 if (strcmp (name.string, "bb"))
|
|
1199 error_at (bb_loc, "was expecting `%s'", "bb");
|
|
1200 read_name (&name);
|
|
1201 int bb_idx = atoi (name.string);
|
|
1202 add_fixup_note_insn_basic_block (bb_loc, x, idx,
|
|
1203 bb_idx);
|
|
1204 require_char_ws (']');
|
|
1205 }
|
|
1206 else
|
|
1207 unread_char (c);
|
|
1208 }
|
|
1209
|
|
1210 return x;
|
|
1211 }
|
|
1212
|
|
1213 /* Implementation of rtx_reader::handle_any_trailing_information.
|
|
1214 Handle the various additional information that print-rtl.c can
|
|
1215 write after the regular fields, when parsing X. */
|
|
1216
|
|
1217 void
|
|
1218 function_reader::handle_any_trailing_information (rtx x)
|
|
1219 {
|
|
1220 struct md_name name;
|
|
1221
|
|
1222 switch (GET_CODE (x))
|
|
1223 {
|
|
1224 case MEM:
|
|
1225 {
|
|
1226 int ch;
|
|
1227 require_char_ws ('[');
|
|
1228 read_name (&name);
|
|
1229 set_mem_alias_set (x, atoi (name.string));
|
|
1230 /* We have either a MEM_EXPR, or a space. */
|
|
1231 if (peek_char () != ' ')
|
|
1232 {
|
|
1233 file_location loc = get_current_location ();
|
|
1234 char *desc = read_until (" +", false);
|
|
1235 add_fixup_expr (loc, consolidate_singletons (x), desc);
|
|
1236 free (desc);
|
|
1237 }
|
|
1238 else
|
|
1239 read_char ();
|
|
1240
|
|
1241 /* We may optionally have '+' for MEM_OFFSET_KNOWN_P. */
|
|
1242 ch = read_skip_spaces ();
|
|
1243 if (ch == '+')
|
|
1244 {
|
|
1245 read_name (&name);
|
|
1246 set_mem_offset (x, atoi (name.string));
|
|
1247 }
|
|
1248 else
|
|
1249 unread_char (ch);
|
|
1250
|
|
1251 /* Handle optional " S" for MEM_SIZE. */
|
|
1252 ch = read_skip_spaces ();
|
|
1253 if (ch == 'S')
|
|
1254 {
|
|
1255 read_name (&name);
|
|
1256 set_mem_size (x, atoi (name.string));
|
|
1257 }
|
|
1258 else
|
|
1259 unread_char (ch);
|
|
1260
|
|
1261 /* Handle optional " A" for MEM_ALIGN. */
|
|
1262 ch = read_skip_spaces ();
|
|
1263 if (ch == 'A' && peek_char () != 'S')
|
|
1264 {
|
|
1265 read_name (&name);
|
|
1266 set_mem_align (x, atoi (name.string));
|
|
1267 }
|
|
1268 else
|
|
1269 unread_char (ch);
|
|
1270
|
|
1271 /* Handle optional " AS" for MEM_ADDR_SPACE. */
|
|
1272 ch = read_skip_spaces ();
|
|
1273 if (ch == 'A' && peek_char () == 'S')
|
|
1274 {
|
|
1275 read_char ();
|
|
1276 read_name (&name);
|
|
1277 set_mem_addr_space (x, atoi (name.string));
|
|
1278 }
|
|
1279 else
|
|
1280 unread_char (ch);
|
|
1281
|
|
1282 require_char (']');
|
|
1283 }
|
|
1284 break;
|
|
1285
|
|
1286 case CODE_LABEL:
|
|
1287 /* Assume that LABEL_NUSES was not dumped. */
|
|
1288 /* TODO: parse LABEL_KIND. */
|
|
1289 /* For now, skip until closing ')'. */
|
|
1290 do
|
|
1291 {
|
|
1292 char ch = read_char ();
|
|
1293 if (ch == ')')
|
|
1294 {
|
|
1295 unread_char (ch);
|
|
1296 break;
|
|
1297 }
|
|
1298 }
|
|
1299 while (1);
|
|
1300 break;
|
|
1301
|
|
1302 default:
|
|
1303 break;
|
|
1304 }
|
|
1305 }
|
|
1306
|
|
1307 /* Parse a tree dump for a MEM_EXPR in DESC and turn it back into a tree.
|
|
1308 We handle "<retval>" and param names within cfun, but for anything else
|
|
1309 we "cheat" by building a global VAR_DECL of type "int" with that name
|
|
1310 (returning the same global for a name if we see the same name more
|
|
1311 than once). */
|
|
1312
|
|
1313 tree
|
|
1314 function_reader::parse_mem_expr (const char *desc)
|
|
1315 {
|
|
1316 tree fndecl = cfun->decl;
|
|
1317
|
131
|
1318 if (strcmp (desc, "<retval>") == 0)
|
111
|
1319 return DECL_RESULT (fndecl);
|
|
1320
|
|
1321 tree param = find_param_by_name (fndecl, desc);
|
|
1322 if (param)
|
|
1323 return param;
|
|
1324
|
|
1325 /* Search within decls we already created.
|
|
1326 FIXME: use a hash rather than linear search. */
|
|
1327 int i;
|
|
1328 tree t;
|
|
1329 FOR_EACH_VEC_ELT (m_fake_scope, i, t)
|
|
1330 if (id_equal (DECL_NAME (t), desc))
|
|
1331 return t;
|
|
1332
|
|
1333 /* Not found? Create it.
|
|
1334 This allows mimicking of real data but avoids having to specify
|
|
1335 e.g. names of locals, params etc.
|
|
1336 Though this way we don't know if we have a PARM_DECL vs a VAR_DECL,
|
|
1337 and we don't know the types. Fake it by making everything be
|
|
1338 a VAR_DECL of "int" type. */
|
|
1339 t = build_decl (UNKNOWN_LOCATION, VAR_DECL,
|
|
1340 get_identifier (desc),
|
|
1341 integer_type_node);
|
|
1342 m_fake_scope.safe_push (t);
|
|
1343 return t;
|
|
1344 }
|
|
1345
|
|
1346 /* Record that at LOC we saw an insn uid INSN_UID for the operand with index
|
|
1347 OPERAND_IDX within INSN, so that the pointer value can be fixed up in
|
|
1348 later post-processing. */
|
|
1349
|
|
1350 void
|
|
1351 function_reader::add_fixup_insn_uid (file_location loc, rtx insn, int operand_idx,
|
|
1352 int insn_uid)
|
|
1353 {
|
|
1354 m_fixups.safe_push (new fixup_insn_uid (loc, insn, operand_idx, insn_uid));
|
|
1355 }
|
|
1356
|
|
1357 /* Record that at LOC we saw an basic block index BB_IDX for the operand with index
|
|
1358 OPERAND_IDX within INSN, so that the pointer value can be fixed up in
|
|
1359 later post-processing. */
|
|
1360
|
|
1361 void
|
|
1362 function_reader::add_fixup_note_insn_basic_block (file_location loc, rtx insn,
|
|
1363 int operand_idx, int bb_idx)
|
|
1364 {
|
|
1365 m_fixups.safe_push (new fixup_note_insn_basic_block (loc, insn, operand_idx,
|
|
1366 bb_idx));
|
|
1367 }
|
|
1368
|
|
1369 /* Placeholder hook for recording source location information seen in a dump.
|
|
1370 This is empty for now. */
|
|
1371
|
|
1372 void
|
|
1373 function_reader::add_fixup_source_location (file_location, rtx_insn *,
|
145
|
1374 const char *, int, int)
|
111
|
1375 {
|
|
1376 }
|
|
1377
|
|
1378 /* Record that at LOC we saw textual description DESC of the MEM_EXPR or REG_EXPR
|
|
1379 of INSN, so that the fields can be fixed up in later post-processing. */
|
|
1380
|
|
1381 void
|
|
1382 function_reader::add_fixup_expr (file_location loc, rtx insn,
|
|
1383 const char *desc)
|
|
1384 {
|
|
1385 gcc_assert (desc);
|
|
1386 /* Fail early if the RTL reader erroneously hands us an int. */
|
|
1387 gcc_assert (!ISDIGIT (desc[0]));
|
|
1388
|
|
1389 m_fixups.safe_push (new fixup_expr (loc, insn, desc));
|
|
1390 }
|
|
1391
|
|
1392 /* Helper function for consolidate_reg. Return the global rtx for
|
|
1393 the register with regno REGNO. */
|
|
1394
|
|
1395 static rtx
|
|
1396 lookup_global_register (int regno)
|
|
1397 {
|
|
1398 /* We can't use a switch here, as some of the REGNUMs might not be constants
|
|
1399 for some targets. */
|
|
1400 if (regno == STACK_POINTER_REGNUM)
|
|
1401 return stack_pointer_rtx;
|
|
1402 else if (regno == FRAME_POINTER_REGNUM)
|
|
1403 return frame_pointer_rtx;
|
|
1404 else if (regno == HARD_FRAME_POINTER_REGNUM)
|
|
1405 return hard_frame_pointer_rtx;
|
|
1406 else if (regno == ARG_POINTER_REGNUM)
|
|
1407 return arg_pointer_rtx;
|
|
1408 else if (regno == VIRTUAL_INCOMING_ARGS_REGNUM)
|
|
1409 return virtual_incoming_args_rtx;
|
|
1410 else if (regno == VIRTUAL_STACK_VARS_REGNUM)
|
|
1411 return virtual_stack_vars_rtx;
|
|
1412 else if (regno == VIRTUAL_STACK_DYNAMIC_REGNUM)
|
|
1413 return virtual_stack_dynamic_rtx;
|
|
1414 else if (regno == VIRTUAL_OUTGOING_ARGS_REGNUM)
|
|
1415 return virtual_outgoing_args_rtx;
|
|
1416 else if (regno == VIRTUAL_CFA_REGNUM)
|
|
1417 return virtual_cfa_rtx;
|
|
1418 else if (regno == VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM)
|
|
1419 return virtual_preferred_stack_boundary_rtx;
|
|
1420 #ifdef return_ADDRESS_POINTER_REGNUM
|
|
1421 else if (regno == RETURN_ADDRESS_POINTER_REGNUM)
|
|
1422 return return_address_pointer_rtx;
|
|
1423 #endif
|
|
1424
|
|
1425 return NULL;
|
|
1426 }
|
|
1427
|
|
1428 /* Ensure that the backend can cope with a REG with regno REGNO.
|
|
1429 Normally REG instances are created by gen_reg_rtx which updates
|
|
1430 regno_reg_rtx, growing it as necessary.
|
|
1431 The REG instances created from the dumpfile weren't created this
|
|
1432 way, so we need to manually update regno_reg_rtx. */
|
|
1433
|
|
1434 static void
|
|
1435 ensure_regno (int regno)
|
|
1436 {
|
|
1437 if (reg_rtx_no < regno + 1)
|
|
1438 reg_rtx_no = regno + 1;
|
|
1439
|
|
1440 crtl->emit.ensure_regno_capacity ();
|
|
1441 gcc_assert (regno < crtl->emit.regno_pointer_align_length);
|
|
1442 }
|
|
1443
|
|
1444 /* Helper function for consolidate_singletons, for handling REG instances.
|
|
1445 Given REG instance X of some regno, return the singleton rtx for that
|
|
1446 regno, if it exists, or X. */
|
|
1447
|
|
1448 static rtx
|
|
1449 consolidate_reg (rtx x)
|
|
1450 {
|
|
1451 gcc_assert (GET_CODE (x) == REG);
|
|
1452
|
|
1453 unsigned int regno = REGNO (x);
|
|
1454
|
|
1455 ensure_regno (regno);
|
|
1456
|
|
1457 /* Some register numbers have their rtx created in init_emit_regs
|
|
1458 e.g. stack_pointer_rtx for STACK_POINTER_REGNUM.
|
|
1459 Consolidate on this. */
|
|
1460 rtx global_reg = lookup_global_register (regno);
|
|
1461 if (global_reg)
|
|
1462 return global_reg;
|
|
1463
|
|
1464 /* Populate regno_reg_rtx if necessary. */
|
|
1465 if (regno_reg_rtx[regno] == NULL)
|
|
1466 regno_reg_rtx[regno] = x;
|
|
1467 /* Use it. */
|
|
1468 gcc_assert (GET_CODE (regno_reg_rtx[regno]) == REG);
|
|
1469 gcc_assert (REGNO (regno_reg_rtx[regno]) == regno);
|
|
1470 if (GET_MODE (x) == GET_MODE (regno_reg_rtx[regno]))
|
|
1471 return regno_reg_rtx[regno];
|
|
1472
|
|
1473 return x;
|
|
1474 }
|
|
1475
|
|
1476 /* When reading RTL function dumps, we must consolidate some
|
|
1477 rtx so that we use singletons where singletons are expected
|
|
1478 (e.g. we don't want multiple "(const_int 0 [0])" rtx, since
|
|
1479 these are tested via pointer equality against const0_rtx.
|
|
1480
|
|
1481 Return the equivalent singleton rtx for X, if any, otherwise X. */
|
|
1482
|
|
1483 rtx
|
|
1484 function_reader::consolidate_singletons (rtx x)
|
|
1485 {
|
|
1486 if (!x)
|
|
1487 return x;
|
|
1488
|
|
1489 switch (GET_CODE (x))
|
|
1490 {
|
|
1491 case PC: return pc_rtx;
|
|
1492 case RETURN: return ret_rtx;
|
|
1493 case SIMPLE_RETURN: return simple_return_rtx;
|
|
1494 case CC0: return cc0_rtx;
|
|
1495
|
|
1496 case REG:
|
|
1497 return consolidate_reg (x);
|
|
1498
|
|
1499 case CONST_INT:
|
|
1500 return gen_rtx_CONST_INT (GET_MODE (x), INTVAL (x));
|
|
1501
|
|
1502 default:
|
|
1503 break;
|
|
1504 }
|
|
1505
|
|
1506 return x;
|
|
1507 }
|
|
1508
|
|
1509 /* Parse an rtx directive, including both the opening/closing parentheses,
|
|
1510 and the name. */
|
|
1511
|
|
1512 rtx
|
|
1513 function_reader::parse_rtx ()
|
|
1514 {
|
|
1515 require_char_ws ('(');
|
|
1516 struct md_name directive;
|
|
1517 read_name (&directive);
|
|
1518 rtx result
|
|
1519 = consolidate_singletons (read_rtx_code (directive.string));
|
|
1520 require_char_ws (')');
|
|
1521
|
|
1522 return result;
|
|
1523 }
|
|
1524
|
|
1525 /* Implementation of rtx_reader::postprocess for reading function dumps.
|
|
1526 Return the equivalent singleton rtx for X, if any, otherwise X. */
|
|
1527
|
|
1528 rtx
|
|
1529 function_reader::postprocess (rtx x)
|
|
1530 {
|
|
1531 return consolidate_singletons (x);
|
|
1532 }
|
|
1533
|
|
1534 /* Implementation of rtx_reader::finalize_string for reading function dumps.
|
|
1535 Make a GC-managed copy of STRINGBUF. */
|
|
1536
|
|
1537 const char *
|
|
1538 function_reader::finalize_string (char *stringbuf)
|
|
1539 {
|
|
1540 return ggc_strdup (stringbuf);
|
|
1541 }
|
|
1542
|
|
1543 /* Attempt to parse optional location information for insn INSN, as
|
|
1544 potentially written out by rtx_writer::print_rtx_operand_code_i.
|
|
1545 We look for a quoted string followed by a colon. */
|
|
1546
|
|
1547 void
|
|
1548 function_reader::maybe_read_location (rtx_insn *insn)
|
|
1549 {
|
|
1550 file_location loc = get_current_location ();
|
|
1551
|
|
1552 /* Attempt to parse a quoted string. */
|
|
1553 int ch = read_skip_spaces ();
|
|
1554 if (ch == '"')
|
|
1555 {
|
|
1556 char *filename = read_quoted_string ();
|
|
1557 require_char (':');
|
|
1558 struct md_name line_num;
|
|
1559 read_name (&line_num);
|
145
|
1560
|
|
1561 int column = 0;
|
|
1562 int ch = read_char ();
|
|
1563 if (ch == ':')
|
|
1564 {
|
|
1565 struct md_name column_num;
|
|
1566 read_name (&column_num);
|
|
1567 column = atoi (column_num.string);
|
|
1568 }
|
|
1569 else
|
|
1570 unread_char (ch);
|
|
1571 add_fixup_source_location (loc, insn, filename,
|
|
1572 atoi (line_num.string),
|
|
1573 column);
|
111
|
1574 }
|
|
1575 else
|
|
1576 unread_char (ch);
|
|
1577 }
|
|
1578
|
|
1579 /* Postprocessing subroutine of function_reader::parse_function.
|
|
1580 Populate m_insns_by_uid. */
|
|
1581
|
|
1582 void
|
|
1583 function_reader::handle_insn_uids ()
|
|
1584 {
|
|
1585 /* Locate the currently assigned INSN_UID values, storing
|
|
1586 them in m_insns_by_uid. */
|
|
1587 int max_uid = 0;
|
|
1588 for (rtx_insn *insn = get_insns (); insn; insn = NEXT_INSN (insn))
|
|
1589 {
|
|
1590 if (m_insns_by_uid.get (INSN_UID (insn)))
|
|
1591 error ("duplicate insn UID: %i", INSN_UID (insn));
|
|
1592 m_insns_by_uid.put (INSN_UID (insn), insn);
|
|
1593 if (INSN_UID (insn) > max_uid)
|
|
1594 max_uid = INSN_UID (insn);
|
|
1595 }
|
|
1596
|
|
1597 /* Ensure x_cur_insn_uid is 1 more than the biggest insn UID seen.
|
|
1598 This is normally updated by the various make_*insn_raw functions. */
|
|
1599 crtl->emit.x_cur_insn_uid = max_uid + 1;
|
|
1600 }
|
|
1601
|
|
1602 /* Apply all of the recorded fixups. */
|
|
1603
|
|
1604 void
|
|
1605 function_reader::apply_fixups ()
|
|
1606 {
|
|
1607 int i;
|
|
1608 fixup *f;
|
|
1609 FOR_EACH_VEC_ELT (m_fixups, i, f)
|
|
1610 f->apply (this);
|
|
1611 }
|
|
1612
|
|
1613 /* Given a UID value, try to locate a pointer to the corresponding
|
|
1614 rtx_insn *, or NULL if if can't be found. */
|
|
1615
|
|
1616 rtx_insn **
|
|
1617 function_reader::get_insn_by_uid (int uid)
|
|
1618 {
|
|
1619 return m_insns_by_uid.get (uid);
|
|
1620 }
|
|
1621
|
|
1622 /* Run the RTL dump parser, parsing a dump located at PATH.
|
|
1623 Return true iff the file was successfully parsed. */
|
|
1624
|
|
1625 bool
|
|
1626 read_rtl_function_body (const char *path)
|
|
1627 {
|
|
1628 initialize_rtl ();
|
145
|
1629 crtl->abi = &default_function_abi;
|
111
|
1630 init_emit ();
|
|
1631 init_varasm_status ();
|
|
1632
|
|
1633 function_reader reader;
|
|
1634 if (!reader.read_file (path))
|
|
1635 return false;
|
|
1636
|
|
1637 return true;
|
|
1638 }
|
|
1639
|
|
1640 /* Run the RTL dump parser on the range of lines between START_LOC and
|
|
1641 END_LOC (including those lines). */
|
|
1642
|
|
1643 bool
|
|
1644 read_rtl_function_body_from_file_range (location_t start_loc,
|
|
1645 location_t end_loc)
|
|
1646 {
|
|
1647 expanded_location exploc_start = expand_location (start_loc);
|
|
1648 expanded_location exploc_end = expand_location (end_loc);
|
|
1649
|
|
1650 if (exploc_start.file != exploc_end.file)
|
|
1651 {
|
|
1652 error_at (end_loc, "start/end of RTL fragment are in different files");
|
|
1653 return false;
|
|
1654 }
|
|
1655 if (exploc_start.line >= exploc_end.line)
|
|
1656 {
|
|
1657 error_at (end_loc,
|
|
1658 "start of RTL fragment must be on an earlier line than end");
|
|
1659 return false;
|
|
1660 }
|
|
1661
|
|
1662 initialize_rtl ();
|
145
|
1663 crtl->abi = &fndecl_abi (cfun->decl).base_abi ();
|
111
|
1664 init_emit ();
|
|
1665 init_varasm_status ();
|
|
1666
|
|
1667 function_reader reader;
|
|
1668 if (!reader.read_file_fragment (exploc_start.file, exploc_start.line,
|
|
1669 exploc_end.line - 1))
|
|
1670 return false;
|
|
1671
|
|
1672 return true;
|
|
1673 }
|
|
1674
|
|
1675 #if CHECKING_P
|
|
1676
|
|
1677 namespace selftest {
|
|
1678
|
|
1679 /* Verify that parse_edge_flags works. */
|
|
1680
|
|
1681 static void
|
|
1682 test_edge_flags ()
|
|
1683 {
|
|
1684 /* parse_edge_flags modifies its input (due to strtok), so we must make
|
|
1685 a copy of the literals. */
|
|
1686 #define ASSERT_PARSE_EDGE_FLAGS(EXPECTED, STR) \
|
|
1687 do { \
|
|
1688 char *str = xstrdup (STR); \
|
|
1689 ASSERT_EQ (EXPECTED, parse_edge_flags (str)); \
|
|
1690 free (str); \
|
|
1691 } while (0)
|
|
1692
|
|
1693 ASSERT_PARSE_EDGE_FLAGS (0, "");
|
|
1694 ASSERT_PARSE_EDGE_FLAGS (EDGE_FALLTHRU, "FALLTHRU");
|
|
1695 ASSERT_PARSE_EDGE_FLAGS (EDGE_ABNORMAL_CALL, "ABNORMAL_CALL");
|
|
1696 ASSERT_PARSE_EDGE_FLAGS (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL,
|
|
1697 "ABNORMAL | ABNORMAL_CALL");
|
|
1698
|
|
1699 #undef ASSERT_PARSE_EDGE_FLAGS
|
|
1700 }
|
|
1701
|
|
1702 /* Verify that lookup_reg_by_dump_name works. */
|
|
1703
|
|
1704 static void
|
|
1705 test_parsing_regnos ()
|
|
1706 {
|
|
1707 ASSERT_EQ (-1, lookup_reg_by_dump_name ("this is not a register"));
|
|
1708
|
|
1709 /* Verify lookup of virtual registers. */
|
|
1710 ASSERT_EQ (VIRTUAL_INCOMING_ARGS_REGNUM,
|
|
1711 lookup_reg_by_dump_name ("virtual-incoming-args"));
|
|
1712 ASSERT_EQ (VIRTUAL_STACK_VARS_REGNUM,
|
|
1713 lookup_reg_by_dump_name ("virtual-stack-vars"));
|
|
1714 ASSERT_EQ (VIRTUAL_STACK_DYNAMIC_REGNUM,
|
|
1715 lookup_reg_by_dump_name ("virtual-stack-dynamic"));
|
|
1716 ASSERT_EQ (VIRTUAL_OUTGOING_ARGS_REGNUM,
|
|
1717 lookup_reg_by_dump_name ("virtual-outgoing-args"));
|
|
1718 ASSERT_EQ (VIRTUAL_CFA_REGNUM,
|
|
1719 lookup_reg_by_dump_name ("virtual-cfa"));
|
|
1720 ASSERT_EQ (VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM,
|
|
1721 lookup_reg_by_dump_name ("virtual-preferred-stack-boundary"));
|
|
1722
|
|
1723 /* Verify lookup of non-virtual pseudos. */
|
|
1724 ASSERT_EQ (LAST_VIRTUAL_REGISTER + 1, lookup_reg_by_dump_name ("<0>"));
|
|
1725 ASSERT_EQ (LAST_VIRTUAL_REGISTER + 2, lookup_reg_by_dump_name ("<1>"));
|
|
1726 }
|
|
1727
|
|
1728 /* Verify that edge E is as expected, with the src and dest basic blocks
|
|
1729 having indices EXPECTED_SRC_IDX and EXPECTED_DEST_IDX respectively, and
|
|
1730 the edge having flags equal to EXPECTED_FLAGS.
|
|
1731 Use LOC as the effective location when reporting failures. */
|
|
1732
|
|
1733 static void
|
|
1734 assert_edge_at (const location &loc, edge e, int expected_src_idx,
|
|
1735 int expected_dest_idx, int expected_flags)
|
|
1736 {
|
|
1737 ASSERT_EQ_AT (loc, expected_src_idx, e->src->index);
|
|
1738 ASSERT_EQ_AT (loc, expected_dest_idx, e->dest->index);
|
|
1739 ASSERT_EQ_AT (loc, expected_flags, e->flags);
|
|
1740 }
|
|
1741
|
|
1742 /* Verify that edge EDGE is as expected, with the src and dest basic blocks
|
|
1743 having indices EXPECTED_SRC_IDX and EXPECTED_DEST_IDX respectively, and
|
|
1744 the edge having flags equal to EXPECTED_FLAGS. */
|
|
1745
|
|
1746 #define ASSERT_EDGE(EDGE, EXPECTED_SRC_IDX, EXPECTED_DEST_IDX, \
|
|
1747 EXPECTED_FLAGS) \
|
|
1748 assert_edge_at (SELFTEST_LOCATION, EDGE, EXPECTED_SRC_IDX, \
|
|
1749 EXPECTED_DEST_IDX, EXPECTED_FLAGS)
|
|
1750
|
|
1751 /* Verify that we can load RTL dumps. */
|
|
1752
|
|
1753 static void
|
|
1754 test_loading_dump_fragment_1 ()
|
|
1755 {
|
|
1756 // TODO: filter on target?
|
|
1757 rtl_dump_test t (SELFTEST_LOCATION, locate_file ("asr_div1.rtl"));
|
|
1758
|
|
1759 /* Verify that the insns were loaded correctly. */
|
|
1760 rtx_insn *insn_1 = get_insns ();
|
|
1761 ASSERT_TRUE (insn_1);
|
|
1762 ASSERT_EQ (1, INSN_UID (insn_1));
|
|
1763 ASSERT_EQ (INSN, GET_CODE (insn_1));
|
|
1764 ASSERT_EQ (SET, GET_CODE (PATTERN (insn_1)));
|
|
1765 ASSERT_EQ (NULL, PREV_INSN (insn_1));
|
|
1766
|
|
1767 rtx_insn *insn_2 = NEXT_INSN (insn_1);
|
|
1768 ASSERT_TRUE (insn_2);
|
|
1769 ASSERT_EQ (2, INSN_UID (insn_2));
|
|
1770 ASSERT_EQ (INSN, GET_CODE (insn_2));
|
|
1771 ASSERT_EQ (insn_1, PREV_INSN (insn_2));
|
|
1772 ASSERT_EQ (NULL, NEXT_INSN (insn_2));
|
|
1773
|
|
1774 /* Verify that registers were loaded correctly. */
|
|
1775 rtx insn_1_dest = SET_DEST (PATTERN (insn_1));
|
|
1776 ASSERT_EQ (REG, GET_CODE (insn_1_dest));
|
|
1777 ASSERT_EQ ((LAST_VIRTUAL_REGISTER + 1) + 2, REGNO (insn_1_dest));
|
|
1778 rtx insn_1_src = SET_SRC (PATTERN (insn_1));
|
|
1779 ASSERT_EQ (LSHIFTRT, GET_CODE (insn_1_src));
|
|
1780 rtx reg = XEXP (insn_1_src, 0);
|
|
1781 ASSERT_EQ (REG, GET_CODE (reg));
|
|
1782 ASSERT_EQ (LAST_VIRTUAL_REGISTER + 1, REGNO (reg));
|
|
1783
|
|
1784 /* Verify that get_insn_by_uid works. */
|
|
1785 ASSERT_EQ (insn_1, get_insn_by_uid (1));
|
|
1786 ASSERT_EQ (insn_2, get_insn_by_uid (2));
|
|
1787
|
|
1788 /* Verify that basic blocks were created. */
|
|
1789 ASSERT_EQ (2, BLOCK_FOR_INSN (insn_1)->index);
|
|
1790 ASSERT_EQ (2, BLOCK_FOR_INSN (insn_2)->index);
|
|
1791
|
|
1792 /* Verify that the CFG was recreated. */
|
|
1793 ASSERT_TRUE (cfun);
|
|
1794 verify_three_block_rtl_cfg (cfun);
|
|
1795 basic_block bb2 = BASIC_BLOCK_FOR_FN (cfun, 2);
|
|
1796 ASSERT_TRUE (bb2 != NULL);
|
|
1797 ASSERT_EQ (BB_RTL, bb2->flags & BB_RTL);
|
|
1798 ASSERT_EQ (2, bb2->index);
|
|
1799 ASSERT_EQ (insn_1, BB_HEAD (bb2));
|
|
1800 ASSERT_EQ (insn_2, BB_END (bb2));
|
|
1801 }
|
|
1802
|
|
1803 /* Verify loading another RTL dump. */
|
|
1804
|
|
1805 static void
|
|
1806 test_loading_dump_fragment_2 ()
|
|
1807 {
|
|
1808 rtl_dump_test t (SELFTEST_LOCATION, locate_file ("simple-cse.rtl"));
|
|
1809
|
|
1810 rtx_insn *insn_1 = get_insn_by_uid (1);
|
|
1811 rtx_insn *insn_2 = get_insn_by_uid (2);
|
|
1812 rtx_insn *insn_3 = get_insn_by_uid (3);
|
|
1813
|
|
1814 rtx set1 = single_set (insn_1);
|
|
1815 ASSERT_NE (NULL, set1);
|
|
1816 rtx set2 = single_set (insn_2);
|
|
1817 ASSERT_NE (NULL, set2);
|
|
1818 rtx set3 = single_set (insn_3);
|
|
1819 ASSERT_NE (NULL, set3);
|
|
1820
|
|
1821 rtx src1 = SET_SRC (set1);
|
|
1822 ASSERT_EQ (PLUS, GET_CODE (src1));
|
|
1823
|
|
1824 rtx src2 = SET_SRC (set2);
|
|
1825 ASSERT_EQ (PLUS, GET_CODE (src2));
|
|
1826
|
|
1827 /* Both src1 and src2 refer to "(reg:SI %0)".
|
|
1828 Verify that we have pointer equality. */
|
|
1829 rtx lhs1 = XEXP (src1, 0);
|
|
1830 rtx lhs2 = XEXP (src2, 0);
|
|
1831 ASSERT_EQ (lhs1, lhs2);
|
|
1832
|
|
1833 /* Verify that the CFG was recreated. */
|
|
1834 ASSERT_TRUE (cfun);
|
|
1835 verify_three_block_rtl_cfg (cfun);
|
|
1836 }
|
|
1837
|
|
1838 /* Verify that CODE_LABEL insns are loaded correctly. */
|
|
1839
|
|
1840 static void
|
|
1841 test_loading_labels ()
|
|
1842 {
|
|
1843 rtl_dump_test t (SELFTEST_LOCATION, locate_file ("example-labels.rtl"));
|
|
1844
|
|
1845 rtx_insn *insn_100 = get_insn_by_uid (100);
|
|
1846 ASSERT_EQ (CODE_LABEL, GET_CODE (insn_100));
|
|
1847 ASSERT_EQ (100, INSN_UID (insn_100));
|
|
1848 ASSERT_EQ (NULL, LABEL_NAME (insn_100));
|
|
1849 ASSERT_EQ (0, LABEL_NUSES (insn_100));
|
|
1850 ASSERT_EQ (30, CODE_LABEL_NUMBER (insn_100));
|
|
1851
|
|
1852 rtx_insn *insn_200 = get_insn_by_uid (200);
|
|
1853 ASSERT_EQ (CODE_LABEL, GET_CODE (insn_200));
|
|
1854 ASSERT_EQ (200, INSN_UID (insn_200));
|
|
1855 ASSERT_STREQ ("some_label_name", LABEL_NAME (insn_200));
|
|
1856 ASSERT_EQ (0, LABEL_NUSES (insn_200));
|
|
1857 ASSERT_EQ (40, CODE_LABEL_NUMBER (insn_200));
|
|
1858
|
|
1859 /* Ensure that the presence of CODE_LABEL_NUMBER == 40
|
|
1860 means that the next label num to be handed out will be 41. */
|
|
1861 ASSERT_EQ (41, max_label_num ());
|
|
1862
|
|
1863 /* Ensure that label names read from a dump are GC-managed
|
|
1864 and are found through the insn. */
|
|
1865 forcibly_ggc_collect ();
|
|
1866 ASSERT_TRUE (ggc_marked_p (insn_200));
|
|
1867 ASSERT_TRUE (ggc_marked_p (LABEL_NAME (insn_200)));
|
|
1868 }
|
|
1869
|
|
1870 /* Verify that the loader copes with an insn with a mode. */
|
|
1871
|
|
1872 static void
|
|
1873 test_loading_insn_with_mode ()
|
|
1874 {
|
|
1875 rtl_dump_test t (SELFTEST_LOCATION, locate_file ("insn-with-mode.rtl"));
|
|
1876 rtx_insn *insn = get_insns ();
|
|
1877 ASSERT_EQ (INSN, GET_CODE (insn));
|
|
1878
|
|
1879 /* Verify that the "TI" mode was set from "insn:TI". */
|
|
1880 ASSERT_EQ (TImode, GET_MODE (insn));
|
|
1881 }
|
|
1882
|
|
1883 /* Verify that the loader copes with a jump_insn to a label_ref. */
|
|
1884
|
|
1885 static void
|
|
1886 test_loading_jump_to_label_ref ()
|
|
1887 {
|
|
1888 rtl_dump_test t (SELFTEST_LOCATION, locate_file ("jump-to-label-ref.rtl"));
|
|
1889
|
|
1890 rtx_insn *jump_insn = get_insn_by_uid (1);
|
|
1891 ASSERT_EQ (JUMP_INSN, GET_CODE (jump_insn));
|
|
1892
|
|
1893 rtx_insn *barrier = get_insn_by_uid (2);
|
|
1894 ASSERT_EQ (BARRIER, GET_CODE (barrier));
|
|
1895
|
|
1896 rtx_insn *code_label = get_insn_by_uid (100);
|
|
1897 ASSERT_EQ (CODE_LABEL, GET_CODE (code_label));
|
|
1898
|
|
1899 /* Verify the jump_insn. */
|
|
1900 ASSERT_EQ (4, BLOCK_FOR_INSN (jump_insn)->index);
|
|
1901 ASSERT_EQ (SET, GET_CODE (PATTERN (jump_insn)));
|
|
1902 /* Ensure that the "(pc)" is using the global singleton. */
|
|
1903 ASSERT_RTX_PTR_EQ (pc_rtx, SET_DEST (PATTERN (jump_insn)));
|
|
1904 rtx label_ref = SET_SRC (PATTERN (jump_insn));
|
|
1905 ASSERT_EQ (LABEL_REF, GET_CODE (label_ref));
|
|
1906 ASSERT_EQ (code_label, label_ref_label (label_ref));
|
|
1907 ASSERT_EQ (code_label, JUMP_LABEL (jump_insn));
|
|
1908
|
|
1909 /* Verify the code_label. */
|
|
1910 ASSERT_EQ (5, BLOCK_FOR_INSN (code_label)->index);
|
|
1911 ASSERT_EQ (NULL, LABEL_NAME (code_label));
|
|
1912 ASSERT_EQ (1, LABEL_NUSES (code_label));
|
|
1913
|
|
1914 /* Verify the generated CFG. */
|
|
1915
|
|
1916 /* Locate blocks. */
|
|
1917 basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (cfun);
|
|
1918 ASSERT_TRUE (entry != NULL);
|
|
1919 ASSERT_EQ (ENTRY_BLOCK, entry->index);
|
|
1920
|
|
1921 basic_block exit = EXIT_BLOCK_PTR_FOR_FN (cfun);
|
|
1922 ASSERT_TRUE (exit != NULL);
|
|
1923 ASSERT_EQ (EXIT_BLOCK, exit->index);
|
|
1924
|
|
1925 basic_block bb4 = (*cfun->cfg->x_basic_block_info)[4];
|
|
1926 basic_block bb5 = (*cfun->cfg->x_basic_block_info)[5];
|
|
1927 ASSERT_EQ (4, bb4->index);
|
|
1928 ASSERT_EQ (5, bb5->index);
|
|
1929
|
|
1930 /* Entry block. */
|
|
1931 ASSERT_EQ (NULL, entry->preds);
|
|
1932 ASSERT_EQ (1, entry->succs->length ());
|
|
1933 ASSERT_EDGE ((*entry->succs)[0], 0, 4, EDGE_FALLTHRU);
|
|
1934
|
|
1935 /* bb4. */
|
|
1936 ASSERT_EQ (1, bb4->preds->length ());
|
|
1937 ASSERT_EDGE ((*bb4->preds)[0], 0, 4, EDGE_FALLTHRU);
|
|
1938 ASSERT_EQ (1, bb4->succs->length ());
|
|
1939 ASSERT_EDGE ((*bb4->succs)[0], 4, 5, 0x0);
|
|
1940
|
|
1941 /* bb5. */
|
|
1942 ASSERT_EQ (1, bb5->preds->length ());
|
|
1943 ASSERT_EDGE ((*bb5->preds)[0], 4, 5, 0x0);
|
|
1944 ASSERT_EQ (1, bb5->succs->length ());
|
|
1945 ASSERT_EDGE ((*bb5->succs)[0], 5, 1, EDGE_FALLTHRU);
|
|
1946
|
|
1947 /* Exit block. */
|
|
1948 ASSERT_EQ (1, exit->preds->length ());
|
|
1949 ASSERT_EDGE ((*exit->preds)[0], 5, 1, EDGE_FALLTHRU);
|
|
1950 ASSERT_EQ (NULL, exit->succs);
|
|
1951 }
|
|
1952
|
|
1953 /* Verify that the loader copes with a jump_insn to a label_ref
|
|
1954 marked "return". */
|
|
1955
|
|
1956 static void
|
|
1957 test_loading_jump_to_return ()
|
|
1958 {
|
|
1959 rtl_dump_test t (SELFTEST_LOCATION, locate_file ("jump-to-return.rtl"));
|
|
1960
|
|
1961 rtx_insn *jump_insn = get_insn_by_uid (1);
|
|
1962 ASSERT_EQ (JUMP_INSN, GET_CODE (jump_insn));
|
|
1963 ASSERT_RTX_PTR_EQ (ret_rtx, JUMP_LABEL (jump_insn));
|
|
1964 }
|
|
1965
|
|
1966 /* Verify that the loader copes with a jump_insn to a label_ref
|
|
1967 marked "simple_return". */
|
|
1968
|
|
1969 static void
|
|
1970 test_loading_jump_to_simple_return ()
|
|
1971 {
|
|
1972 rtl_dump_test t (SELFTEST_LOCATION,
|
|
1973 locate_file ("jump-to-simple-return.rtl"));
|
|
1974
|
|
1975 rtx_insn *jump_insn = get_insn_by_uid (1);
|
|
1976 ASSERT_EQ (JUMP_INSN, GET_CODE (jump_insn));
|
|
1977 ASSERT_RTX_PTR_EQ (simple_return_rtx, JUMP_LABEL (jump_insn));
|
|
1978 }
|
|
1979
|
|
1980 /* Verify that the loader copes with a NOTE_INSN_BASIC_BLOCK. */
|
|
1981
|
|
1982 static void
|
|
1983 test_loading_note_insn_basic_block ()
|
|
1984 {
|
|
1985 rtl_dump_test t (SELFTEST_LOCATION,
|
|
1986 locate_file ("note_insn_basic_block.rtl"));
|
|
1987
|
|
1988 rtx_insn *note = get_insn_by_uid (1);
|
|
1989 ASSERT_EQ (NOTE, GET_CODE (note));
|
|
1990 ASSERT_EQ (2, BLOCK_FOR_INSN (note)->index);
|
|
1991
|
|
1992 ASSERT_EQ (NOTE_INSN_BASIC_BLOCK, NOTE_KIND (note));
|
|
1993 ASSERT_EQ (2, NOTE_BASIC_BLOCK (note)->index);
|
|
1994 ASSERT_EQ (BASIC_BLOCK_FOR_FN (cfun, 2), NOTE_BASIC_BLOCK (note));
|
|
1995 }
|
|
1996
|
|
1997 /* Verify that the loader copes with a NOTE_INSN_DELETED. */
|
|
1998
|
|
1999 static void
|
|
2000 test_loading_note_insn_deleted ()
|
|
2001 {
|
|
2002 rtl_dump_test t (SELFTEST_LOCATION, locate_file ("note-insn-deleted.rtl"));
|
|
2003
|
|
2004 rtx_insn *note = get_insn_by_uid (1);
|
|
2005 ASSERT_EQ (NOTE, GET_CODE (note));
|
|
2006 ASSERT_EQ (NOTE_INSN_DELETED, NOTE_KIND (note));
|
|
2007 }
|
|
2008
|
|
2009 /* Verify that the const_int values are consolidated, since
|
|
2010 pointer equality corresponds to value equality.
|
|
2011 TODO: do this for all in CASE_CONST_UNIQUE. */
|
|
2012
|
|
2013 static void
|
|
2014 test_loading_const_int ()
|
|
2015 {
|
|
2016 rtl_dump_test t (SELFTEST_LOCATION, locate_file ("const-int.rtl"));
|
|
2017
|
|
2018 /* Verify that const_int values below MAX_SAVED_CONST_INT use
|
|
2019 the global values. */
|
|
2020 ASSERT_EQ (const0_rtx, SET_SRC (PATTERN (get_insn_by_uid (1))));
|
|
2021 ASSERT_EQ (const1_rtx, SET_SRC (PATTERN (get_insn_by_uid (2))));
|
|
2022 ASSERT_EQ (constm1_rtx, SET_SRC (PATTERN (get_insn_by_uid (3))));
|
|
2023
|
|
2024 /* Verify that other const_int values are consolidated. */
|
|
2025 rtx int256 = gen_rtx_CONST_INT (SImode, 256);
|
|
2026 ASSERT_EQ (int256, SET_SRC (PATTERN (get_insn_by_uid (4))));
|
|
2027 }
|
|
2028
|
|
2029 /* Verify that the loader copes with a SYMBOL_REF. */
|
|
2030
|
|
2031 static void
|
|
2032 test_loading_symbol_ref ()
|
|
2033 {
|
|
2034 rtl_dump_test t (SELFTEST_LOCATION, locate_file ("symbol-ref.rtl"));
|
|
2035
|
|
2036 rtx_insn *insn = get_insns ();
|
|
2037
|
|
2038 rtx high = SET_SRC (PATTERN (insn));
|
|
2039 ASSERT_EQ (HIGH, GET_CODE (high));
|
|
2040
|
|
2041 rtx symbol_ref = XEXP (high, 0);
|
|
2042 ASSERT_EQ (SYMBOL_REF, GET_CODE (symbol_ref));
|
|
2043
|
|
2044 /* Verify that "[flags 0xc0]" was parsed. */
|
|
2045 ASSERT_EQ (0xc0, SYMBOL_REF_FLAGS (symbol_ref));
|
|
2046 /* TODO: we don't yet load SYMBOL_REF_DECL. */
|
|
2047 }
|
|
2048
|
|
2049 /* Verify that the loader can rebuild a CFG. */
|
|
2050
|
|
2051 static void
|
|
2052 test_loading_cfg ()
|
|
2053 {
|
|
2054 rtl_dump_test t (SELFTEST_LOCATION, locate_file ("cfg-test.rtl"));
|
|
2055
|
|
2056 ASSERT_STREQ ("cfg_test", IDENTIFIER_POINTER (DECL_NAME (cfun->decl)));
|
|
2057
|
|
2058 ASSERT_TRUE (cfun);
|
|
2059
|
|
2060 ASSERT_TRUE (cfun->cfg != NULL);
|
|
2061 ASSERT_EQ (6, n_basic_blocks_for_fn (cfun));
|
|
2062 ASSERT_EQ (6, n_edges_for_fn (cfun));
|
|
2063
|
|
2064 /* The "fake" basic blocks. */
|
|
2065 basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (cfun);
|
|
2066 ASSERT_TRUE (entry != NULL);
|
|
2067 ASSERT_EQ (ENTRY_BLOCK, entry->index);
|
|
2068
|
|
2069 basic_block exit = EXIT_BLOCK_PTR_FOR_FN (cfun);
|
|
2070 ASSERT_TRUE (exit != NULL);
|
|
2071 ASSERT_EQ (EXIT_BLOCK, exit->index);
|
|
2072
|
|
2073 /* The "real" basic blocks. */
|
|
2074 basic_block bb2 = (*cfun->cfg->x_basic_block_info)[2];
|
|
2075 basic_block bb3 = (*cfun->cfg->x_basic_block_info)[3];
|
|
2076 basic_block bb4 = (*cfun->cfg->x_basic_block_info)[4];
|
|
2077 basic_block bb5 = (*cfun->cfg->x_basic_block_info)[5];
|
|
2078
|
|
2079 ASSERT_EQ (2, bb2->index);
|
|
2080 ASSERT_EQ (3, bb3->index);
|
|
2081 ASSERT_EQ (4, bb4->index);
|
|
2082 ASSERT_EQ (5, bb5->index);
|
|
2083
|
|
2084 /* Verify connectivity. */
|
|
2085
|
|
2086 /* Entry block. */
|
|
2087 ASSERT_EQ (NULL, entry->preds);
|
|
2088 ASSERT_EQ (1, entry->succs->length ());
|
|
2089 ASSERT_EDGE ((*entry->succs)[0], 0, 2, EDGE_FALLTHRU);
|
|
2090
|
|
2091 /* bb2. */
|
|
2092 ASSERT_EQ (1, bb2->preds->length ());
|
|
2093 ASSERT_EDGE ((*bb2->preds)[0], 0, 2, EDGE_FALLTHRU);
|
|
2094 ASSERT_EQ (2, bb2->succs->length ());
|
|
2095 ASSERT_EDGE ((*bb2->succs)[0], 2, 3, EDGE_TRUE_VALUE);
|
|
2096 ASSERT_EDGE ((*bb2->succs)[1], 2, 4, EDGE_FALSE_VALUE);
|
|
2097
|
|
2098 /* bb3. */
|
|
2099 ASSERT_EQ (1, bb3->preds->length ());
|
|
2100 ASSERT_EDGE ((*bb3->preds)[0], 2, 3, EDGE_TRUE_VALUE);
|
|
2101 ASSERT_EQ (1, bb3->succs->length ());
|
|
2102 ASSERT_EDGE ((*bb3->succs)[0], 3, 5, EDGE_FALLTHRU);
|
|
2103
|
|
2104 /* bb4. */
|
|
2105 ASSERT_EQ (1, bb4->preds->length ());
|
|
2106 ASSERT_EDGE ((*bb4->preds)[0], 2, 4, EDGE_FALSE_VALUE);
|
|
2107 ASSERT_EQ (1, bb4->succs->length ());
|
|
2108 ASSERT_EDGE ((*bb4->succs)[0], 4, 5, EDGE_FALLTHRU);
|
|
2109
|
|
2110 /* bb5. */
|
|
2111 ASSERT_EQ (2, bb5->preds->length ());
|
|
2112 ASSERT_EDGE ((*bb5->preds)[0], 3, 5, EDGE_FALLTHRU);
|
|
2113 ASSERT_EDGE ((*bb5->preds)[1], 4, 5, EDGE_FALLTHRU);
|
|
2114 ASSERT_EQ (1, bb5->succs->length ());
|
|
2115 ASSERT_EDGE ((*bb5->succs)[0], 5, 1, EDGE_FALLTHRU);
|
|
2116
|
|
2117 /* Exit block. */
|
|
2118 ASSERT_EQ (1, exit->preds->length ());
|
|
2119 ASSERT_EDGE ((*exit->preds)[0], 5, 1, EDGE_FALLTHRU);
|
|
2120 ASSERT_EQ (NULL, exit->succs);
|
|
2121 }
|
|
2122
|
|
2123 /* Verify that the loader copes with sparse block indices.
|
|
2124 This testcase loads a file with a "(block 42)". */
|
|
2125
|
|
2126 static void
|
|
2127 test_loading_bb_index ()
|
|
2128 {
|
|
2129 rtl_dump_test t (SELFTEST_LOCATION, locate_file ("bb-index.rtl"));
|
|
2130
|
|
2131 ASSERT_STREQ ("test_bb_index", IDENTIFIER_POINTER (DECL_NAME (cfun->decl)));
|
|
2132
|
|
2133 ASSERT_TRUE (cfun);
|
|
2134
|
|
2135 ASSERT_TRUE (cfun->cfg != NULL);
|
|
2136 ASSERT_EQ (3, n_basic_blocks_for_fn (cfun));
|
|
2137 ASSERT_EQ (43, basic_block_info_for_fn (cfun)->length ());
|
|
2138 ASSERT_EQ (2, n_edges_for_fn (cfun));
|
|
2139
|
|
2140 ASSERT_EQ (NULL, (*cfun->cfg->x_basic_block_info)[41]);
|
|
2141 basic_block bb42 = (*cfun->cfg->x_basic_block_info)[42];
|
|
2142 ASSERT_NE (NULL, bb42);
|
|
2143 ASSERT_EQ (42, bb42->index);
|
|
2144 }
|
|
2145
|
|
2146 /* Verify that function_reader::handle_any_trailing_information correctly
|
|
2147 parses all the possible items emitted for a MEM. */
|
|
2148
|
|
2149 static void
|
|
2150 test_loading_mem ()
|
|
2151 {
|
|
2152 rtl_dump_test t (SELFTEST_LOCATION, locate_file ("mem.rtl"));
|
|
2153
|
|
2154 ASSERT_STREQ ("test_mem", IDENTIFIER_POINTER (DECL_NAME (cfun->decl)));
|
|
2155 ASSERT_TRUE (cfun);
|
|
2156
|
|
2157 /* Verify parsing of "[42 i+17 S8 A128 AS5]". */
|
|
2158 rtx_insn *insn_1 = get_insn_by_uid (1);
|
|
2159 rtx set1 = single_set (insn_1);
|
|
2160 rtx mem1 = SET_DEST (set1);
|
|
2161 ASSERT_EQ (42, MEM_ALIAS_SET (mem1));
|
|
2162 /* "+17". */
|
|
2163 ASSERT_TRUE (MEM_OFFSET_KNOWN_P (mem1));
|
131
|
2164 ASSERT_KNOWN_EQ (17, MEM_OFFSET (mem1));
|
111
|
2165 /* "S8". */
|
131
|
2166 ASSERT_KNOWN_EQ (8, MEM_SIZE (mem1));
|
111
|
2167 /* "A128. */
|
|
2168 ASSERT_EQ (128, MEM_ALIGN (mem1));
|
|
2169 /* "AS5. */
|
|
2170 ASSERT_EQ (5, MEM_ADDR_SPACE (mem1));
|
|
2171
|
|
2172 /* Verify parsing of "43 i+18 S9 AS6"
|
|
2173 (an address space without an alignment). */
|
|
2174 rtx_insn *insn_2 = get_insn_by_uid (2);
|
|
2175 rtx set2 = single_set (insn_2);
|
|
2176 rtx mem2 = SET_DEST (set2);
|
|
2177 ASSERT_EQ (43, MEM_ALIAS_SET (mem2));
|
|
2178 /* "+18". */
|
|
2179 ASSERT_TRUE (MEM_OFFSET_KNOWN_P (mem2));
|
131
|
2180 ASSERT_KNOWN_EQ (18, MEM_OFFSET (mem2));
|
111
|
2181 /* "S9". */
|
131
|
2182 ASSERT_KNOWN_EQ (9, MEM_SIZE (mem2));
|
111
|
2183 /* "AS6. */
|
|
2184 ASSERT_EQ (6, MEM_ADDR_SPACE (mem2));
|
|
2185 }
|
|
2186
|
131
|
2187 /* Verify that "repeated xN" is read correctly. */
|
|
2188
|
|
2189 static void
|
|
2190 test_loading_repeat ()
|
|
2191 {
|
|
2192 rtl_dump_test t (SELFTEST_LOCATION, locate_file ("repeat.rtl"));
|
|
2193
|
|
2194 rtx_insn *insn_1 = get_insn_by_uid (1);
|
|
2195 ASSERT_EQ (PARALLEL, GET_CODE (PATTERN (insn_1)));
|
|
2196 ASSERT_EQ (64, XVECLEN (PATTERN (insn_1), 0));
|
|
2197 for (int i = 0; i < 64; i++)
|
|
2198 ASSERT_EQ (const0_rtx, XVECEXP (PATTERN (insn_1), 0, i));
|
|
2199 }
|
|
2200
|
111
|
2201 /* Run all of the selftests within this file. */
|
|
2202
|
|
2203 void
|
|
2204 read_rtl_function_c_tests ()
|
|
2205 {
|
|
2206 test_edge_flags ();
|
|
2207 test_parsing_regnos ();
|
|
2208 test_loading_dump_fragment_1 ();
|
|
2209 test_loading_dump_fragment_2 ();
|
|
2210 test_loading_labels ();
|
|
2211 test_loading_insn_with_mode ();
|
|
2212 test_loading_jump_to_label_ref ();
|
|
2213 test_loading_jump_to_return ();
|
|
2214 test_loading_jump_to_simple_return ();
|
|
2215 test_loading_note_insn_basic_block ();
|
|
2216 test_loading_note_insn_deleted ();
|
|
2217 test_loading_const_int ();
|
|
2218 test_loading_symbol_ref ();
|
|
2219 test_loading_cfg ();
|
|
2220 test_loading_bb_index ();
|
|
2221 test_loading_mem ();
|
131
|
2222 test_loading_repeat ();
|
111
|
2223 }
|
|
2224
|
|
2225 } // namespace selftest
|
|
2226
|
|
2227 #endif /* #if CHECKING_P */
|