blob: 2417c21f1f269175e0743d5fa7be6a2a4a4d9fa7 [file] [log] [blame]
/* Code for GIMPLE range trace and debugging related routines.
Copyright (C) 2019-2021 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"