/* Write the GIMPLE representation to a file stream.
- Copyright (C) 2009-2015 Free Software Foundation, Inc.
+ Copyright (C) 2009-2020 Free Software Foundation, Inc.
Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
Re-implemented by Diego Novillo <dnovillo@google.com>
#include "system.h"
#include "coretypes.h"
#include "backend.h"
+#include "target.h"
+#include "rtl.h"
#include "tree.h"
#include "gimple.h"
-#include "rtl.h"
+#include "tree-pass.h"
#include "ssa.h"
+#include "gimple-streamer.h"
#include "alias.h"
-#include "fold-const.h"
#include "stor-layout.h"
-#include "flags.h"
-#include "insn-config.h"
-#include "expmed.h"
-#include "dojump.h"
-#include "explow.h"
-#include "calls.h"
-#include "emit-rtl.h"
-#include "varasm.h"
-#include "stmt.h"
-#include "expr.h"
-#include "params.h"
-#include "internal-fn.h"
#include "gimple-iterator.h"
-#include "tree-pass.h"
-#include "diagnostic-core.h"
#include "except.h"
#include "lto-symtab.h"
#include "cgraph.h"
-#include "target.h"
-#include "gimple-streamer.h"
#include "cfgloop.h"
#include "builtins.h"
#include "gomp-constants.h"
+#include "debug.h"
+#include "omp-offload.h"
+#include "print-tree.h"
+#include "tree-dfa.h"
static void lto_write_tree (struct output_block*, tree, bool);
ob->current_file = NULL;
ob->current_line = 0;
ob->current_col = 0;
+ ob->current_sysp = false;
}
create_output_block (enum lto_section_type section_type)
{
struct output_block *ob = XCNEW (struct output_block);
+ if (streamer_dump_file)
+ fprintf (streamer_dump_file, "Creating output block for %s\n",
+ lto_section_name [section_type]);
ob->section_type = section_type;
ob->decl_state = lto_get_out_decl_state ();
lto_output_type_ref_index (ob->decl_state, ob->main_stream, node);
}
+/* Wrapper around variably_modified_type_p avoiding type modification
+ during WPA streaming. */
+
+static bool
+lto_variably_modified_type_p (tree type)
+{
+ return (in_lto_p
+ ? TYPE_LANG_FLAG_0 (TYPE_MAIN_VARIANT (type))
+ : variably_modified_type_p (type, NULL_TREE));
+}
+
/* Return true if tree node T is written to various tables. For these
nodes, we sometimes want to write their phyiscal representation
definition. */
if ((TREE_CODE (t) == PARM_DECL || TREE_CODE (t) == RESULT_DECL)
&& DECL_CONTEXT (t))
- return variably_modified_type_p (TREE_TYPE (DECL_CONTEXT (t)), NULL_TREE);
- /* IMPORTED_DECL is put into BLOCK and thus it never can be shared. */
+ return lto_variably_modified_type_p (TREE_TYPE (DECL_CONTEXT (t)));
+ /* IMPORTED_DECL is put into BLOCK and thus it never can be shared.
+ We should no longer need to stream it. */
else if (TREE_CODE (t) == IMPORTED_DECL)
- return false;
- else if (((TREE_CODE (t) == VAR_DECL && !TREE_STATIC (t))
+ gcc_unreachable ();
+ else if (TREE_CODE (t) == LABEL_DECL)
+ return FORCED_LABEL (t) || DECL_NONLOCAL (t);
+ else if (((VAR_P (t) && !TREE_STATIC (t))
|| TREE_CODE (t) == TYPE_DECL
|| TREE_CODE (t) == CONST_DECL
|| TREE_CODE (t) == NAMELIST_DECL)
them we have to localize their members as well.
??? In theory that includes non-FIELD_DECLs as well. */
else if (TYPE_P (t)
- && variably_modified_type_p (t, NULL_TREE))
+ && lto_variably_modified_type_p (t))
return false;
else if (TREE_CODE (t) == FIELD_DECL
- && variably_modified_type_p (DECL_CONTEXT (t), NULL_TREE))
+ && lto_variably_modified_type_p (DECL_CONTEXT (t)))
return false;
else
return (TYPE_P (t) || DECL_P (t) || TREE_CODE (t) == SSA_NAME);
bp_pack_value (bp, ob->current_col != xloc.column, 1);
if (ob->current_file != xloc.file)
- bp_pack_string (ob, bp, xloc.file, true);
+ {
+ bp_pack_string (ob, bp, xloc.file, true);
+ bp_pack_value (bp, xloc.sysp, 1);
+ }
ob->current_file = xloc.file;
+ ob->current_sysp = xloc.sysp;
if (ob->current_line != xloc.line)
bp_pack_var_len_unsigned (bp, xloc.line);
case VAR_DECL:
case DEBUG_EXPR_DECL:
gcc_assert (decl_function_context (expr) == NULL || TREE_STATIC (expr));
+ /* FALLTHRU */
case PARM_DECL:
streamer_write_record_start (ob, LTO_global_decl_ref);
lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
name version in lto_output_tree_ref (see output_ssa_names). */
return !is_lang_specific (expr)
&& code != SSA_NAME
- && code != CALL_EXPR
&& code != LANG_TYPE
&& code != MODIFY_EXPR
&& code != INIT_EXPR
|| TREE_CODE_CLASS (code) != tcc_statement);
}
+/* Very rough estimate of streaming size of the initializer. If we ignored
+ presence of strings, we could simply just count number of non-indexable
+ tree nodes and number of references to indexable nodes. Strings however
+ may be very large and we do not want to dump them int othe global stream.
+
+ Count the size of initializer until the size in DATA is positive. */
+
+static tree
+subtract_estimated_size (tree *tp, int *ws, void *data)
+{
+ long *sum = (long *)data;
+ if (tree_is_indexable (*tp))
+ {
+ /* Indexable tree is one reference to global stream.
+ Guess it may be about 4 bytes. */
+ *sum -= 4;
+ *ws = 0;
+ }
+ /* String table entry + base of tree node needs to be streamed. */
+ if (TREE_CODE (*tp) == STRING_CST)
+ *sum -= TREE_STRING_LENGTH (*tp) + 8;
+ else
+ {
+ /* Identifiers are also variable length but should not appear
+ naked in constructor. */
+ gcc_checking_assert (TREE_CODE (*tp) != IDENTIFIER_NODE);
+ /* We do not really make attempt to work out size of pickled tree, as
+ it is very variable. Make it bigger than the reference. */
+ *sum -= 16;
+ }
+ if (*sum < 0)
+ return *tp;
+ return NULL_TREE;
+}
+
/* For EXPR lookup and return what we want to stream to OB as DECL_INITIAL. */
/* Handle DECL_INITIAL for symbols. */
tree initial = DECL_INITIAL (expr);
- if (TREE_CODE (expr) == VAR_DECL
+ if (VAR_P (expr)
&& (TREE_STATIC (expr) || DECL_EXTERNAL (expr))
&& !DECL_IN_CONSTANT_POOL (expr)
&& initial)
varpool_node *vnode;
/* Extra section needs about 30 bytes; do not produce it for simple
scalar values. */
- if (TREE_CODE (DECL_INITIAL (expr)) == CONSTRUCTOR
- || !(vnode = varpool_node::get (expr))
+ if (!(vnode = varpool_node::get (expr))
|| !lto_symtab_encoder_encode_initializer_p (encoder, vnode))
initial = error_mark_node;
+ if (initial != error_mark_node)
+ {
+ long max_size = 30;
+ if (walk_tree (&initial, subtract_estimated_size, (void *)&max_size,
+ NULL))
+ initial = error_mark_node;
+ }
}
return initial;
(ob->decl_state->symtab_node_encoder, expr);
stream_write_tree (ob, initial, ref_p);
}
+
+ /* Stream references to early generated DIEs. Keep in sync with the
+ trees handled in dwarf2out_die_ref_for_decl. */
+ if ((DECL_P (expr)
+ && TREE_CODE (expr) != FIELD_DECL
+ && TREE_CODE (expr) != DEBUG_EXPR_DECL
+ && TREE_CODE (expr) != TYPE_DECL)
+ || TREE_CODE (expr) == BLOCK)
+ {
+ const char *sym;
+ unsigned HOST_WIDE_INT off;
+ if (debug_info_level > DINFO_LEVEL_NONE
+ && debug_hooks->die_ref_for_decl (expr, &sym, &off))
+ {
+ streamer_write_string (ob, ob->main_stream, sym, true);
+ streamer_write_uhwi (ob, off);
+ }
+ else
+ streamer_write_string (ob, ob->main_stream, NULL, true);
+ }
}
/* Write a physical representation of tree node EXPR to output block
bool exists_p = streamer_tree_cache_insert (ob->writer_cache,
expr, hash, &ix);
gcc_assert (!exists_p);
- if (streamer_handle_as_builtin_p (expr))
- {
- /* MD and NORMAL builtins do not need to be written out
- completely as they are always instantiated by the
- compiler on startup. The only builtins that need to
- be written out are BUILT_IN_FRONTEND. For all other
- builtins, we simply write the class and code. */
- streamer_write_builtin (ob, expr);
- }
- else if (TREE_CODE (expr) == INTEGER_CST
- && !TREE_OVERFLOW (expr))
+ if (TREE_CODE (expr) == INTEGER_CST
+ && !TREE_OVERFLOW (expr))
{
/* Shared INTEGER_CST nodes are special because they need their
original type to be materialized by the reader (to implement
tree t;
hashval_t hash;
};
- vec<scc_entry> sccstack;
+ auto_vec<scc_entry,32> sccstack;
private:
struct sccs
bool ref_p, bool this_ref_p);
hash_map<tree, sccs *> sccstate;
- vec<worklist> worklist_vec;
+ auto_vec<worklist, 32> worklist_vec;
struct obstack sccstate_obstack;
};
bool single_p)
{
unsigned int next_dfs_num = 1;
- sccstack.create (0);
gcc_obstack_init (&sccstate_obstack);
- worklist_vec = vNULL;
DFS_write_tree (ob, NULL, expr, ref_p, this_ref_p);
while (!worklist_vec.is_empty ())
{
cstate->low = cstate->dfsnum;
w.cstate = cstate;
- if (streamer_handle_as_builtin_p (expr))
- ;
- else if (TREE_CODE (expr) == INTEGER_CST
- && !TREE_OVERFLOW (expr))
+ if (TREE_CODE (expr) == INTEGER_CST
+ && !TREE_OVERFLOW (expr))
DFS_write_tree (ob, cstate, TREE_TYPE (expr), ref_p, ref_p);
else
{
std::swap (sccstack[first + i],
sccstack[first + entry_start + i]);
- if (scc_entry_len == 1)
- ; /* We already sorted SCC deterministically in hash_scc. */
- else
- /* Check that we have only one SCC.
- Naturally we may have conflicts if hash function is not
- strong enough. Lets see how far this gets. */
- {
-#ifdef ENABLE_CHECKING
- gcc_unreachable ();
-#endif
- }
+ /* We already sorted SCC deterministically in hash_scc. */
+
+ /* Check that we have only one SCC.
+ Naturally we may have conflicts if hash function is not
+ strong enough. Lets see how far this gets. */
+ gcc_checking_assert (scc_entry_len == 1);
}
/* Write LTO_tree_scc. */
"in LTO streams",
get_tree_code_name (TREE_CODE (t)));
- gcc_checking_assert (!streamer_handle_as_builtin_p (t));
-
/* Write the header, containing everything needed to
materialize EXPR on the reading side. */
streamer_write_tree_header (ob, t);
from_state->low = MIN (cstate->dfsnum, from_state->low);
worklist_vec.pop ();
}
- worklist_vec.release ();
}
DFS::~DFS ()
{
- sccstack.release ();
obstack_free (&sccstate_obstack, NULL);
}
enum tree_code code;
+ if (streamer_dump_file)
+ {
+ print_node_brief (streamer_dump_file, " Streaming ",
+ expr, 4);
+ fprintf (streamer_dump_file, " to %s\n",
+ lto_section_name [ob->section_type]);
+ }
+
code = TREE_CODE (expr);
if (CODE_CONTAINS_STRUCT (code, TS_TYPED))
if (CODE_CONTAINS_STRUCT (code, TS_VECTOR))
{
- for (unsigned i = 0; i < VECTOR_CST_NELTS (expr); ++i)
- DFS_follow_tree_edge (VECTOR_CST_ELT (expr, i));
+ unsigned int count = vector_cst_encoded_nelts (expr);
+ for (unsigned int i = 0; i < count; ++i)
+ DFS_follow_tree_edge (VECTOR_CST_ENCODED_ELT (expr, i));
}
+ if (CODE_CONTAINS_STRUCT (code, TS_POLY_INT_CST))
+ for (unsigned int i = 0; i < NUM_POLY_INT_COEFFS; ++i)
+ DFS_follow_tree_edge (POLY_INT_CST_COEFF (expr, i));
+
if (CODE_CONTAINS_STRUCT (code, TS_COMPLEX))
{
DFS_follow_tree_edge (TREE_REALPART (expr));
/* Drop names that were created for anonymous entities. */
if (DECL_NAME (expr)
&& TREE_CODE (DECL_NAME (expr)) == IDENTIFIER_NODE
- && anon_aggrname_p (DECL_NAME (expr)))
+ && IDENTIFIER_ANON_P (DECL_NAME (expr)))
;
else
DFS_follow_tree_edge (DECL_NAME (expr));
- DFS_follow_tree_edge (DECL_CONTEXT (expr));
+ if (TREE_CODE (expr) != TRANSLATION_UNIT_DECL
+ && ! DECL_CONTEXT (expr))
+ DFS_follow_tree_edge ((*all_translation_units)[0]);
+ else
+ DFS_follow_tree_edge (DECL_CONTEXT (expr));
}
if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
DFS_follow_tree_edge (DECL_ATTRIBUTES (expr));
- /* Do not follow DECL_ABSTRACT_ORIGIN. We cannot handle debug information
- for early inlining so drop it on the floor instead of ICEing in
- dwarf2out.c. */
+ /* We use DECL_ABSTRACT_ORIGIN == error_mark_node to mark
+ declarations which should be eliminated by decl merging. Be sure none
+ leaks to this point. */
+ gcc_assert (DECL_ABSTRACT_ORIGIN (expr) != error_mark_node);
+ DFS_follow_tree_edge (DECL_ABSTRACT_ORIGIN (expr));
- if ((TREE_CODE (expr) == VAR_DECL
+ if ((VAR_P (expr)
|| TREE_CODE (expr) == PARM_DECL)
&& DECL_HAS_VALUE_EXPR_P (expr))
DFS_follow_tree_edge (DECL_VALUE_EXPR (expr));
- if (TREE_CODE (expr) == VAR_DECL)
+ if (VAR_P (expr)
+ && DECL_HAS_DEBUG_EXPR_P (expr))
DFS_follow_tree_edge (DECL_DEBUG_EXPR (expr));
}
- if (CODE_CONTAINS_STRUCT (code, TS_DECL_NON_COMMON))
- {
- if (TREE_CODE (expr) == TYPE_DECL)
- DFS_follow_tree_edge (DECL_ORIGINAL_TYPE (expr));
- }
-
if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
{
/* Make sure we don't inadvertently set the assembler name. */
DFS_follow_tree_edge (DECL_BIT_FIELD_TYPE (expr));
DFS_follow_tree_edge (DECL_BIT_FIELD_REPRESENTATIVE (expr));
DFS_follow_tree_edge (DECL_FIELD_BIT_OFFSET (expr));
- DFS_follow_tree_edge (DECL_FCONTEXT (expr));
+ gcc_checking_assert (!DECL_FCONTEXT (expr));
}
if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL))
{
- DFS_follow_tree_edge (DECL_VINDEX (expr));
+ gcc_checking_assert (DECL_VINDEX (expr) == NULL);
DFS_follow_tree_edge (DECL_FUNCTION_PERSONALITY (expr));
DFS_follow_tree_edge (DECL_FUNCTION_SPECIFIC_TARGET (expr));
DFS_follow_tree_edge (DECL_FUNCTION_SPECIFIC_OPTIMIZATION (expr));
DFS_follow_tree_edge (TYPE_CONTEXT (expr));
/* TYPE_CANONICAL is re-computed during type merging, so no need
to follow it here. */
- DFS_follow_tree_edge (TYPE_STUB_DECL (expr));
+ /* Do not stream TYPE_STUB_DECL; it is not needed by LTO but currently
+ it cannot be freed by free_lang_data without triggering ICEs in
+ langhooks. */
}
if (CODE_CONTAINS_STRUCT (code, TS_TYPE_NON_COMMON))
DFS_follow_tree_edge (TYPE_ARG_TYPES (expr));
if (!POINTER_TYPE_P (expr))
- DFS_follow_tree_edge (TYPE_MINVAL (expr));
- DFS_follow_tree_edge (TYPE_MAXVAL (expr));
- if (RECORD_OR_UNION_TYPE_P (expr))
- DFS_follow_tree_edge (TYPE_BINFO (expr));
+ DFS_follow_tree_edge (TYPE_MIN_VALUE_RAW (expr));
+ DFS_follow_tree_edge (TYPE_MAX_VALUE_RAW (expr));
}
if (CODE_CONTAINS_STRUCT (code, TS_LIST))
if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
{
for (tree t = BLOCK_VARS (expr); t; t = TREE_CHAIN (t))
- if (VAR_OR_FUNCTION_DECL_P (t)
- && DECL_EXTERNAL (t))
- /* We have to stream externals in the block chain as
- non-references. See also
- tree-streamer-out.c:streamer_write_chain. */
- DFS_write_tree (ob, expr_state, t, ref_p, false);
- else
+ {
+ /* We would have to stream externals in the block chain as
+ non-references but we should have dropped them in
+ free-lang-data. */
+ gcc_assert (!VAR_OR_FUNCTION_DECL_P (t) || !DECL_EXTERNAL (t));
DFS_follow_tree_edge (t);
+ }
DFS_follow_tree_edge (BLOCK_SUPERCONTEXT (expr));
+ DFS_follow_tree_edge (BLOCK_ABSTRACT_ORIGIN (expr));
- /* Follow BLOCK_ABSTRACT_ORIGIN for the limited cases we can
- handle - those that represent inlined function scopes.
- For the drop rest them on the floor instead of ICEing
- in dwarf2out.c. */
- if (inlined_function_outer_scope_p (expr))
- {
- tree ultimate_origin = block_ultimate_origin (expr);
- DFS_follow_tree_edge (ultimate_origin);
- }
/* Do not follow BLOCK_NONLOCALIZED_VARS. We cannot handle debug
information for early inlined BLOCKs so drop it on the floor instead
of ICEing in dwarf2out.c. */
DFS_follow_tree_edge (t);
DFS_follow_tree_edge (BINFO_OFFSET (expr));
DFS_follow_tree_edge (BINFO_VTABLE (expr));
- DFS_follow_tree_edge (BINFO_VPTR_FIELD (expr));
- /* The number of BINFO_BASE_ACCESSES has already been emitted in
- EXPR's bitfield section. */
- FOR_EACH_VEC_SAFE_ELT (BINFO_BASE_ACCESSES (expr), i, t)
- DFS_follow_tree_edge (t);
-
- /* Do not walk BINFO_INHERITANCE_CHAIN, BINFO_SUBVTT_INDEX
- and BINFO_VPTR_INDEX; these are used by C++ FE only. */
+ /* Do not walk BINFO_INHERITANCE_CHAIN, BINFO_SUBVTT_INDEX,
+ BINFO_BASE_ACCESSES and BINFO_VPTR_INDEX; these are used
+ by C++ FE only. */
}
if (CODE_CONTAINS_STRUCT (code, TS_CONSTRUCTOR))
hstate.add_flag (TREE_PRIVATE (t));
if (TYPE_P (t))
{
- hstate.add_flag (TYPE_SATURATING (t));
+ hstate.add_flag (AGGREGATE_TYPE_P (t)
+ ? TYPE_REVERSE_STORAGE_ORDER (t) : TYPE_SATURATING (t));
hstate.add_flag (TYPE_ADDR_SPACE (t));
}
else if (code == SSA_NAME)
hstate.commit_flag ();
if (CODE_CONTAINS_STRUCT (code, TS_INT_CST))
- {
- int i;
- hstate.add_wide_int (TREE_INT_CST_NUNITS (t));
- hstate.add_wide_int (TREE_INT_CST_EXT_NUNITS (t));
- for (i = 0; i < TREE_INT_CST_NUNITS (t); i++)
- hstate.add_wide_int (TREE_INT_CST_ELT (t, i));
- }
+ hstate.add_wide_int (wi::to_widest (t));
if (CODE_CONTAINS_STRUCT (code, TS_REAL_CST))
{
if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
{
- hstate.add_wide_int (DECL_MODE (t));
+ hstate.add_hwi (DECL_MODE (t));
hstate.add_flag (DECL_NONLOCAL (t));
hstate.add_flag (DECL_VIRTUAL_P (t));
hstate.add_flag (DECL_IGNORED_P (t));
{
hstate.add_flag (DECL_PACKED (t));
hstate.add_flag (DECL_NONADDRESSABLE_P (t));
+ hstate.add_flag (DECL_PADDING_P (t));
hstate.add_int (DECL_OFFSET_ALIGN (t));
}
else if (code == VAR_DECL)
hstate.add_int (DECL_BUILT_IN_CLASS (t));
hstate.add_flag (DECL_STATIC_CONSTRUCTOR (t));
hstate.add_flag (DECL_STATIC_DESTRUCTOR (t));
+ hstate.add_flag (FUNCTION_DECL_DECL_TYPE (t));
hstate.add_flag (DECL_UNINLINABLE (t));
hstate.add_flag (DECL_POSSIBLY_INLINED (t));
hstate.add_flag (DECL_IS_NOVOPS (t));
hstate.add_flag (DECL_IS_RETURNS_TWICE (t));
hstate.add_flag (DECL_IS_MALLOC (t));
- hstate.add_flag (DECL_IS_OPERATOR_NEW (t));
hstate.add_flag (DECL_DECLARED_INLINE_P (t));
hstate.add_flag (DECL_STATIC_CHAIN (t));
hstate.add_flag (DECL_NO_INLINE_WARNING_P (t));
hstate.add_flag (DECL_LOOPING_CONST_OR_PURE_P (t));
hstate.commit_flag ();
if (DECL_BUILT_IN_CLASS (t) != NOT_BUILT_IN)
- hstate.add_int (DECL_FUNCTION_CODE (t));
+ hstate.add_int (DECL_UNCHECKED_FUNCTION_CODE (t));
}
if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON))
{
- hstate.add_wide_int (TYPE_MODE (t));
- hstate.add_flag (TYPE_STRING_FLAG (t));
+ hstate.add_hwi (TYPE_MODE (t));
/* TYPE_NO_FORCE_BLK is private to stor-layout and need
no streaming. */
- hstate.add_flag (TYPE_NEEDS_CONSTRUCTING (t));
hstate.add_flag (TYPE_PACKED (t));
hstate.add_flag (TYPE_RESTRICT (t));
hstate.add_flag (TYPE_USER_ALIGN (t));
{
hstate.add_flag (TYPE_TRANSPARENT_AGGR (t));
hstate.add_flag (TYPE_FINAL_P (t));
+ hstate.add_flag (TYPE_CXX_ODR_P (t));
}
else if (code == ARRAY_TYPE)
hstate.add_flag (TYPE_NONALIASED_COMPONENT (t));
+ if (code == ARRAY_TYPE || code == INTEGER_TYPE)
+ hstate.add_flag (TYPE_STRING_FLAG (t));
+ if (AGGREGATE_TYPE_P (t))
+ hstate.add_flag (TYPE_TYPELESS_STORAGE (t));
hstate.commit_flag ();
hstate.add_int (TYPE_PRECISION (t));
hstate.add_int (TYPE_ALIGN (t));
- hstate.add_int ((TYPE_ALIAS_SET (t) == 0
- || (!in_lto_p
- && get_alias_set (t) == 0))
- ? 0 : -1);
+ hstate.add_int (TYPE_EMPTY_P (t));
}
if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION)
/* We don't stream these when passing things to a different target. */
&& !lto_stream_offload_p)
- hstate.add_wide_int (cl_target_option_hash (TREE_TARGET_OPTION (t)));
+ hstate.add_hwi (cl_target_option_hash (TREE_TARGET_OPTION (t)));
if (CODE_CONTAINS_STRUCT (code, TS_OPTIMIZATION))
- hstate.add_wide_int (cl_optimization_hash (TREE_OPTIMIZATION (t)));
+ hstate.add_hwi (cl_optimization_hash (TREE_OPTIMIZATION (t)));
if (CODE_CONTAINS_STRUCT (code, TS_IDENTIFIER))
hstate.merge_hash (IDENTIFIER_HASH_VALUE (t));
}
if (CODE_CONTAINS_STRUCT (code, TS_VECTOR))
- for (unsigned i = 0; i < VECTOR_CST_NELTS (t); ++i)
- visit (VECTOR_CST_ELT (t, i));
+ {
+ unsigned int count = vector_cst_encoded_nelts (t);
+ for (unsigned int i = 0; i < count; ++i)
+ visit (VECTOR_CST_ENCODED_ELT (t, i));
+ }
+
+ if (CODE_CONTAINS_STRUCT (code, TS_POLY_INT_CST))
+ for (unsigned int i = 0; i < NUM_POLY_INT_COEFFS; ++i)
+ visit (POLY_INT_CST_COEFF (t, i));
if (CODE_CONTAINS_STRUCT (code, TS_COMPLEX))
{
/* Drop names that were created for anonymous entities. */
if (DECL_NAME (t)
&& TREE_CODE (DECL_NAME (t)) == IDENTIFIER_NODE
- && anon_aggrname_p (DECL_NAME (t)))
+ && IDENTIFIER_ANON_P (DECL_NAME (t)))
;
else
visit (DECL_NAME (t));
be able to call get_symbol_initial_value. */
}
- if (CODE_CONTAINS_STRUCT (code, TS_DECL_NON_COMMON))
- {
- if (code == TYPE_DECL)
- visit (DECL_ORIGINAL_TYPE (t));
- }
-
if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
{
if (DECL_ASSEMBLER_NAME_SET_P (t))
visit (DECL_BIT_FIELD_TYPE (t));
visit (DECL_BIT_FIELD_REPRESENTATIVE (t));
visit (DECL_FIELD_BIT_OFFSET (t));
- visit (DECL_FCONTEXT (t));
}
if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL))
{
- visit (DECL_VINDEX (t));
visit (DECL_FUNCTION_PERSONALITY (t));
visit (DECL_FUNCTION_SPECIFIC_TARGET (t));
visit (DECL_FUNCTION_SPECIFIC_OPTIMIZATION (t));
;
else
visit (TYPE_CONTEXT (t));
- visit (TYPE_STUB_DECL (t));
}
if (CODE_CONTAINS_STRUCT (code, TS_TYPE_NON_COMMON))
|| code == METHOD_TYPE)
visit (TYPE_ARG_TYPES (t));
if (!POINTER_TYPE_P (t))
- visit (TYPE_MINVAL (t));
- visit (TYPE_MAXVAL (t));
- if (RECORD_OR_UNION_TYPE_P (t))
- visit (TYPE_BINFO (t));
+ visit (TYPE_MIN_VALUE_RAW (t));
+ visit (TYPE_MAX_VALUE_RAW (t));
}
if (CODE_CONTAINS_STRUCT (code, TS_LIST))
if (CODE_CONTAINS_STRUCT (code, TS_EXP))
{
- hstate.add_wide_int (TREE_OPERAND_LENGTH (t));
+ hstate.add_hwi (TREE_OPERAND_LENGTH (t));
for (int i = 0; i < TREE_OPERAND_LENGTH (t); ++i)
visit (TREE_OPERAND (t, i));
}
visit (b);
visit (BINFO_OFFSET (t));
visit (BINFO_VTABLE (t));
- visit (BINFO_VPTR_FIELD (t));
- FOR_EACH_VEC_SAFE_ELT (BINFO_BASE_ACCESSES (t), i, b)
- visit (b);
/* Do not walk BINFO_INHERITANCE_CHAIN, BINFO_SUBVTT_INDEX
- and BINFO_VPTR_INDEX; these are used by C++ FE only. */
+ BINFO_BASE_ACCESSES and BINFO_VPTR_INDEX; these are used
+ by C++ FE only. */
}
if (CODE_CONTAINS_STRUCT (code, TS_CONSTRUCTOR))
{
unsigned i;
tree index, value;
- hstate.add_wide_int (CONSTRUCTOR_NELTS (t));
+ hstate.add_hwi (CONSTRUCTOR_NELTS (t));
FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), i, index, value)
{
visit (index);
int i;
HOST_WIDE_INT val;
- hstate.add_wide_int (OMP_CLAUSE_CODE (t));
+ hstate.add_hwi (OMP_CLAUSE_CODE (t));
switch (OMP_CLAUSE_CODE (t))
{
case OMP_CLAUSE_DEFAULT:
val = OMP_CLAUSE_PROC_BIND_KIND (t);
break;
case OMP_CLAUSE_REDUCTION:
+ case OMP_CLAUSE_TASK_REDUCTION:
+ case OMP_CLAUSE_IN_REDUCTION:
val = OMP_CLAUSE_REDUCTION_CODE (t);
break;
default:
val = 0;
break;
}
- hstate.add_wide_int (val);
+ hstate.add_hwi (val);
for (i = 0; i < omp_clause_num_ops[OMP_CLAUSE_CODE (t)]; i++)
visit (OMP_CLAUSE_OPERAND (t, i));
visit (OMP_CLAUSE_CHAIN (t));
we stream out. */
gcc_assert (!in_dfs_walk);
+ if (streamer_dump_file)
+ {
+ print_node_brief (streamer_dump_file, " Streaming SCC of ",
+ expr, 4);
+ fprintf (streamer_dump_file, "\n");
+ }
+
/* Start the DFS walk. */
/* Save ob state ... */
/* let's see ... */
streamer_write_uhwi (ob, ix);
streamer_write_enum (ob->main_stream, LTO_tags, LTO_NUM_TAGS,
lto_tree_code_to_tag (TREE_CODE (expr)));
+ if (streamer_dump_file)
+ {
+ print_node_brief (streamer_dump_file, " Finished SCC of ",
+ expr, 4);
+ fprintf (streamer_dump_file, "\n\n");
+ }
lto_stats.num_pickle_refs_output++;
}
}
if (ptr == NULL_TREE
|| SSA_NAME_IN_FREE_LIST (ptr)
- || virtual_operand_p (ptr))
+ || virtual_operand_p (ptr)
+ /* Simply skip unreleased SSA names. */
+ || (! SSA_NAME_IS_DEFAULT_DEF (ptr)
+ && (! SSA_NAME_DEF_STMT (ptr)
+ || ! gimple_bb (SSA_NAME_DEF_STMT (ptr)))))
continue;
streamer_write_uhwi (ob, i);
}
-/* Output a wide-int. */
-
-static void
-streamer_write_wi (struct output_block *ob,
- const widest_int &w)
-{
- int len = w.get_len ();
-
- streamer_write_uhwi (ob, w.get_precision ());
- streamer_write_uhwi (ob, len);
- for (int i = 0; i < len; i++)
- streamer_write_hwi (ob, w.elt (i));
-}
-
/* Output the cfg. */
FOR_EACH_EDGE (e, ei, bb->succs)
{
streamer_write_uhwi (ob, e->dest->index);
- streamer_write_hwi (ob, e->probability);
- streamer_write_gcov_count (ob, e->count);
+ e->probability.stream_out (ob);
streamer_write_uhwi (ob, e->flags);
}
}
streamer_write_hwi (ob, -1);
- bb = ENTRY_BLOCK_PTR_FOR_FN (cfun);
+ bb = ENTRY_BLOCK_PTR_FOR_FN (fn);
while (bb->next_bb)
{
streamer_write_hwi (ob, bb->next_bb->index);
streamer_write_hwi (ob, -1);
- /* ??? The cfgloop interface is tied to cfun. */
- gcc_assert (cfun == fn);
-
/* Output the number of loops. */
streamer_write_uhwi (ob, number_of_loops (fn));
/* Output each loop, skipping the tree root which has number zero. */
for (unsigned i = 1; i < number_of_loops (fn); ++i)
{
- struct loop *loop = get_loop (fn, i);
+ class loop *loop = get_loop (fn, i);
/* Write the index of the loop header. That's enough to rebuild
the loop tree on the reader side. Stream -1 for an unused
loop_estimation, EST_LAST, loop->estimate_state);
streamer_write_hwi (ob, loop->any_upper_bound);
if (loop->any_upper_bound)
- streamer_write_wi (ob, loop->nb_iterations_upper_bound);
+ streamer_write_widest_int (ob, loop->nb_iterations_upper_bound);
+ streamer_write_hwi (ob, loop->any_likely_upper_bound);
+ if (loop->any_likely_upper_bound)
+ streamer_write_widest_int (ob, loop->nb_iterations_likely_upper_bound);
streamer_write_hwi (ob, loop->any_estimate);
if (loop->any_estimate)
- streamer_write_wi (ob, loop->nb_iterations_estimate);
+ streamer_write_widest_int (ob, loop->nb_iterations_estimate);
/* Write OMP SIMD related info. */
streamer_write_hwi (ob, loop->safelen);
+ streamer_write_hwi (ob, loop->unroll);
+ streamer_write_hwi (ob, loop->owned_clique);
streamer_write_hwi (ob, loop->dont_vectorize);
streamer_write_hwi (ob, loop->force_vectorize);
stream_write_tree (ob, loop->simduid, true);
if (section_type == LTO_section_function_body)
{
const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fn));
- section_name = lto_get_section_name (section_type, name, NULL);
+ section_name = lto_get_section_name (section_type, name,
+ symtab_node::get (fn)->order,
+ NULL);
}
else
- section_name = lto_get_section_name (section_type, NULL, NULL);
+ section_name = lto_get_section_name (section_type, NULL, 0, NULL);
lto_begin_section (section_name, !flag_wpa);
free (section_name);
/* The entire header is stream computed here. */
memset (&header, 0, sizeof (struct lto_function_header));
- /* Write the header. */
- header.major_version = LTO_major_version;
- header.minor_version = LTO_minor_version;
-
if (section_type == LTO_section_function_body)
header.cfg_size = ob->cfg_stream->total_size;
header.main_size = ob->main_stream->total_size;
bp_pack_value (&bp, fn->after_inlining, 1);
bp_pack_value (&bp, fn->stdarg, 1);
bp_pack_value (&bp, fn->has_nonlocal_label, 1);
+ bp_pack_value (&bp, fn->has_forced_label_in_static, 1);
bp_pack_value (&bp, fn->calls_alloca, 1);
bp_pack_value (&bp, fn->calls_setjmp, 1);
+ bp_pack_value (&bp, fn->calls_eh_return, 1);
bp_pack_value (&bp, fn->has_force_vectorize_loops, 1);
bp_pack_value (&bp, fn->has_simduid_loops, 1);
bp_pack_value (&bp, fn->va_list_fpr_size, 8);
stream_output_location (ob, &bp, fn->function_start_locus);
stream_output_location (ob, &bp, fn->function_end_locus);
+ /* Save the instance discriminator if present. */
+ int *instance_number_p = NULL;
+ if (decl_to_instance_map)
+ instance_number_p = decl_to_instance_map->get (fn->decl);
+ bp_pack_value (&bp, !!instance_number_p, 1);
+ if (instance_number_p)
+ bp_pack_value (&bp, *instance_number_p, sizeof (int) * CHAR_BIT);
+
streamer_write_bitpack (&bp);
}
+/* Collect all leaf BLOCKs beyond ROOT into LEAFS. */
+
+static void
+collect_block_tree_leafs (tree root, vec<tree> &leafs)
+{
+ for (root = BLOCK_SUBBLOCKS (root); root; root = BLOCK_CHAIN (root))
+ if (! BLOCK_SUBBLOCKS (root))
+ leafs.safe_push (root);
+ else
+ collect_block_tree_leafs (BLOCK_SUBBLOCKS (root), leafs);
+}
+
+/* This performs function body modifications that are needed for streaming
+ to work. */
+
+void
+lto_prepare_function_for_streaming (struct cgraph_node *node)
+{
+ struct function *fn = DECL_STRUCT_FUNCTION (node->decl);
+ basic_block bb;
+
+ if (number_of_loops (fn))
+ {
+ push_cfun (fn);
+ loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
+ loop_optimizer_finalize ();
+ pop_cfun ();
+ }
+ /* We will renumber the statements. The code that does this uses
+ the same ordering that we use for serializing them so we can use
+ the same code on the other end and not have to write out the
+ statement numbers. We do not assign UIDs to PHIs here because
+ virtual PHIs get re-computed on-the-fly which would make numbers
+ inconsistent. */
+ set_gimple_stmt_max_uid (fn, 0);
+ FOR_ALL_BB_FN (bb, fn)
+ {
+ for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
+ gsi_next (&gsi))
+ {
+ gphi *stmt = gsi.phi ();
+
+ /* Virtual PHIs are not going to be streamed. */
+ if (!virtual_operand_p (gimple_phi_result (stmt)))
+ gimple_set_uid (stmt, inc_gimple_stmt_max_uid (fn));
+ }
+ for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi);
+ gsi_next (&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+ gimple_set_uid (stmt, inc_gimple_stmt_max_uid (fn));
+ }
+ }
+ /* To avoid keeping duplicate gimple IDs in the statements, renumber
+ virtual phis now. */
+ FOR_ALL_BB_FN (bb, fn)
+ {
+ for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
+ gsi_next (&gsi))
+ {
+ gphi *stmt = gsi.phi ();
+ if (virtual_operand_p (gimple_phi_result (stmt)))
+ gimple_set_uid (stmt, inc_gimple_stmt_max_uid (fn));
+ }
+ }
+
+}
+
/* Output the body of function NODE->DECL. */
static void
basic_block bb;
struct output_block *ob;
+ if (streamer_dump_file)
+ fprintf (streamer_dump_file, "\nStreaming body of %s\n",
+ node->name ());
+
function = node->decl;
fn = DECL_STRUCT_FUNCTION (function);
ob = create_output_block (LTO_section_function_body);
gcc_assert (current_function_decl == NULL_TREE && cfun == NULL);
- /* Set current_function_decl and cfun. */
- push_cfun (fn);
-
/* Make string 0 be a NULL string. */
streamer_write_char_stream (ob->string_stream, 0);
stream_write_tree (ob, DECL_RESULT (function), true);
streamer_write_chain (ob, DECL_ARGUMENTS (function), true);
+ /* Output debug args if available. */
+ vec<tree, va_gc> **debugargs = decl_debug_args_lookup (function);
+ if (! debugargs)
+ streamer_write_uhwi (ob, 0);
+ else
+ {
+ streamer_write_uhwi (ob, (*debugargs)->length ());
+ for (unsigned i = 0; i < (*debugargs)->length (); ++i)
+ stream_write_tree (ob, (**debugargs)[i], true);
+ }
+
/* Output DECL_INITIAL for the function, which contains the tree of
lexical scopes. */
stream_write_tree (ob, DECL_INITIAL (function), true);
+ /* As we do not recurse into BLOCK_SUBBLOCKS but only BLOCK_SUPERCONTEXT
+ collect block tree leafs and stream those. */
+ auto_vec<tree> block_tree_leafs;
+ if (DECL_INITIAL (function))
+ collect_block_tree_leafs (DECL_INITIAL (function), block_tree_leafs);
+ streamer_write_uhwi (ob, block_tree_leafs.length ());
+ for (unsigned i = 0; i < block_tree_leafs.length (); ++i)
+ stream_write_tree (ob, block_tree_leafs[i], true);
/* We also stream abstract functions where we stream only stuff needed for
debug info. */
/* Output any exception handling regions. */
output_eh_regions (ob, fn);
-
- /* We will renumber the statements. The code that does this uses
- the same ordering that we use for serializing them so we can use
- the same code on the other end and not have to write out the
- statement numbers. We do not assign UIDs to PHIs here because
- virtual PHIs get re-computed on-the-fly which would make numbers
- inconsistent. */
- set_gimple_stmt_max_uid (cfun, 0);
- FOR_ALL_BB_FN (bb, cfun)
- {
- for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
- gsi_next (&gsi))
- {
- gphi *stmt = gsi.phi ();
-
- /* Virtual PHIs are not going to be streamed. */
- if (!virtual_operand_p (gimple_phi_result (stmt)))
- gimple_set_uid (stmt, inc_gimple_stmt_max_uid (cfun));
- }
- for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi);
- gsi_next (&gsi))
- {
- gimple stmt = gsi_stmt (gsi);
- gimple_set_uid (stmt, inc_gimple_stmt_max_uid (cfun));
- }
- }
- /* To avoid keeping duplicate gimple IDs in the statements, renumber
- virtual phis now. */
- FOR_ALL_BB_FN (bb, cfun)
- {
- for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
- gsi_next (&gsi))
- {
- gphi *stmt = gsi.phi ();
- if (virtual_operand_p (gimple_phi_result (stmt)))
- gimple_set_uid (stmt, inc_gimple_stmt_max_uid (cfun));
- }
- }
-
/* Output the code for the function. */
FOR_ALL_BB_FN (bb, fn)
output_bb (ob, bb, fn);
streamer_write_record_start (ob, LTO_null);
output_cfg (ob, fn);
-
- pop_cfun ();
}
else
streamer_write_uhwi (ob, 0);
produce_asm (ob, function);
destroy_output_block (ob);
+ if (streamer_dump_file)
+ fprintf (streamer_dump_file, "Finished streaming %s\n",
+ node->name ());
}
/* Output the body of function NODE->DECL. */
tree var = node->decl;
struct output_block *ob;
+ if (streamer_dump_file)
+ fprintf (streamer_dump_file, "\nStreaming constructor of %s\n",
+ node->name ());
+
+ timevar_push (TV_IPA_LTO_CTORS_OUT);
ob = create_output_block (LTO_section_function_body);
clear_line_info (ob);
produce_asm (ob, var);
destroy_output_block (ob);
+ if (streamer_dump_file)
+ fprintf (streamer_dump_file, "Finished streaming %s\n",
+ node->name ());
+ timevar_pop (TV_IPA_LTO_CTORS_OUT);
}
streamer_write_string_cst (ob, ob->main_stream, NULL_TREE);
- section_name = lto_get_section_name (LTO_section_asm, NULL, NULL);
+ section_name = lto_get_section_name (LTO_section_asm, NULL, 0, NULL);
lto_begin_section (section_name, !flag_wpa);
free (section_name);
/* The entire header stream is computed here. */
memset (&header, 0, sizeof (header));
- /* Write the header. */
- header.major_version = LTO_major_version;
- header.minor_version = LTO_minor_version;
-
header.main_size = ob->main_stream->total_size;
header.string_size = ob->string_stream->total_size;
lto_write_data (&header, sizeof header);
size_t len;
const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (function));
char *section_name =
- lto_get_section_name (LTO_section_function_body, name, NULL);
+ lto_get_section_name (LTO_section_function_body, name, node->order, NULL);
size_t i, j;
struct lto_in_decl_state *in_state;
struct lto_out_decl_state *out_state = lto_get_out_decl_state ();
- lto_begin_section (section_name, !flag_wpa);
+ if (streamer_dump_file)
+ fprintf (streamer_dump_file, "Copying section for %s\n", name);
+ lto_begin_section (section_name, false);
free (section_name);
/* We may have renamed the declaration, e.g., a static function. */
name = lto_get_decl_name_mapping (file_data, name);
- data = lto_get_section_data (file_data, LTO_section_function_body,
- name, &len);
+ data = lto_get_raw_section_data (file_data, LTO_section_function_body,
+ name, node->order - file_data->order_base,
+ &len);
gcc_assert (data);
/* Do a bit copy of the function body. */
- lto_write_data (data, len);
+ lto_write_raw_data (data, len);
/* Copy decls. */
in_state =
lto_get_function_in_decl_state (node->lto_file_data, function);
+ out_state->compressed = in_state->compressed;
gcc_assert (in_state);
for (i = 0; i < LTO_N_DECL_STREAMS; i++)
encoder->trees.safe_push ((*trees)[j]);
}
- lto_free_section_data (file_data, LTO_section_function_body, name,
- data, len);
+ lto_free_raw_section_data (file_data, LTO_section_function_body, name,
+ data, len);
lto_end_section ();
}
{
tree t = *tp;
if (handled_component_p (t)
- && TREE_CODE (TREE_OPERAND (t, 0)) == VAR_DECL)
+ && TREE_CODE (TREE_OPERAND (t, 0)) == VAR_DECL
+ && TREE_PUBLIC (TREE_OPERAND (t, 0)))
{
tree decl = TREE_OPERAND (t, 0);
tree ptrtype = build_pointer_type (TREE_TYPE (decl));
return NULL_TREE;
}
+/* Remove functions that are no longer used from offload_funcs, and mark the
+ remaining ones with DECL_PRESERVE_P. */
+
+static void
+prune_offload_funcs (void)
+{
+ if (!offload_funcs)
+ return;
+
+ unsigned ix, ix2;
+ tree *elem_ptr;
+ VEC_ORDERED_REMOVE_IF (*offload_funcs, ix, ix2, elem_ptr,
+ cgraph_node::get (*elem_ptr) == NULL);
+
+ tree fn_decl;
+ FOR_EACH_VEC_ELT (*offload_funcs, ix, fn_decl)
+ DECL_PRESERVE_P (fn_decl) = 1;
+}
+
+/* Produce LTO section that contains global information
+ about LTO bytecode. */
+
+static void
+produce_lto_section ()
+{
+ /* Stream LTO meta section. */
+ output_block *ob = create_output_block (LTO_section_lto);
+
+ char * section_name = lto_get_section_name (LTO_section_lto, NULL, 0, NULL);
+ lto_begin_section (section_name, false);
+ free (section_name);
+
+#ifdef HAVE_ZSTD_H
+ lto_compression compression = ZSTD;
+#else
+ lto_compression compression = ZLIB;
+#endif
+
+ bool slim_object = flag_generate_lto && !flag_fat_lto_objects;
+ lto_section s
+ = { LTO_major_version, LTO_minor_version, slim_object, 0 };
+ s.set_compression (compression);
+ lto_write_data (&s, sizeof s);
+ lto_end_section ();
+ destroy_output_block (ob);
+}
+
+/* Compare symbols to get them sorted by filename (to optimize streaming) */
+
+static int
+cmp_symbol_files (const void *pn1, const void *pn2)
+{
+ const symtab_node *n1 = *(const symtab_node * const *)pn1;
+ const symtab_node *n2 = *(const symtab_node * const *)pn2;
+
+ int file_order1 = n1->lto_file_data ? n1->lto_file_data->order : -1;
+ int file_order2 = n2->lto_file_data ? n2->lto_file_data->order : -1;
+
+ /* Order files same way as they appeared in the command line to reduce
+ seeking while copying sections. */
+ if (file_order1 != file_order2)
+ return file_order1 - file_order2;
+
+ /* Order within static library. */
+ if (n1->lto_file_data && n1->lto_file_data->id != n2->lto_file_data->id)
+ {
+ if (n1->lto_file_data->id > n2->lto_file_data->id)
+ return 1;
+ if (n1->lto_file_data->id < n2->lto_file_data->id)
+ return -1;
+ }
+
+ /* And finaly order by the definition order. */
+ return n1->order - n2->order;
+}
+
/* Main entry point from the pass manager. */
void
lto_output (void)
{
struct lto_out_decl_state *decl_state;
-#ifdef ENABLE_CHECKING
- bitmap output = lto_bitmap_alloc ();
-#endif
- int i, n_nodes;
+ bitmap output = NULL;
+ bitmap_obstack output_obstack;
+ unsigned int i, n_nodes;
lto_symtab_encoder_t encoder = lto_get_out_decl_state ()->symtab_node_encoder;
+ auto_vec<symtab_node *> symbols_to_copy;
+
+ prune_offload_funcs ();
+
+ if (flag_checking)
+ {
+ bitmap_obstack_initialize (&output_obstack);
+ output = BITMAP_ALLOC (&output_obstack);
+ }
/* Initialize the streamer. */
lto_streamer_init ();
+ produce_lto_section ();
+
n_nodes = lto_symtab_encoder_size (encoder);
- /* Process only the functions with bodies. */
+ /* Prepare vector of functions to output and then sort it to optimize
+ section copying. */
for (i = 0; i < n_nodes; i++)
{
symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
+ if (snode->alias)
+ continue;
if (cgraph_node *node = dyn_cast <cgraph_node *> (snode))
{
- if (lto_symtab_encoder_encode_body_p (encoder, node)
- && !node->alias)
- {
-#ifdef ENABLE_CHECKING
- gcc_assert (!bitmap_bit_p (output, DECL_UID (node->decl)));
- bitmap_set_bit (output, DECL_UID (node->decl));
-#endif
- decl_state = lto_new_out_decl_state ();
- lto_push_out_decl_state (decl_state);
- if (gimple_has_body_p (node->decl) || !flag_wpa
- /* Thunks have no body but they may be synthetized
- at WPA time. */
- || DECL_ARGUMENTS (node->decl))
- output_function (node);
- else
- copy_function_or_variable (node);
- gcc_assert (lto_get_out_decl_state () == decl_state);
- lto_pop_out_decl_state ();
- lto_record_function_out_decl_state (node->decl, decl_state);
- }
+ if (lto_symtab_encoder_encode_body_p (encoder, node))
+ symbols_to_copy.safe_push (node);
}
else if (varpool_node *node = dyn_cast <varpool_node *> (snode))
{
if (ctor && !in_lto_p)
walk_tree (&ctor, wrap_refs, NULL, NULL);
if (get_symbol_initial_value (encoder, node->decl) == error_mark_node
- && lto_symtab_encoder_encode_initializer_p (encoder, node)
- && !node->alias)
- {
- timevar_push (TV_IPA_LTO_CTORS_OUT);
-#ifdef ENABLE_CHECKING
- gcc_assert (!bitmap_bit_p (output, DECL_UID (node->decl)));
- bitmap_set_bit (output, DECL_UID (node->decl));
-#endif
- decl_state = lto_new_out_decl_state ();
- lto_push_out_decl_state (decl_state);
- if (DECL_INITIAL (node->decl) != error_mark_node
- || !flag_wpa)
- output_constructor (node);
- else
- copy_function_or_variable (node);
- gcc_assert (lto_get_out_decl_state () == decl_state);
- lto_pop_out_decl_state ();
- lto_record_function_out_decl_state (node->decl, decl_state);
- timevar_pop (TV_IPA_LTO_CTORS_OUT);
- }
+ && lto_symtab_encoder_encode_initializer_p (encoder, node))
+ symbols_to_copy.safe_push (node);
}
}
+ symbols_to_copy.qsort (cmp_symbol_files);
+ for (i = 0; i < symbols_to_copy.length (); i++)
+ {
+ symtab_node *snode = symbols_to_copy[i];
+ cgraph_node *cnode;
+ varpool_node *vnode;
+
+ if (flag_checking)
+ gcc_assert (bitmap_set_bit (output, DECL_UID (snode->decl)));
+
+ decl_state = lto_new_out_decl_state ();
+ lto_push_out_decl_state (decl_state);
+
+ if ((cnode = dyn_cast <cgraph_node *> (snode))
+ && (gimple_has_body_p (cnode->decl)
+ || (!flag_wpa
+ && flag_incremental_link != INCREMENTAL_LINK_LTO)
+ /* Thunks have no body but they may be synthetized
+ at WPA time. */
+ || DECL_ARGUMENTS (cnode->decl)))
+ output_function (cnode);
+ else if ((vnode = dyn_cast <varpool_node *> (snode))
+ && (DECL_INITIAL (vnode->decl) != error_mark_node
+ || (!flag_wpa
+ && flag_incremental_link != INCREMENTAL_LINK_LTO)))
+ output_constructor (vnode);
+ else
+ copy_function_or_variable (snode);
+ gcc_assert (lto_get_out_decl_state () == decl_state);
+ lto_pop_out_decl_state ();
+ lto_record_function_out_decl_state (snode->decl, decl_state);
+ }
/* Emit the callgraph after emitting function bodies. This needs to
be done now to make sure that all the statements in every function
output_offload_tables ();
-#ifdef ENABLE_CHECKING
- lto_bitmap_free (output);
-#endif
+ if (flag_checking)
+ {
+ BITMAP_FREE (output);
+ bitmap_obstack_release (&output_obstack);
+ }
}
/* Write each node in encoded by ENCODER to OB, as well as those reachable
for (index = 0; index < size; index++)
{
t = lto_tree_ref_encoder_get_tree (encoder, index);
+ if (streamer_dump_file)
+ {
+ fprintf (streamer_dump_file, " %i:", (int)index);
+ print_node_brief (streamer_dump_file, "", t, 4);
+ fprintf (streamer_dump_file, "\n");
+ }
if (!streamer_tree_cache_lookup (ob->writer_cache, t, NULL))
stream_write_tree (ob, t, false);
}
for (index = 0; index < size; index++)
{
- uint32_t slot_num;
+ unsigned slot_num;
t = lto_tree_ref_encoder_get_tree (encoder, index);
streamer_tree_cache_lookup (ob->writer_cache, t, &slot_num);
struct lto_out_decl_state *state)
{
unsigned i;
- uint32_t ref;
+ unsigned ref;
tree decl;
/* Write reference to FUNCTION_DECL. If there is not function,
decl = (state->fn_decl) ? state->fn_decl : void_type_node;
streamer_tree_cache_lookup (ob->writer_cache, decl, &ref);
gcc_assert (ref != (unsigned)-1);
+ ref = ref * 2 + (state->compressed ? 1 : 0);
lto_write_data (&ref, sizeof (uint32_t));
for (i = 0; i < LTO_N_DECL_STREAMS; i++)
const char *comdat;
unsigned char c;
- /* None of the following kinds of symbols are needed in the
- symbol table. */
- if (!TREE_PUBLIC (t)
- || is_builtin_fn (t)
- || DECL_ABSTRACT_P (t)
- || (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t)))
- return;
- gcc_assert (TREE_CODE (t) != RESULT_DECL);
-
- gcc_assert (TREE_CODE (t) == VAR_DECL
- || TREE_CODE (t) == FUNCTION_DECL);
+ gcc_assert (VAR_OR_FUNCTION_DECL_P (t));
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (t));
kind = GCCPK_DEF;
/* When something is defined, it should have node attached. */
- gcc_assert (alias || TREE_CODE (t) != VAR_DECL
- || varpool_node::get (t)->definition);
+ gcc_assert (alias || !VAR_P (t) || varpool_node::get (t)->definition);
gcc_assert (alias || TREE_CODE (t) != FUNCTION_DECL
|| (cgraph_node::get (t)
&& cgraph_node::get (t)->definition));
lto_write_data (&slot_num, 4);
}
-/* Return true if NODE should appear in the plugin symbol table. */
-
-bool
-output_symbol_p (symtab_node *node)
-{
- struct cgraph_node *cnode;
- if (!node->real_symbol_p ())
- return false;
- /* We keep external functions in symtab for sake of inlining
- and devirtualization. We do not want to see them in symbol table as
- references unless they are really used. */
- cnode = dyn_cast <cgraph_node *> (node);
- if (cnode && (!node->definition || DECL_EXTERNAL (cnode->decl))
- && cnode->callers)
- return true;
-
- /* Ignore all references from external vars initializers - they are not really
- part of the compilation unit until they are used by folding. Some symbols,
- like references to external construction vtables can not be referred to at all.
- We decide this at can_refer_decl_in_current_unit_p. */
- if (!node->definition || DECL_EXTERNAL (node->decl))
- {
- int i;
- struct ipa_ref *ref;
- for (i = 0; node->iterate_referring (i, ref); i++)
- {
- if (ref->use == IPA_REF_ALIAS)
- continue;
- if (is_a <cgraph_node *> (ref->referring))
- return true;
- if (!DECL_EXTERNAL (ref->referring->decl))
- return true;
- }
- return false;
- }
- return true;
-}
-
-
/* Write an IL symbol table to OB.
SET and VSET are cgraph/varpool node sets we are outputting. */
produce_symtab (struct output_block *ob)
{
struct streamer_tree_cache_d *cache = ob->writer_cache;
- char *section_name = lto_get_section_name (LTO_section_symtab, NULL, NULL);
+ char *section_name = lto_get_section_name (LTO_section_symtab, NULL, 0, NULL);
lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder;
lto_symtab_encoder_iterator lsei;
{
symtab_node *node = lsei_node (lsei);
- if (!output_symbol_p (node) || DECL_EXTERNAL (node->decl))
+ if (DECL_EXTERNAL (node->decl) || !node->output_to_lto_symbol_table_p ())
continue;
write_symbol (cache, node->decl, &seen, false);
}
{
symtab_node *node = lsei_node (lsei);
- if (!output_symbol_p (node) || !DECL_EXTERNAL (node->decl))
+ if (!DECL_EXTERNAL (node->decl) || !node->output_to_lto_symbol_table_p ())
continue;
write_symbol (cache, node->decl, &seen, false);
}
ob = create_output_block (LTO_section_mode_table);
bitpack_d bp = bitpack_create (ob->main_stream);
- /* Ensure that for GET_MODE_INNER (m) != VOIDmode we have
+ /* Ensure that for GET_MODE_INNER (m) != m we have
also the inner mode marked. */
for (int i = 0; i < (int) MAX_MACHINE_MODE; i++)
if (streamer_mode_table[i])
{
machine_mode m = (machine_mode) i;
- if (GET_MODE_INNER (m) != m)
- streamer_mode_table[(int) GET_MODE_INNER (m)] = 1;
+ machine_mode inner_m = GET_MODE_INNER (m);
+ if (inner_m != m)
+ streamer_mode_table[(int) inner_m] = 1;
}
- /* First stream modes that have GET_MODE_INNER (m) == VOIDmode,
+ /* First stream modes that have GET_MODE_INNER (m) == m,
so that we can refer to them afterwards. */
for (int pass = 0; pass < 2; pass++)
for (int i = 0; i < (int) MAX_MACHINE_MODE; i++)
continue;
bp_pack_value (&bp, m, 8);
bp_pack_enum (&bp, mode_class, MAX_MODE_CLASS, GET_MODE_CLASS (m));
- bp_pack_value (&bp, GET_MODE_SIZE (m), 8);
- bp_pack_value (&bp, GET_MODE_PRECISION (m), 16);
+ bp_pack_poly_value (&bp, GET_MODE_SIZE (m), 16);
+ bp_pack_poly_value (&bp, GET_MODE_PRECISION (m), 16);
bp_pack_value (&bp, GET_MODE_INNER (m), 8);
- bp_pack_value (&bp, GET_MODE_NUNITS (m), 8);
+ bp_pack_poly_value (&bp, GET_MODE_NUNITS (m), 16);
switch (GET_MODE_CLASS (m))
{
case MODE_FRACT:
streamer_write_bitpack (&bp);
char *section_name
- = lto_get_section_name (LTO_section_mode_table, NULL, NULL);
+ = lto_get_section_name (LTO_section_mode_table, NULL, 0, NULL);
lto_begin_section (section_name, !flag_wpa);
free (section_name);
struct lto_simple_header_with_strings header;
memset (&header, 0, sizeof (header));
- /* Write the header. */
- header.major_version = LTO_major_version;
- header.minor_version = LTO_minor_version;
-
header.main_size = ob->main_stream->total_size;
header.string_size = ob->string_stream->total_size;
lto_write_data (&header, sizeof header);
memset (&header, 0, sizeof (struct lto_decl_header));
- section_name = lto_get_section_name (LTO_section_decls, NULL, NULL);
+ section_name = lto_get_section_name (LTO_section_decls, NULL, 0, NULL);
lto_begin_section (section_name, !flag_wpa);
free (section_name);
}
/* Write the global symbols. */
+ if (streamer_dump_file)
+ fprintf (streamer_dump_file, "Outputting global stream\n");
lto_output_decl_state_streams (ob, out_state);
num_fns = lto_function_decl_states.length ();
for (idx = 0; idx < num_fns; idx++)
{
fn_out_state =
lto_function_decl_states[idx];
+ if (streamer_dump_file)
+ fprintf (streamer_dump_file, "Outputting stream for %s\n",
+ IDENTIFIER_POINTER
+ (DECL_ASSEMBLER_NAME (fn_out_state->fn_decl)));
lto_output_decl_state_streams (ob, fn_out_state);
}
- header.major_version = LTO_major_version;
- header.minor_version = LTO_minor_version;
-
/* Currently not used. This field would allow us to preallocate
the globals vector, so that it need not be resized as it is extended. */
header.num_nodes = -1;