]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/lto-streamer-in.c
Merge from trunk.
[thirdparty/gcc.git] / gcc / lto-streamer-in.c
index 02889a99501144b29c94a625c3918928e14776a8..c5b73ffb8d90a3c86b10bf4054155d0c0f2ed056 100644 (file)
@@ -26,15 +26,22 @@ along with GCC; see the file COPYING3.  If not see
 #include "tm.h"
 #include "toplev.h"
 #include "tree.h"
+#include "stringpool.h"
 #include "expr.h"
 #include "flags.h"
 #include "params.h"
 #include "input.h"
 #include "hashtab.h"
 #include "basic-block.h"
-#include "tree-flow.h"
+#include "gimple.h"
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+#include "tree-cfg.h"
+#include "tree-ssanames.h"
+#include "tree-into-ssa.h"
+#include "tree-dfa.h"
+#include "tree-ssa.h"
 #include "tree-pass.h"
-#include "cgraph.h"
 #include "function.h"
 #include "ggc.h"
 #include "diagnostic.h"
@@ -581,7 +588,7 @@ make_new_block (struct function *fn, unsigned int index)
   basic_block bb = alloc_block ();
   bb->index = index;
   SET_BASIC_BLOCK_FOR_FUNCTION (fn, index, bb);
-  n_basic_blocks_for_function (fn)++;
+  n_basic_blocks_for_fn (fn)++;
   return bb;
 }
 
@@ -652,7 +659,7 @@ input_cfg (struct lto_input_block *ib, struct function *fn,
       index = streamer_read_hwi (ib);
     }
 
