/* Read the GIMPLE representation from a file stream.
- Copyright 2009 Free Software Foundation, Inc.
+ Copyright 2009, 2010 Free Software Foundation, Inc.
Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
Re-implemented by Diego Novillo <dnovillo@google.com>
#include "flags.h"
#include "params.h"
#include "input.h"
-#include "varray.h"
#include "hashtab.h"
#include "basic-block.h"
#include "tree-flow.h"
unsigned int len;
unsigned int loc;
const char *result;
-
+
loc = lto_input_uleb128 (ib);
LTO_INIT_INPUT_BLOCK (str_tab, data_in->strings, loc, data_in->strings_len);
len = lto_input_uleb128 (&str_tab);
if (str_tab.p + len > data_in->strings_len)
internal_error ("bytecode stream: string too long for the string table");
-
+
result = (const char *)(data_in->strings + str_tab.p);
return result;
{
enum LTO_tags tag = (enum LTO_tags) lto_input_uleb128 (ib);
return tag;
-}
+}
/* Lookup STRING in file_name_hash_table. If found, return the existing
xloc.file = canon_file_name (xloc.file);
xloc.line = lto_input_sleb128 (ib);
xloc.column = lto_input_sleb128 (ib);
+ xloc.sysp = lto_input_sleb128 (ib);
if (data_in->current_file != xloc.file)
{
if (data_in->current_file)
linemap_add (line_table, LC_LEAVE, false, NULL, 0);
- linemap_add (line_table, LC_ENTER, false, xloc.file, xloc.line);
+ linemap_add (line_table, LC_ENTER, xloc.sysp, xloc.file, xloc.line);
}
else if (data_in->current_line != xloc.line)
linemap_line_start (line_table, xloc.line, xloc.column);
function scope for the read tree. */
static tree
-lto_input_tree_ref (struct lto_input_block *ib, struct data_in *data_in,
+lto_input_tree_ref (struct lto_input_block *ib, struct data_in *data_in,
struct function *fn, enum LTO_tags tag)
{
unsigned HOST_WIDE_INT ix_u;
case LTO_label_decl_ref:
ix_u = lto_input_uleb128 (ib);
result = lto_file_decl_data_get_var_decl (data_in->file_data, ix_u);
- if (tag == LTO_global_decl_ref)
- varpool_mark_needed_node (varpool_node (result));
break;
default:
static void
lto_init_eh (void)
{
+ static bool eh_initialized_p = false;
+
+ if (eh_initialized_p)
+ return;
+
/* Contrary to most other FEs, we only initialize EH support when at
least one of the files in the set contains exception regions in
it. Since this happens much later than the call to init_eh in
if (dwarf2out_do_frame ())
dwarf2out_frame_init ();
#endif
+
+ eh_initialized_p = true;
}
{
HOST_WIDE_INT i, root_region, len;
enum LTO_tags tag;
- static bool eh_initialized_p = false;
-
+
tag = input_record_start (ib);
if (tag == LTO_null)
return;
/* If the file contains EH regions, then it was compiled with
-fexceptions. In that case, initialize the backend EH
machinery. */
- if (!eh_initialized_p)
- {
- lto_init_eh ();
- eh_initialized_p = true;
- }
+ lto_init_eh ();
gcc_assert (fn->eh);
/* Read the CFG for function FN from input block IB. */
-static void
+static void
input_cfg (struct lto_input_block *ib, struct function *fn)
{
unsigned int bb_count;
init_empty_tree_cfg_for_function (fn);
init_ssa_operands ();
- profile_status_for_function (fn) =
+ profile_status_for_function (fn) =
(enum profile_status_d) lto_input_uleb128 (ib);
bb_count = lto_input_uleb128 (ib);
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,
+ VEC_safe_grow_cleared (basic_block, gc,
label_to_block_map_for_function (fn), bb_count);
index = lto_input_sleb128 (ib);
dest = BASIC_BLOCK_FOR_FUNCTION (fn, dest_index);
- if (dest == NULL)
+ if (dest == NULL)
dest = make_new_block (fn, dest_index);
e = make_edge (bb, dest, edge_flags);
int src_index = lto_input_uleb128 (ib);
location_t arg_loc = lto_input_location (ib, data_in);
basic_block sbb = BASIC_BLOCK_FOR_FUNCTION (fn, src_index);
-
+
edge e = NULL;
int j;
-
+
for (j = 0; j < len; j++)
if (EDGE_PRED (bb, j)->src == sbb)
{
break;
}
- add_phi_arg (result, def, e, arg_loc);
+ add_phi_arg (result, def, e, arg_loc);
}
return result;
set_default_def (SSA_NAME_VAR (ssa_name), ssa_name);
i = lto_input_uleb128 (ib);
- }
+ }
}
}
/* Fixup reference tree operands for substituted prevailing decls
- with mismatched types in STMT. */
+ with mismatched types in STMT. This handles plain DECLs where
+ we need the stmt for context to lookup the required type. */
static void
maybe_fixup_decls (gimple stmt)
gimple_assign_set_rhs1 (stmt, build1 (VIEW_CONVERT_EXPR,
TREE_TYPE (lhs), rhs));
}
- else if (handled_component_p (rhs))
- maybe_fixup_handled_component (rhs);
/* Then catch scalar stores. */
else if (TREE_CODE (lhs) == VAR_DECL)
{
gimple_assign_set_lhs (stmt, build1 (VIEW_CONVERT_EXPR,
TREE_TYPE (rhs), lhs));
}
- else if (handled_component_p (lhs))
- maybe_fixup_handled_component (lhs);
}
else if (is_gimple_call (stmt))
{
gimple_call_return_type (stmt),
lhs));
}
- else if (lhs && handled_component_p (lhs))
- maybe_fixup_handled_component (lhs);
/* Arguments, especially for varargs functions will be funny... */
}
stmt->gimple_asm.ni = lto_input_uleb128 (ib);
stmt->gimple_asm.no = lto_input_uleb128 (ib);
stmt->gimple_asm.nc = lto_input_uleb128 (ib);
+ stmt->gimple_asm.nl = lto_input_uleb128 (ib);
str = input_string_cst (data_in, ib);
stmt->gimple_asm.string = TREE_STRING_POINTER (str);
}
{
tree op = lto_input_tree (ib, data_in);
gimple_set_op (stmt, i, op);
+ if (!op)
+ continue;
+
+ /* Fixup reference tree operands for substituted prevailing decls
+ with mismatched types. For plain VAR_DECLs we need to look
+ at context to determine the wanted type - we do that below
+ after the stmt is completed. */
+ if (TREE_CODE (op) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (op, 0)) == VAR_DECL
+ && !useless_type_conversion_p (TREE_TYPE (TREE_TYPE (op)),
+ TREE_TYPE (op)))
+ {
+ TREE_OPERAND (op, 0)
+ = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (TREE_TYPE (op)),
+ TREE_OPERAND (op, 0));
+ continue;
+ }
- /* Fixup FIELD_DECLs. */
- while (op && handled_component_p (op))
+ /* Fixup FIELD_DECLs in COMPONENT_REFs, they are not handled
+ by decl merging. */
+ if (TREE_CODE (op) == ADDR_EXPR)
+ op = TREE_OPERAND (op, 0);
+ while (handled_component_p (op))
{
if (TREE_CODE (op) == COMPONENT_REF)
{
{
if (tem == field
|| (TREE_TYPE (tem) == TREE_TYPE (field)
- && (DECL_FIELD_OFFSET (tem)
- == DECL_FIELD_OFFSET (field))
- && (DECL_FIELD_BIT_OFFSET (tem)
- == DECL_FIELD_BIT_OFFSET (field))
- && (DECL_OFFSET_ALIGN (tem)
- == DECL_OFFSET_ALIGN (field))))
+ && DECL_NONADDRESSABLE_P (tem)
+ == DECL_NONADDRESSABLE_P (field)
+ && gimple_compare_field_offset (tem, field)))
break;
}
/* In case of type mismatches across units we can fail
to unify some types and thus not find a proper
- field-decl here. Just do nothing in this case. */
+ field-decl here. So only assert here if checking
+ is enabled. */
+#ifdef ENABLE_CHECKING
+ gcc_assert (tem != NULL_TREE);
+#endif
if (tem != NULL_TREE)
TREE_OPERAND (op, 1) = tem;
}
+ /* Preserve the last handled component for the fixup of
+ its operand below. */
+ if (!handled_component_p (TREE_OPERAND (op, 0)))
+ break;
op = TREE_OPERAND (op, 0);
}
+
+ /* Fixup reference tree operands for substituted prevailing decls
+ with mismatched types. */
+ if (handled_component_p (op))
+ maybe_fixup_handled_component (op);
}
break;
}
}
+ /* Reset alias information. */
+ if (code == GIMPLE_CALL)
+ gimple_call_reset_alias_info (stmt);
+
/* Fixup reference tree operands for substituted prevailing decls
with mismatched types. */
maybe_fixup_decls (stmt);
return stmt;
}
-
+
/* Read a basic block with tag TAG from DATA_IN using input block IB.
FN is the function being processed. */
static void
-input_bb (struct lto_input_block *ib, enum LTO_tags tag,
+input_bb (struct lto_input_block *ib, enum LTO_tags tag,
struct data_in *data_in, struct function *fn)
{
unsigned int index;
struct cgraph_edge *cedge;
for (cedge = node->callees; cedge; cedge = cedge->next_callee)
cedge->call_stmt = stmts[cedge->lto_stmt_uid];
+ for (cedge = node->indirect_calls; cedge; cedge = cedge->next_callee)
+ cedge->call_stmt = stmts[cedge->lto_stmt_uid];
}
/* Fixup call_stmt pointers in NODE and all clones. */
/* Read the body of function FN_DECL from DATA_IN using input block IB. */
static void
-input_function (tree fn_decl, struct data_in *data_in,
+input_function (tree fn_decl, struct data_in *data_in,
struct lto_input_block *ib)
{
struct function *fn;
gimple *stmts;
basic_block bb;
struct bitpack_d *bp;
+ struct cgraph_node *node;
+ tree args, narg, oarg;
fn = DECL_STRUCT_FUNCTION (fn_decl);
tag = input_record_start (ib);
fn->has_nonlocal_label = bp_unpack_value (bp, 1);
fn->calls_alloca = bp_unpack_value (bp, 1);
fn->calls_setjmp = bp_unpack_value (bp, 1);
- fn->function_frequency = (enum function_frequency) bp_unpack_value (bp, 2);
fn->va_list_fpr_size = bp_unpack_value (bp, 8);
fn->va_list_gpr_size = bp_unpack_value (bp, 8);
bitpack_delete (bp);
+ /* Input the current IL state of the function. */
+ fn->curr_properties = lto_input_uleb128 (ib);
+
/* Read the static chain and non-local goto save area. */
fn->static_chain_decl = lto_input_tree (ib, data_in);
fn->nonlocal_goto_save_area = lto_input_tree (ib, data_in);
/* Read all the local symbols. */
fn->local_decls = lto_input_tree (ib, data_in);
+ /* Read all function arguments. We need to re-map them here to the
+ arguments of the merged function declaration. */
+ args = lto_input_tree (ib, data_in);
+ for (oarg = args, narg = DECL_ARGUMENTS (fn_decl);
+ oarg && narg;
+ oarg = TREE_CHAIN (oarg), narg = TREE_CHAIN (narg))
+ {
+ int ix;
+ bool res;
+ res = lto_streamer_cache_lookup (data_in->reader_cache, oarg, &ix);
+ gcc_assert (res);
+ /* Replace the argument in the streamer cache. */
+ lto_streamer_cache_insert_at (data_in->reader_cache, narg, ix);
+ }
+ gcc_assert (!oarg && !narg);
+
/* Read all the SSA names. */
input_ssa_names (ib, data_in, fn);
gcc_assert (DECL_INITIAL (fn_decl));
DECL_SAVED_TREE (fn_decl) = NULL_TREE;
- /* Read all function arguments. */
- DECL_ARGUMENTS (fn_decl) = lto_input_tree (ib, data_in);
-
/* Read all the basic blocks. */
tag = input_record_start (ib);
while (tag)
gimple_set_body (fn_decl, bb_seq (ei_edge (ei)->dest));
}
- fixup_call_stmt_edges (cgraph_node (fn_decl), stmts);
+ node = cgraph_node (fn_decl);
+ fixup_call_stmt_edges (node, stmts);
+ execute_all_ipa_stmt_fixups (node, stmts);
- update_ssa (TODO_update_ssa_only_virtuals);
+ update_ssa (TODO_update_ssa_only_virtuals);
free_dominance_info (CDI_DOMINATORS);
free_dominance_info (CDI_POST_DOMINATORS);
free (stmts);
{
const char *orig_name, *new_name;
alias_pair *p;
-
+
p = VEC_safe_push (alias_pair, gc, alias_pairs, NULL);
p->decl = var;
p->target = lto_input_tree (ib, data_in);
section type is LTO_section_function_body, FN must be the decl for
that function. */
-static void
+static void
lto_read_body (struct lto_file_decl_data *file_data, tree fn_decl,
const char *data, enum lto_section_type section_type)
{
struct lto_input_block ib_main;
header = (const struct lto_function_header *) data;
- cfg_offset = sizeof (struct lto_function_header);
+ cfg_offset = sizeof (struct lto_function_header);
main_offset = cfg_offset + header->cfg_size;
string_offset = main_offset + header->main_size;
data + main_offset,
0,
header->main_size);
-
+
data_in = lto_data_in_create (file_data, data + string_offset,
header->string_size, NULL);
/* We should now be in SSA. */
cfun->gimple_df->in_ssa_p = true;
- /* Fill in properties we know hold for the rebuilt CFG. */
- cfun->curr_properties = PROP_ssa
- | PROP_cfg
- | PROP_gimple_any
- | PROP_gimple_lcf
- | PROP_gimple_leh
- | PROP_referenced_vars;
-
/* Restore decl state */
file_data->current_decl_state = file_data->global_decl_state;
- /* FIXME: ipa_transforms_to_apply holds list of passes that have optimization
- summaries computed and needs to apply changes. At the moment WHOPR only
- supports inlining, so we can push it here by hand. In future we need to stream
- this field into ltrans compilation. This will also need to move the field
- from struct function into cgraph node where it belongs. */
- if (flag_ltrans && !cgraph_node (fn_decl)->global.inlined_to)
- VEC_safe_push (ipa_opt_pass, heap,
- cfun->ipa_transforms_to_apply,
- (ipa_opt_pass)&pass_ipa_inline);
pop_cfun ();
}
- else
+ else
{
input_alias_pairs (&ib_main, data_in);
}
/* Read the body of FN_DECL using DATA. FILE_DATA holds the global
decls and types. */
-void
+void
lto_input_function_body (struct lto_file_decl_data *file_data,
tree fn_decl, const char *data)
{
/* Read in VAR_DECL using DATA. FILE_DATA holds the global decls and
types. */
-void
+void
lto_input_constructors_and_inits (struct lto_file_decl_data *file_data,
const char *data)
{
if (data_in->globals_resolution)
{
ld_plugin_symbol_resolution_t ret;
- gcc_assert (index < VEC_length (ld_plugin_symbol_resolution_t,
- data_in->globals_resolution));
+ /* We can have references to not emitted functions in
+ DECL_FUNCTION_PERSONALITY at least. So we can and have
+ to indeed return LDPR_UNKNOWN in some cases. */
+ if (VEC_length (ld_plugin_symbol_resolution_t,
+ data_in->globals_resolution) <= index)
+ return LDPR_UNKNOWN;
ret = VEC_index (ld_plugin_symbol_resolution_t,
data_in->globals_resolution,
index);
- gcc_assert (ret != LDPR_UNKNOWN);
return ret;
}
else
unsigned i;
REAL_VALUE_TYPE r;
REAL_VALUE_TYPE *rp;
-
+
r.cl = (unsigned) bp_unpack_value (bp, 2);
r.decimal = (unsigned) bp_unpack_value (bp, 1);
r.sign = (unsigned) bp_unpack_value (bp, 1);
unpack_ts_fixed_cst_value_fields (struct bitpack_d *bp, tree expr)
{
struct fixed_value fv;
-
+
fv.data.low = (HOST_WIDE_INT) bp_unpack_value (bp, HOST_BITS_PER_WIDE_INT);
fv.data.high = (HOST_WIDE_INT) bp_unpack_value (bp, HOST_BITS_PER_WIDE_INT);
TREE_FIXED_CST (expr) = fv;
if (TREE_CODE (expr) == VAR_DECL
|| TREE_CODE (expr) == PARM_DECL)
DECL_HAS_VALUE_EXPR_P (expr) = (unsigned) bp_unpack_value (bp, 1);
+ DECL_RESTRICTED_P (expr) = (unsigned) bp_unpack_value (bp, 1);
}
}
{
DECL_HARD_REGISTER (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_IN_TEXT_SECTION (expr) = (unsigned) bp_unpack_value (bp, 1);
+ DECL_IN_CONSTANT_POOL (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_TLS_MODEL (expr) = (enum tls_model) bp_unpack_value (bp, 3);
}
SET_TYPE_MODE (expr, mode);
TYPE_STRING_FLAG (expr) = (unsigned) bp_unpack_value (bp, 1);
TYPE_NO_FORCE_BLK (expr) = (unsigned) bp_unpack_value (bp, 1);
- TYPE_NEEDS_CONSTRUCTING(expr) = (unsigned) bp_unpack_value (bp, 1);
- if (TREE_CODE (expr) == UNION_TYPE)
- TYPE_TRANSPARENT_UNION (expr) = (unsigned) bp_unpack_value (bp, 1);
+ TYPE_NEEDS_CONSTRUCTING (expr) = (unsigned) bp_unpack_value (bp, 1);
+ if (RECORD_OR_UNION_TYPE_P (expr))
+ TYPE_TRANSPARENT_AGGR (expr) = (unsigned) bp_unpack_value (bp, 1);
TYPE_PACKED (expr) = (unsigned) bp_unpack_value (bp, 1);
TYPE_RESTRICT (expr) = (unsigned) bp_unpack_value (bp, 1);
TYPE_CONTAINS_PLACEHOLDER_INTERNAL (expr)
{
int i, count;
tree first, prev, curr;
-
+
first = prev = NULL_TREE;
count = lto_input_sleb128 (ib);
for (i = 0; i < count; i++)
return first;
}
-
+
/* Read all pointer fields in the TS_COMMON structure of EXPR from input
block IB. DATA_IN contains tables and descriptors for the
file being read. */
if (TREE_CODE (expr) == PARM_DECL)
TREE_CHAIN (expr) = lto_input_chain (ib, data_in);
+
+ if ((TREE_CODE (expr) == VAR_DECL
+ || TREE_CODE (expr) == PARM_DECL)
+ && DECL_HAS_VALUE_EXPR_P (expr))
+ SET_DECL_VALUE_EXPR (expr, lto_input_tree (ib, data_in));
}
struct data_in *data_in, tree expr)
{
tree id;
-
+
id = lto_input_tree (ib, data_in);
if (id)
{
DECL_FUNCTION_PERSONALITY (expr) = lto_input_tree (ib, data_in);
DECL_FUNCTION_SPECIFIC_TARGET (expr) = lto_input_tree (ib, data_in);
DECL_FUNCTION_SPECIFIC_OPTIMIZATION (expr) = lto_input_tree (ib, data_in);
+
+ /* If the file contains a function with an EH personality set,
+ then it was compiled with -fexceptions. In that case, initialize
+ the backend EH machinery. */
+ if (DECL_FUNCTION_PERSONALITY (expr))
+ lto_init_eh ();
}
TYPE_VALUES (expr) = lto_input_tree (ib, data_in);
else if (TREE_CODE (expr) == ARRAY_TYPE)
TYPE_DOMAIN (expr) = lto_input_tree (ib, data_in);
- else if (TREE_CODE (expr) == RECORD_TYPE || TREE_CODE (expr) == UNION_TYPE)
+ else if (RECORD_OR_UNION_TYPE_P (expr))
TYPE_FIELDS (expr) = lto_input_tree (ib, data_in);
- else if (TREE_CODE (expr) == FUNCTION_TYPE || TREE_CODE (expr) == METHOD_TYPE)
+ else if (TREE_CODE (expr) == FUNCTION_TYPE
+ || TREE_CODE (expr) == METHOD_TYPE)
TYPE_ARG_TYPES (expr) = lto_input_tree (ib, data_in);
else if (TREE_CODE (expr) == VECTOR_TYPE)
TYPE_DEBUG_REPRESENTATION_TYPE (expr) = lto_input_tree (ib, data_in);
TYPE_BINFO (expr) = lto_input_tree (ib, data_in);
TYPE_CONTEXT (expr) = lto_input_tree (ib, data_in);
TYPE_CANONICAL (expr) = lto_input_tree (ib, data_in);
+ TYPE_STUB_DECL (expr) = lto_input_tree (ib, data_in);
}
confuse any attempt to unmangle it. */
const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
char *label;
-
+
ASM_FORMAT_PRIVATE_NAME (label, name, DECL_UID (decl));
SET_DECL_ASSEMBLER_NAME (decl, get_identifier (label));
rest_of_decl_compilation (decl, 1, 0);
attempt to unmangle it. */
const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
char *label;
-
+
ASM_FORMAT_PRIVATE_NAME (label, name, DECL_UID (decl));
SET_DECL_ASSEMBLER_NAME (decl, get_identifier (label));
/* Also register the reverse mapping so that we can find the
new name given to an existing assembler name (used when
- restoring alias pairs in input_constructors_or_inits. */
+ restoring alias pairs in input_constructors_or_inits. */
lto_record_renamed_decl (data_in->file_data,
IDENTIFIER_POINTER (new_assembler_name),
IDENTIFIER_POINTER (old_assembler_name));
- }
+ }
}
/* If this variable has already been declared, queue the
if (!result || result == error_mark_node)
fatal_error ("target specific builtin not available");
}
+ else
+ gcc_unreachable ();
asmname = input_string (data_in, ib);
if (asmname)
enum LTO_tags tag)
{
tree result;
- char end_marker;
int ix;
result = lto_materialize_tree (ib, data_in, tag, &ix);
else if (TREE_CODE (result) == FUNCTION_DECL && !DECL_BUILT_IN (result))
lto_register_function_decl_in_symtab (data_in, result);
- end_marker = lto_input_1_unsigned (ib);
+ /* end_marker = */ lto_input_1_unsigned (ib);
#ifdef LTO_STREAMER_DEBUG
/* Remove the mapping to RESULT's original address set by
{
enum LTO_tags tag;
tree result;
-
+
tag = input_record_start (ib);
gcc_assert ((unsigned) tag < (unsigned) LTO_NUM_TAGS);