diff mbox

[3/4] libcpp/input.c: Add a way to visualize the linemaps

Message ID 1431525401.11565.51.camel@surprise
State New
Headers show

Commit Message

David Malcolm May 13, 2015, 1:56 p.m. UTC
On Mon, 2015-05-04 at 13:19 -0600, Jeff Law wrote:
> On 05/01/2015 06:56 PM, David Malcolm wrote:
> > 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.
> Maybe "dump-internal-locations"?  Not sure I want to bikeshed on the 
> name any more than that.   If you feel strongly about the option name, 
> then I won't stress about it.
> 
> 
> 
> > +void
> > +dump_location_info (FILE *stream)
> > +{
> > +  if (0)
> > +    line_table_dump (stream,
> > +		     line_table,
> > +		     LINEMAPS_ORDINARY_USED (line_table),
> > +		     LINEMAPS_MACRO_USED (line_table));
> Should the if (0) code go away?
> 
> > +
> > +  /* 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 */
> And again.
> 
> 
> So I think with removing the if (0) code and the possible option name 
> change this is good to go.

Thanks.  I removed the if (0) code and renamed it to
-fdump-internal-locations.

Bootstrapped&regrtested on x86_64-unknown-linux-gnu (Fedora 20).

Committed to trunk as r223163 (attached).
diff mbox

Patch

Index: gcc/input.c
===================================================================
--- gcc/input.c	(revision 223162)
+++ gcc/input.c	(revision 223163)
@@ -23,6 +23,7 @@ 
 #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,226 @@ 
            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)
+{
+  /* 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);
+}
Index: gcc/input.h
===================================================================
--- gcc/input.h	(revision 223162)
+++ gcc/input.h	(revision 223163)
@@ -77,6 +77,8 @@ 
 
 void dump_line_table_statistics (void);
 
+void dump_location_info (FILE *stream);
+
 void diagnostics_file_cache_fini (void);
 
 #endif
Index: gcc/toplev.c
===================================================================
--- gcc/toplev.c	(revision 223162)
+++ gcc/toplev.c	(revision 223163)
@@ -593,6 +593,9 @@ 
   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.  */
 
Index: gcc/ChangeLog
===================================================================
--- gcc/ChangeLog	(revision 223162)
+++ gcc/ChangeLog	(revision 223163)
@@ -1,3 +1,16 @@ 
+2015-05-13  David Malcolm  <dmalcolm@redhat.com>
+
+	* common.opt (fdump-internal-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.
+
 2015-05-13  Eric Botcazou  <ebotcazou@adacore.com>
 
 	* gimple-expr.h (is_gimple_constant): Reorder.
Index: gcc/common.opt
===================================================================
--- gcc/common.opt	(revision 223162)
+++ gcc/common.opt	(revision 223163)
@@ -1166,6 +1166,10 @@ 
 Collect and dump debug information into temporary file if ICE in C/C++
 compiler occured.
 
+fdump-internal-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
Index: libcpp/location-example.txt
===================================================================
--- libcpp/location-example.txt	(revision 0)
+++ libcpp/location-example.txt	(revision 223163)
@@ -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-internal-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: <built-in>
+  starting at line: 0
+  column bits: 0
+
+ORDINARY MAP: 2
+  source_location interval: 4 <= loc < 5
+  file: <command-line>
+  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: <command-line>
+  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
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Index: libcpp/include/line-map.h
===================================================================
--- libcpp/include/line-map.h	(revision 223162)
+++ libcpp/include/line-map.h	(revision 223163)
@@ -113,7 +113,9 @@ 
   ...        |                               |
   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.  */
Index: libcpp/ChangeLog
===================================================================
--- libcpp/ChangeLog	(revision 223162)
+++ libcpp/ChangeLog	(revision 223163)
@@ -1,5 +1,11 @@ 
 2015-05-13  David Malcolm  <dmalcolm@redhat.com>
 
+	* include/line-map.h (source_location): Add a reference to
+	location-example.txt to the descriptive comment.
+	* location-example.txt: New file.
+
+2015-05-13  David Malcolm  <dmalcolm@redhat.com>
+
 	* include/line-map.h (MAX_SOURCE_LOCATION): Convert from a macro
 	to a const source_location.
 	(RESERVED_LOCATION_COUNT): Likewise.