The expected way to create a new map in a line_map object is to call
linemap_add() and/or linemap_line_start(), which contain the necessary logic
to decide if a location can be encoded in the currently active map or if a
new map is required, and, in the latter case, what properties the new map
requires. This interface works well for the typical use case where a line
map is built up incrementally as source lines are processed, but it does not
provide the user with precise control over the exact properties of the newly
added map (or even whether a map is added at all).
That level of control will be needed for an upcoming change to the approach
to streaming location data for the LTO front end. Enable it by adding a new
function linemap_add_raw_map(), which simply allows the user (i.e., the LTO
front end) to add maps with the desired properties. The user is then
responsible for making sure the resulting state makes sense.
This patch adds self-tests for the new function, but does not otherwise make
any observable changes yet.
gcc/ChangeLog:
* input.cc (test_accessing_ordinary_linemaps): Test new
line_map_add_raw_map() functionality.
libcpp/ChangeLog:
* include/line-map.h (linemap_next_start_location): New function.
(linemap_add_raw_map): Declare new function.
* line-map.cc (linemap_add): Minor refactor to make use of
linemap_next_start_location().
(linemap_add_raw_map): New function.
(linemap_lookup): Update the comment for clarity.
---
libcpp/include/line-map.h | 26 +++++++++++++++++++----
libcpp/line-map.cc | 44 ++++++++++++++++++++++++++++++++-------
gcc/input.cc | 22 ++++++++++++++++++++
3 files changed, 81 insertions(+), 11 deletions(-)
diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h
index 2cd54d0770e..4856e6b4cb8 100644
--- a/libcpp/include/line-map.h
+++ b/libcpp/include/line-map.h
@@ -1071,6 +1071,15 @@ extern location_t linemap_line_start
/* Allocate a raw block of line maps, zero initialized. */
extern line_map *line_map_new_raw (line_maps *, bool, line_map_uint_t);
+/* Return the location_t at which a new line map with RANGE_BITS range bits
+ would begin, if it needs to begin at least at START_LOC. */
+inline location_t
+linemap_next_start_location (location_t start_loc, int range_bits)
+{
+ const auto mask = (location_t (1) << range_bits) - 1;
+ return (start_loc + mask) & ~mask;
+}
+
/* Add a mapping of logical source line to physical source file and
line number. This function creates an "ordinary map", which is a
map that records locations of tokens that are not part of macro
@@ -1088,6 +1097,17 @@ extern const line_map *linemap_add
(class line_maps *, enum lc_reason, unsigned int sysp,
const char *to_file, linenum_type to_line);
+/* Create a map with exactly the requested parameters. Not intended for
general
+ use, but useful for applications that need to work with linemap internals
+ directly. NUM_LINES is the number of lines this map should be able to hold;
+ this just ensures that set->highest_location is set properly so that the
next
+ added map will leave sufficient room for NUM_LINES lines in this map. */
+extern line_map_ordinary *
+linemap_add_raw_map (line_maps *set, lc_reason reason, location_t start_loc,
+ unsigned int sysp, int column_and_range_bits,
+ int range_bits, const char *to_file, linenum_type to_line,
+ line_map_uint_t num_lines);
+
/* Create a macro map. A macro map encodes source locations of tokens
that are part of a macro replacement-list, at a macro expansion
point. See the extensive comments of struct line_map and struct
@@ -1128,10 +1148,8 @@ extern location_t linemap_module_restore
/* Given a logical source location, returns the map which the
corresponding (source file, line, column) triplet can be deduced
- from. Since the set is built chronologically, the logical lines are
- monotonic increasing, and so the list is sorted and we can use a
- binary search. If no line map have been allocated yet, this
- function returns NULL. */
+ from. Since the start_location of each map is monotonic increasing,
+ this can be done with binary search. */
extern const line_map *linemap_lookup
(const line_maps *, location_t);
diff --git a/libcpp/line-map.cc b/libcpp/line-map.cc
index 2875bf2092b..eba6f201485 100644
--- a/libcpp/line-map.cc
+++ b/libcpp/line-map.cc
@@ -576,9 +576,7 @@ linemap_add (line_maps *set, enum lc_reason reason,
unsigned range_bits = 0;
if (start_location < LINE_MAP_MAX_LOCATION_WITH_COLS)
range_bits = set->default_range_bits;
- start_location += (loc_one << range_bits) - 1;
- start_location &= ~((loc_one << range_bits) - 1);
-
+ start_location = linemap_next_start_location (start_location, range_bits);
linemap_assert (!LINEMAPS_ORDINARY_USED (set)
|| (start_location
>= MAP_START_LOCATION (LINEMAPS_LAST_ORDINARY_MAP
(set))));
@@ -712,6 +710,35 @@ linemap_add (line_maps *set, enum lc_reason reason,
return map;
}
+line_map_ordinary *
+linemap_add_raw_map (line_maps *set, lc_reason reason, location_t start_loc,
+ unsigned int sysp, int column_and_range_bits,
+ int range_bits, const char *to_file, linenum_type to_line,
+ line_map_uint_t num_lines)
+{
+ start_loc = linemap_next_start_location (start_loc, range_bits);
+ gcc_assert (start_loc > set->highest_location);
+ location_t last_loc = start_loc + (loc_one << column_and_range_bits) - 1;
+ if (num_lines > 1)
+ last_loc += (num_lines - 1) << column_and_range_bits;
+ if (last_loc >= LINE_MAP_MAX_LOCATION)
+ return nullptr;
+ const auto map = linemap_check_ordinary (new_linemap (set, start_loc));
+ map->reason = reason;
+ map->sysp = sysp;
+ map->m_column_and_range_bits = column_and_range_bits;
+ map->m_range_bits = range_bits;
+ map->to_file = to_file;
+ map->to_line = to_line;
+ set->info_ordinary.m_cache = LINEMAPS_ORDINARY_USED (set) - 1;
+ set->highest_location = last_loc;
+ set->highest_line
+ = start_loc + ((last_loc - start_loc)
+ & (line_map_uint_t (-1) << column_and_range_bits));
+ set->max_column_hint = 1U << (column_and_range_bits - range_bits);
+ return map;
+}
+
/* Create a location for a module NAME imported at FROM. */
location_t
@@ -1151,10 +1178,13 @@ linemap_lookup (const line_maps *set, location_t line)
return linemap_ordinary_map_lookup (set, line);
}
-/* Given a source location yielded by an ordinary map, returns that
- map. Since the set is built chronologically, the logical lines are
- monotonic increasing, and so the list is sorted and we can use a
- binary search. */
+/* Given a source location yielded by an ordinary map, returns that map. Since
+ the start_location of each map is larger than the prior one, this can be
done
+ with binary search. Note that the line maps are not necessarily sorted by
+ file name or by line number, although they often are, at least in a local
+ region, since things like #line directives, multiple includes, or
+ manipulations outside the normal usage during parsing can all affect the
+ sorting. But they are always sorted by start_location. */
static const line_map_ordinary *
linemap_ordinary_map_lookup (const line_maps *set, location_t line)
diff --git a/gcc/input.cc b/gcc/input.cc
index 665dbe3d605..4836b450a13 100644
--- a/gcc/input.cc
+++ b/gcc/input.cc
@@ -1363,6 +1363,28 @@ test_accessing_ordinary_linemaps (const line_table_case
&case_)
source_range src_range = get_range_from_loc (line_table, range_c_b_d);
ASSERT_EQ (loc_b, src_range.m_start);
ASSERT_EQ (loc_d, src_range.m_finish);
+
+ /* Verify raw line map usage. The map should have the requested properties,
+ irrespective of limits like LINE_MAP_MAX_LOCATION_WITH_COLS. */
+ for (int sysp = 0; sysp != 3; ++sysp)
+ {
+ constexpr int column_bits = 8, range_bits = 7;
+ const int line = 1 + sysp;
+ const auto map = linemap_add_raw_map (line_table, LC_RENAME,
+ line_table->highest_location + 1,
+ sysp, column_bits + range_bits,
+ range_bits, "foo2.c", line, 1);
+ ASSERT_NE (map, nullptr);
+ ASSERT_EQ (map->reason, LC_RENAME);
+ ASSERT_EQ (map->m_column_and_range_bits, column_bits + range_bits);
+ ASSERT_EQ (map->m_range_bits, range_bits);
+ const line_map_uint_t col = 200 + sysp;
+ const location_t loc = MAP_START_LOCATION (map) + (col << range_bits);
+ ASSERT_GT (loc, line_table->highest_line);
+ ASSERT_LT (loc, line_table->highest_location);
+ ASSERT_EQ (in_system_header_at (loc), sysp);
+ assert_loceq ("foo2.c", line, col, loc);
+ }
}
/* Verify various properties of UNKNOWN_LOCATION. */