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