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