]> 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 ddb91d8557c5257812d333762a1f95e788c8a880..c5b73ffb8d90a3c86b10bf4054155d0c0f2ed056 100644 (file)
@@ -1,6 +1,6 @@
 /* Read the GIMPLE representation from a file stream.
 
-   Copyright 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2009-2013 Free Software Foundation, Inc.
    Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
    Re-implemented by Diego Novillo <dnovillo@google.com>
 
@@ -26,23 +26,28 @@ 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"
-#include "libfuncs.h"
 #include "except.h"
 #include "debug.h"
 #include "vec.h"
-#include "timevar.h"
 #include "ipa-utils.h"
 #include "data-streamer.h"
 #include "gimple-streamer.h"
@@ -50,9 +55,22 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-streamer.h"
 #include "tree-pass.h"
 #include "streamer-hooks.h"
+#include "cfgloop.h"
+
+
+struct freeing_string_slot_hasher : string_slot_hasher
+{
+  static inline void remove (value_type *);
+};
+
+inline void
+freeing_string_slot_hasher::remove (value_type *v)
+{
+  free (v);
+}
 
 /* The table to hold the file names.  */
-static htab_t file_name_hash_table;
+static hash_table <freeing_string_slot_hasher> file_name_hash_table;
 
 
 /* Check that tag ACTUAL has one of the given values.  NUM_TAGS is the
@@ -96,14 +114,14 @@ lto_input_data_block (struct lto_input_block *ib, void *addr, size_t length)
 static const char *
 canon_file_name (const char *string)
 {
-  void **slot;
+  string_slot **slot;
   struct string_slot s_slot;
   size_t len = strlen (string);
 
   s_slot.s = string;
   s_slot.len = len;
 
-  slot = htab_find_slot (file_name_hash_table, &s_slot, INSERT);
+  slot = file_name_hash_table.find_slot (&s_slot, INSERT);
   if (*slot == NULL)
     {
       char *saved_string;
@@ -119,84 +137,54 @@ canon_file_name (const char *string)
     }
   else
     {
-      struct string_slot *old_slot = (struct string_slot *) *slot;
+      struct string_slot *old_slot = *slot;
       return old_slot->s;
     }
 }
 
 
-/* Clear the line info stored in DATA_IN.  */
-
-static void
-clear_line_info (struct data_in *data_in)
-{
-  if (data_in->current_file)
-    linemap_add (line_table, LC_LEAVE, false, NULL, 0);
-  data_in->current_file = NULL;
-  data_in->current_line = 0;
-  data_in->current_col = 0;
-}
-
-
 /* Read a location bitpack from input block IB.  */
 
-static location_t
-lto_input_location_bitpack (struct data_in *data_in, struct bitpack_d *bp)
+location_t
+lto_input_location (struct bitpack_d *bp, struct data_in *data_in)
 {
+  static const char *current_file;
+  static int current_line;
+  static int current_col;
   bool file_change, line_change, column_change;
   unsigned len;
-  bool prev_file = data_in->current_file != NULL;
+  bool prev_file = current_file != NULL;
 
   if (bp_unpack_value (bp, 1))
     return UNKNOWN_LOCATION;
 
   file_change = bp_unpack_value (bp, 1);
+  line_change = bp_unpack_value (bp, 1);
+  column_change = bp_unpack_value (bp, 1);
+
   if (file_change)
-    data_in->current_file = canon_file_name
-                             (string_for_index (data_in,
-                                                bp_unpack_var_len_unsigned (bp),
-                                                &len));
+    current_file = canon_file_name
+                    (string_for_index (data_in,
+                                       bp_unpack_var_len_unsigned (bp),
+                                       &len));
 
-  line_change = bp_unpack_value (bp, 1);
   if (line_change)
-    data_in->current_line = bp_unpack_var_len_unsigned (bp);
+    current_line = bp_unpack_var_len_unsigned (bp);
 
-  column_change = bp_unpack_value (bp, 1);
   if (column_change)
-    data_in->current_col = bp_unpack_var_len_unsigned (bp);
+    current_col = bp_unpack_var_len_unsigned (bp);
 
   if (file_change)
     {
       if (prev_file)
        linemap_add (line_table, LC_LEAVE, false, NULL, 0);
 
-      linemap_add (line_table, LC_ENTER, false, data_in->current_file,
-                  data_in->current_line);
+      linemap_add (line_table, LC_ENTER, false, current_file, current_line);
     }
   else if (line_change)
-    linemap_line_start (line_table, data_in->current_line, data_in->current_col);
-
-  return linemap_position_for_column (line_table, data_in->current_col);
-}
-
-
-/* Read a location from input block IB.
-   If the input_location streamer hook exists, call it.
-   Otherwise, proceed with reading the location from the
-   expanded location bitpack.  */
-
-location_t
-lto_input_location (struct lto_input_block *ib, struct data_in *data_in)
-{
-  if (streamer_hooks.input_location)
-    return streamer_hooks.input_location (ib, data_in);
-  else
-    {
-      struct bitpack_d bp;
+    linemap_line_start (line_table, current_line, current_col);
 
-      bp = streamer_read_bitpack (ib);
-      return lto_input_location_bitpack (data_in, &bp);
-    }
+  return linemap_position_for_column (line_table, current_col);
 }
 
 
