This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[debugalicious] verification code
- From: Aldy Hernandez <aldyh at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org, amacleod at redhat dot com
- Date: Mon, 6 Apr 2009 15:19:46 -0400
- Subject: [debugalicious] verification code
Hi folks.
This patch adds verification and sanity checks to the debuglocus code.
With it we now dump which debuglocus entries were added or deleted in a
given pass, as well as which entries are no longer referenced, or which
entries are erroneously shared. This all happens with
-fdump-tree-*-debuglocus.
I have also added -fdump-tree-*-debuglocus-details which dumps the
entire debuglocus bitmap.
Andrew approved this off-list. Committing to branch.
* debuglocus.c (debuglocus_bitmap_populate_helper): New.
(debuglocus_bitmap_populate_gimple): New.
(debuglocus_bitmap_populate_tree): New.
(debuglocus_bitmap_populate): New.
(dump_debuglocus_entry): New.
(dump_debuglocus_table): New.
(debuglocus_bitmap_verify): New.
* debuglocus.h: Fix typo.
* tree-dump.c (dump_option_value_in): Add TDF_DEBUGLOCUS.
* tree-pass.h (TDF_DEBUGLOCUS): New.
* gimple-pretty-print.c (dump_gimple_phi): Only dump debuglocus
info when TDF_DEBUGLOCUS.
(dump_gimple_stmt): Same.
(dump_implicit_edges): Same.
* Makefile.in (debuglocus.o): Depend on INPUT_H.
* passes.c (execute_one_pass): Verify debuglocus entries before
and after pass.
Index: debuglocus.c
===================================================================
--- debuglocus.c (revision 145125)
+++ debuglocus.c (working copy)
@@ -35,6 +35,7 @@ along with GCC; see the file COPYING3.
#include "toplev.h"
#include "debuglocus.h"
#include "hashtab.h"
+#include "input.h"
/* This file contains data and functions required to implement debuglocus
@@ -512,5 +513,244 @@ debuglocus_var_iter_next (debuglocus_ite
return next->decl;
return NULL;
}
+
+/* Debuglocus verification routines. */
+/* Debuglocus bitmap for entire translation unit. */
+bitmap_head global_dl_bitmap;
+
+/* Callback WI info for the walkers. */
+struct dlb_info
+{
+ /* The bitmap. */
+ bitmap bits;
+ /* DUMPFILE to dump errors out to. */
+ FILE *dumpfile;
+ /* TRUE if BITS is the bitmap for BEFORE the pass ran. */
+ bool before_pass_p;
+};
+
+/* If the given LOCUS is a debuglocus, set the corresponding bit in
+ bitmap B. Complain about shared debuglocus entries.
+
+ DUMPFILE is the dump file to output errors to.
+
+ BEFORE_PASS_P is true if this is the bitmap before the pass ran,
+ or false if the bitmap is for after the pass completed. */
+static void
+debuglocus_bitmap_populate_helper (bitmap b, location_t locus,
+ FILE *dumpfile, bool before_pass_p)
+{
+ if (is_debuglocus (locus))
+ {
+ unsigned int i = DEBUGLOCUS_INDEX (locus);
+
+ if (bitmap_bit_p (b, i))
+ fprintf (dumpfile, "Duplicated debuglocus %s this pass: %u\n",
+ before_pass_p ? "before" : "after", i);
+ else
+ bitmap_set_bit (b, (int) i);
+ }
+}
+
+/* Callback to walk gimple statements. Populate debuglocus bitmap
+ with each statement's debuglocus. */
+static tree
+debuglocus_bitmap_populate_gimple (gimple_stmt_iterator *gsi,
+ bool *handled_ops ATTRIBUTE_UNUSED,
+ struct walk_stmt_info *wi)
+{
+ gimple stmt = gsi_stmt (*gsi);
+ struct dlb_info *dlb = (struct dlb_info *)wi->info;
+
+ debuglocus_bitmap_populate_helper (dlb->bits, gimple_location (stmt),
+ dlb->dumpfile, dlb->before_pass_p);
+ return NULL_TREE;
+}
+
+/* Same, but for gimple operands (trees). */
+static tree
+debuglocus_bitmap_populate_tree (tree *tp,
+ int *walk_subtrees ATTRIBUTE_UNUSED,
+ void *data)
+{
+ struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
+ struct dlb_info *dlb = (struct dlb_info *)wi->info;
+
+ if (CAN_HAVE_LOCATION_P (*tp))
+ debuglocus_bitmap_populate_helper (dlb->bits, EXPR_LOCATION (*tp),
+ dlb->dumpfile, dlb->before_pass_p);
+ return NULL_TREE;
+}
+
+/* Initialize and populate a bitmap of debuglocus entries.
+ B is the bitmap to populate.
+ DUMPFILE is the file to dump errors out to.
+ BEFORE_PASS_P is true if this is the bitmap for before the pass ran. */
+void
+debuglocus_bitmap_populate (bitmap b, FILE *dumpfile, bool before_pass_p)
+{
+ debuglocus_table_t *tab = current_debuglocus_table ();
+ tree func;
+ struct walk_stmt_info wi;
+ struct dlb_info dlb;
+
+ bitmap_initialize (b, NULL);
+
+ if (!tab || !cfun)
+ return;
+
+ func = cfun->decl;
+
+ dlb.bits = b;
+ dlb.dumpfile = dumpfile;
+ dlb.before_pass_p = before_pass_p;
+ memset (&wi, 0, sizeof (wi));
+ wi.info = (void *)&dlb;
+
+ /* If we haven't lowered to gimple, ignore this pass. */
+ if (DECL_SAVED_TREE (func) != NULL)
+ return;
+
+ if (bitmap_empty_p (&global_dl_bitmap))
+ bitmap_initialize (&global_dl_bitmap, NULL);
+
+ /* If the CFG has been built, traverse the CFG. */
+ if (cfun->cfg && basic_block_info)
+ {
+ basic_block bb;
+ gimple_stmt_iterator gsi;
+
+ FOR_EACH_BB (bb)
+ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ walk_gimple_stmt (&gsi,
+ debuglocus_bitmap_populate_gimple,
+ debuglocus_bitmap_populate_tree,
+ &wi);
+ }
+ }
+ else
+ {
+ /* Otherwise, plain gimple. Traverse the sequence of
+ statements. */
+ walk_gimple_seq (gimple_body (func),
+ debuglocus_bitmap_populate_gimple,
+ debuglocus_bitmap_populate_tree,
+ &wi);
+ }
+
+ /* If the pass has already run, update the global debugloc
+ bitmap. */
+ if (before_pass_p == false)
+ bitmap_ior_into (&global_dl_bitmap, b);
+}
+
+/* Dump the contents of debuglocus entry DL.
+ F is the dumpfile. DL is the debuglocus entry.
+ INDEX is the debuglocus index for the entry. */
+static void
+dump_debuglocus_entry (FILE *f, debuglocus_p dl, unsigned int index)
+{
+ expanded_location xloc = expand_location (dl->locus);
+
+ fprintf (f, "index #%u\n", index);
+ fputs ("decl = [", f);
+ print_generic_decl (f, dl->decl, /*flags=*/0);
+ fputs ("]\n", f);
+ fprintf (f, "order = %d\n", dl->order);
+ fprintf (f, "locus = %u {file='%s', line=%d, col=%d}\n",
+ (unsigned int) dl->locus, xloc.file, xloc.line, xloc.column);
+ fprintf (f, "prev = %d\n", dl->prev);
+ fprintf (f, "next = %d\n", dl->next);
+}
+
+/* Dump the entire contents of the debuglocus table.
+ F is the dumpfile. TAB is the table. */
+static void
+dump_debuglocus_table (FILE *f, debuglocus_table_t *tab)
+{
+ unsigned int i;
+ debuglocus_p d;
+
+ if (!tab || tab->size <= 1)
+ return;
+
+ fputs ("\ndebuglocus table contents after pass executed\n", f);
+ fputs ("-----------------------------------------------\n", f);
+ fprintf (f, "number of elements=%d\n", tab->size);
+ for (i = 1; i < tab->size; ++i)
+ {
+ d = get_debuglocus_entry (tab, i);
+ dump_debuglocus_entry (f, d, i);
+ }
+ fputs ("-------------------------\n", f);
+}
+
+/* Verify the debuglocus entries created by the current pass.
+
+ BEFORE is the debuglocus bitmap before the pass. AFTER is the
+ debuglocus bitmap after the pass. F is the dumpfile to dump the
+ verification information. FLAGS is are the TDF dump flags from the
+ pass. */
+void
+debuglocus_bitmap_verify (FILE *f, bitmap before, bitmap after,
+ unsigned int flags)
+{
+ const char *comma;
+ unsigned i;
+ bitmap_iterator bi;
+ bool first = true;
+ debuglocus_table_t *tab = current_debuglocus_table ();
+
+ if (tab && flags & TDF_DETAILS)
+ dump_debuglocus_table (f, tab);
+
+ /* Dump new debuglocus entries generated in this pass. */
+ comma = "";
+ EXECUTE_IF_SET_IN_BITMAP (after, 0, i, bi)
+ {
+ if (!bitmap_bit_p (before, i))
+ {
+ if (first)
+ {
+ fputs ("new debuglocus entries in this pass\n", f);
+ first = false;
+ }
+ fprintf (f, "%s%u", comma, i);
+ comma = ", ";
+ }
+ }
+ if (!first)
+ fputc ('\n', f);
+
+ /* Dump debuglocus entries that went missing in this pass. */
+ first = true;
+ comma = "";
+ EXECUTE_IF_SET_IN_BITMAP (before, 0, i, bi)
+ {
+ if (!bitmap_bit_p (after, i))
+ {
+ if (first)
+ {
+ fputs ("deleted debuglocus entries in this pass:\n", f);
+ first = false;
+ }
+ fprintf (f, "%s%u", comma, i);
+ comma = ", ";
+ }
+ }
+ if (!first)
+ fputc ('\n', f);
+
+
+ if (tab)
+ {
+ /* Dump debuglocus entries that are no longer referenced after this
+ pass. */
+ for (i = 1; i < tab->size; ++i)
+ if (!bitmap_bit_p (&global_dl_bitmap, i))
+ fprintf (f, "debuglocus: orphaned debuglocus entry: %u\n", i);
+ }
+}
Index: debuglocus.h
===================================================================
--- debuglocus.h (revision 145125)
+++ debuglocus.h (working copy)
@@ -64,9 +64,12 @@ void merge_debuglocus (debuglocus_p, deb
debuglocus_p find_debuglocus (gimple, tree, source_location);
debuglocus_p find_and_detach_debuglocus (gimple, tree, source_location);
source_location find_and_detach_or_create_debuglocus (gimple, tree, source_location);
+bitmap current_debuglocus_bitmap (void);
+void debuglocus_bitmap_populate (bitmap, FILE *, bool);
+void debuglocus_bitmap_verify (FILE *, bitmap, bitmap, unsigned int);
/* Iterate over the different debuglocus's in a single list. No iterations are
- performed if ther locus is just a regular source location.
+ performed if their locus is just a regular source location.
usage:
source_location locus = gimple_location (stmt);
Index: tree-dump.c
===================================================================
--- tree-dump.c (revision 145125)
+++ tree-dump.c (working copy)
@@ -815,13 +815,14 @@ static const struct dump_option_value_in
{"blocks", TDF_BLOCKS},
{"vops", TDF_VOPS},
{"lineno", TDF_LINENO},
+ {"debuglocus", TDF_DEBUGLOCUS},
{"uid", TDF_UID},
{"stmtaddr", TDF_STMTADDR},
{"memsyms", TDF_MEMSYMS},
{"verbose", TDF_VERBOSE},
{"all", ~(TDF_RAW | TDF_SLIM | TDF_LINENO | TDF_TREE | TDF_RTL | TDF_IPA
| TDF_STMTADDR | TDF_GRAPH | TDF_DIAGNOSTIC | TDF_VERBOSE
- | TDF_RHS_ONLY)},
+ | TDF_RHS_ONLY | TDF_DEBUGLOCUS)},
{NULL, 0}
};
Index: tree-pass.h
===================================================================
--- tree-pass.h (revision 145125)
+++ tree-pass.h (working copy)
@@ -75,6 +75,7 @@ enum tree_dump_index
dumper to print stmts. */
#define TDF_RHS_ONLY (1 << 17) /* a flag to only print the RHS of
a gimple stmt. */
+#define TDF_DEBUGLOCUS (1 << 18) /* dump debuglocus information */
extern char *get_dump_file_name (enum tree_dump_index);
extern int dump_enabled_p (enum tree_dump_index);
Index: gimple-pretty-print.c
===================================================================
--- gimple-pretty-print.c (revision 145125)
+++ gimple-pretty-print.c (working copy)
@@ -1183,7 +1183,9 @@ dump_gimple_phi (pretty_printer *buffer,
pp_character (buffer, '(');
pp_decimal_int (buffer, gimple_phi_arg_edge (phi, i)->src->index);
pp_character (buffer, ')');
- if ((flags & TDF_LINENO) && gimple_phi_arg_has_location (phi, i))
+ if (((flags & TDF_LINENO)
+ || (flags & TDF_DEBUGLOCUS))
+ && gimple_phi_arg_has_location (phi, i))
{
expanded_location xloc;
@@ -1195,7 +1197,7 @@ dump_gimple_phi (pretty_printer *buffer,
pp_string (buffer, " : ");
}
pp_decimal_int (buffer, xloc.line);
- if (xloc.debuglocus != DEBUGLOCUS_NONE)
+ if ((flags & TDF_DEBUGLOCUS) && xloc.debuglocus != DEBUGLOCUS_NONE)
{
tree decl;
debuglocus_iterator iter;
@@ -1497,7 +1499,9 @@ dump_gimple_stmt (pretty_printer *buffer
if (flags & TDF_STMTADDR)
pp_printf (buffer, "<&%p> ", (void *) gs);
- if ((flags & TDF_LINENO) && gimple_has_location (gs))
+ if (((flags & TDF_LINENO)
+ || (flags & TDF_DEBUGLOCUS))
+ && gimple_has_location (gs))
{
expanded_location xloc = expand_location (gimple_location (gs));
pp_character (buffer, '[');
@@ -1507,7 +1511,7 @@ dump_gimple_stmt (pretty_printer *buffer
pp_string (buffer, " : ");
}
pp_decimal_int (buffer, xloc.line);
- if (xloc.debuglocus != DEBUGLOCUS_NONE)
+ if ((flags & TDF_DEBUGLOCUS) && xloc.debuglocus != DEBUGLOCUS_NONE)
{
tree decl;
debuglocus_iterator iter;
@@ -1854,7 +1858,7 @@ dump_implicit_edges (pretty_printer *buf
{
INDENT (indent);
- if ((flags & TDF_LINENO)
+ if (((flags & TDF_LINENO) || (flags & TDF_DEBUGLOCUS))
&& e->goto_locus != UNKNOWN_LOCATION
)
{
@@ -1867,7 +1871,8 @@ dump_implicit_edges (pretty_printer *buf
pp_string (buffer, " : ");
}
pp_decimal_int (buffer, goto_xloc.line);
- if (goto_xloc.debuglocus != DEBUGLOCUS_NONE)
+ if ((flags & TDF_DEBUGLOCUS)
+ && goto_xloc.debuglocus != DEBUGLOCUS_NONE)
{
tree decl;
debuglocus_iterator iter;
Index: Makefile.in
===================================================================
--- Makefile.in (revision 145125)
+++ Makefile.in (working copy)
@@ -2544,7 +2544,7 @@ dbxout.o : dbxout.c $(CONFIG_H) $(SYSTEM
$(TOPLEV_H) $(GGC_H) $(OBSTACK_H) $(EXPR_H) gt-dbxout.h
debug.o : debug.c debug.h $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H)
debuglocus.o : debuglocus.c debuglocus.h $(CONFIG_H) $(SYSTEM_H) coretypes.h \
- $(TM_H)
+ $(TM_H) $(INPUT_H)
sdbout.o : sdbout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) debug.h \
$(TREE_H) $(GGC_H) $(RTL_H) $(REGS_H) $(FLAGS_H) insn-config.h \
output.h $(TOPLEV_H) $(TM_P_H) gsyms.h langhooks.h $(TARGET_H) sdbout.h \
Index: passes.c
===================================================================
--- passes.c (revision 145125)
+++ passes.c (working copy)
@@ -84,6 +84,7 @@ along with GCC; see the file COPYING3.
#include "tree-dump.h"
#include "df.h"
#include "predict.h"
+#include "debuglocus.h"
#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
#include "dwarf2out.h"
@@ -1218,6 +1219,7 @@ execute_one_pass (struct opt_pass *pass)
{
bool initializing_dump;
unsigned int todo_after = 0;
+ bitmap_head debuglocus_before, debuglocus_after;
/* IPA passes are executed on whole program, so cfun should be NULL.
Other passes need function context set. */
@@ -1267,6 +1269,12 @@ execute_one_pass (struct opt_pass *pass)
initializing_dump = pass_init_dump_file (pass);
+ if ((dump_flags & TDF_DEBUGLOCUS)
+ && (pass->todo_flags_finish & TODO_dump_func)
+ && dump_file)
+ debuglocus_bitmap_populate (&debuglocus_before, dump_file,
+ /*before_pass_p=*/true);
+
/* If a timevar is present, start it. */
if (pass->tv_id)
timevar_push (pass->tv_id);
@@ -1282,6 +1290,18 @@ execute_one_pass (struct opt_pass *pass)
if (pass->tv_id)
timevar_pop (pass->tv_id);
+ if ((dump_flags & TDF_DEBUGLOCUS)
+ && (pass->todo_flags_finish & TODO_dump_func)
+ && dump_file)
+ {
+ debuglocus_bitmap_populate (&debuglocus_after, dump_file,
+ /*before_pass_p=*/false);
+
+ debuglocus_bitmap_verify (dump_file,
+ &debuglocus_before, &debuglocus_after,
+ dump_flags);
+ }
+
do_per_function (update_properties_after_pass, pass);
if (initializing_dump