-  p_bb = ENTRY_BLOCK_PTR_FOR_FUNCTION(fn);
+  p_bb = ENTRY_BLOCK_PTR_FOR_F(fn);
   index = streamer_read_hwi (ib);
   while (index != -1)
     {
@@ -695,14 +702,26 @@ input_cfg (struct lto_input_block *ib, struct function *fn,
       loop->any_upper_bound = streamer_read_hwi (ib);
       if (loop->any_upper_bound)
        {
-         loop->nb_iterations_upper_bound.low = streamer_read_uhwi (ib);
-         loop->nb_iterations_upper_bound.high = streamer_read_hwi (ib);
+         HOST_WIDE_INT a[WIDE_INT_MAX_ELTS];
+         int i;
+         int prec ATTRIBUTE_UNUSED = streamer_read_uhwi (ib);
+         int len = streamer_read_uhwi (ib);
+         for (i = 0; i < len; i++)
+           a[i] = streamer_read_hwi (ib);
+         
+         loop->nb_iterations_upper_bound = widest_int::from_array (a, len);
        }
       loop->any_estimate = streamer_read_hwi (ib);
       if (loop->any_estimate)
        {
-         loop->nb_iterations_estimate.low = streamer_read_uhwi (ib);
-         loop->nb_iterations_estimate.high = streamer_read_hwi (ib);
+         HOST_WIDE_INT a[WIDE_INT_MAX_ELTS];
+         int i;
+         int prec ATTRIBUTE_UNUSED = streamer_read_uhwi (ib);
+         int len = streamer_read_uhwi (ib);
+         for (i = 0; i < len; i++)
+           a[i] = streamer_read_hwi (ib);
+         
+         loop->nb_iterations_estimate = widest_int::from_array (a, len);
        }
 
       place_new_loop (fn, loop);
@@ -755,30 +774,60 @@ input_ssa_names (struct lto_input_block *ib, struct data_in *data_in,
    so they point to STMTS.  */
 
 static void
-fixup_call_stmt_edges_1 (struct cgraph_node *node, gimple *stmts)
+fixup_call_stmt_edges_1 (struct cgraph_node *node, gimple *stmts,
+                        struct function *fn)
 {
   struct cgraph_edge *cedge;
+  struct ipa_ref *ref;
+  unsigned int i;
+
   for (cedge = node->callees; cedge; cedge = cedge->next_callee)
-    cedge->call_stmt = stmts[cedge->lto_stmt_uid];
+    {
+      if (gimple_stmt_max_uid (fn) < cedge->lto_stmt_uid)
+        fatal_error ("Cgraph edge statement index out of range");
+      cedge->call_stmt = stmts[cedge->lto_stmt_uid - 1];
+      if (!cedge->call_stmt)
+        fatal_error ("Cgraph edge statement index not found");
+    }
   for (cedge = node->indirect_calls; cedge; cedge = cedge->next_callee)
-    cedge->call_stmt = stmts[cedge->lto_stmt_uid];
+    {
+      if (gimple_stmt_max_uid (fn) < cedge->lto_stmt_uid)
+        fatal_error ("Cgraph edge statement index out of range");
+      cedge->call_stmt = stmts[cedge->lto_stmt_uid - 1];
+      if (!cedge->call_stmt)
+        fatal_error ("Cgraph edge statement index not found");
+    }
+  for (i = 0;
+       ipa_ref_list_reference_iterate (&node->ref_list, i, ref);
+       i++)
+    if (ref->lto_stmt_uid)
+      {
+       if (gimple_stmt_max_uid (fn) < ref->lto_stmt_uid)
+         fatal_error ("Reference statement index out of range");
+       ref->stmt = stmts[ref->lto_stmt_uid - 1];
+       if (!ref->stmt)
+         fatal_error ("Reference statement index not found");
+      }
 }
 
+
 /* Fixup call_stmt pointers in NODE and all clones.  */
 
 static void
 fixup_call_stmt_edges (struct cgraph_node *orig, gimple *stmts)
 {
   struct cgraph_node *node;
+  struct function *fn;
 
   while (orig->clone_of)
     orig = orig->clone_of;
+  fn = DECL_STRUCT_FUNCTION (orig->decl);
 
-  fixup_call_stmt_edges_1 (orig, stmts);
+  fixup_call_stmt_edges_1 (orig, stmts, fn);
   if (orig->clones)
     for (node = orig->clones; node != orig;)
       {
-       fixup_call_stmt_edges_1 (node, stmts);
+       fixup_call_stmt_edges_1 (node, stmts, fn);
        if (node->clones)
          node = node->clones;
        else if (node->next_sibling_clone)
@@ -851,7 +900,7 @@ input_struct_function_base (struct function *fn, struct data_in *data_in,
 
 static void
 input_function (tree fn_decl, struct data_in *data_in,
-               struct lto_input_block *ib)
+               struct lto_input_block *ib, struct lto_input_block *ib_cfg)
 {
   struct function *fn;
   enum LTO_tags tag;
@@ -859,13 +908,32 @@ input_function (tree fn_decl, struct data_in *data_in,
   basic_block bb;
   struct cgraph_node *node;
 
-  fn = DECL_STRUCT_FUNCTION (fn_decl);
   tag = streamer_read_record_start (ib);
+  lto_tag_check (tag, LTO_function);
+
+  /* Read decls for parameters and args.  */
+  DECL_RESULT (fn_decl) = stream_read_tree (ib, data_in);
+  DECL_ARGUMENTS (fn_decl) = streamer_read_chain (ib, data_in);
+
+  /* Read the tree of lexical scopes for the function.  */
+  DECL_INITIAL (fn_decl) = stream_read_tree (ib, data_in);
+
+  if (!streamer_read_uhwi (ib))
+    return;
+
+  push_struct_function (fn_decl);
+  fn = DECL_STRUCT_FUNCTION (fn_decl);
+  init_tree_ssa (fn);
+  /* We input IL in SSA form.  */
+  cfun->gimple_df->in_ssa_p = true;
 
   gimple_register_cfg_hooks ();
-  lto_tag_check (tag, LTO_function);
 
+  node = cgraph_get_node (fn_decl);
+  if (!node)
+    node = cgraph_create_node (fn_decl);
   input_struct_function_base (fn, data_in, ib);
+  input_cfg (ib_cfg, fn, node->count_materialization_scale);
 
   /* Read all the SSA names.  */
   input_ssa_names (ib, data_in, fn);
@@ -873,11 +941,8 @@ input_function (tree fn_decl, struct data_in *data_in,
   /* Read the exception handling regions in the function.  */
   input_eh_regions (ib, data_in, fn);
 
-  /* Read the tree of lexical scopes for the function.  */
-  DECL_INITIAL (fn_decl) = stream_read_tree (ib, data_in);
   gcc_assert (DECL_INITIAL (fn_decl));
   DECL_SAVED_TREE (fn_decl) = NULL_TREE;
-  node = cgraph_get_create_node (fn_decl);
 
   /* Read all the basic blocks.  */
   tag = streamer_read_record_start (ib);
@@ -894,6 +959,11 @@ input_function (tree fn_decl, struct data_in *data_in,
   FOR_ALL_BB (bb)
     {
       gimple_stmt_iterator gsi;
+      for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+       {
+         gimple stmt = gsi_stmt (gsi);
+         gimple_set_uid (stmt, inc_gimple_stmt_max_uid (cfun));
+       }
       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
        {
          gimple stmt = gsi_stmt (gsi);
@@ -903,7 +973,14 @@ input_function (tree fn_decl, struct data_in *data_in,
   stmts = (gimple *) xcalloc (gimple_stmt_max_uid (fn), sizeof (gimple));
   FOR_ALL_BB (bb)
     {
-      gimple_stmt_iterator bsi = gsi_start_bb (bb);
+      gimple_stmt_iterator bsi = gsi_start_phis (bb);
+      while (!gsi_end_p (bsi))
+       {
+         gimple stmt = gsi_stmt (bsi);
+         gsi_next (&bsi);
+         stmts[gimple_uid (stmt)] = stmt;
+       }
+      bsi = gsi_start_bb (bb);
       while (!gsi_end_p (bsi))
        {
          gimple stmt = gsi_stmt (bsi);
@@ -931,7 +1008,7 @@ input_function (tree fn_decl, struct data_in *data_in,
      of a gimple body is used by the cgraph routines, but we should
      really use the presence of the CFG.  */
   {
-    edge_iterator ei = ei_start (ENTRY_BLOCK_PTR->succs);
+    edge_iterator ei = ei_start (ENTRY_BLOCK_PTR_FOR_FN (cfun)->succs);
     gimple_set_body (fn_decl, bb_seq (ei_edge (ei)->dest));
   }
 
@@ -942,17 +1019,18 @@ input_function (tree fn_decl, struct data_in *data_in,
   free_dominance_info (CDI_DOMINATORS);
   free_dominance_info (CDI_POST_DOMINATORS);
   free (stmts);
+  pop_cfun ();
 }
 
 
-/* Read the body from DATA for function FN_DECL and fill it in.
+/* Read the body from DATA for function NODE and fill it in.
    FILE_DATA are the global decls and types.  SECTION_TYPE is either
    LTO_section_function_body or LTO_section_static_initializer.  If
    section type is LTO_section_function_body, FN must be the decl for
    that function.  */
 
 static void
-lto_read_body (struct lto_file_decl_data *file_data, tree fn_decl,
+lto_read_body (struct lto_file_decl_data *file_data, struct cgraph_node *node,
               const char *data, enum lto_section_type section_type)
 {
   const struct lto_function_header *header;
@@ -962,6 +1040,7 @@ lto_read_body (struct lto_file_decl_data *file_data, tree fn_decl,
   int string_offset;
   struct lto_input_block ib_cfg;
   struct lto_input_block ib_main;
+  tree fn_decl = node->decl;
 
   header = (const struct lto_function_header *) data;
   cfg_offset = sizeof (struct lto_function_header);
@@ -987,28 +1066,20 @@ lto_read_body (struct lto_file_decl_data *file_data, tree fn_decl,
 
   if (section_type == LTO_section_function_body)
     {
-      struct function *fn = DECL_STRUCT_FUNCTION (fn_decl);
       struct lto_in_decl_state *decl_state;
-      struct cgraph_node *node = cgraph_get_node (fn_decl);
       unsigned from;
 
       gcc_checking_assert (node);
-      push_cfun (fn);
-      init_tree_ssa (fn);
-
-      /* We input IL in SSA form.  */
-      cfun->gimple_df->in_ssa_p = true;
 
       /* Use the function's decl state. */
       decl_state = lto_get_function_in_decl_state (file_data, fn_decl);
       gcc_assert (decl_state);
       file_data->current_decl_state = decl_state;
 
-      input_cfg (&ib_cfg, fn, node->count_materialization_scale);
 
       /* Set up the struct function.  */
       from = data_in->reader_cache->nodes.length ();
-      input_function (fn_decl, data_in, &ib_main);
+      input_function (fn_decl, data_in, &ib_main, &ib_cfg);
       /* And fixup types we streamed locally.  */
        {
          struct streamer_tree_cache_d *cache = data_in->reader_cache;
@@ -1016,7 +1087,7 @@ lto_read_body (struct lto_file_decl_data *file_data, tree fn_decl,
          unsigned i;
          for (i = len; i-- > from;)
            {
-             tree t = cache->nodes[i];
+             tree t = streamer_tree_cache_get_tree (cache, i);
              if (t == NULL_TREE)
                continue;
 
@@ -1037,31 +1108,60 @@ lto_read_body (struct lto_file_decl_data *file_data, tree fn_decl,
 
       /* Restore decl state */
       file_data->current_decl_state = file_data->global_decl_state;
-
-      pop_cfun ();
     }
 
   lto_data_in_delete (data_in);
 }
 
 
-/* Read the body of FN_DECL using DATA.  FILE_DATA holds the global
+/* Read the body of NODE using DATA.  FILE_DATA holds the global
    decls and types.  */
 
 void
 lto_input_function_body (struct lto_file_decl_data *file_data,
-                        tree fn_decl, const char *data)
+                        struct cgraph_node *node, const char *data)
 {
-  lto_read_body (file_data, fn_decl, data, LTO_section_function_body);
+  lto_read_body (file_data, node, data, LTO_section_function_body);
 }
 
 
+/* Read the physical representation of a tree node EXPR from
+   input block IB using the per-file context in DATA_IN.  */
+
+static void
+lto_read_tree_1 (struct lto_input_block *ib, struct data_in *data_in, tree expr)
+{
+  /* Read all the bitfield values in EXPR.  Note that for LTO, we
+     only write language-independent bitfields, so no more unpacking is
+     needed.  */
+  streamer_read_tree_bitfields (ib, data_in, expr);
+
+  /* Read all the pointer fields in EXPR.  */
+  streamer_read_tree_body (ib, data_in, expr);
+
+  /* Read any LTO-specific data not read by the tree streamer.  */
+  if (DECL_P (expr)
+      && TREE_CODE (expr) != FUNCTION_DECL
+      && TREE_CODE (expr) != TRANSLATION_UNIT_DECL)
+    DECL_INITIAL (expr) = stream_read_tree (ib, data_in);
+
+  /* We should never try to instantiate an MD or NORMAL builtin here.  */
+  if (TREE_CODE (expr) == FUNCTION_DECL)
+    gcc_assert (!streamer_handle_as_builtin_p (expr));
+
+#ifdef LTO_STREAMER_DEBUG
+  /* Remove the mapping to RESULT's original address set by
+     streamer_alloc_tree.  */
+  lto_orig_address_remove (expr);
+#endif
+}
+
 /* Read the physical representation of a tree node with tag TAG from
    input block IB using the per-file context in DATA_IN.  */
 
 static tree
 lto_read_tree (struct lto_input_block *ib, struct data_in *data_in,
-              enum LTO_tags tag)
+              enum LTO_tags tag, hashval_t hash)
 {
   /* Instantiate a new tree node.  */
   tree result = streamer_alloc_tree (ib, data_in, tag);
@@ -1069,35 +1169,70 @@ lto_read_tree (struct lto_input_block *ib, struct data_in *data_in,
   /* Enter RESULT in the reader cache.  This will make RESULT
      available so that circular references in the rest of the tree
      structure can be resolved in subsequent calls to stream_read_tree.  */
-  streamer_tree_cache_append (data_in->reader_cache, result);
+  streamer_tree_cache_append (data_in->reader_cache, result, hash);
 
-  /* Read all the bitfield values in RESULT.  Note that for LTO, we
-     only write language-independent bitfields, so no more unpacking is
-     needed.  */
-  streamer_read_tree_bitfields (ib, data_in, result);
+  lto_read_tree_1 (ib, data_in, result);
 
-  /* Read all the pointer fields in RESULT.  */
-  streamer_read_tree_body (ib, data_in, result);
+  /* end_marker = */ streamer_read_uchar (ib);
 
-  /* Read any LTO-specific data not read by the tree streamer.  */
-  if (DECL_P (result)
-      && TREE_CODE (result) != FUNCTION_DECL
-      && TREE_CODE (result) != TRANSLATION_UNIT_DECL)
-    DECL_INITIAL (result) = stream_read_tree (ib, data_in);
+  return result;
+}
 
-  /* We should never try to instantiate an MD or NORMAL builtin here.  */
-  if (TREE_CODE (result) == FUNCTION_DECL)
-    gcc_assert (!streamer_handle_as_builtin_p (result));
 
-  /* end_marker = */ streamer_read_uchar (ib);
+/* Populate the reader cache with trees materialized from the SCC
+   following in the IB, DATA_IN stream.  */
 
-#ifdef LTO_STREAMER_DEBUG
-  /* Remove the mapping to RESULT's original address set by
-     streamer_alloc_tree.  */
-  lto_orig_address_remove (result);
-#endif
+hashval_t
+lto_input_scc (struct lto_input_block *ib, struct data_in *data_in,
+              unsigned *len, unsigned *entry_len)
+{
+  /* A blob of unnamed tree nodes, fill the cache from it and
+     recurse.  */
+  unsigned size = streamer_read_uhwi (ib);
+  hashval_t scc_hash = streamer_read_uhwi (ib);
+  unsigned scc_entry_len = 1;
 
-  return result;
+  if (size == 1)
+    {
+      enum LTO_tags tag = streamer_read_record_start (ib);
+      lto_input_tree_1 (ib, data_in, tag, scc_hash);
+    }
+  else
+    {
+      unsigned int first = data_in->reader_cache->nodes.length ();
+      tree result;
+
+      scc_entry_len = streamer_read_uhwi (ib);
+
+      /* Materialize size trees by reading their headers.  */
+      for (unsigned i = 0; i < size; ++i)
+       {
+         enum LTO_tags tag = streamer_read_record_start (ib);
+         if (tag == LTO_null
+             || (tag >= LTO_field_decl_ref && tag <= LTO_global_decl_ref)
+             || tag == LTO_tree_pickle_reference
+             || tag == LTO_builtin_decl
+             || tag == LTO_integer_cst
+             || tag == LTO_tree_scc)
+           gcc_unreachable ();
+
+         result = streamer_alloc_tree (ib, data_in, tag);
+         streamer_tree_cache_append (data_in->reader_cache, result, 0);
+       }
+
+      /* Read the tree bitpacks and references.  */
+      for (unsigned i = 0; i < size; ++i)
+       {
+         result = streamer_tree_cache_get_tree (data_in->reader_cache,
+                                                first + i);
+         lto_read_tree_1 (ib, data_in, result);
+         /* end_marker = */ streamer_read_uchar (ib);
+       }
+    }
+
+  *len = size;
+  *entry_len = scc_entry_len;
+  return scc_hash;
 }
 
 
@@ -1106,12 +1241,11 @@ lto_read_tree (struct lto_input_block *ib, struct data_in *data_in,
    to previously read nodes.  */
 
 tree
-lto_input_tree (struct lto_input_block *ib, struct data_in *data_in)
+lto_input_tree_1 (struct lto_input_block *ib, struct data_in *data_in,
+                 enum LTO_tags tag, hashval_t hash)
 {
-  enum LTO_tags tag;
   tree result;
 
-  tag = streamer_read_record_start (ib);
   gcc_assert ((unsigned) tag < (unsigned) LTO_NUM_TAGS);
 
   if (tag == LTO_null)
@@ -1137,19 +1271,44 @@ lto_input_tree (struct lto_input_block *ib, struct data_in *data_in)
     }
   else if (tag == LTO_integer_cst)
     {
-      /* For shared integer constants we only need the type and its hi/low
-        words.  */
-      result = streamer_read_integer_cst (ib, data_in);
+      /* For shared integer constants in singletons we can use the
+         existing tree integer constant merging code.  */
+      tree type = stream_read_tree (ib, data_in);
+      unsigned HOST_WIDE_INT len = streamer_read_uhwi (ib);
+      unsigned HOST_WIDE_INT i;
+      HOST_WIDE_INT a[WIDE_INT_MAX_ELTS]; 
+
+      for (i = 0; i < len; i++)
+       a[i] = streamer_read_hwi (ib);
+      result = wide_int_to_tree (type, wide_int::from_array
+                                (a, len, TYPE_PRECISION (type)));
+      streamer_tree_cache_append (data_in->reader_cache, result, hash);
+    }
+  else if (tag == LTO_tree_scc)
+    {
+      unsigned len, entry_len;
+
+      /* Input and skip the SCC.  */
+      lto_input_scc (ib, data_in, &len, &entry_len);
+
+      /* Recurse.  */
+      return lto_input_tree (ib, data_in);
     }
   else
     {
       /* Otherwise, materialize a new node from IB.  */
-      result = lto_read_tree (ib, data_in, tag);
+      result = lto_read_tree (ib, data_in, tag, hash);
     }
 
   return result;
 }
 
+tree
+lto_input_tree (struct lto_input_block *ib, struct data_in *data_in)
+{
+  return lto_input_tree_1 (ib, data_in, streamer_read_record_start (ib), 0);
+}
+
 
 /* Input toplevel asms.  */
 
@@ -1220,7 +1379,7 @@ lto_data_in_create (struct lto_file_decl_data *file_data, const char *strings,
   data_in->strings = strings;
   data_in->strings_len = len;
   data_in->globals_resolution = resolutions;
-  data_in->reader_cache = streamer_tree_cache_create ();
+  data_in->reader_cache = streamer_tree_cache_create (false, false);
 
   return data_in;
 }