@@ -225,7 +213,7 @@ lto_input_tree_ref (struct lto_input_block *ib, struct data_in *data_in,
 
     case LTO_ssa_name_ref:
       ix_u = streamer_read_uhwi (ib);
-      result = VEC_index (tree, SSANAMES (fn), ix_u);
+      result = (*SSANAMES (fn))[ix_u];
       break;
 
     case LTO_field_decl_ref:
@@ -370,9 +358,13 @@ input_eh_region (struct lto_input_block *ib, struct data_in *data_in, int ix)
        break;
 
       case LTO_ert_must_not_throw:
-       r->type = ERT_MUST_NOT_THROW;
-       r->u.must_not_throw.failure_decl = stream_read_tree (ib, data_in);
-       r->u.must_not_throw.failure_loc = lto_input_location (ib, data_in);
+       {
+         r->type = ERT_MUST_NOT_THROW;
+         r->u.must_not_throw.failure_decl = stream_read_tree (ib, data_in);
+         bitpack_d bp = streamer_read_bitpack (ib);
+         r->u.must_not_throw.failure_loc
+          = stream_input_location (&bp, data_in);
+       }
        break;
 
       default:
@@ -421,24 +413,22 @@ static void
 fixup_eh_region_pointers (struct function *fn, HOST_WIDE_INT root_region)
 {
   unsigned i;
-  VEC(eh_region,gc) *eh_array = fn->eh->region_array;
-  VEC(eh_landing_pad,gc) *lp_array = fn->eh->lp_array;
+  vec<eh_region, va_gc> *eh_array = fn->eh->region_array;
+  vec<eh_landing_pad, va_gc> *lp_array = fn->eh->lp_array;
   eh_region r;
   eh_landing_pad lp;
 
   gcc_assert (eh_array && lp_array);
 
   gcc_assert (root_region >= 0);
-  fn->eh->region_tree = VEC_index (eh_region, eh_array, root_region);
+  fn->eh->region_tree = (*eh_array)[root_region];
 
-#define FIXUP_EH_REGION(r) (r) = VEC_index (eh_region, eh_array, \
-                                           (HOST_WIDE_INT) (intptr_t) (r))
-#define FIXUP_EH_LP(p) (p) = VEC_index (eh_landing_pad, lp_array, \
-                                       (HOST_WIDE_INT) (intptr_t) (p))
+#define FIXUP_EH_REGION(r) (r) = (*eh_array)[(HOST_WIDE_INT) (intptr_t) (r)]
+#define FIXUP_EH_LP(p) (p) = (*lp_array)[(HOST_WIDE_INT) (intptr_t) (p)]
 
   /* Convert all the index numbers stored in pointer fields into
      pointers to the corresponding slots in the EH region array.  */
