/* Read the GIMPLE representation from a file stream.
- Copyright (C) 2009-2017 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 "cgraph.h"
#include "cfgloop.h"
#include "debug.h"
+#include "alloc-pool.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);
-}
+/* Allocator used to hold string slot entries for line map streaming. */
+static struct object_allocator<struct string_slot> *string_slot_allocator;
/* The table to hold the file names. */
-static hash_table<freeing_string_slot_hasher> *file_name_hash_table;
+static hash_table<string_slot_hasher> *file_name_hash_table;
+
+/* This obstack holds file names used in locators. Line map datastructures
+ points here and thus it needs to be kept allocated as long as linemaps
+ exists. */
+static struct obstack file_name_obstack;
/* Check that tag ACTUAL has one of the given values. NUM_TAGS is the
/* Read LENGTH bytes from STREAM to ADDR. */
void
-lto_input_data_block (struct lto_input_block *ib, void *addr, size_t length)
+lto_input_data_block (class lto_input_block *ib, void *addr, size_t length)
{
size_t i;
unsigned char *const buffer = (unsigned char *) addr;
char *saved_string;
struct string_slot *new_slot;
- saved_string = (char *) xmalloc (len + 1);
- new_slot = XCNEW (struct string_slot);
+ saved_string = XOBNEWVEC (&file_name_obstack, char, len + 1);
+ new_slot = string_slot_allocator->allocate ();
memcpy (saved_string, string, len + 1);
new_slot->s = saved_string;
new_slot->len = len;
void
lto_location_cache::input_location (location_t *loc, struct bitpack_d *bp,
- struct data_in *data_in)
+ class data_in *data_in)
{
static const char *stream_file;
static int stream_line;
void
lto_input_location (location_t *loc, struct bitpack_d *bp,
- struct data_in *data_in)
+ class data_in *data_in)
{
data_in->location_cache.input_location (loc, bp, data_in);
}
discarded. */
location_t
-stream_input_location_now (struct bitpack_d *bp, struct data_in *data_in)
+stream_input_location_now (struct bitpack_d *bp, class data_in *data_in)
{
location_t loc;
stream_input_location (&loc, bp, data_in);
function scope for the read tree. */
tree
-lto_input_tree_ref (struct lto_input_block *ib, struct data_in *data_in,
+lto_input_tree_ref (class lto_input_block *ib, class data_in *data_in,
struct function *fn, enum LTO_tags tag)
{
unsigned HOST_WIDE_INT ix_u;
block IB, using descriptors in DATA_IN. */
static struct eh_catch_d *
-lto_input_eh_catch_list (struct lto_input_block *ib, struct data_in *data_in,
+lto_input_eh_catch_list (class lto_input_block *ib, class data_in *data_in,
eh_catch *last_p)
{
eh_catch first;
in DATA_IN. */
static eh_region
-input_eh_region (struct lto_input_block *ib, struct data_in *data_in, int ix)
+input_eh_region (class lto_input_block *ib, class data_in *data_in, int ix)
{
enum LTO_tags tag;
eh_region r;
in DATA_IN. */
static eh_landing_pad
-input_eh_lp (struct lto_input_block *ib, struct data_in *data_in, int ix)
+input_eh_lp (class lto_input_block *ib, class data_in *data_in, int ix)
{
enum LTO_tags tag;
eh_landing_pad lp;
in DATA_IN. */
static void
-input_eh_regions (struct lto_input_block *ib, struct data_in *data_in,
+input_eh_regions (class lto_input_block *ib, class data_in *data_in,
struct function *fn)
{
HOST_WIDE_INT i, root_region, len;
lto_tag_check_range (tag, LTO_eh_table, LTO_eh_table);
- /* If the file contains EH regions, then it was compiled with
- -fexceptions. In that case, initialize the backend EH
- machinery. */
- lto_init_eh ();
-
gcc_assert (fn->eh);
root_region = streamer_read_hwi (ib);
/* Read the CFG for function FN from input block IB. */
static void
-input_cfg (struct lto_input_block *ib, struct data_in *data_in,
- struct function *fn,
- int count_materialization_scale)
+input_cfg (class lto_input_block *ib, class data_in *data_in,
+ struct function *fn)
{
unsigned int bb_count;
basic_block p_bb;
unsigned int edge_flags;
basic_block dest;
profile_probability probability;
- profile_count count;
edge e;
dest_index = streamer_read_uhwi (ib);
probability = profile_probability::stream_in (ib);
- count = profile_count::stream_in (ib).apply_scale
- (count_materialization_scale, REG_BR_PROB_BASE);
edge_flags = streamer_read_uhwi (ib);
dest = BASIC_BLOCK_FOR_FN (fn, dest_index);
e = make_edge (bb, dest, edge_flags);
e->probability = probability;
- e->count = count;
}
index = streamer_read_hwi (ib);
continue;
}
- struct loop *loop = alloc_loop ();
+ class loop *loop = alloc_loop ();
loop->header = BASIC_BLOCK_FOR_FN (fn, header_index);
loop->header->loop_father = loop;
/* Read OMP SIMD related info. */
loop->safelen = streamer_read_hwi (ib);
+ loop->unroll = streamer_read_hwi (ib);
+ loop->owned_clique = streamer_read_hwi (ib);
loop->dont_vectorize = streamer_read_hwi (ib);
loop->force_vectorize = streamer_read_hwi (ib);
+ loop->finite_p = streamer_read_hwi (ib);
loop->simduid = stream_read_tree (ib, data_in);
place_new_loop (fn, loop);
block IB. */
static void
-input_ssa_names (struct lto_input_block *ib, struct data_in *data_in,
+input_ssa_names (class lto_input_block *ib, class data_in *data_in,
struct function *fn)
{
unsigned int i, size;
fatal_error (input_location,
"Cgraph edge statement index out of range");
cedge->call_stmt = as_a <gcall *> (stmts[cedge->lto_stmt_uid - 1]);
+ cedge->lto_stmt_uid = 0;
if (!cedge->call_stmt)
fatal_error (input_location,
"Cgraph edge statement index not found");
fatal_error (input_location,
"Cgraph edge statement index out of range");
cedge->call_stmt = as_a <gcall *> (stmts[cedge->lto_stmt_uid - 1]);
+ cedge->lto_stmt_uid = 0;
if (!cedge->call_stmt)
fatal_error (input_location, "Cgraph edge statement index not found");
}
fatal_error (input_location,
"Reference statement index out of range");
ref->stmt = stmts[ref->lto_stmt_uid - 1];
+ ref->lto_stmt_uid = 0;
if (!ref->stmt)
fatal_error (input_location, "Reference statement index not found");
}
using input block IB. */
static void
-input_struct_function_base (struct function *fn, struct data_in *data_in,
- struct lto_input_block *ib)
+input_struct_function_base (struct function *fn, class data_in *data_in,
+ class lto_input_block *ib)
{
struct bitpack_d bp;
int len;
fn->has_forced_label_in_static = bp_unpack_value (&bp, 1);
fn->calls_alloca = bp_unpack_value (&bp, 1);
fn->calls_setjmp = bp_unpack_value (&bp, 1);
+ fn->calls_eh_return = bp_unpack_value (&bp, 1);
fn->has_force_vectorize_loops = bp_unpack_value (&bp, 1);
fn->has_simduid_loops = bp_unpack_value (&bp, 1);
fn->va_list_fpr_size = bp_unpack_value (&bp, 8);
/* Input the function start and end loci. */
fn->function_start_locus = stream_input_location_now (&bp, data_in);
fn->function_end_locus = stream_input_location_now (&bp, data_in);
+
+ /* Restore the instance discriminators if present. */
+ int instance_number = bp_unpack_value (&bp, 1);
+ if (instance_number)
+ {
+ instance_number = bp_unpack_value (&bp, sizeof (int) * CHAR_BIT);
+ maybe_create_decl_to_instance_map ()->put (fn->decl, instance_number);
+ }
}
/* 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,
- struct lto_input_block *ib, struct lto_input_block *ib_cfg)
+input_function (tree fn_decl, class data_in *data_in,
+ class lto_input_block *ib, class lto_input_block *ib_cfg,
+ cgraph_node *node)
{
struct function *fn;
enum LTO_tags tag;
gimple **stmts;
basic_block bb;
- struct cgraph_node *node;
tag = streamer_read_record_start (ib);
lto_tag_check (tag, LTO_function);
gimple_register_cfg_hooks ();
- node = cgraph_node::get (fn_decl);
- if (!node)
- node = cgraph_node::create (fn_decl);
input_struct_function_base (fn, data_in, ib);
- input_cfg (ib_cfg, data_in, fn, node->count_materialization_scale);
+ input_cfg (ib_cfg, data_in, fn);
/* Read all the SSA names. */
input_ssa_names (ib, data_in, fn);
Similarly remove all IFN_*SAN_* internal calls */
if (!flag_wpa)
{
- if (!MAY_HAVE_DEBUG_STMTS && is_gimple_debug (stmt))
+ if (is_gimple_debug (stmt)
+ && (gimple_debug_nonbind_marker_p (stmt)
+ ? !MAY_HAVE_DEBUG_MARKER_STMTS
+ : !MAY_HAVE_DEBUG_BIND_STMTS))
+ remove = true;
+ /* In case the linemap overflows locations can be dropped
+ to zero. Thus do not keep nonsensical inline entry markers
+ we'd later ICE on. */
+ tree block;
+ if (gimple_debug_inline_entry_p (stmt)
+ && (((block = gimple_block (stmt))
+ && !inlined_function_outer_scope_p (block))
+ || !debug_inline_points))
remove = true;
if (is_gimple_call (stmt)
&& gimple_call_internal_p (stmt))
{
+ bool replace = false;
switch (gimple_call_internal_fn (stmt))
{
case IFN_UBSAN_NULL:
if ((flag_sanitize
& (SANITIZE_NULL | SANITIZE_ALIGNMENT)) == 0)
- remove = true;
+ replace = true;
break;
case IFN_UBSAN_BOUNDS:
if ((flag_sanitize & SANITIZE_BOUNDS) == 0)
- remove = true;
+ replace = true;
break;
case IFN_UBSAN_VPTR:
if ((flag_sanitize & SANITIZE_VPTR) == 0)
- remove = true;
+ replace = true;
break;
case IFN_UBSAN_OBJECT_SIZE:
if ((flag_sanitize & SANITIZE_OBJECT_SIZE) == 0)
- remove = true;
+ replace = true;
break;
case IFN_UBSAN_PTR:
if ((flag_sanitize & SANITIZE_POINTER_OVERFLOW) == 0)
- remove = true;
+ replace = true;
break;
case IFN_ASAN_MARK:
if ((flag_sanitize & SANITIZE_ADDRESS) == 0)
- remove = true;
+ replace = true;
break;
case IFN_TSAN_FUNC_EXIT:
if ((flag_sanitize & SANITIZE_THREAD) == 0)
- remove = true;
+ replace = true;
break;
default:
break;
}
- gcc_assert (!remove || gimple_call_lhs (stmt) == NULL_TREE);
+ if (replace)
+ {
+ gimple_call_set_internal_fn (as_a <gcall *> (stmt),
+ IFN_NOP);
+ update_stmt (stmt);
+ }
}
}
if (remove)
{
gsi_next (&bsi);
stmts[gimple_uid (stmt)] = stmt;
+
+ /* Remember that the input function has begin stmt
+ markers, so that we know to expect them when emitting
+ debug info. */
+ if (!cfun->debug_nonbind_markers
+ && gimple_debug_nonbind_marker_p (stmt))
+ cfun->debug_nonbind_markers = true;
}
}
}
gimple_set_body (fn_decl, bb_seq (ei_edge (ei)->dest));
}
+ update_max_bb_count ();
fixup_call_stmt_edges (node, stmts);
execute_all_ipa_stmt_fixups (node, stmts);
- update_ssa (TODO_update_ssa_only_virtuals);
free_dominance_info (CDI_DOMINATORS);
free_dominance_info (CDI_POST_DOMINATORS);
free (stmts);
/* Read the body of function FN_DECL from DATA_IN using input block IB. */
static void
-input_constructor (tree var, struct data_in *data_in,
- struct lto_input_block *ib)
+input_constructor (tree var, class data_in *data_in,
+ class lto_input_block *ib)
{
DECL_INITIAL (var) = stream_read_tree (ib, data_in);
}
const char *data, enum lto_section_type section_type)
{
const struct lto_function_header *header;
- struct data_in *data_in;
+ class data_in *data_in;
int cfg_offset;
int main_offset;
int string_offset;
{
lto_input_block ib_cfg (data + cfg_offset, header->cfg_size,
file_data->mode_table);
- input_function (fn_decl, data_in, &ib_main, &ib_cfg);
+ input_function (fn_decl, data_in, &ib_main, &ib_cfg,
+ dyn_cast <cgraph_node *>(node));
}
else
input_constructor (fn_decl, data_in, &ib_main);
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)
+lto_read_tree_1 (class lto_input_block *ib, class 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
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,
+lto_read_tree (class lto_input_block *ib, class data_in *data_in,
enum LTO_tags tag, hashval_t hash)
{
/* Instantiate a new tree node. */
lto_read_tree_1 (ib, data_in, result);
- /* end_marker = */ streamer_read_uchar (ib);
-
return result;
}
/* Populate the reader cache with trees materialized from the SCC
- following in the IB, DATA_IN stream. */
+ following in the IB, DATA_IN stream.
+ If SHARED_SCC is true we input LTO_tree_scc. */
hashval_t
-lto_input_scc (struct lto_input_block *ib, struct data_in *data_in,
- unsigned *len, unsigned *entry_len)
+lto_input_scc (class lto_input_block *ib, class data_in *data_in,
+ unsigned *len, unsigned *entry_len, bool shared_scc)
{
- /* 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);
+ hashval_t scc_hash = 0;
unsigned scc_entry_len = 1;
+ if (shared_scc)
+ {
+ if (size & 1)
+ scc_entry_len = streamer_read_uhwi (ib);
+ size /= 2;
+ scc_hash = streamer_read_uhwi (ib);
+ }
+
if (size == 1)
{
enum LTO_tags tag = streamer_read_record_start (ib);
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)
{
|| (tag >= LTO_field_decl_ref && tag <= LTO_global_decl_ref)
|| tag == LTO_tree_pickle_reference
|| tag == LTO_integer_cst
- || tag == LTO_tree_scc)
+ || tag == LTO_tree_scc
+ || tag == LTO_trees)
gcc_unreachable ();
result = streamer_alloc_tree (ib, data_in, tag);
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);
}
}
to previously read nodes. */
tree
-lto_input_tree_1 (struct lto_input_block *ib, struct data_in *data_in,
+lto_input_tree_1 (class lto_input_block *ib, class data_in *data_in,
enum LTO_tags tag, hashval_t hash)
{
tree result;
(a, len, TYPE_PRECISION (type)));
streamer_tree_cache_append (data_in->reader_cache, result, hash);
}
- else if (tag == LTO_tree_scc)
+ else if (tag == LTO_tree_scc || tag == LTO_trees)
gcc_unreachable ();
else
{
}
tree
-lto_input_tree (struct lto_input_block *ib, struct data_in *data_in)
+lto_input_tree (class lto_input_block *ib, class data_in *data_in)
{
enum LTO_tags tag;
- /* Input and skip SCCs. */
- while ((tag = streamer_read_record_start (ib)) == LTO_tree_scc)
+ /* Input pickled trees needed to stream in the reference. */
+ while ((tag = streamer_read_record_start (ib)) == LTO_trees)
{
unsigned len, entry_len;
- lto_input_scc (ib, data_in, &len, &entry_len);
+ lto_input_scc (ib, data_in, &len, &entry_len, false);
/* Register DECLs with the debuginfo machinery. */
while (!dref_queue.is_empty ())
debug_hooks->register_external_die (e.decl, e.sym, e.off);
}
}
- return lto_input_tree_1 (ib, data_in, tag, 0);
+ tree t = lto_input_tree_1 (ib, data_in, tag, 0);
+
+ if (!dref_queue.is_empty ())
+ {
+ dref_entry e = dref_queue.pop ();
+ debug_hooks->register_external_die (e.decl, e.sym, e.off);
+ gcc_checking_assert (dref_queue.is_empty ());
+ }
+ return t;
}
lto_input_toplevel_asms (struct lto_file_decl_data *file_data, int order_base)
{
size_t len;
- const char *data = lto_get_section_data (file_data, LTO_section_asm,
- NULL, &len);
+ const char *data
+ = lto_get_summary_section_data (file_data, LTO_section_asm, &len);
const struct lto_simple_header_with_strings *header
= (const struct lto_simple_header_with_strings *) data;
int string_offset;
- struct data_in *data_in;
+ class data_in *data_in;
tree str;
if (! data)
lto_input_mode_table (struct lto_file_decl_data *file_data)
{
size_t len;
- const char *data = lto_get_section_data (file_data, LTO_section_mode_table,
- NULL, &len);
+ const char *data
+ = lto_get_summary_section_data (file_data, LTO_section_mode_table, &len);
if (! data)
{
internal_error ("cannot read LTO mode table from %s",
const struct lto_simple_header_with_strings *header
= (const struct lto_simple_header_with_strings *) data;
int string_offset;
- struct data_in *data_in;
+ class data_in *data_in;
string_offset = sizeof (*header) + header->main_size;
lto_input_block ib (data + sizeof (*header), header->main_size, NULL);
{
enum mode_class mclass
= bp_unpack_enum (&bp, mode_class, MAX_MODE_CLASS);
- unsigned int size = bp_unpack_value (&bp, 8);
- unsigned int prec = bp_unpack_value (&bp, 16);
+ poly_uint16 size = bp_unpack_poly_value (&bp, 16);
+ poly_uint16 prec = bp_unpack_poly_value (&bp, 16);
machine_mode inner = (machine_mode) bp_unpack_value (&bp, 8);
- unsigned int nunits = bp_unpack_value (&bp, 8);
+ poly_uint16 nunits = bp_unpack_poly_value (&bp, 16);
unsigned int ibit = 0, fbit = 0;
unsigned int real_fmt_len = 0;
const char *real_fmt_name = NULL;
: GET_CLASS_NARROWEST_MODE (mclass);
pass ? mr < MAX_MACHINE_MODE : mr != VOIDmode;
pass ? mr = (machine_mode) (mr + 1)
- : mr = GET_MODE_WIDER_MODE (mr))
+ : mr = GET_MODE_WIDER_MODE (mr).else_void ())
if (GET_MODE_CLASS (mr) != mclass
- || GET_MODE_SIZE (mr) != size
- || GET_MODE_PRECISION (mr) != prec
+ || maybe_ne (GET_MODE_SIZE (mr), size)
+ || maybe_ne (GET_MODE_PRECISION (mr), prec)
|| (inner == m
? GET_MODE_INNER (mr) != mr
: GET_MODE_INNER (mr) != table[(int) inner])
|| GET_MODE_IBIT (mr) != ibit
|| GET_MODE_FBIT (mr) != fbit
- || GET_MODE_NUNITS (mr) != nunits)
+ || maybe_ne (GET_MODE_NUNITS (mr), nunits))
continue;
else if ((mclass == MODE_FLOAT || mclass == MODE_DECIMAL_FLOAT)
&& strcmp (REAL_MODE_FORMAT (mr)->name, real_fmt_name) != 0)
{
switch (mclass)
{
+ case MODE_VECTOR_BOOL:
case MODE_VECTOR_INT:
case MODE_VECTOR_FLOAT:
case MODE_VECTOR_FRACT:
}
/* FALLTHRU */
default:
- fatal_error (UNKNOWN_LOCATION, "unsupported mode %s\n", mname);
+ /* This is only used for offloading-target compilations and
+ is a user-facing error. Give a better error message for
+ the common modes; see also mode-classes.def. */
+ if (mclass == MODE_FLOAT)
+ fatal_error (UNKNOWN_LOCATION,
+ "%s - %u-bit-precision floating-point numbers "
+ "unsupported (mode %qs)", TARGET_MACHINE,
+ prec.to_constant (), mname);
+ else if (mclass == MODE_DECIMAL_FLOAT)
+ fatal_error (UNKNOWN_LOCATION,
+ "%s - %u-bit-precision decimal floating-point "
+ "numbers unsupported (mode %qs)", TARGET_MACHINE,
+ prec.to_constant (), mname);
+ else if (mclass == MODE_COMPLEX_FLOAT)
+ fatal_error (UNKNOWN_LOCATION,
+ "%s - %u-bit-precision complex floating-point "
+ "numbers unsupported (mode %qs)", TARGET_MACHINE,
+ prec.to_constant (), mname);
+ else if (mclass == MODE_INT)
+ fatal_error (UNKNOWN_LOCATION,
+ "%s - %u-bit integer numbers unsupported (mode "
+ "%qs)", TARGET_MACHINE, prec.to_constant (), mname);
+ else
+ fatal_error (UNKNOWN_LOCATION, "%s - unsupported mode %qs",
+ TARGET_MACHINE, mname);
break;
}
}
{
lto_streamer_init ();
file_name_hash_table
- = new hash_table<freeing_string_slot_hasher> (37);
+ = new hash_table<string_slot_hasher> (37);
+ string_slot_allocator = new object_allocator <struct string_slot>
+ ("line map file name hash");
+ gcc_obstack_init (&file_name_obstack);
+}
+
+/* Free hash table used to stream in location file names. */
+
+void
+lto_free_file_name_hash (void)
+{
+ delete file_name_hash_table;
+ file_name_hash_table = NULL;
+ delete string_slot_allocator;
+ string_slot_allocator = NULL;
+ /* file_name_obstack must stay allocated since it is referred to by
+ line map table. */
}
table to use with LEN strings. RESOLUTIONS is the vector of linker
resolutions (NULL if not using a linker plugin). */
-struct data_in *
+class data_in *
lto_data_in_create (struct lto_file_decl_data *file_data, const char *strings,
unsigned len,
vec<ld_plugin_symbol_resolution_t> resolutions)
{
- struct data_in *data_in = new (struct data_in);
+ class data_in *data_in = new (class data_in);
data_in->file_data = file_data;
data_in->strings = strings;
data_in->strings_len = len;
/* Remove DATA_IN. */
void
-lto_data_in_delete (struct data_in *data_in)
+lto_data_in_delete (class data_in *data_in)
{
data_in->globals_resolution.release ();
streamer_tree_cache_delete (data_in->reader_cache);