};
static loc_spans spans;
+
+/* Information about macro locations we stream out. */
+struct macro_info
+{
+ const line_map_macro *src; // original expansion
+ unsigned remap; // serialization
+
+ static int compare (const void *a_, const void *b_)
+ {
+ auto *a = static_cast<const macro_info *> (a_);
+ auto *b = static_cast<const macro_info *> (b_);
+
+ gcc_checking_assert (MAP_START_LOCATION (a->src)
+ != MAP_START_LOCATION (b->src));
+ if (MAP_START_LOCATION (a->src) < MAP_START_LOCATION (b->src))
+ return -1;
+ else
+ return +1;
+ }
+};
+struct macro_traits
+{
+ typedef macro_info value_type;
+ typedef const line_map_macro *compare_type;
+
+ static const bool empty_zero_p = false;
+
+ static hashval_t hash (compare_type p)
+ {
+ return pointer_hash<const line_map_macro>::hash (p);
+ }
+ static hashval_t hash (const value_type &v)
+ {
+ return hash (v.src);
+ }
+ static bool equal (const value_type &v, const compare_type p)
+ {
+ return v.src == p;
+ }
+
+ static void mark_empty (value_type &v)
+ {
+ v.src = nullptr;
+ }
+ static bool is_empty (value_type &v)
+ {
+ return !v.src;
+ }
+
+ static bool is_deleted (value_type &) { return false; }
+ static void mark_deleted (value_type &) { gcc_unreachable (); }
+
+ static void remove (value_type &) {}
+};
+/* Table keyed by line_map_macro, used for noting. */
+static hash_table<macro_traits> *macro_table;
+/* Sorted vector, used for writing. */
+static vec<macro_info> *macro_remap;
+
/* Indirection to allow bsearching imports by ordinary location. */
static vec<module_state *> *ool;
/* Location ranges for this module. adhoc-locs are decomposed, so
don't have a range. */
loc_range_t GTY((skip)) ordinary_locs;
- loc_range_t GTY((skip)) macro_locs;
+ loc_range_t GTY((skip)) macro_locs; // [lwm,num)
/* LOC is first set too the importing location. When initially
loaded it refers to a module loc whose parent is the importing
bool read_entities (unsigned count, unsigned lwm, unsigned hwm);
private:
+ void write_init_maps ();
location_map_info write_prepare_maps (module_state_config *);
bool read_prepare_maps (const module_state_config *);
bool read_ordinary_maps ();
void write_macro_maps (elf_out *to, location_map_info &,
module_state_config *, unsigned *crc_ptr);
- bool read_macro_maps ();
+ bool read_macro_maps (unsigned);
private:
void write_define (bytes_out &, const cpp_macro *, bool located = true);
static cpp_macro *deferred_macro (cpp_reader *, location_t, cpp_hashnode *);
public:
+ static void note_location (location_t);
static void write_location (bytes_out &, location_t);
location_t read_location (bytes_in &) const;
else if (TREE_VISITED (decl))
/* A global tree. */;
else if (item->get_entity_kind () == EK_NAMESPACE)
- add_namespace_context (current, CP_DECL_CONTEXT (decl));
+ {
+ module->note_location (DECL_SOURCE_LOCATION (decl));
+ add_namespace_context (current, CP_DECL_CONTEXT (decl));
+ }
else
{
walker.mark_declaration (decl, current->has_defn ());
{
unsigned half = len / 2;
module_state *probe = (*modules)[pos + half];
- if (loc >= probe->macro_locs.second)
- len = half;
- else if (loc >= probe->macro_locs.first)
- return probe;
- else
+ if (loc < probe->macro_locs.first)
{
pos += half + 1;
len = len - (half + 1);
}
+ else if (loc >= (probe->macro_locs.first + probe->macro_locs.second))
+ len = half;
+ else
+ return probe;
}
return NULL;
return from;
}
+/* Note that LOC will need writing. This allows us to prune locations
+ that are not needed. */
+
+void
+module_state::note_location (location_t loc)
+{
+ if (!macro_table)
+ ;
+ else if (loc < RESERVED_LOCATION_COUNT)
+ ;
+ else if (IS_ADHOC_LOC (loc))
+ {
+ location_t locus = get_location_from_adhoc_loc (line_table, loc);
+ note_location (locus);
+ source_range range = get_range_from_loc (line_table, loc);
+ if (range.m_start != locus)
+ note_location (range.m_start);
+ note_location (range.m_finish);
+ }
+ else if (loc >= LINEMAPS_MACRO_LOWEST_LOCATION (line_table))
+ {
+ if (spans.macro (loc))
+ {
+ const line_map *map = linemap_lookup (line_table, loc);
+ const line_map_macro *mac_map = linemap_check_macro (map);
+ hashval_t hv = macro_traits::hash (mac_map);
+ macro_info *slot
+ = macro_table->find_slot_with_hash (mac_map, hv, INSERT);
+ if (!slot->src)
+ {
+ slot->src = mac_map;
+ slot->remap = 0;
+ // Expansion locations could themselves be from a
+ // macro, we need to note them all.
+ note_location (mac_map->expansion);
+ gcc_checking_assert (mac_map->n_tokens);
+ location_t tloc = UNKNOWN_LOCATION;
+ for (unsigned ix = mac_map->n_tokens * 2; ix--;)
+ if (mac_map->macro_locations[ix] != tloc)
+ {
+ tloc = mac_map->macro_locations[ix];
+ note_location (tloc);
+ }
+ }
+ }
+ }
+ else if (IS_ORDINARY_LOC (loc))
+ {
+ /* This is where we should note we use this location. See comment
+ about write_ordinary_maps. */
+ }
+ else
+ gcc_unreachable ();
+ return;
+}
+
/* If we're not streaming, record that we need location LOC.
Otherwise stream it. */
module_state::write_location (bytes_out &sec, location_t loc)
{
if (!sec.streaming_p ())
- /* This is where we should note we use this location. See comment
- about write_ordinary_maps. */
- return;
+ {
+ note_location (loc);
+ return;
+ }
if (loc < RESERVED_LOCATION_COUNT)
{
}
else if (loc >= LINEMAPS_MACRO_LOWEST_LOCATION (line_table))
{
- if (const loc_spans::span *span = spans.macro (loc))
+ const macro_info *info = nullptr;
+ unsigned offset = 0;
+ if (unsigned hwm = macro_remap->length ())
{
- unsigned off = MAX_LOCATION_T - loc;
+ info = macro_remap->begin ();
+ while (hwm != 1)
+ {
+ unsigned mid = hwm / 2;
+ if (MAP_START_LOCATION (info[mid].src) <= loc)
+ {
+ info += mid;
+ hwm -= mid;
+ }
+ else
+ hwm = mid;
+ }
+ offset = loc - MAP_START_LOCATION (info->src);
+ if (offset > info->src->n_tokens)
+ info = nullptr;
+ }
- off -= span->macro_delta;
+ gcc_checking_assert (bool (info) == bool (spans.macro (loc)));
+ if (info)
+ {
+ offset += info->remap;
sec.u (LK_MACRO);
- sec.u (off);
+ sec.u (offset);
dump (dumper::LOCATION)
- && dump ("Macro location %u output %u", loc, off);
+ && dump ("Macro location %u output %u", loc, offset);
}
else if (const module_state *import = module_for_macro_loc (loc))
{
- unsigned off = import->macro_locs.second - loc - 1;
+ unsigned off = loc - import->macro_locs.first;
sec.u (LK_IMPORT_MACRO);
sec.u (import->remap);
sec.u (off);
if (macro_locs.first)
{
- location_t adjusted = MAX_LOCATION_T - off;
- adjusted -= slurp->loc_deltas.second;
- if (adjusted < macro_locs.first)
- sec.set_overrun ();
- else if (adjusted < macro_locs.second)
- locus = adjusted;
+ if (off < macro_locs.second)
+ locus = off + macro_locs.first;
else
sec.set_overrun ();
}
{
if (!import->macro_locs.first)
locus = import->loc;
- else if (off < import->macro_locs.second - macro_locs.first)
- locus = import->macro_locs.second - off - 1;
+ else if (off < import->macro_locs.second)
+ locus = off + import->macro_locs.first;
else
sec.set_overrun ();
}
// should decompose locations so that we can have a more graceful
// degradation upon running out?
+void
+module_state::write_init_maps ()
+{
+ macro_table = new hash_table<macro_traits> (EXPERIMENT (1, 400));
+}
+
location_map_info
-module_state::write_prepare_maps (module_state_config *)
+module_state::write_prepare_maps (module_state_config *cfg)
{
dump () && dump ("Preparing locations");
dump.indent ();
/* Adjust the maps. Ordinary ones ascend, and we must maintain
alignment. Macro ones descend, but are unaligned. */
location_t ord_off = spans[loc_spans::SPAN_FIRST].ordinary.first;
- location_t mac_off = spans[loc_spans::SPAN_FIRST].macro.second;
location_t range_mask = (1u << max_range) - 1;
dump () && dump ("Ordinary maps range bits:%u, preserve:%x, zero:%u",
{
loc_spans::span &span = spans[ix];
- span.macro_delta = mac_off - span.macro.second;
- mac_off -= span.macro.second - span.macro.first;
- dump () && dump ("Macro span:%u [%u,%u):%u->%d(%u)", ix,
- span.macro.first, span.macro.second,
- span.macro.second - span.macro.first,
- span.macro_delta, span.macro.first + span.macro_delta);
-
line_map_ordinary const *omap
= linemap_check_ordinary (linemap_lookup (line_table,
- span.ordinary.first));
+ span.ordinary.first));
location_t base = MAP_START_LOCATION (omap);
/* Preserve the low MAX_RANGE bits of base by incrementing ORD_OFF. */
ord_off = span.ordinary.second + span.ordinary_delta;
}
- dump () && dump ("Ordinary:%u maps hwm:%u macro:%u maps lwm:%u ",
+ vec_alloc (macro_remap, macro_table->size ());
+ for (auto iter = macro_table->begin (), end = macro_table->end ();
+ iter != end; ++iter)
+ macro_remap->quick_push (*iter);
+ delete macro_table;
+ macro_table = nullptr;
+
+ macro_remap->qsort (¯o_info::compare);
+ unsigned offset = 0;
+ for (auto iter = macro_remap->begin (), end = macro_remap->end ();
+ iter != end; ++iter)
+ {
+ auto mac = iter->src;
+ iter->remap = offset;
+ offset += mac->n_tokens;
+ }
+ info.num_maps.second = macro_remap->length ();
+ cfg->macro_locs = offset;
+
+ dump () && dump ("Ordinary:%u maps hwm:%u macro:%u maps %u locs",
info.num_maps.first, ord_off,
- info.num_maps.second, mac_off);
+ info.num_maps.second, cfg->macro_locs);
dump.outdent ();
info.max_range = max_range;
-
+
return info;
}
void
module_state::write_macro_maps (elf_out *to, location_map_info &info,
- module_state_config *cfg, unsigned *crc_p)
+ module_state_config *, unsigned *crc_p)
{
dump () && dump ("Writing macro location maps");
dump.indent ();
dump () && dump ("Macro maps:%u", info.num_maps.second);
sec.u (info.num_maps.second);
- location_t offset = spans[loc_spans::SPAN_FIRST].macro.second;
- sec.u (offset);
-
unsigned macro_num = 0;
- for (unsigned ix = loc_spans::SPAN_FIRST; ix != spans.length (); ix++)
- {
- loc_spans::span &span = spans[ix];
- if (span.macro.first == span.macro.second)
- /* Empty span. */
- continue;
-
- for (unsigned macro
- = linemap_lookup_macro_index (line_table, span.macro.second - 1);
- macro < LINEMAPS_MACRO_USED (line_table);
- macro++)
+ for (auto iter = macro_remap->end (), begin = macro_remap->begin ();
+ iter-- != begin;)
+ {
+ auto mac = iter->src;
+ sec.u (iter->remap);
+ sec.u (mac->n_tokens);
+ sec.cpp_node (mac->macro);
+ write_location (sec, mac->expansion);
+ const location_t *locs = mac->macro_locations;
+ /* There are lots of identical runs. */
+ location_t prev = UNKNOWN_LOCATION;
+ unsigned count = 0;
+ unsigned runs = 0;
+ for (unsigned jx = mac->n_tokens * 2; jx--;)
{
- line_map_macro const *mmap
- = LINEMAPS_MACRO_MAP_AT (line_table, macro);
- location_t start_loc = MAP_START_LOCATION (mmap);
- if (start_loc < span.macro.first)
- /* Fallen out of the span. */
- break;
-
- if (!mmap->n_tokens)
- /* Empty expansion. */
- continue;
-
- sec.u (offset);
- sec.u (mmap->n_tokens);
- sec.cpp_node (mmap->macro);
- write_location (sec, mmap->expansion);
- const location_t *locs = mmap->macro_locations;
- /* There are lots of identical runs. */
- location_t prev = UNKNOWN_LOCATION;
- unsigned count = 0;
- unsigned runs = 0;
- for (unsigned jx = mmap->n_tokens * 2; jx--;)
+ location_t tok_loc = locs[jx];
+ if (tok_loc == prev)
{
- location_t tok_loc = locs[jx];
- if (tok_loc == prev)
- {
- count++;
- continue;
- }
- runs++;
- sec.u (count);
- count = 1;
- prev = tok_loc;
- write_location (sec, tok_loc);
+ count++;
+ continue;
}
+ runs++;
sec.u (count);
- dump (dumper::LOCATION)
- && dump ("Span:%u macro:%u %I %u/%u*2 locations [%u,%u)->%u",
- ix, macro_num, identifier (mmap->macro),
- runs, mmap->n_tokens,
- start_loc, start_loc + mmap->n_tokens,
- start_loc + span.macro_delta);
- macro_num++;
- offset -= mmap->n_tokens;
- gcc_checking_assert (offset == start_loc + span.macro_delta);
+ count = 1;
+ prev = tok_loc;
+ write_location (sec, tok_loc);
}
+ sec.u (count);
+ dump (dumper::LOCATION)
+ && dump ("Macro:%u %I %u/%u*2 locations [%u,%u)->%u",
+ macro_num, identifier (mac->macro),
+ runs, mac->n_tokens,
+ MAP_START_LOCATION (mac),
+ MAP_START_LOCATION (mac) + mac->n_tokens,
+ iter->remap);
+ macro_num++;
}
- dump () && dump ("Macro location lwm:%u", offset);
- sec.u (offset);
gcc_assert (macro_num == info.num_maps.second);
- cfg->macro_locs = MAX_LOCATION_T + 1 - offset;
-
sec.end (to, to->name (MOD_SNAME_PFX ".mlm"), crc_p);
dump.outdent ();
}
}
bool
-module_state::read_macro_maps ()
+module_state::read_macro_maps (unsigned num_macro_locs)
{
bytes_in sec;
dump.indent ();
unsigned num_macros = sec.u ();
- location_t zero = sec.u ();
- dump () && dump ("Macro maps:%u zero:%u", num_macros, zero);
+ dump () && dump ("Macro maps:%u locs:%u", num_macros, num_macro_locs);
bool propagated = spans.maybe_propagate (this,
line_table->highest_location + 1);
location_t offset = LINEMAPS_MACRO_LOWEST_LOCATION (line_table);
- slurp->loc_deltas.second = zero - offset;
- macro_locs.second = zero - slurp->loc_deltas.second;
- dump () && dump ("Macro loc delta %d", slurp->loc_deltas.second);
+ macro_locs.second = num_macro_locs;
+ macro_locs.first = offset - num_macro_locs;
+
+ dump () && dump ("Macro loc delta %d", offset);
+ dump () && dump ("Macro locations [%u,%u)",
+ macro_locs.first, macro_locs.second);
for (unsigned ix = 0; ix != num_macros && !sec.get_overrun (); ix++)
{
- unsigned lwm = sec.u ();
- /* Record the current LWM so that the below read_location is
- ok. */
- macro_locs.first = lwm - slurp->loc_deltas.second;
-
+ unsigned offset = sec.u ();
unsigned n_tokens = sec.u ();
cpp_hashnode *node = sec.cpp_node ();
location_t exp_loc = read_location (sec);
/* We shouldn't run out of locations, as we checked that we
had enough before starting. */
break;
+ gcc_checking_assert (MAP_START_LOCATION (macro)
+ == offset + macro_locs.first);
location_t *locs = macro->macro_locations;
location_t tok_loc = UNKNOWN_LOCATION;
MAP_START_LOCATION (macro),
MAP_START_LOCATION (macro) + n_tokens);
}
- location_t lwm = sec.u ();
- macro_locs.first = lwm - slurp->loc_deltas.second;
dump () && dump ("Macro location lwm:%u", macro_locs.first);
-
if (propagated)
spans.close ();
/* No partitions present. */
partitions = nullptr;
+ write_init_maps ();
+
/* Find the set of decls we must write out. */
depset::hash table (DECL_NAMESPACE_BINDINGS (global_namespace)->size () * 8);
/* Add the specializations before the writables, so that we can
gcc_assert (!from ()->is_frozen ());
/* Macro maps after the imports. */
- if (ok && have_locs && !read_macro_maps ())
+ if (ok && have_locs && !read_macro_maps (config.macro_locs))
ok = false;
/* Note whether there's an active initializer. */