-  FOR_EACH_VEC_ELT (eh_region, eh_array, i, r)
+  FOR_EACH_VEC_ELT (*eh_array, i, r)
     {
       /* The array may contain NULL regions.  */
       if (r == NULL)
@@ -453,7 +443,7 @@ fixup_eh_region_pointers (struct function *fn, HOST_WIDE_INT root_region)
 
   /* Convert all the index numbers stored in pointer fields into
      pointers to the corresponding slots in the EH landing pad array.  */
-  FOR_EACH_VEC_ELT (eh_landing_pad, lp_array, i, lp)
+  FOR_EACH_VEC_ELT (*lp_array, i, lp)
     {
       /* The array may contain NULL landing pads.  */
       if (lp == NULL)
@@ -522,11 +512,11 @@ input_eh_regions (struct lto_input_block *ib, struct data_in *data_in,
   gcc_assert (len == (int) len);
   if (len > 0)
     {
-      VEC_safe_grow (eh_region, gc, fn->eh->region_array, len);
+      vec_safe_grow_cleared (fn->eh->region_array, len);
       for (i = 0; i < len; i++)
        {
          eh_region r = input_eh_region (ib, data_in, i);
-         VEC_replace (eh_region, fn->eh->region_array, i, r);
+         (*fn->eh->region_array)[i] = r;
        }
     }
 
@@ -535,11 +525,11 @@ input_eh_regions (struct lto_input_block *ib, struct data_in *data_in,
   gcc_assert (len == (int) len);
   if (len > 0)
     {
-      VEC_safe_grow (eh_landing_pad, gc, fn->eh->lp_array, len);
+      vec_safe_grow_cleared (fn->eh->lp_array, len);
       for (i = 0; i < len; i++)
        {
          eh_landing_pad lp = input_eh_lp (ib, data_in, i);
-         VEC_replace (eh_landing_pad, fn->eh->lp_array, i, lp);
+         (*fn->eh->lp_array)[i] = lp;
        }
     }
 
@@ -548,11 +538,11 @@ input_eh_regions (struct lto_input_block *ib, struct data_in *data_in,
   gcc_assert (len == (int) len);
   if (len > 0)
     {
-      VEC_safe_grow (tree, gc, fn->eh->ttype_data, len);
+      vec_safe_grow_cleared (fn->eh->ttype_data, len);
       for (i = 0; i < len; i++)
        {
          tree ttype = stream_read_tree (ib, data_in);
-         VEC_replace (tree, fn->eh->ttype_data, i, ttype);
+         (*fn->eh->ttype_data)[i] = ttype;
        }
     }
 
@@ -563,20 +553,20 @@ input_eh_regions (struct lto_input_block *ib, struct data_in *data_in,
     {
       if (targetm.arm_eabi_unwinder)
        {
-         VEC_safe_grow (tree, gc, fn->eh->ehspec_data.arm_eabi, len);
+         vec_safe_grow_cleared (fn->eh->ehspec_data.arm_eabi, len);
          for (i = 0; i < len; i++)
            {
              tree t = stream_read_tree (ib, data_in);
-             VEC_replace (tree, fn->eh->ehspec_data.arm_eabi, i, t);
+             (*fn->eh->ehspec_data.arm_eabi)[i] = t;
            }
        }
       else
        {
-         VEC_safe_grow (uchar, gc, fn->eh->ehspec_data.other, len);
+         vec_safe_grow_cleared (fn->eh->ehspec_data.other, len);
          for (i = 0; i < len; i++)
            {
              uchar c = streamer_read_uchar (ib);
-             VEC_replace (uchar, fn->eh->ehspec_data.other, i, c);
+             (*fn->eh->ehspec_data.other)[i] = c;
            }
        }
     }
@@ -598,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;
 }
 
@@ -623,13 +613,11 @@ input_cfg (struct lto_input_block *ib, struct function *fn,
   bb_count = streamer_read_uhwi (ib);
 
   last_basic_block_for_function (fn) = bb_count;
-  if (bb_count > VEC_length (basic_block, basic_block_info_for_function (fn)))
-    VEC_safe_grow_cleared (basic_block, gc,
-                          basic_block_info_for_function (fn), bb_count);
+  if (bb_count > basic_block_info_for_function (fn)->length ())
+    vec_safe_grow_cleared (basic_block_info_for_function (fn), bb_count);
 
-  if (bb_count > VEC_length (basic_block, label_to_block_map_for_function (fn)))
-    VEC_safe_grow_cleared (basic_block, gc,
-                          label_to_block_map_for_function (fn), bb_count);
+  if (bb_count > label_to_block_map_for_function (fn)->length ())
+    vec_safe_grow_cleared (label_to_block_map_for_function (fn), bb_count);
 
   index = streamer_read_hwi (ib);
   while (index != -1)
@@ -654,8 +642,8 @@ input_cfg (struct lto_input_block *ib, struct function *fn,
 
          dest_index = streamer_read_uhwi (ib);
          probability = (int) streamer_read_hwi (ib);
-         count = ((gcov_type) streamer_read_hwi (ib) * count_materialization_scale
-                  + REG_BR_PROB_BASE / 2) / REG_BR_PROB_BASE;
+         count = apply_scale ((gcov_type) streamer_read_gcov_count (ib),
+                               count_materialization_scale);
          edge_flags = streamer_read_uhwi (ib);
 
          dest = BASIC_BLOCK_FOR_FUNCTION (fn, dest_index);
@@ -671,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)
     {
@@ -681,6 +669,70 @@ input_cfg (struct lto_input_block *ib, struct function *fn,
       p_bb = bb;
       index = streamer_read_hwi (ib);
     }
+
+  /* ???  The cfgloop interface is tied to cfun.  */
+  gcc_assert (cfun == fn);
+
+  /* Input the loop tree.  */
+  unsigned n_loops = streamer_read_uhwi (ib);
+  if (n_loops == 0)
+    return;
+
+  struct loops *loops = ggc_alloc_cleared_loops ();
+  init_loops_structure (fn, loops, n_loops);
+  set_loops_for_fn (fn, loops);
+
+  /* Input each loop and associate it with its loop header so
+     flow_loops_find can rebuild the loop tree.  */
+  for (unsigned i = 1; i < n_loops; ++i)
+    {
+      int header_index = streamer_read_hwi (ib);
+      if (header_index == -1)
+       {
+         loops->larray->quick_push (NULL);
+         continue;
+       }
+
+      struct loop *loop = alloc_loop ();
+      loop->header = BASIC_BLOCK_FOR_FUNCTION (fn, header_index);
+      loop->header->loop_father = loop;
+
+      /* Read everything copy_loop_info copies.  */
+      loop->estimate_state = streamer_read_enum (ib, loop_estimation, EST_LAST);
+      loop->any_upper_bound = streamer_read_hwi (ib);
+      if (loop->any_upper_bound)
+       {
+         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)
+       {
+         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);
+
+      /* flow_loops_find doesn't like loops not in the tree, hook them
+         all as siblings of the tree root temporarily.  */
+      flow_loop_tree_node_add (loops->tree_root, loop);
+    }
+
+  /* Rebuild the loop tree.  */
+  flow_loops_find (loops);
 }
 
 
@@ -703,15 +755,15 @@ input_ssa_names (struct lto_input_block *ib, struct data_in *data_in,
       bool is_default_def;
 
       /* Skip over the elements that had been freed.  */
-      while (VEC_length (tree, SSANAMES (fn)) < i)
-       VEC_quick_push (tree, SSANAMES (fn), NULL_TREE);
+      while (SSANAMES (fn)->length () < i)
+       SSANAMES (fn)->quick_push (NULL_TREE);
 
       is_default_def = (streamer_read_uchar (ib) != 0);
       name = stream_read_tree (ib, data_in);
       ssa_name = make_ssa_name_fn (fn, name, gimple_build_nop ());
 
       if (is_default_def)
-       set_default_def (SSA_NAME_VAR (ssa_name), ssa_name);
+       set_ssa_default_def (cfun, SSA_NAME_VAR (ssa_name), ssa_name);
 
       i = streamer_read_uhwi (ib);
     }
@@ -722,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)
@@ -780,18 +862,14 @@ input_struct_function_base (struct function *fn, struct data_in *data_in,
   if (len > 0)
     {
       int i;
-      VEC_safe_grow (tree, gc, fn->local_decls, len);
+      vec_safe_grow_cleared (fn->local_decls, len);
       for (i = 0; i < len; i++)
        {
          tree t = stream_read_tree (ib, data_in);
-         VEC_replace (tree, fn->local_decls, i, t);
+         (*fn->local_decls)[i] = t;
        }
     }
 
-  /* Input the function start and end loci.  */
-  fn->function_start_locus = lto_input_location (ib, data_in);
-  fn->function_end_locus = lto_input_location (ib, data_in);
-
   /* Input the current IL state of the function.  */
   fn->curr_properties = streamer_read_uhwi (ib);
 
@@ -799,10 +877,10 @@ input_struct_function_base (struct function *fn, struct data_in *data_in,
   bp = streamer_read_bitpack (ib);
   fn->is_thunk = bp_unpack_value (&bp, 1);
   fn->has_local_explicit_reg_vars = bp_unpack_value (&bp, 1);
-  fn->after_tree_profile = bp_unpack_value (&bp, 1);
   fn->returns_pcc_struct = bp_unpack_value (&bp, 1);
   fn->returns_struct = bp_unpack_value (&bp, 1);
   fn->can_throw_non_call_exceptions = bp_unpack_value (&bp, 1);
+  fn->can_delete_dead_exceptions = bp_unpack_value (&bp, 1);
   fn->always_inline_functions_inlined = bp_unpack_value (&bp, 1);
   fn->after_inlining = bp_unpack_value (&bp, 1);
   fn->stdarg = bp_unpack_value (&bp, 1);
@@ -811,6 +889,10 @@ input_struct_function_base (struct function *fn, struct data_in *data_in,
   fn->calls_setjmp = bp_unpack_value (&bp, 1);
   fn->va_list_fpr_size = bp_unpack_value (&bp, 8);
   fn->va_list_gpr_size = bp_unpack_value (&bp, 8);
+
+  /* Input the function start and end loci.  */
+  fn->function_start_locus = stream_input_location (&bp, data_in);
+  fn->function_end_locus = stream_input_location (&bp, data_in);
 }
 
 
@@ -818,39 +900,40 @@ 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;
   gimple *stmts;
   basic_block bb;
   struct cgraph_node *node;
-  tree args, narg, oarg;
 
-  fn = DECL_STRUCT_FUNCTION (fn_decl);
   tag = streamer_read_record_start (ib);
-  clear_line_info (data_in);
+  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);
-
-  /* Read all function arguments.  We need to re-map them here to the
-     arguments of the merged function declaration.  */
-  args = stream_read_tree (ib, data_in);
-  for (oarg = args, narg = DECL_ARGUMENTS (fn_decl);
-       oarg && narg;
-       oarg = TREE_CHAIN (oarg), narg = TREE_CHAIN (narg))
-    {
-      unsigned ix;
-      bool res;
-      res = streamer_tree_cache_lookup (data_in->reader_cache, oarg, &ix);
-      gcc_assert (res);
-      /* Replace the argument in the streamer cache.  */
-      streamer_tree_cache_insert_at (data_in->reader_cache, narg, ix);
-    }
-  gcc_assert (!oarg && !narg);
+  input_cfg (ib_cfg, fn, node->count_materialization_scale);
 
   /* Read all the SSA names.  */
   input_ssa_names (ib, data_in, fn);
@@ -858,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);
@@ -879,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);
@@ -888,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);
@@ -916,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));
   }
 
