public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: David Malcolm <dmalcolm@redhat.com>
To: gcc-patches@gcc.gnu.org
Cc: David Malcolm <dmalcolm@redhat.com>
Subject: [PATCH 3/4] libcpp/input.c: Add a way to visualize the linemaps
Date: Sat, 02 May 2015 00:44:00 -0000	[thread overview]
Message-ID: <1430528215-19648-4-git-send-email-dmalcolm@redhat.com> (raw)
In-Reply-To: <1430528215-19648-1-git-send-email-dmalcolm@redhat.com>

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: <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
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-- 
1.8.5.3

  parent reply	other threads:[~2015-05-02  0:44 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-05-02  0:44 [PATCH 0/4] libcpp patches David Malcolm
2015-05-02  0:44 ` [PATCH 4/4] Replace line_map union with C++ class hierarchy David Malcolm
2015-05-04 20:45   ` Jeff Law
2015-05-04 21:34     ` David Malcolm
2015-05-14 15:20       ` Jeff Law
2015-05-02  0:44 ` David Malcolm [this message]
2015-05-04 19:20   ` [PATCH 3/4] libcpp/input.c: Add a way to visualize the linemaps Jeff Law
2015-05-13 14:05     ` David Malcolm
2015-05-02  0:44 ` [PATCH 1/4] libcpp: Improvements to comments in line-map.h/c David Malcolm
2015-05-04 17:18   ` Jeff Law
2015-05-02  0:44 ` [PATCH 2/4] libcpp: Replace macro usage with C++ constructs David Malcolm
2015-05-04 19:15   ` Jeff Law
2015-05-05 18:08     ` [PATCH 2/4 v2] libcpp: Replace macro usage with C++ constructs) David Malcolm
2015-05-05 18:08       ` [PATCH 5/4] libcpp: Eliminate most of the non-const/reference-returning inline fns David Malcolm
2015-05-08 21:49         ` Jeff Law
2015-05-05 18:08       ` [PATCH 2/4 v2: part 1] Move linemap_assert higher up within the file David Malcolm
2015-05-08 21:35         ` Jeff Law
2015-05-05 18:08       ` [PATCH 2/4 v2: part 2] libcpp: Replace macro usage with C++ constructs David Malcolm
2015-05-08 21:47         ` Jeff Law
2015-07-08 14:50         ` Thomas Schwinge
2015-07-08 15:14           ` David Malcolm
2015-05-08 21:45       ` [PATCH 2/4 v2] libcpp: Replace macro usage with C++ constructs) Jeff Law
2015-05-10 15:39         ` Jan Hubicka

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1430528215-19648-4-git-send-email-dmalcolm@redhat.com \
    --to=dmalcolm@redhat.com \
    --cc=gcc-patches@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).