c++: Prune ordinary locations

Like macro locations, we only need to emit ordinary location
information for locations emitted into the CMI. This adds a hash table
noting which ordinary lines are needed.  These are then sorted and
(sufficiently) adjacent lines are coalesced to a single map.  There is
a tradeoff here, allowing greater separation reduces the number of
line maps, but increases the number of locations.  It appears allowing
2 or 3 intervening lines is the sweet spot, and this patch chooses 2.

Compiling a hello-world #includeing <iostream> in it's GMF gives a
reduction in number of locations of 5 fold, but an increase in number
of maps about 4 fold.  Examining one of the xtreme-header tests we
halve the number of locations and increase the number of maps by 9
fold.

Module interfaces that emit no entities (or macros, if a header-unit),
will now have no location tables.

	gcc/cp/
	* module.cc
	(struct ord_loc_info, ord_loc_traits): New.
	(ord_loc_tabke, ord_loc_remap): New globals.
	(struct location_map_info): Delete.
	(struct module_state_config): Rename ordinary_loc_align to
	loc_range_bits.
	(module_for_ordinary_loc): Adjust.
	(module_state::note_location): Note ordinary locations,
	return bool.
	(module_state::write_location): Adjust ordinary location
	streaming.
	(module_state::read_location): Likewise.
	(module_state::write_init_maps): Allocate ord_loc_table.
	(module_state::write_prepare_maps): Reimplement ordinary
	map preparation.
	(module_state::read_prepare_maps): Adjust.
	(module_state::write_ordinary_maps): Reimplement.
	(module_state::write_macro_maps): Adjust.
	(module_state::read_ordinary_maps): Reimplement.
	(module_state::write_macros): Adjust.
	(module_state::write_config): Adjust.
	(module_state::read_config): Adjust.
	(module_state::write_begin): Adjust.
	(module_state::read_initial): Adjust.
	gcc/testsuite/
	* g++.dg/modules/loc-prune-1.C: Adjust.
	* g++.dg/modules/loc-prune-4.C: New.
	* g++.dg/modules/pr98718_a.C: Adjust.
	* g++.dg/modules/pr98718_b.C: Adjust.
	* g++.dg/modules/pr99072.H: Adjust.
This commit is contained in:
Nathan Sidwell 2022-06-24 05:57:42 -07:00
parent 07dd0f7ba2
commit 069f46c71e
6 changed files with 373 additions and 284 deletions

View File