@@ -927,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;
@@ -947,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);
@@ -964,7 +1058,7 @@ lto_read_body (struct lto_file_decl_data *file_data, tree fn_decl,
                        header->main_size);
 
   data_in = lto_data_in_create (file_data, data + string_offset,
-                               header->string_size, NULL);
+                             header->string_size, vNULL);
 
   /* Make sure the file was generated by the exact same compiler.  */
   lto_check_version (header->lto_header.major_version,
@@ -972,33 +1066,28 @@ 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);
 
       /* 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 = VEC_length (tree, data_in->reader_cache->nodes);
-      input_function (fn_decl, data_in, &ib_main);
+      from = data_in->reader_cache->nodes.length ();
+      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;
-         unsigned len = VEC_length (tree, cache->nodes);
+         unsigned len = cache->nodes.length ();
          unsigned i;
          for (i = len; i-- > from;)
            {
-             tree t = VEC_index (tree, cache->nodes, i);
+             tree t = streamer_tree_cache_get_tree (cache, i);
              if (t == NULL_TREE)
                continue;
 
@@ -1017,38 +1106,62 @@ lto_read_body (struct lto_file_decl_data *file_data, tree fn_decl,
            }
        }
 
-      /* We should now be in SSA.  */
-      cfun->gimple_df->in_ssa_p = true;
-
       /* Restore decl state */
       file_data->current_decl_state = file_data->global_decl_state;
