231 lines
5.4 KiB
C++
231 lines
5.4 KiB
C++
/* Code for GIMPLE range trace and debugging related routines.
|
|
Copyright (C) 2019-2022 Free Software Foundation, Inc.
|
|
Contributed by Andrew MacLeod <amacleod@redhat.com>
|
|
and Aldy Hernandez <aldyh@redhat.com>.
|
|
|
|
This file is part of GCC.
|
|
|
|
GCC is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3, or (at your option)
|
|
any later version.
|
|
|
|
GCC is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with GCC; see the file COPYING3. If not see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
#include "config.h"
|
|
#include "system.h"
|
|
#include "coretypes.h"
|
|
#include "backend.h"
|
|
#include "tree.h"
|
|
#include "gimple.h"
|
|
#include "ssa.h"
|
|
#include "gimple-pretty-print.h"
|
|
#include "gimple-iterator.h"
|
|
#include "tree-cfg.h"
|
|
#include "fold-const.h"
|
|
#include "tree-cfg.h"
|
|
#include "cfgloop.h"
|
|
#include "tree-scalar-evolution.h"
|
|
#include "gimple-range.h"
|
|
|
|
|
|
// Breakpoint to trap at a specific index. From GDB, this provides a simple
|
|
// place to put a breakpoint to stop at a given trace line.
|
|
// ie. b range_tracer::breakpoint if index == 45678
|
|
|
|
void
|
|
range_tracer::breakpoint (unsigned index ATTRIBUTE_UNUSED)
|
|
{
|
|
}
|
|
|
|
// Construct a range_tracer with component NAME.
|
|
|
|
range_tracer::range_tracer (const char *name)
|
|
{
|
|
gcc_checking_assert (strlen(name) < name_len -1);
|
|
strcpy (component, name);
|
|
indent = 0;
|
|
tracing = false;
|
|
}
|
|
|
|
// This routine does the initial line spacing/indenting for a trace.
|
|
// If BLANKS is false, then IDX is printed, otherwise spaces.
|
|
|
|
void
|
|
range_tracer::print_prefix (unsigned idx, bool blanks)
|
|
{
|
|
// Print counter index as well as INDENT spaces.
|
|
if (!blanks)
|
|
fprintf (dump_file, "%-7u ", idx);
|
|
else
|
|
fprintf (dump_file, " ");
|
|
fprintf (dump_file, "%s ", component);
|
|
unsigned x;
|
|
for (x = 0; x< indent; x++)
|
|
fputc (' ', dump_file);
|
|
|
|
}
|
|
// If dumping, return the next call index and print the prefix for the next
|
|
// output line. If not, retrurn 0.
|
|
// Counter is static to monotonically increase across the compilation unit.
|
|
|
|
unsigned
|
|
range_tracer::do_header (const char *str)
|
|
{
|
|
static unsigned trace_count = 0;
|
|
|
|
unsigned idx = ++trace_count;
|
|
print_prefix (idx, false);
|
|
fprintf (dump_file, "%s", str);
|
|
indent += bump;
|
|
breakpoint (idx);
|
|
return idx;
|
|
}
|
|
|
|
// Print a line without starting or ending a trace.
|
|
|
|
void
|
|
range_tracer::print (unsigned counter, const char *str)
|
|
{
|
|
print_prefix (counter, true);
|
|
fprintf (dump_file, "%s", str);
|
|
}
|
|
|
|
// End a trace and print the CALLER, NAME, and RESULT and range R,
|
|
|
|
void
|
|
range_tracer::trailer (unsigned counter, const char *caller, bool result,
|
|
tree name, const irange &r)
|
|
{
|
|
gcc_checking_assert (tracing && counter != 0);
|
|
|
|
indent -= bump;
|
|
print_prefix (counter, true);
|
|
fputs(result ? "TRUE : " : "FALSE : ", dump_file);
|
|
fprintf (dump_file, "(%u) ", counter);
|
|
fputs (caller, dump_file);
|
|
fputs (" (",dump_file);
|
|
if (name)
|
|
print_generic_expr (dump_file, name, TDF_SLIM);
|
|
fputs (") ",dump_file);
|
|
if (result)
|
|
{
|
|
r.dump (dump_file);
|
|
fputc('\n', dump_file);
|
|
}
|
|
else
|
|
fputc('\n', dump_file);
|
|
}
|
|
|
|
// =========================================
|
|
// Debugging helpers.
|
|
// =========================================
|
|
|
|
// Query all statements in the IL to precalculate computable ranges in RANGER.
|
|
|
|
DEBUG_FUNCTION void
|
|
debug_seed_ranger (gimple_ranger &ranger)
|
|
{
|
|
// Recalculate SCEV to make sure the dump lists everything.
|
|
if (scev_initialized_p ())
|
|
{
|
|
scev_finalize ();
|
|
scev_initialize ();
|
|
}
|
|
|
|
basic_block bb;
|
|
int_range_max r;
|
|
gimple_stmt_iterator gsi;
|
|
FOR_EACH_BB_FN (bb, cfun)
|
|
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
|
|
{
|
|
gimple *stmt = gsi_stmt (gsi);
|
|
|
|
if (is_gimple_debug (stmt))
|
|
continue;
|
|
|
|
ranger.range_of_stmt (r, stmt);
|
|
}
|
|
}
|
|
|
|
// Change the current dump_file and dump_flags to F and FLAGS while
|
|
// saving them for later restoring.
|
|
|
|
push_dump_file::push_dump_file (FILE *f, dump_flags_t flags)
|
|
{
|
|
old_dump_file = dump_file;
|
|
old_dump_flags = dump_flags;
|
|
dump_file = f;
|
|
dump_flags = flags;
|
|
}
|
|
|
|
// Restore saved dump_file and dump_flags.
|
|
|
|
push_dump_file::~push_dump_file ()
|
|
{
|
|
dump_file = old_dump_file;
|
|
dump_flags = old_dump_flags;
|
|
}
|
|
|
|
// Dump all that ranger knows for the current function.
|
|
|
|
void
|
|
dump_ranger (FILE *out)
|
|
{
|
|
push_dump_file save (out, dump_flags);
|
|
gimple_ranger ranger;
|
|
|
|
fprintf (out, ";; Function ");
|
|
print_generic_expr (out, current_function_decl);
|
|
fprintf (out, "\n");
|
|
|
|
debug_seed_ranger (ranger);
|
|
ranger.dump (out);
|
|
}
|
|
|
|
DEBUG_FUNCTION void
|
|
debug_ranger ()
|
|
{
|
|
dump_ranger (stderr);
|
|
}
|
|
|
|
// Dump all that ranger knows on a path of BBs.
|
|
//
|
|
// Note that the blocks are in reverse order, thus the exit block is
|
|
// path[0].
|
|
|
|
void
|
|
dump_ranger (FILE *dump_file, const vec<basic_block> &path)
|
|
{
|
|
if (path.length () == 0)
|
|
{
|
|
fprintf (dump_file, "empty\n");
|
|
return;
|
|
}
|
|
|
|
gimple_ranger ranger;
|
|
debug_seed_ranger (ranger);
|
|
|
|
unsigned i = path.length ();
|
|
do
|
|
{
|
|
i--;
|
|
ranger.dump_bb (dump_file, path[i]);
|
|
}
|
|
while (i > 0);
|
|
}
|
|
|
|
DEBUG_FUNCTION void
|
|
debug_ranger (const vec<basic_block> &path)
|
|
{
|
|
dump_ranger (stderr, path);
|
|
}
|
|
|
|
#include "gimple-range-tests.cc"
|