@ -3240,6 +3240,66 @@ public:
static loc_spans spans; static loc_spans spans;
/* Information about ordinary locations we stream out. */
struct ord_loc_info
{
const line_map_ordinary *src; // line map we're based on
unsigned offset; // offset to this line
unsigned span; // number of locs we span
unsigned remap; // serialization
static int compare (const void *a_, const void *b_)
{
auto *a = static_cast<const ord_loc_info *> (a_);
auto *b = static_cast<const ord_loc_info *> (b_);
if (a->src != b->src)
return a->src < b->src ? -1 : +1;
// Ensure no overlap
gcc_checking_assert (a->offset + a->span <= b->offset
|| b->offset + b->span <= a->offset);
gcc_checking_assert (a->offset != b->offset);
return a->offset < b->offset ? -1 : +1;
}
};
struct ord_loc_traits
{
typedef ord_loc_info value_type;
typedef value_type compare_type;
static const bool empty_zero_p = false;
static hashval_t hash (const value_type &v)
{
auto h = pointer_hash<const line_map_ordinary>::hash (v.src);
return iterative_hash_hashval_t (v.offset, h);
}
static bool equal (const value_type &v, const compare_type p)
{
return v.src == p.src && v.offset == p.offset;
}
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 ord_loc_info, used for noting. */
static hash_table<ord_loc_traits> *ord_loc_table;
/* Sorted vector, used for writing. */
static vec<ord_loc_info> *ord_loc_remap;
/* Information about macro locations we stream out. */ /* Information about macro locations we stream out. */
struct macro_loc_info struct macro_loc_info
{ {
@ -3401,15 +3461,7 @@ void slurping::release_macros ()
elf_in::release (from, macro_tbl); elf_in::release (from, macro_tbl);
} }
/* Information about location maps used during writing. */ /* Flags for extensions that end up being streamed. */
struct location_map_info {
range_t num_maps;
unsigned max_range;
};
/* Flage for extensions that end up being streamed. */
enum streamed_extensions { enum streamed_extensions {
SE_OPENMP = 1 << 0, SE_OPENMP = 1 << 0,
@ -3652,14 +3704,13 @@ class GTY((chain_next ("%h.parent"), for_user)) module_state {
private: private:
void write_init_maps (); void write_init_maps ();
location_map_info write_prepare_maps (module_state_config *); range_t write_prepare_maps (module_state_config *, bool);
bool read_prepare_maps (const module_state_config *); bool read_prepare_maps (const module_state_config *);
void write_ordinary_maps (elf_out *to, location_map_info &, void write_ordinary_maps (elf_out *to, range_t &,
module_state_config *, bool, unsigned *crc_ptr); bool, unsigned *crc_ptr);
bool read_ordinary_maps (); bool read_ordinary_maps (unsigned, unsigned);
void write_macro_maps (elf_out *to, location_map_info &, void write_macro_maps (elf_out *to, range_t &, unsigned *crc_ptr);
module_state_config *, unsigned *crc_ptr);
bool read_macro_maps (unsigned); bool read_macro_maps (unsigned);
private: private:
@ -3678,7 +3729,7 @@ class GTY((chain_next ("%h.parent"), for_user)) module_state {
static cpp_macro *deferred_macro (cpp_reader *, location_t, cpp_hashnode *); static cpp_macro *deferred_macro (cpp_reader *, location_t, cpp_hashnode *);
public: public:
static void note_location (location_t); static bool note_location (location_t);
static void write_location (bytes_out &, location_t); static void write_location (bytes_out &, location_t);
location_t read_location (bytes_in &) const; location_t read_location (bytes_in &) const;
@ -14444,14 +14495,14 @@ struct module_state_config {
unsigned num_entities; unsigned num_entities;
unsigned ordinary_locs; unsigned ordinary_locs;
unsigned macro_locs; unsigned macro_locs;
unsigned ordinary_loc_align; unsigned loc_range_bits;
unsigned active_init; unsigned active_init;
public: public:
module_state_config () module_state_config ()
:dialect_str (get_dialect ()), :dialect_str (get_dialect ()),
num_imports (0), num_partitions (0), num_entities (0), num_imports (0), num_partitions (0), num_entities (0),
ordinary_locs (0), macro_locs (0), ordinary_loc_align (0), ordinary_locs (0), macro_locs (0), loc_range_bits (0),
active_init (0) active_init (0)
{ {
} }
@ -15562,7 +15613,7 @@ module_for_ordinary_loc (location_t loc)
module_state *probe = (*ool)[pos + half]; module_state *probe = (*ool)[pos + half];
if (loc < probe->ordinary_locs.first) if (loc < probe->ordinary_locs.first)
len = half; len = half;
else if (loc < probe->ordinary_locs.second) else if (loc < probe->ordinary_locs.first + probe->ordinary_locs.second)
return probe; return probe;
else else
{ {
@ -15589,7 +15640,7 @@ module_for_macro_loc (location_t loc)
pos += half + 1; pos += half + 1;
len = len - (half + 1); len = len - (half + 1);
} }
else if (loc >= (probe->macro_locs.first + probe->macro_locs.second)) else if (loc >= probe->macro_locs.first + probe->macro_locs.second)
len = half; len = half;
else else
return probe; return probe;
@ -15614,10 +15665,11 @@ module_state::imported_from () const
/* Note that LOC will need writing. This allows us to prune locations /* Note that LOC will need writing. This allows us to prune locations
that are not needed. */ that are not needed. */
void bool
module_state::note_location (location_t loc) module_state::note_location (location_t loc)
{ {
if (!macro_loc_table) bool added = false;
if (!macro_loc_table && !ord_loc_table)
; ;
else if (loc < RESERVED_LOCATION_COUNT) else if (loc < RESERVED_LOCATION_COUNT)
; ;
@ -15654,17 +15706,33 @@ module_state::note_location (location_t loc)
tloc = mac_map->macro_locations[ix]; tloc = mac_map->macro_locations[ix];
note_location (tloc); note_location (tloc);
} }
added = true;
} }
} }
} }
else if (IS_ORDINARY_LOC (loc)) else if (IS_ORDINARY_LOC (loc))
{ {
/* This is where we should note we use this location. See comment if (spans.ordinary (loc))
about write_ordinary_maps. */ {
const line_map *map = linemap_lookup (line_table, loc);
const line_map_ordinary *ord_map = linemap_check_ordinary (map);
ord_loc_info lkup;
lkup.src = ord_map;
lkup.span = 1 << ord_map->m_column_and_range_bits;
lkup.offset = (loc - MAP_START_LOCATION (ord_map)) & ~(lkup.span - 1);
lkup.remap = 0;
ord_loc_info *slot = (ord_loc_table->find_slot_with_hash
(lkup, ord_loc_traits::hash (lkup), INSERT));
if (!slot->src)
{
*slot = lkup;
added = true;
}
}
} }
else else
gcc_unreachable (); gcc_unreachable ();
return; return added;
} }
/* If we're not streaming, record that we need location LOC. /* If we're not streaming, record that we need location LOC.
@ -15745,16 +15813,37 @@ module_state::write_location (bytes_out &sec, location_t loc)
} }
else if (IS_ORDINARY_LOC (loc)) else if (IS_ORDINARY_LOC (loc))
{ {
if (const loc_spans::span *span = spans.ordinary (loc)) const ord_loc_info *info = nullptr;
unsigned offset = 0;
if (unsigned hwm = ord_loc_remap->length ())
{ {
unsigned off = loc; info = ord_loc_remap->begin ();
while (hwm != 1)
{
unsigned mid = hwm / 2;
if (MAP_START_LOCATION (info[mid].src) + info[mid].offset <= loc)
{
info += mid;
hwm -= mid;
}
else
hwm = mid;
}
offset = loc - MAP_START_LOCATION (info->src) - info->offset;
if (offset > info->span)
info = nullptr;
}
off += span->ordinary_delta; gcc_checking_assert (bool (info) == bool (spans.ordinary (loc)));
if (info)
{
offset += info->remap;
sec.u (LK_ORDINARY); sec.u (LK_ORDINARY);
sec.u (off); sec.u (offset);
dump (dumper::LOCATION) dump (dumper::LOCATION)
&& dump ("Ordinary location %u output %u", loc, off); && dump ("Ordinary location %u output %u", loc, offset);
} }
else if (const module_state *import = module_for_ordinary_loc (loc)) else if (const module_state *import = module_for_ordinary_loc (loc))
{ {
@ -15809,7 +15898,7 @@ module_state::read_location (bytes_in &sec) const
{ {
unsigned off = sec.u (); unsigned off = sec.u ();
if (macro_locs.first) if (macro_locs.second)
{ {
if (off < macro_locs.second) if (off < macro_locs.second)
locus = off + macro_locs.first; locus = off + macro_locs.first;
@ -15828,15 +15917,10 @@ module_state::read_location (bytes_in &sec) const
unsigned off = sec.u (); unsigned off = sec.u ();
if (ordinary_locs.second) if (ordinary_locs.second)
{ {
location_t adjusted = off; if (off < ordinary_locs.second)
locus = off + ordinary_locs.first;
adjusted += slurp->loc_deltas.first; else
if (adjusted >= ordinary_locs.second)
sec.set_overrun (); sec.set_overrun ();
else if (adjusted >= ordinary_locs.first)
locus = adjusted;
else if (adjusted < spans.main_start ())
locus = off;
} }
else else
locus = loc; locus = loc;
@ -15870,7 +15954,7 @@ module_state::read_location (bytes_in &sec) const
{ {
if (kind == LK_IMPORT_MACRO) if (kind == LK_IMPORT_MACRO)
{ {
if (!import->macro_locs.first) if (!import->macro_locs.second)
locus = import->loc; locus = import->loc;
else if (off < import->macro_locs.second) else if (off < import->macro_locs.second)
locus = off + import->macro_locs.first; locus = off + import->macro_locs.first;
@ -15881,8 +15965,7 @@ module_state::read_location (bytes_in &sec) const
{ {
if (!import->ordinary_locs.second) if (!import->ordinary_locs.second)
locus = import->loc; locus = import->loc;
else if (off < (import->ordinary_locs.second else if (off < import->ordinary_locs.second)
- import->ordinary_locs.first))
locus = import->ordinary_locs.first + off; locus = import->ordinary_locs.first + off;
else else
sec.set_overrun (); sec.set_overrun ();
@ -15895,26 +15978,21 @@ module_state::read_location (bytes_in &sec) const
return locus; return locus;
} }
/* Prepare the span adjustments. */ /* Allocate hash tables to record needed locations. */
// FIXME:QOI I do not prune the unreachable locations. Modules with
// textually-large GMFs could well cause us to run out of locations.
// Regular single-file modules could also be affected. We should
// determine which locations we need to represent, so that we do not
// grab more locations than necessary. An example is in
// write_macro_maps where we work around macro expansions that are not
// covering any locations -- the macro expands to nothing. Perhaps we
// should decompose locations so that we can have a more graceful
// degradation upon running out?
void void
module_state::write_init_maps () module_state::write_init_maps ()
{ {
macro_loc_table = new hash_table<macro_loc_traits> (EXPERIMENT (1, 400)); macro_loc_table = new hash_table<macro_loc_traits> (EXPERIMENT (1, 400));
ord_loc_table = new hash_table<ord_loc_traits> (EXPERIMENT (1, 400));
} }
location_map_info /* Prepare the span adjustments. We prune unneeded locations -- at
module_state::write_prepare_maps (module_state_config *cfg) this point every needed location must have been seen by
note_location. */
range_t
module_state::write_prepare_maps (module_state_config *cfg, bool has_partitions)
{ {
dump () && dump ("Preparing locations"); dump () && dump ("Preparing locations");
dump.indent (); dump.indent ();
@ -15925,82 +16003,98 @@ module_state::write_prepare_maps (module_state_config *cfg)
spans[loc_spans::SPAN_RESERVED].macro.first, spans[loc_spans::SPAN_RESERVED].macro.first,
spans[loc_spans::SPAN_RESERVED].macro.second); spans[loc_spans::SPAN_RESERVED].macro.second);
location_map_info info; range_t info {0, 0};
info.num_maps.first = info.num_maps.second = 0; // Sort the noted lines.
vec_alloc (ord_loc_remap, ord_loc_table->size ());
for (auto iter = ord_loc_table->begin (), end = ord_loc_table->end ();
iter != end; ++iter)
ord_loc_remap->quick_push (*iter);
ord_loc_remap->qsort (&ord_loc_info::compare);
/* Figure the alignment of ordinary location spans. */ // Note included-from maps.
unsigned max_range = 0; bool added = false;
for (unsigned ix = loc_spans::SPAN_FIRST; ix != spans.length (); ix++) const line_map_ordinary *current = nullptr;
for (auto iter = ord_loc_remap->begin (), end = ord_loc_remap->end ();
iter != end; ++iter)
if (iter->src != current)
{
current = iter->src;
for (auto probe = current;
auto from = linemap_included_from (probe);
probe = linemap_check_ordinary (linemap_lookup (line_table, from)))
{
if (has_partitions)
{
// Partition locations need to elide their module map
// entry.
probe
= linemap_check_ordinary (linemap_lookup (line_table, from));
if (MAP_MODULE_P (probe))
from = linemap_included_from (probe);
}
if (!note_location (from))
break;
added = true;
}
}
if (added)
{ {
loc_spans::span &span = spans[ix]; // Reconstruct the line array as we added items to the hash table.
vec_free (ord_loc_remap);
vec_alloc (ord_loc_remap, ord_loc_table->size ());
for (auto iter = ord_loc_table->begin (), end = ord_loc_table->end ();
iter != end; ++iter)
ord_loc_remap->quick_push (*iter);
ord_loc_remap->qsort (&ord_loc_info::compare);
}
delete ord_loc_table;
ord_loc_table = nullptr;
if (span.ordinary.first != span.ordinary.second) // Merge (sufficiently) adjacent spans, and calculate remapping.
constexpr unsigned adjacency = 2; // Allow 2 missing lines.
auto begin = ord_loc_remap->begin (), end = ord_loc_remap->end ();
auto dst = begin;
unsigned offset = 0, range_bits = 0;
ord_loc_info *base = nullptr;
for (auto iter = begin; iter != end; ++iter)
{
if (base && iter->src == base->src)
{ {
line_map_ordinary const *omap if (base->offset + base->span +
= linemap_check_ordinary (linemap_lookup (line_table, ((adjacency << base->src->m_column_and_range_bits)
span.ordinary.first)); // If there are few c&r bits, allow further separation.
| (adjacency << 4))
/* We should exactly match up. */ >= iter->offset)
gcc_checking_assert (MAP_START_LOCATION (omap) == span.ordinary.first);
line_map_ordinary const *fmap = omap;
for (; MAP_START_LOCATION (omap) < span.ordinary.second; omap++)
{ {
/* We should never find a module linemap in an interval. */ // Merge.
gcc_checking_assert (!MAP_MODULE_P (omap)); offset -= base->span;
base->span = iter->offset + iter->span - base->offset;
if (max_range < omap->m_range_bits) offset += base->span;
max_range = omap->m_range_bits; continue;
} }
info.num_maps.first += omap - fmap;
} }
else if (range_bits < iter->src->m_range_bits)
range_bits = iter->src->m_range_bits;
offset += ((1u << iter->src->m_range_bits) - 1);
offset &= ~((1u << iter->src->m_range_bits) - 1);
iter->remap = offset;
offset += iter->span;
base = dst;
*dst++ = *iter;
} }
ord_loc_remap->truncate (dst - begin);
/* Adjust the maps. Ordinary ones ascend, and we must maintain info.first = ord_loc_remap->length ();
alignment. Macro ones descend, but are unaligned. */ cfg->ordinary_locs = offset;
location_t ord_off = spans[loc_spans::SPAN_FIRST].ordinary.first; cfg->loc_range_bits = range_bits;
location_t range_mask = (1u << max_range) - 1; dump () && dump ("Ordinary maps:%u locs:%u range_bits:%u",
info.first, cfg->ordinary_locs,
dump () && dump ("Ordinary maps range bits:%u, preserve:%x, zero:%u", cfg->loc_range_bits);
max_range, ord_off & range_mask, ord_off & ~range_mask);
for (unsigned ix = loc_spans::SPAN_FIRST; ix != spans.length (); ix++)
{
loc_spans::span &span = spans[ix];
line_map_ordinary const *omap
= linemap_check_ordinary (linemap_lookup (line_table,
span.ordinary.first));
location_t base = MAP_START_LOCATION (omap);
/* Preserve the low MAX_RANGE bits of base by incrementing ORD_OFF. */
unsigned low_bits = base & range_mask;
if ((ord_off & range_mask) > low_bits)
low_bits += range_mask + 1;
ord_off = (ord_off & ~range_mask) + low_bits;
span.ordinary_delta = ord_off - base;
for (; MAP_START_LOCATION (omap) < span.ordinary.second; omap++)
{
location_t start_loc = MAP_START_LOCATION (omap);
unsigned to = start_loc + span.ordinary_delta;
location_t end_loc = MAP_START_LOCATION (omap + 1);
dump () && dump ("Ordinary span:%u [%u,%u):%u->%d(%u)",
ix, start_loc,
end_loc, end_loc - start_loc,
span.ordinary_delta, to);
/* There should be no change in the low order bits. */
gcc_checking_assert (((start_loc ^ to) & range_mask) == 0);
}
/* The ending serialized value. */
ord_off = span.ordinary.second + span.ordinary_delta;
}
// Remap the macro locations.
vec_alloc (macro_loc_remap, macro_loc_table->size ()); vec_alloc (macro_loc_remap, macro_loc_table->size ());
for (auto iter = macro_loc_table->begin (), end = macro_loc_table->end (); for (auto iter = macro_loc_table->begin (), end = macro_loc_table->end ();
iter != end; ++iter) iter != end; ++iter)
@ -16009,7 +16103,7 @@ module_state::write_prepare_maps (module_state_config *cfg)
macro_loc_table = nullptr; macro_loc_table = nullptr;
macro_loc_remap->qsort (&macro_loc_info::compare); macro_loc_remap->qsort (&macro_loc_info::compare);
unsigned offset = 0; offset = 0;
for (auto iter = macro_loc_remap->begin (), end = macro_loc_remap->end (); for (auto iter = macro_loc_remap->begin (), end = macro_loc_remap->end ();
iter != end; ++iter) iter != end; ++iter)
{ {
@ -16017,16 +16111,15 @@ module_state::write_prepare_maps (module_state_config *cfg)
iter->remap = offset; iter->remap = offset;
offset += mac->n_tokens; offset += mac->n_tokens;
} }
info.num_maps.second = macro_loc_remap->length (); info.second = macro_loc_remap->length ();
cfg->macro_locs = offset; cfg->macro_locs = offset;
dump () && dump ("Ordinary:%u maps hwm:%u macro:%u maps %u locs", dump () && dump ("Macro maps:%u locs:%u", info.second, cfg->macro_locs);
info.num_maps.first, ord_off,
info.num_maps.second, cfg->macro_locs);
dump.outdent (); dump.outdent ();
info.max_range = max_range; // If we have no ordinary locs, we must also have no macro locs.
gcc_checking_assert (cfg->ordinary_locs || !cfg->macro_locs);
return info; return info;
} }
@ -16035,8 +16128,6 @@ bool
module_state::read_prepare_maps (const module_state_config *cfg) module_state::read_prepare_maps (const module_state_config *cfg)
{ {
location_t ordinary = line_table->highest_location + 1; location_t ordinary = line_table->highest_location + 1;
ordinary = ((ordinary + (1u << cfg->ordinary_loc_align))
& ~((1u << cfg->ordinary_loc_align) - 1));
ordinary += cfg->ordinary_locs; ordinary += cfg->ordinary_locs;
location_t macro = LINEMAPS_MACRO_LOWEST_LOCATION (line_table); location_t macro = LINEMAPS_MACRO_LOWEST_LOCATION (line_table);
@ -16061,13 +16152,12 @@ module_state::read_prepare_maps (const module_state_config *cfg)
return false; return false;
} }
/* Write the location maps. This also determines the shifts for the /* Write & read the location maps. Not called if there are no
location spans. */ locations. */
void void
module_state::write_ordinary_maps (elf_out *to, location_map_info &info, module_state::write_ordinary_maps (elf_out *to, range_t &info,
module_state_config *cfg, bool has_partitions, bool has_partitions, unsigned *crc_p)
unsigned *crc_p)
{ {
dump () && dump ("Writing ordinary location maps"); dump () && dump ("Writing ordinary location maps");
dump.indent (); dump.indent ();
@ -16076,45 +16166,36 @@ module_state::write_ordinary_maps (elf_out *to, location_map_info &info,
filenames.create (20); filenames.create (20);
/* Determine the unique filenames. */ /* Determine the unique filenames. */
// FIXME:QOI We should find the set of filenames when working out const line_map_ordinary *current = nullptr;
// which locations we actually need. See write_prepare_maps. for (auto iter = ord_loc_remap->begin (), end = ord_loc_remap->end ();
for (unsigned ix = loc_spans::SPAN_FIRST; ix != spans.length (); ix++) iter != end; ++iter)
{ if (iter->src != current)
loc_spans::span &span = spans[ix]; {
line_map_ordinary const *omap current = iter->src;
= linemap_check_ordinary (linemap_lookup (line_table, const char *fname = ORDINARY_MAP_FILE_NAME (iter->src);
span.ordinary.first));
/* We should exactly match up. */ /* We should never find a module linemap in an interval. */
gcc_checking_assert (MAP_START_LOCATION (omap) == span.ordinary.first); gcc_checking_assert (!MAP_MODULE_P (iter->src));
for (; MAP_START_LOCATION (omap) < span.ordinary.second; omap++) /* We expect very few filenames, so just an array.
{ (Not true when headers are still in play :() */
const char *fname = ORDINARY_MAP_FILE_NAME (omap); for (unsigned jx = filenames.length (); jx--;)
{
/* We should never find a module linemap in an interval. */ const char *name = filenames[jx];
gcc_checking_assert (!MAP_MODULE_P (omap)); if (0 == strcmp (name, fname))
{
/* We expect very few filenames, so just an array. /* Reset the linemap's name, because for things like
(Not true when headers are still in play :() */ preprocessed input we could have multiple instances
for (unsigned jx = filenames.length (); jx--;) of the same name, and we'd rather not percolate
{ that. */
const char *name = filenames[jx]; const_cast<line_map_ordinary *> (iter->src)->to_file = name;
if (0 == strcmp (name, fname)) fname = NULL;
{ break;
/* Reset the linemap's name, because for things like }
preprocessed input we could have multiple }
instances of the same name, and we'd rather not if (fname)
percolate that. */ filenames.safe_push (fname);
const_cast<line_map_ordinary *> (omap)->to_file = name; }
fname = NULL;
break;
}
}
if (fname)
filenames.safe_push (fname);
}
}
bytes_out sec (to); bytes_out sec (to);
sec.begin (); sec.begin ();
@ -16130,56 +16211,45 @@ module_state::write_ordinary_maps (elf_out *to, location_map_info &info,
sec.str (fname); sec.str (fname);
} }
location_t offset = spans[loc_spans::SPAN_FIRST].ordinary.first; sec.u (info.first); /* Num maps. */
location_t range_mask = (1u << info.max_range) - 1; const ord_loc_info *base = nullptr;
for (auto iter = ord_loc_remap->begin (), end = ord_loc_remap->end ();
dump () && dump ("Ordinary maps:%u, range bits:%u, preserve:%x, zero:%u", iter != end; ++iter)
info.num_maps.first, info.max_range, offset & range_mask,
offset & ~range_mask);
sec.u (info.num_maps.first); /* Num maps. */
sec.u (info.max_range); /* Maximum range bits */
sec.u (offset & range_mask); /* Bits to preserve. */
sec.u (offset & ~range_mask);
for (unsigned ix = loc_spans::SPAN_FIRST; ix != spans.length (); ix++)
{ {
loc_spans::span &span = spans[ix]; dump (dumper::LOCATION)
line_map_ordinary const *omap && dump ("Span:%u ordinary [%u+%u,+%u)->[%u,+%u)",
= linemap_check_ordinary (linemap_lookup (line_table, iter - ord_loc_remap->begin (),
span.ordinary.first)); MAP_START_LOCATION (iter->src), iter->offset, iter->span,
for (; MAP_START_LOCATION (omap) < span.ordinary.second; omap++) iter->remap, iter->span);
if (!base || iter->src != base->src)
base = iter;
sec.u (iter->offset - base->offset);
if (base == iter)
{ {
location_t start_loc = MAP_START_LOCATION (omap); sec.u (iter->src->sysp);
unsigned to = start_loc + span.ordinary_delta; sec.u (iter->src->m_range_bits);
sec.u (iter->src->m_column_and_range_bits - iter->src->m_range_bits);
dump (dumper::LOCATION) const char *fname = ORDINARY_MAP_FILE_NAME (iter->src);
&& dump ("Span:%u ordinary [%u,%u)->%u", ix, start_loc,
MAP_START_LOCATION (omap + 1), to);
/* There should be no change in the low order bits. */
gcc_checking_assert (((start_loc ^ to) & range_mask) == 0);
sec.u (to);
/* Making accessors just for here, seems excessive. */
sec.u (omap->reason);
sec.u (omap->sysp);
sec.u (omap->m_range_bits);
sec.u (omap->m_column_and_range_bits - omap->m_range_bits);
const char *fname = ORDINARY_MAP_FILE_NAME (omap);
for (unsigned ix = 0; ix != filenames.length (); ix++) for (unsigned ix = 0; ix != filenames.length (); ix++)
if (filenames[ix] == fname) if (filenames[ix] == fname)
{ {
sec.u (ix); sec.u (ix);
break; break;
} }
sec.u (ORDINARY_MAP_STARTING_LINE_NUMBER (omap)); unsigned line = ORDINARY_MAP_STARTING_LINE_NUMBER (iter->src);
line += iter->offset >> iter->src->m_column_and_range_bits;
sec.u (line);
}
sec.u (iter->remap);
if (base == iter)
{
/* Write the included from location, which means reading it /* Write the included from location, which means reading it
while reading in the ordinary maps. So we'd better not while reading in the ordinary maps. So we'd better not
be getting ahead of ourselves. */ be getting ahead of ourselves. */
location_t from = linemap_included_from (omap); location_t from = linemap_included_from (iter->src);
gcc_checking_assert (from < MAP_START_LOCATION (omap)); gcc_checking_assert (from < MAP_START_LOCATION (iter->src));
if (from != UNKNOWN_LOCATION && has_partitions) if (from != UNKNOWN_LOCATION && has_partitions)
{ {
/* A partition's span will have a from pointing at a /* A partition's span will have a from pointing at a
@ -16191,15 +16261,7 @@ module_state::write_ordinary_maps (elf_out *to, location_map_info &info,
} }
write_location (sec, from); write_location (sec, from);
} }
/* The ending serialized value. */
offset = MAP_START_LOCATION (omap) + span.ordinary_delta;
} }
dump () && dump ("Ordinary location hwm:%u", offset);
sec.u (offset);
// Record number of locations and alignment.
cfg->ordinary_loc_align = info.max_range;
cfg->ordinary_locs = offset;
filenames.release (); filenames.release ();
@ -16208,8 +16270,7 @@ module_state::write_ordinary_maps (elf_out *to, location_map_info &info,
} }
void void
module_state::write_macro_maps (elf_out *to, location_map_info &info, module_state::write_macro_maps (elf_out *to, range_t &info, unsigned *crc_p)
module_state_config *, unsigned *crc_p)
{ {
dump () && dump ("Writing macro location maps"); dump () && dump ("Writing macro location maps");
dump.indent (); dump.indent ();
@ -16217,8 +16278,8 @@ module_state::write_macro_maps (elf_out *to, location_map_info &info,
bytes_out sec (to); bytes_out sec (to);
sec.begin (); sec.begin ();
dump () && dump ("Macro maps:%u", info.num_maps.second); dump () && dump ("Macro maps:%u", info.second);
sec.u (info.num_maps.second); sec.u (info.second);
unsigned macro_num = 0; unsigned macro_num = 0;
for (auto iter = macro_loc_remap->end (), begin = macro_loc_remap->begin (); for (auto iter = macro_loc_remap->end (), begin = macro_loc_remap->begin ();
@ -16258,14 +16319,14 @@ module_state::write_macro_maps (elf_out *to, location_map_info &info,
iter->remap); iter->remap);
macro_num++; macro_num++;
} }
gcc_assert (macro_num == info.num_maps.second); gcc_assert (macro_num == info.second);
sec.end (to, to->name (MOD_SNAME_PFX ".mlm"), crc_p); sec.end (to, to->name (MOD_SNAME_PFX ".mlm"), crc_p);
dump.outdent (); dump.outdent ();
} }
bool bool
module_state::read_ordinary_maps () module_state::read_ordinary_maps (unsigned num_ord_locs, unsigned range_bits)
{ {
bytes_in sec; bytes_in sec;
@ -16291,70 +16352,62 @@ module_state::read_ordinary_maps ()
filenames.quick_push (fname); filenames.quick_push (fname);
} }
unsigned num_ordinary = sec.u (); unsigned num_ordinary = sec.u ();
unsigned max_range = sec.u (); dump () && dump ("Ordinary maps:%u, range_bits:%u", num_ordinary, range_bits);
unsigned low_bits = sec.u ();
location_t zero = sec.u ();
location_t range_mask = (1u << max_range) - 1;
dump () && dump ("Ordinary maps:%u, range bits:%u, preserve:%x, zero:%u",
num_ordinary, max_range, low_bits, zero);
location_t offset = line_table->highest_location + 1; location_t offset = line_table->highest_location + 1;
/* Ensure offset doesn't go backwards at the start. */ offset += ((1u << range_bits) - 1);
if ((offset & range_mask) > low_bits) offset &= ~((1u << range_bits) - 1);
offset += range_mask + 1; ordinary_locs.first = offset;
offset = (offset & ~range_mask);
bool propagated = spans.maybe_propagate (this, offset + low_bits);
bool propagated = spans.maybe_propagate (this, offset);
line_map_ordinary *maps = static_cast<line_map_ordinary *> line_map_ordinary *maps = static_cast<line_map_ordinary *>
(line_map_new_raw (line_table, false, num_ordinary)); (line_map_new_raw (line_table, false, num_ordinary));
location_t lwm = offset; const line_map_ordinary *base = nullptr;
slurp->loc_deltas.first = offset - zero;
ordinary_locs.first = zero + low_bits + slurp->loc_deltas.first;
dump () && dump ("Ordinary loc delta %d", slurp->loc_deltas.first);
for (unsigned ix = 0; ix != num_ordinary && !sec.get_overrun (); ix++) for (unsigned ix = 0; ix != num_ordinary && !sec.get_overrun (); ix++)
{ {
line_map_ordinary *map = &maps[ix]; line_map_ordinary *map = &maps[ix];
unsigned hwm = sec.u ();
/* Record the current HWM so that the below read_location is unsigned offset = sec.u ();
ok. */ if (!offset)
ordinary_locs.second = hwm + slurp->loc_deltas.first; {
map->start_location = hwm + (offset - zero); map->reason = LC_RENAME;
if (map->start_location < lwm) map->sysp = sec.u ();
sec.set_overrun (); map->m_range_bits = sec.u ();
lwm = map->start_location; map->m_column_and_range_bits = sec.u () + map->m_range_bits;
dump (dumper::LOCATION) && dump ("Map:%u %u->%u", ix, hwm, lwm); unsigned fnum = sec.u ();
map->reason = lc_reason (sec.u ()); map->to_file = (fnum < filenames.length () ? filenames[fnum] : "");
map->sysp = sec.u (); map->to_line = sec.u ();
map->m_range_bits = sec.u (); base = map;
map->m_column_and_range_bits = map->m_range_bits + sec.u (); }
else
unsigned fnum = sec.u (); {
map->to_file = (fnum < filenames.length () ? filenames[fnum] : ""); *map = *base;
map->to_line = sec.u (); map->to_line += offset >> map->m_column_and_range_bits;
}
/* Root the outermost map at our location. */ unsigned remap = sec.u ();
location_t from = read_location (sec); map->start_location = remap + ordinary_locs.first;
map->included_from = from != UNKNOWN_LOCATION ? from : loc; if (base == map)
{
/* Root the outermost map at our location. */
ordinary_locs.second = remap;
location_t from = read_location (sec);
map->included_from = from != UNKNOWN_LOCATION ? from : loc;
}
} }
location_t hwm = sec.u (); ordinary_locs.second = num_ord_locs;
ordinary_locs.second = hwm + slurp->loc_deltas.first;
/* highest_location is the one handed out, not the next one to /* highest_location is the one handed out, not the next one to
hand out. */ hand out. */
line_table->highest_location = ordinary_locs.second - 1; line_table->highest_location = ordinary_locs.first + ordinary_locs.second - 1;
if (line_table->highest_location >= LINE_MAP_MAX_LOCATION_WITH_COLS) if (line_table->highest_location >= LINE_MAP_MAX_LOCATION_WITH_COLS)
/* We shouldn't run out of locations, as we checked before /* We shouldn't run out of locations, as we checked before
starting. */ starting. */
sec.set_overrun (); sec.set_overrun ();
dump () && dump ("Ordinary location hwm:%u", ordinary_locs.second); dump () && dump ("Ordinary location [%u,+%u)",
ordinary_locs.first, ordinary_locs.second);
if (propagated) if (propagated)
spans.close (); spans.close ();
@ -16988,6 +17041,10 @@ module_state::write_macros (elf_out *to, vec<cpp_hashnode *> *macros,
if (mac.def) if (mac.def)
write_define (sec, mac.def); write_define (sec, mac.def);
} }
if (count)
// We may have ended on a tokenless macro with a very short
// location, that will cause problems reading its bit flags.
sec.u (0);
sec.end (to, to->name (MOD_SNAME_PFX ".def"), crc_p); sec.end (to, to->name (MOD_SNAME_PFX ".def"), crc_p);
if (count) if (count)
@ -17453,7 +17510,7 @@ module_state::write_config (elf_out *to, module_state_config &config,
cfg.u (config.ordinary_locs); cfg.u (config.ordinary_locs);
cfg.u (config.macro_locs); cfg.u (config.macro_locs);
cfg.u (config.ordinary_loc_align); cfg.u (config.loc_range_bits);
cfg.u (config.active_init); cfg.u (config.active_init);
@ -17639,7 +17696,7 @@ module_state::read_config (module_state_config &config)
config.ordinary_locs = cfg.u (); config.ordinary_locs = cfg.u ();
config.macro_locs = cfg.u (); config.macro_locs = cfg.u ();
config.ordinary_loc_align = cfg.u (); config.loc_range_bits = cfg.u ();
config.active_init = cfg.u (); config.active_init = cfg.u ();
@ -17656,7 +17713,7 @@ ool_cmp (const void *a_, const void *b_)
auto *b = *static_cast<const module_state *const *> (b_); auto *b = *static_cast<const module_state *const *> (b_);
if (a == b) if (a == b)
return 0; return 0;
else if (a->ordinary_locs.first < b->ordinary_locs.second) else if (a->ordinary_locs.first < b->ordinary_locs.first)
return -1; return -1;
else else
return +1; return +1;
@ -17690,6 +17747,7 @@ module_state::write_begin (elf_out *to, cpp_reader *reader,
bitmap partitions = NULL; bitmap partitions = NULL;
if (!is_header () && !is_partition ()) if (!is_header () && !is_partition ())
partitions = BITMAP_GGC_ALLOC (); partitions = BITMAP_GGC_ALLOC ();
write_init_maps ();
unsigned mod_hwm = 1; unsigned mod_hwm = 1;
for (unsigned ix = 1; ix != modules->length (); ix++) for (unsigned ix = 1; ix != modules->length (); ix++)
@ -17727,14 +17785,15 @@ module_state::write_begin (elf_out *to, cpp_reader *reader,
gcc_checking_assert (!slot->is_lazy ()); gcc_checking_assert (!slot->is_lazy ());
} }
} }
if (imp->is_direct () && (imp->remap || imp->is_partition ()))
note_location (imp->imported_from ());
} }
if (partitions && bitmap_empty_p (partitions)) if (partitions && bitmap_empty_p (partitions))
/* No partitions present. */ /* No partitions present. */
partitions = nullptr; partitions = nullptr;
write_init_maps ();
/* Find the set of decls we must write out. */ /* Find the set of decls we must write out. */
depset::hash table (DECL_NAMESPACE_BINDINGS (global_namespace)->size () * 8); depset::hash table (DECL_NAMESPACE_BINDINGS (global_namespace)->size () * 8);
/* Add the specializations before the writables, so that we can /* Add the specializations before the writables, so that we can
@ -17785,11 +17844,10 @@ module_state::write_begin (elf_out *to, cpp_reader *reader,
if (is_header ()) if (is_header ())
macros = prepare_macros (reader); macros = prepare_macros (reader);
location_map_info map_info = write_prepare_maps (&config);
unsigned counts[MSC_HWM];
config.num_imports = mod_hwm; config.num_imports = mod_hwm;
config.num_partitions = modules->length () - mod_hwm; config.num_partitions = modules->length () - mod_hwm;
auto map_info = write_prepare_maps (&config, bool (config.num_partitions));
unsigned counts[MSC_HWM];
memset (counts, 0, sizeof (counts)); memset (counts, 0, sizeof (counts));
/* depset::cluster is the cluster number, /* depset::cluster is the cluster number,
@ -17926,8 +17984,10 @@ module_state::write_begin (elf_out *to, cpp_reader *reader,
write_partitions (to, config.num_partitions, &crc); write_partitions (to, config.num_partitions, &crc);
/* Write the line maps. */ /* Write the line maps. */
write_ordinary_maps (to, map_info, &config, config.num_partitions, &crc); if (config.ordinary_locs)
write_macro_maps (to, map_info, &config, &crc); write_ordinary_maps (to, map_info, bool (config.num_partitions), &crc);
if (config.macro_locs)
write_macro_maps (to, map_info, &crc);
if (is_header ()) if (is_header ())
{ {
@ -17947,6 +18007,7 @@ module_state::write_begin (elf_out *to, cpp_reader *reader,
sccs.release (); sccs.release ();
vec_free (macro_loc_remap); vec_free (macro_loc_remap);
vec_free (ord_loc_remap);
vec_free (ool); vec_free (ool);
// FIXME:QOI: Have a command line switch to control more detailed // FIXME:QOI: Have a command line switch to control more detailed
@ -17990,7 +18051,9 @@ module_state::read_initial (cpp_reader *reader)
bool have_locs = ok && read_prepare_maps (&config); bool have_locs = ok && read_prepare_maps (&config);
/* Ordinary maps before the imports. */ /* Ordinary maps before the imports. */
if (have_locs && !read_ordinary_maps ()) if (!(have_locs && config.ordinary_locs))
ordinary_locs.first = line_table->highest_location + 1;
else if (!read_ordinary_maps (config.ordinary_locs, config.loc_range_bits))
ok = false; ok = false;
/* Allocate the REMAP vector. */ /* Allocate the REMAP vector. */
@ -18017,7 +18080,7 @@ module_state::read_initial (cpp_reader *reader)
{ {
/* Allocate space in the entities array now -- that array must be /* Allocate space in the entities array now -- that array must be
monotionically in step with the modules array. */ monotonically in step with the modules array. */
entity_lwm = vec_safe_length (entity_ary); entity_lwm = vec_safe_length (entity_ary);
entity_num = config.num_entities; entity_num = config.num_entities;
gcc_checking_assert (modules->length () == 1 gcc_checking_assert (modules->length () == 1
@ -18048,7 +18111,9 @@ module_state::read_initial (cpp_reader *reader)
gcc_assert (!from ()->is_frozen ()); gcc_assert (!from ()->is_frozen ());
/* Macro maps after the imports. */ /* Macro maps after the imports. */
if (ok && have_locs && !read_macro_maps (config.macro_locs)) if (!(ok && have_locs && config.macro_locs))
macro_locs.first = LINEMAPS_MACRO_LOWEST_LOCATION (line_table);
else if (!read_macro_maps (config.macro_locs))
ok = false; ok = false;
/* Note whether there's an active initializer. */ /* Note whether there's an active initializer. */

View File

@ -14,6 +14,6 @@ int foo (int = YES)
// { dg-final { scan-lang-dump { Macro maps:1} module } } // { dg-final { scan-lang-dump { Macro maps:1} module } }
// { dg-final { scan-lang-dump { Macro:0 YES 1/1.2 locations } module } } // { dg-final { scan-lang-dump { Macro:0 YES 1/1.2 locations } module } }
// { dg-final { scan-lang-dump { Ordinary:[0-9]* maps hwm:[0-9]* macro:1 maps 1 locs} module } } // { dg-final { scan-lang-dump { Macro maps:1 locs:1} module } }
// { dg-final { scan-lang-dump-not {Macro:. NOT } module } } // { dg-final { scan-lang-dump-not {Macro:. NOT } module } }
// { dg-final { scan-lang-dump-not {Macro:. AGAIN_NO } module } } // { dg-final { scan-lang-dump-not {Macro:. AGAIN_NO } module } }

View File

@ -0,0 +1,22 @@
// { dg-additional-options {-Wno-pedantic -fmodules-ts -fdump-lang-module-lineno} }
# 4 "unused" 1
# 5 "" 2
export module foo;
int foo (int) // separate
{
return 0;
}
int bar (int); // merge lines
int baz (int);
// { dg-final { scan-lang-dump {Ordinary maps:2 locs:12288 range_bits:5} module } }
// { dg-final { scan-lang-dump { 1 source file names\n Source file...=[^\n]*loc-prune-4.C\n} module } }
// { dg-final { scan-lang-dump { Span:0 ordinary \[2.....\+12288,\+4096\)->\[0,\+4096\)} module } }
// { dg-final { scan-lang-dump { Span:1 ordinary \[2.....\+40960,\+8192\)->\[4096,\+8192\)} module } }

View File

@ -14,5 +14,5 @@ namespace std _GLIBCXX_VISIBILITY(default)
export module hello:format; export module hello:format;
// { dg-module-cmi hello:format } // { dg-module-cmi hello:format }
// { dg-final { scan-lang-dump { Ordinary:4 maps hwm:[0-9]* macro:0 maps 0 locs} module } } // { dg-final { scan-lang-dump { Macro maps:0 locs:0} module } }
// { dg-final { scan-lang-dump-not { Macro:. _GLIBCXX_VISIBILITY} module } } // { dg-final { scan-lang-dump-not { Macro:. _GLIBCXX_VISIBILITY} module } }

View File

@ -14,5 +14,5 @@ export module hello;
export import :format; export import :format;
// { dg-module-cmi hello } // { dg-module-cmi hello }
// { dg-final { scan-lang-dump { Ordinary:8 maps hwm:[0-9]* macro:0 maps 0 locs} module } } // { dg-final { scan-lang-dump { Macro maps:0 locs:0} module } }
// { dg-final { scan-lang-dump-not { Macro:. _GLIBCXX_VISIBILITY} module } } // { dg-final { scan-lang-dump-not { Macro:. _GLIBCXX_VISIBILITY} module } }

View File

@ -7,4 +7,6 @@
# 1 "REALNAME" # 1 "REALNAME"
// { dg-additional-options {-fmodule-header -fpreprocessed -fdump-lang-module-lineno} } // { dg-additional-options {-fmodule-header -fpreprocessed -fdump-lang-module-lineno} }
// { dg-final { scan-lang-dump { 4 source file names\n Source file\[0\]=REALNAME\n Source file\[1\]=<built-in>\n Source file\[2\]=<command-line>\n Source file\[3\]=/usr/include/stdc-predef.h\n} module } } // All locations are pruned.
// { dg-final { scan-lang-dump-not {Writing ordinary location maps} module } }
// { dg-final { scan-lang-dump-not { Span:. ordinary } module } }