-
-      pop_cfun ();
     }
 
-  clear_line_info (data_in);
   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)
 {
-  current_function_decl = fn_decl;
-  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);
@@ -1056,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, 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;
 }
 
 
@@ -1093,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)
@@ -1122,21 +1269,46 @@ lto_input_tree (struct lto_input_block *ib, struct data_in *data_in)
         the code and class.  */
       result = streamer_get_builtin_tree (ib, data_in);
     }
-  else if (tag == lto_tree_code_to_tag (INTEGER_CST))
+  else if (tag == LTO_integer_cst)
+    {
+      /* 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)
     {
-      /* For integer constants we only need the type and its hi/low
-        words.  */
-      result = streamer_read_integer_cst (ib, data_in);
+      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.  */
 
@@ -1163,7 +1335,7 @@ lto_input_toplevel_asms (struct lto_file_decl_data *file_data, int order_base)
                        header->main_size);
 
   data_in = lto_data_in_create (file_data, data + string_offset,
-                               header->string_size, NULL);
+                             header->string_size, vNULL);
 
   /* Make sure the file was generated by the exact same compiler.  */
   lto_check_version (header->lto_header.major_version,
@@ -1177,7 +1349,6 @@ lto_input_toplevel_asms (struct lto_file_decl_data *file_data, int order_base)
        symtab_order = node->order + 1;
     }
 
