From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 47972 invoked by alias); 2 May 2015 00:44:02 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 47862 invoked by uid 89); 2 May 2015 00:44:01 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.9 required=5.0 tests=AWL,BAYES_20,KAM_LOTSOFHASH,SPF_HELO_PASS,SPF_PASS,T_RP_MATCHES_RCVD autolearn=no version=3.3.2 X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Sat, 02 May 2015 00:43:58 +0000 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by mx1.redhat.com (Postfix) with ESMTPS id 7A51AA0B9E for ; Sat, 2 May 2015 00:43:57 +0000 (UTC) Received: from c64.redhat.com (vpn-224-191.phx2.redhat.com [10.3.224.191]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t420hskn032616; Fri, 1 May 2015 20:43:56 -0400 From: David Malcolm To: gcc-patches@gcc.gnu.org Cc: David Malcolm Subject: [PATCH 3/4] libcpp/input.c: Add a way to visualize the linemaps Date: Sat, 02 May 2015 00:44:00 -0000 Message-Id: <1430528215-19648-4-git-send-email-dmalcolm@redhat.com> In-Reply-To: <1430528215-19648-1-git-send-email-dmalcolm@redhat.com> References: <1430528215-19648-1-git-send-email-dmalcolm@redhat.com> X-IsSubscribed: yes X-SW-Source: 2015-05/txt/msg00112.txt.bz2 As a relative newcomer to GCC, one of the issues I had was becoming comfortable with the linemap API and its internal representation. To familiarize myself with it, I wrote a dumping routine to try to visualize how the source_location space is carved up between line maps, and what each number can mean. It struck me that this would benefit others, so this patch adds this visualization, via an undocumented option -fdump-locations, and adds a text file to libcpp's sources documenting a simple example of compiling a small C file, with a header and macro expansions (built using the -fdump-locations option and a little hand-editing). gcc/ChangeLog: * common.opt (fdump-locations): New option. * input.c: Include diagnostic-core.h. (get_end_location): New function. (write_digit): New function. (write_digit_row): New function. (dump_location_range): New function. (dump_labelled_location_range): New function. (dump_location_info): New function. * input.h (dump_location_info): New prototype. * toplev.c (compile_file): Handle flag_dump_locations. libcpp/ChangeLog: * include/line-map.h (source_location): Add a reference to location-example.txt to the descriptive comment. * location-example.txt: New file. --- gcc/common.opt | 4 + gcc/input.c | 237 ++++++++++++++++++++++++++++++++++++++++++++ gcc/input.h | 2 + gcc/toplev.c | 3 + libcpp/include/line-map.h | 4 +- libcpp/location-example.txt | 216 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 465 insertions(+), 1 deletion(-) create mode 100644 libcpp/location-example.txt diff --git a/gcc/common.opt b/gcc/common.opt index 380848c..444a73a 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -1166,6 +1166,10 @@ Common Driver Var(flag_report_bug) Collect and dump debug information into temporary file if ICE in C/C++ compiler occured. +fdump-locations +Common Var(flag_dump_locations) Init(0) +Dump detailed information on GCC's internal representation of source code locations + fdump-passes Common Var(flag_dump_passes) Init(0) Dump optimization passes diff --git a/gcc/input.c b/gcc/input.c index 18c1e50..922c2f1 100644 --- a/gcc/input.c +++ b/gcc/input.c @@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see #include "intl.h" #include "input.h" #include "vec.h" +#include "diagnostic-core.h" /* This is a cache used by get_next_line to store the content of a file to be searched for file lines. */ @@ -869,3 +870,239 @@ dump_line_table_statistics (void) STAT_LABEL (total_used_map_size)); fprintf (stderr, "\n"); } + +/* Get location one beyond the final location in ordinary map IDX. */ + +static source_location +get_end_location (struct line_maps *set, unsigned int idx) +{ + if (idx == LINEMAPS_ORDINARY_USED (set) - 1) + return set->highest_location; + + struct line_map *next_map = LINEMAPS_ORDINARY_MAP_AT (set, idx + 1); + return MAP_START_LOCATION (next_map); +} + +/* Helper function for write_digit_row. */ + +static void +write_digit (FILE *stream, int digit) +{ + fputc ('0' + (digit % 10), stream); +} + +/* Helper function for dump_location_info. + Write a row of numbers to STREAM, numbering a source line, + giving the units, tens, hundreds etc of the column number. */ + +static void +write_digit_row (FILE *stream, int indent, + source_location loc, int max_col, int divisor) +{ + fprintf (stream, "%*c", indent, ' '); + fprintf (stream, "|"); + for (int column = 1; column < max_col; column++) + { + source_location column_loc = loc + column; + write_digit (stream, column_loc / divisor); + } + fprintf (stream, "\n"); +} + +/* Write a half-closed (START) / half-open (END) interval of + source_location to STREAM. */ + +static void +dump_location_range (FILE *stream, + source_location start, source_location end) +{ + fprintf (stream, + " source_location interval: %u <= loc < %u\n", + start, end); +} + +/* Write a labelled description of a half-closed (START) / half-open (END) + interval of source_location to STREAM. */ + +static void +dump_labelled_location_range (FILE *stream, + const char *name, + source_location start, source_location end) +{ + fprintf (stream, "%s\n", name); + dump_location_range (stream, start, end); + fprintf (stream, "\n"); +} + +/* Write a visualization of the locations in the line_table to STREAM. */ + +void +dump_location_info (FILE *stream) +{ + if (0) + line_table_dump (stream, + line_table, + LINEMAPS_ORDINARY_USED (line_table), + LINEMAPS_MACRO_USED (line_table)); + + /* Visualize the reserved locations. */ + dump_labelled_location_range (stream, "RESERVED LOCATIONS", + 0, RESERVED_LOCATION_COUNT); + + /* Visualize the ordinary line_map instances, rendering the sources. */ + for (unsigned int idx = 0; idx < LINEMAPS_ORDINARY_USED (line_table); idx++) + { + source_location end_location = get_end_location (line_table, idx); + /* half-closed: doesn't include this one. */ + + struct line_map *map = LINEMAPS_ORDINARY_MAP_AT (line_table, idx); + fprintf (stream, "ORDINARY MAP: %i\n", idx); + dump_location_range (stream, + MAP_START_LOCATION (map), end_location); + fprintf (stream, " file: %s\n", ORDINARY_MAP_FILE_NAME (map)); + fprintf (stream, " starting at line: %i\n", + ORDINARY_MAP_STARTING_LINE_NUMBER (map)); + fprintf (stream, " column bits: %i\n", + ORDINARY_MAP_NUMBER_OF_COLUMN_BITS (map)); + + /* Render the span of source lines that this "map" covers. */ + for (source_location loc = MAP_START_LOCATION (map); + loc < end_location; + loc++) + { + expanded_location exploc + = linemap_expand_location (line_table, map, loc); + + if (0 == exploc.column) + { + /* Beginning of a new source line: draw the line. */ + + int line_size; + const char *line_text = location_get_source_line (exploc, &line_size); + if (!line_text) + break; + fprintf (stream, + "%s:%3i|loc:%5i|%.*s\n", + exploc.file, exploc.line, + loc, + line_size, line_text); + + /* "loc" is at column 0, which means "the whole line". + Render the locations *within* the line, by underlining + it, showing the source_location numeric values + at each column. */ + int max_col + = (1 << ORDINARY_MAP_NUMBER_OF_COLUMN_BITS (map)) - 1; + if (max_col > line_size) + max_col = line_size + 1; + + int indent = 14 + strlen (exploc.file); + + /* Thousands. */ + if (end_location > 999) + write_digit_row (stream, indent, loc, max_col, 1000); + + /* Hundreds. */ + if (end_location > 99) + write_digit_row (stream, indent, loc, max_col, 100); + + /* Tens. */ + write_digit_row (stream, indent, loc, max_col, 10); + + /* Units. */ + write_digit_row (stream, indent, loc, max_col, 1); + } + } + fprintf (stream, "\n"); + } + + /* Visualize unallocated values. */ + dump_labelled_location_range (stream, "UNALLOCATED LOCATIONS", + line_table->highest_location, + LINEMAPS_MACRO_LOWEST_LOCATION (line_table)); + + /* Visualize the macro line_map instances, rendering the sources. */ + for (unsigned int i = 0; i < LINEMAPS_MACRO_USED (line_table); i++) + { + /* Each macro map that is allocated owns source_location values + that are *lower* that the one before them. + Hence it's meaningful to view them either in order of ascending + source locations, or in order of ascending macro map index. */ + const bool ascending_source_locations = true; + unsigned int idx = (ascending_source_locations + ? (LINEMAPS_MACRO_USED (line_table) - (i + 1)) + : i); + struct line_map *map = LINEMAPS_MACRO_MAP_AT (line_table, idx); + fprintf (stream, "MACRO %i: %s (%u tokens)\n", + idx, + linemap_map_get_macro_name (map), + MACRO_MAP_NUM_MACRO_TOKENS (map)); + dump_location_range (stream, + map->start_location, + (map->start_location + + MACRO_MAP_NUM_MACRO_TOKENS (map))); + inform (MACRO_MAP_EXPANSION_POINT_LOCATION (map), + "expansion point is location %i", + MACRO_MAP_EXPANSION_POINT_LOCATION (map)); + fprintf (stream, " map->start_location: %u\n", + map->start_location); + + fprintf (stream, " macro_locations:\n"); + for (unsigned int i = 0; i < MACRO_MAP_NUM_MACRO_TOKENS (map); i++) + { + source_location x = MACRO_MAP_LOCATIONS (map)[2 * i]; + source_location y = MACRO_MAP_LOCATIONS (map)[(2 * i) + 1]; + + /* linemap_add_macro_token encodes token numbers in an expansion + by putting them after MAP_START_LOCATION. */ + + /* I'm typically seeing 4 uninitialized entries at the end of + 0xafafafaf. + This appears to be due to macro.c:replace_args + adding 2 extra args for padding tokens; presumably there may + be a leading and/or trailing padding token injected, + each for 2 more location slots. + This would explain there being up to 4 source_locations slots + that may be uninitialized. */ + + fprintf (stream, " %u: %u, %u\n", + i, + x, + y); + if (x == y) + { + if (x < MAP_START_LOCATION (map)) + inform (x, "token %u has x-location == y-location == %u", i, x); + else + fprintf (stream, + "x-location == y-location == %u encodes token # %u\n", + x, x - MAP_START_LOCATION (map)); + } + else + { + inform (x, "token %u has x-location == %u", i, x); + inform (x, "token %u has y-location == %u", i, y); + } + } + fprintf (stream, "\n"); + } + + /* It appears that MAX_SOURCE_LOCATION itself is never assigned to a + macro map, presumably due to an off-by-one error somewhere + between the logic in linemap_enter_macro and + LINEMAPS_MACRO_LOWEST_LOCATION. */ + dump_labelled_location_range (stream, "MAX_SOURCE_LOCATION", + MAX_SOURCE_LOCATION, + MAX_SOURCE_LOCATION + 1); + + /* Visualize ad-hoc values. */ + dump_labelled_location_range (stream, "AD-HOC LOCATIONS", + MAX_SOURCE_LOCATION + 1, UINT_MAX); + + /* A brute-force visualization: emit a warning at every location. */ + if (0) + for (source_location loc = 0; loc < line_table->highest_location; loc++) + warning_at (loc, 0, "this is location %i", loc); + /* Alternatively, we could use inform (), though this + also shows lots of locations in stdc-predef.h */ +} diff --git a/gcc/input.h b/gcc/input.h index 93eb6ed..5ba4d3b 100644 --- a/gcc/input.h +++ b/gcc/input.h @@ -77,6 +77,8 @@ extern location_t input_location; void dump_line_table_statistics (void); +void dump_location_info (FILE *stream); + void diagnostics_file_cache_fini (void); #endif diff --git a/gcc/toplev.c b/gcc/toplev.c index 38de36b..fe86c7e 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -593,6 +593,9 @@ compile_file (void) timevar_pop (TV_PARSE_GLOBAL); timevar_stop (TV_PHASE_PARSING); + if (flag_dump_locations) + dump_location_info (stderr); + /* Compilation is now finished except for writing what's left of the symbol table output. */ diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h index 021ca6e..9dfc396 100644 --- a/libcpp/include/line-map.h +++ b/libcpp/include/line-map.h @@ -113,7 +113,9 @@ typedef unsigned int linenum_type; ... | | 0xffffffff | UINT_MAX | -----------+-------------------------------+------------------------------- - . */ + + To see how this works in practice, see the worked example in + libcpp/location-example.txt. */ typedef unsigned int source_location; /* Memory allocation function typedef. Works like xrealloc. */ diff --git a/libcpp/location-example.txt b/libcpp/location-example.txt new file mode 100644 index 0000000..be53175 --- /dev/null +++ b/libcpp/location-example.txt @@ -0,0 +1,216 @@ +Consider compiling test.c, with this content: +VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV +#include "test.h" + +int +main (int argc, char **argv) +{ + int a = PLUS (1,2); + int b = PLUS (3,4); + return 0; +} +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +...where test.h has this content: +VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV +extern int foo (); + +#define PLUS(A, B) A + B +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + +The undocumented -fdump-locations option outputs this information to stderr, +showing what each source_location value means. Source code lines are quoted, +showing both per-line source_location values and per-line&column +source_location values (written vertically under the corresponding character +of source code). + +VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV +RESERVED LOCATIONS + source_location interval: 0 <= loc < 2 + +ORDINARY MAP: 0 + source_location interval: 2 <= loc < 3 + file: test.c + starting at line: 1 + column bits: 7 +test.c: 1|loc: 2|#include "test.h" + |00000001111111111 + |34567890123456789 + +ORDINARY MAP: 1 + source_location interval: 3 <= loc < 4 + file: + starting at line: 0 + column bits: 0 + +ORDINARY MAP: 2 + source_location interval: 4 <= loc < 5 + file: + starting at line: 0 + column bits: 0 + +ORDINARY MAP: 3 + source_location interval: 5 <= loc < 5005 + file: /usr/include/stdc-predef.h + starting at line: 1 + column bits: 7 +(contents of /usr/include/stdc-predef.h snipped for brevity) + +ORDINARY MAP: 4 + source_location interval: 5005 <= loc < 5006 + file: + starting at line: 1 + column bits: 7 + +ORDINARY MAP: 5 + source_location interval: 5006 <= loc < 5134 + file: test.c + starting at line: 1 + column bits: 7 +test.c: 1|loc: 5006|#include "test.h" + |55555555555555555 + |00000000000000000 + |00011111111112222 + |78901234567890123 + +ORDINARY MAP: 6 + source_location interval: 5134 <= loc < 5416 + file: test.h + starting at line: 1 + column bits: 7 +test.h: 1|loc: 5134|extern int foo (); + |555555555555555555 + |111111111111111111 + |333334444444444555 + |567890123456789012 +test.h: 2|loc: 5262| + | + | + | + | +test.h: 3|loc: 5390|#define PLUS(A, B) A + B + |555555555555555555555555 + |333333333444444444444444 + |999999999000000000011111 + |123456789012345678901234 + +ORDINARY MAP: 7 + source_location interval: 5416 <= loc < 6314 + file: test.c + starting at line: 2 + column bits: 7 +test.c: 2|loc: 5416| + | + | + | + | +test.c: 3|loc: 5544|int + |555 + |555 + |444 + |567 +test.c: 4|loc: 5672|main (int argc, char **argv) + |5555555555555555555555555555 + |6666666666666666666666666667 + |7777777888888888899999999990 + |3456789012345678901234567890 +test.c: 5|loc: 5800|{ + |5 + |8 + |0 + |1 +test.c: 6|loc: 5928| int a = PLUS (1,2); + |555555555555555555555 + |999999999999999999999 + |233333333334444444444 + |901234567890123456789 +test.c: 7|loc: 6056| int b = PLUS (3,4); + |666666666666666666666 + |000000000000000000000 + |555666666666677777777 + |789012345678901234567 +test.c: 8|loc: 6184| return 0; + |66666666666 + |11111111111 + |88888999999 + |56789012345 +test.c: 9|loc: 6312|} + |6 + |3 + |1 + |3 + +UNALLOCATED LOCATIONS + source_location interval: 6314 <= loc < 2147483633 + +MACRO 1: PLUS (7 tokens) + source_location interval: 2147483633 <= loc < 2147483640 +test.c:7:11: note: expansion point is location 6067 + int b = PLUS (3,4); + ^ + map->start_location: 2147483633 + macro_locations: + 0: 6073, 5410 +test.c:7:17: note: token 0 has x-location == 6073 + int b = PLUS (3,4); + ^ +test.c:7:17: note: token 0 has y-location == 5410 + 1: 5412, 5412 +In file included from test.c:1:0: +test.h:3:22: note: token 1 has x-location == y-location == 5412 + #define PLUS(A, B) A + B + ^ + 2: 6075, 5414 +test.c:7:19: note: token 2 has x-location == 6075 + int b = PLUS (3,4); + ^ +test.c:7:19: note: token 2 has y-location == 5414 + 3: 0, 2947526575 +cc1: note: token 3 has x-location == 0 +cc1: note: token 3 has y-location == 2947526575 + 4: 2947526575, 2947526575 +x-location == y-location == 2947526575 encodes token # 800042942 + 5: 2947526575, 2947526575 +x-location == y-location == 2947526575 encodes token # 800042942 + 6: 2947526575, 2947526575 +x-location == y-location == 2947526575 encodes token # 800042942 + +MACRO 0: PLUS (7 tokens) + source_location interval: 2147483640 <= loc < 2147483647 +test.c:6:11: note: expansion point is location 5939 + int a = PLUS (1,2); + ^ + map->start_location: 2147483640 + macro_locations: + 0: 5945, 5410 +test.c:6:17: note: token 0 has x-location == 5945 + int a = PLUS (1,2); + ^ +test.c:6:17: note: token 0 has y-location == 5410 + 1: 5412, 5412 +In file included from test.c:1:0: +test.h:3:22: note: token 1 has x-location == y-location == 5412 + #define PLUS(A, B) A + B + ^ + 2: 5947, 5414 +test.c:6:19: note: token 2 has x-location == 5947 + int a = PLUS (1,2); + ^ +test.c:6:19: note: token 2 has y-location == 5414 + 3: 0, 2947526575 +cc1: note: token 3 has x-location == 0 +cc1: note: token 3 has y-location == 2947526575 + 4: 2947526575, 2947526575 +x-location == y-location == 2947526575 encodes token # 800042935 + 5: 2947526575, 2947526575 +x-location == y-location == 2947526575 encodes token # 800042935 + 6: 2947526575, 2947526575 +x-location == y-location == 2947526575 encodes token # 800042935 + +MAX_SOURCE_LOCATION + source_location interval: 2147483647 <= loc < 2147483648 + +AD-HOC LOCATIONS + source_location interval: 2147483648 <= loc < 4294967295 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- 1.8.5.3