LCOV - code coverage report
Current view: top level - gcc - read-rtl-function.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 94.4 % 950 897
Test Date: 2026-02-28 14:20:25 Functions: 95.7 % 70 67
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.