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