/* 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>
#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"
#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
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;
}
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);
}
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:
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:
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)
/* 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)
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;
}
}
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;
}
}
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;
}
}
{
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;
}
}
}
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;
}
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)
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);
index = streamer_read_hwi (ib);
}
- p_bb = ENTRY_BLOCK_PTR_FOR_FUNCTION(fn);
+ p_bb = ENTRY_BLOCK_PTR_FOR_FN (fn);
index = streamer_read_hwi (ib);
while (index != -1)
{
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);
}
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);
}
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)
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);
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);
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);
}
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);
/* 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);
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);
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);
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));
}
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;
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);
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,
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;
}
}
- /* 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);
/* 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;
}
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)
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. */
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,
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);
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);
}
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;
}
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);