-  clear_line_info (data_in);
   lto_data_in_delete (data_in);
 
   lto_free_section_data (file_data, LTO_section_asm, NULL, data, len);
@@ -1190,8 +1361,7 @@ void
 lto_reader_init (void)
 {
   lto_streamer_init ();
-  file_name_hash_table = htab_create (37, hash_string_slot_node,
-                                     eq_string_slot_node, free);
+  file_name_hash_table.create (37);
 }
 
 
@@ -1202,14 +1372,14 @@ lto_reader_init (void)
 struct data_in *
 lto_data_in_create (struct lto_file_decl_data *file_data, const char *strings,
                    unsigned len,
-                   VEC(ld_plugin_symbol_resolution_t,heap) *resolutions)
+                   vec<ld_plugin_symbol_resolution_t> resolutions)
 {
   struct data_in *data_in = XCNEW (struct data_in);
   data_in->file_data = file_data;
   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;
 }
@@ -1220,7 +1390,7 @@ lto_data_in_create (struct lto_file_decl_data *file_data, const char *strings,
 void
 lto_data_in_delete (struct data_in *data_in)
 {
-  VEC_free (ld_plugin_symbol_resolution_t, heap, data_in->globals_resolution);
+  data_in->globals_resolution.release ();
   streamer_tree_cache_delete (data_in->reader_cache);
   free (data_in->labels);
   free (data_in);