gcc/gcc/sel-sched-dump.c
Lawrence Crowl 7b3b6ae441 Add uniform debug dump function names.
Add some overloaded functions that provide uniform debug dump
function names.  These names are:

  debug: the general debug dumper
  debug_verbose: for more details
  debug_raw: for the gory details
  debug_head: for the heads of declarations, e.g. function heads
  debug_body: for the bodies of declarations, e.g. function bodies

Not all types have the last four versions.

The debug functions come in two flavors, those that take pointers
to the type, and those that take references to the type.  The first
handles printing of '<nil>' for null pointers.  The second assumes
a valid reference, and prints the content.


Example uses are as follows:

  cp_token t, *p;
  debug (t);
  debug (p);

From the debugger, use

  call debug (t)


The functions sets implemented are:

debug (only)

    basic_block_def, const bitmap_head_def, cp_binding_level,
    cp_parser, cp_token, data_reference, die_struct, edge_def,
    gimple_statement_d, ira_allocno, ira_allocno_copy, live_range,
    lra_live_range, omega_pb_d, pt_solution, const rtx_def, sreal,
    tree_live_info_d, _var_map,

    vec<cp_token, va_gc>, vec<data_reference_p>, vec<ddr_p>,
    vec<rtx>, vec<tree, va_gc>,

debug and debug_raw

    simple_bitmap_def

debug and debug_verbose

    expr_def, struct loop, vinsn_def

debug, debug_raw, debug_verbose, debug_head, debug_body

    const tree_node


This patch is somewhat different from the original plan at
gcc.gnu.org/wiki/cxx-conversion/debugging-dumps.  The reason
is that gdb has an incomplete implementation of C++ call syntax;
requiring explicit specification of template arguments and explicit
specification of function arguments even when they have default
values.  So, the original plan would have required typing

  call dump <cp_token> (t, 0, 0, stderr)

which is undesireable.  Instead instead of templates, we overload
plain functions.  This adds a small burden of manually adding
the pointer version of dump for each type.  Instead of default
function arguments, we simply assume the default values.  Most of
the underlying dump functions did not use the options and indent
parameters anyway.  Several provide FILE* parameters, but we expect
debugging to use stderr anyway.  So, the explicit specification of
arguments was not as valuable as we thought initially.  Finally,
a change of name from dump to debug reflect the implicit output
to stderr.


Index: gcc/ChangeLog

2013-03-28  Lawrence Crowl  <crowl@google.com>

	* Makefile.in: Add several missing include dependences.
	(DUMPFILE_H): New.
	(test-dump.o): New.  This object is not added to any executable,
	but is present for ad-hoc testing.
	* bitmap.c
	(debug (const bitmap_head_def &)): New.
	(debug (const bitmap_head_def *)): New.
	* bitmap.h
	(extern debug (const bitmap_head_def &)): New.
	(extern debug (const bitmap_head_def *)): New.
	* cfg.c
	(debug (edge_def &)): New.
	(debug (edge_def *)): New.
	* cfghooks.c
	(debug (basic_block_def &)): New.
	(debug (basic_block_def *)): New.
	* dumpfile.h
	(dump_node (const_tree, int, FILE *)): Correct source file.
	* dwarf2out.c
	(debug (die_struct &)): New.
	(debug (die_struct *)): New.
	* dwarf2out.h
	(extern debug (die_struct &)): New.
	(extern debug (die_struct *)): New.
	* gimple-pretty-print.c
	(debug (gimple_statement_d &)): New.
	(debug (gimple_statement_d *)): New.
	* gimple-pretty-print.h
	(extern debug (gimple_statement_d &)): New.
	(extern debug (gimple_statement_d *)): New.
	* ira-build.c
	(debug (ira_allocno_copy &)): New.
	(debug (ira_allocno_copy *)): New.
	(debug (ira_allocno &)): New.
	(debug (ira_allocno *)): New.
	* ira-int.h
	(extern debug (ira_allocno_copy &)): New.
	(extern debug (ira_allocno_copy *)): New.
	(extern debug (ira_allocno &)): New.
	(extern debug (ira_allocno *)): New.
	* ira-lives.c
	(debug (live_range &)): New.
	(debug (live_range *)): New.
	* lra-int.h
	(debug (lra_live_range &)): New.
	(debug (lra_live_range *)): New.
	* lra-lives.c
	(debug (lra_live_range &)): New.
	(debug (lra_live_range *)): New.
	* omega.c
	(debug (omega_pb_d &)): New.
	(debug (omega_pb_d *)): New.
	* omega.h
	(extern debug (omega_pb_d &)): New.
	(extern debug (omega_pb_d *)): New.
	* print-rtl.c
	(debug (const rtx_def &)): New.
	(debug (const rtx_def *)): New.
	* print-tree.c
	(debug_tree (tree): Move within file.
	(debug_raw (const tree_node &)): New.
	(debug_raw (const tree_node *)): New.
	(dump_tree_via_hooks (const tree_node *, int)): New.
	(debug (const tree_node &)): New.
	(debug (const tree_node *)): New.
	(debug_verbose (const tree_node &)): New.
	(debug_verbose (const tree_node *)): New.
	(debug_head (const tree_node &)): New.
	(debug_head (const tree_node *)): New.
	(debug_body (const tree_node &)): New.
	(debug_body (const tree_node *)): New.
	(debug_vec_tree (tree): Move and reimplement in terms of dump.
	(debug (vec<tree, va_gc> &)): New.
	(debug (vec<tree, va_gc> *)): New.
	* rtl.h
	(extern debug (const rtx_def &)): New.
	(extern debug (const rtx_def *)): New.
	* sbitmap.c
	(debug_raw (simple_bitmap_def &)): New.
	(debug_raw (simple_bitmap_def *)): New.
	(debug (simple_bitmap_def &)): New.
	(debug (simple_bitmap_def *)): New.
	* sbitmap.h
	(extern debug (simple_bitmap_def &)): New.
	(extern debug (simple_bitmap_def *)): New.
	(extern debug_raw (simple_bitmap_def &)): New.
	(extern debug_raw (simple_bitmap_def *)): New.
	* sel-sched-dump.c
	(debug (vinsn_def &)): New.
	(debug (vinsn_def *)): New.
	(debug_verbose (vinsn_def &)): New.
	(debug_verbose (vinsn_def *)): New.
	(debug (expr_def &)): New.
	(debug (expr_def *)): New.
	(debug_verbose (expr_def &)): New.
	(debug_verbose (expr_def *)): New.
	(debug (vec<rtx> &)): New.
	(debug (vec<rtx> *)): New.
	* sel-sched-dump.h
	(extern debug (vinsn_def &)): New.
	(extern debug (vinsn_def *)): New.
	(extern debug_verbose (vinsn_def &)): New.
	(extern debug_verbose (vinsn_def *)): New.
	(extern debug (expr_def &)): New.
	(extern debug (expr_def *)): New.
	(extern debug_verbose (expr_def &)): New.
	(extern debug_verbose (expr_def *)): New.
	(extern debug (vec<rtx> &)): New.
	(extern debug (vec<rtx> *)): New.
	* sel-sched-ir.h
	(_list_iter_cond_expr): Make inline instead of static.
	* sreal.c
	(debug (sreal &)): New.
	(debug (sreal *)): New.
	* sreal.h
	(extern debug (sreal &)): New.
	(extern debug (sreal *)): New.
	* tree.h
	(extern debug_raw (const tree_node &)): New.
	(extern debug_raw (const tree_node *)): New.
	(extern debug (const tree_node &)): New.
	(extern debug (const tree_node *)): New.
	(extern debug_verbose (const tree_node &)): New.
	(extern debug_verbose (const tree_node *)): New.
	(extern debug_head (const tree_node &)): New.
	(extern debug_head (const tree_node *)): New.
	(extern debug_body (const tree_node &)): New.
	(extern debug_body (const tree_node *)): New.
	(extern debug (vec<tree, va_gc> &)): New.
	(extern debug (vec<tree, va_gc> *)): New.
	* tree-cfg.c
	(debug (struct loop &)): New.
	(debug (struct loop *)): New.
	(debug_verbose (struct loop &)): New.
	(debug_verbose (struct loop *)): New.
	* tree-dump.c: Add header dependence.
	* tree-flow.h
	(extern debug (struct loop &)): New.
	(extern debug (struct loop *)): New.
	(extern debug_verbose (struct loop &)): New.
	(extern debug_verbose (struct loop *)): New.
	* tree-data-ref.c
	(debug (data_reference &)): New.
	(debug (data_reference *)): New.
	(debug (vec<data_reference_p> &)): New.
	(debug (vec<data_reference_p> *)): New.
	(debug (vec<ddr_p> &)): New.
	(debug (vec<ddr_p> *)): New.
	* tree-data-ref.h
	(extern debug (data_reference &)): New.
	(extern debug (data_reference *)): New.
	(extern debug (vec<data_reference_p> &)): New.
	(extern debug (vec<data_reference_p> *)): New.
	(extern debug (vec<ddr_p> &)): New.
	(extern debug (vec<ddr_p> *)): New.
	* tree-ssa-alias.c
	(debug (pt_solution &)): New.
	(debug (pt_solution *)): New.
	* tree-ssa-alias.h
	(extern debug (pt_solution &)): New.
	(extern debug (pt_solution *)): New.
	* tree-ssa-alias.c
	(debug (_var_map &)): New.
	(debug (_var_map *)): New.
	(debug (tree_live_info_d &)): New.
	(debug (tree_live_info_d *)): New.
	* tree-ssa-alias.h
	(extern debug (_var_map &)): New.
	(extern debug (_var_map *)): New.
	(extern debug (tree_live_info_d &)): New.
	(extern debug (tree_live_info_d *)): New.

Index: gcc/cp/ChangeLog

2013-03-28  Lawrence Crowl  <crowl@google.com>

	* Make-lang.in
	(CXX_PARSER_H): Add header dependence.
	* cp-tree.h
	(extern debug (cp_binding_level &)): New.
	(extern debug (cp_binding_level *)): New.
	* name-lookup.h
	(debug (cp_binding_level &)): New.
	(debug (cp_binding_level *)): New.
	* parser.c
	(debug (cp_parser &)): New.
	(debug (cp_parser *)): New.
	(debug (cp_token &)): New.
	(debug (cp_token *)): New.
	(debug (vec<cp_token, va_gc> &)): New.
	(debug (vec<cp_token, va_gc> *)): New.
	* parser.c: Add header dependence.
	(extern debug (cp_parser &)): New.
	(extern debug (cp_parser *)): New.
	(extern debug (cp_token &)): New.
	(extern debug (cp_token *)): New.
	(extern debug (vec<cp_token, va_gc> &)): New.
	(extern debug (vec<cp_token, va_gc> *)): New.

From-SVN: r197224
2013-03-29 03:42:21 +00:00

1064 lines
22 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* Instruction scheduling pass. Log dumping infrastructure.
Copyright (C) 2006-2013 Free Software Foundation, Inc.
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 "tm.h"
#include "diagnostic-core.h"
#include "rtl.h"
#include "tm_p.h"
#include "hard-reg-set.h"
#include "regs.h"
#include "function.h"
#include "flags.h"
#include "insn-config.h"
#include "insn-attr.h"
#include "params.h"
#include "basic-block.h"
#include "cselib.h"
#include "target.h"
#ifdef INSN_SCHEDULING
#include "sel-sched-ir.h"
#include "sel-sched-dump.h"
/* These variables control high-level pretty printing. */
static int sel_dump_cfg_flags = SEL_DUMP_CFG_FLAGS;
static int sel_debug_cfg_flags = SEL_DUMP_CFG_FLAGS;
/* True when a cfg should be dumped. */
static bool sel_dump_cfg_p;
/* Variables that are used to build the cfg dump file name. */
static const char * const sel_debug_cfg_root = "./";
static const char * const sel_debug_cfg_root_postfix_default = "";
static const char *sel_debug_cfg_root_postfix = "";
static int sel_dump_cfg_fileno = -1;
static int sel_debug_cfg_fileno = -1;
/* When this flag is on, we are dumping to the .dot file.
When it is off, we are dumping to log.
This is useful to differentiate formatting between log and .dot
files. */
bool sched_dump_to_dot_p = false;
/* Controls how insns from a fence list should be dumped. */
static int dump_flist_insn_flags = (DUMP_INSN_UID | DUMP_INSN_BBN
| DUMP_INSN_SEQNO);
/* The variable used to hold the value of sched_dump when temporarily
switching dump output to the other source, e.g. the .dot file. */
static FILE *saved_sched_dump = NULL;
/* Switch sched_dump to TO. It must not be called twice. */
static void
switch_dump (FILE *to)
{
gcc_assert (saved_sched_dump == NULL);
saved_sched_dump = sched_dump;
sched_dump = to;
}
/* Restore previously switched dump. */
static void
restore_dump (void)
{
sched_dump = saved_sched_dump;
saved_sched_dump = NULL;
}
/* Functions for dumping instructions, av sets, and exprs. */
/* Default flags for dumping insns. */
static int dump_insn_rtx_flags = DUMP_INSN_RTX_UID | DUMP_INSN_RTX_PATTERN;
/* Default flags for dumping vinsns. */
static int dump_vinsn_flags = (DUMP_VINSN_INSN_RTX | DUMP_VINSN_TYPE
| DUMP_VINSN_COUNT);
/* Default flags for dumping expressions. */
static int dump_expr_flags = DUMP_EXPR_ALL;
/* Default flags for dumping insns when debugging. */
static int debug_insn_rtx_flags = DUMP_INSN_RTX_ALL;
/* Default flags for dumping vinsns when debugging. */
static int debug_vinsn_flags = DUMP_VINSN_ALL;
/* Default flags for dumping expressions when debugging. */
static int debug_expr_flags = DUMP_EXPR_ALL;
/* Controls how an insn from stream should be dumped when debugging. */
static int debug_insn_flags = DUMP_INSN_ALL;
/* Print an rtx X. */
void
sel_print_rtl (rtx x)
{
print_rtl_single (sched_dump, x);
}
/* Dump insn INSN honoring FLAGS. */
void
dump_insn_rtx_1 (rtx insn, int flags)
{
int all;
/* flags == -1 also means dumping all. */
all = (flags & 1);;
if (all)
flags |= DUMP_INSN_RTX_ALL;
sel_print ("(");
if (flags & DUMP_INSN_RTX_UID)
sel_print ("%d;", INSN_UID (insn));
if (flags & DUMP_INSN_RTX_PATTERN)
sel_print ("%s;", str_pattern_slim (PATTERN (insn)));
if (flags & DUMP_INSN_RTX_BBN)
{
basic_block bb = BLOCK_FOR_INSN (insn);
sel_print ("bb:%d;", bb != NULL ? bb->index : -1);
}
sel_print (")");
}
/* Dump INSN with default flags. */
void
dump_insn_rtx (rtx insn)
{
dump_insn_rtx_1 (insn, dump_insn_rtx_flags);
}
/* Dump INSN to stderr. */
DEBUG_FUNCTION void
debug_insn_rtx (rtx insn)
{
switch_dump (stderr);
dump_insn_rtx_1 (insn, debug_insn_rtx_flags);
sel_print ("\n");
restore_dump ();
}
/* Dump vinsn VI honoring flags. */
void
dump_vinsn_1 (vinsn_t vi, int flags)
{
int all;
/* flags == -1 also means dumping all. */
all = flags & 1;
if (all)
flags |= DUMP_VINSN_ALL;
sel_print ("(");
if (flags & DUMP_VINSN_INSN_RTX)
dump_insn_rtx_1 (VINSN_INSN_RTX (vi), dump_insn_rtx_flags | all);
if (flags & DUMP_VINSN_TYPE)
sel_print ("type:%s;", GET_RTX_NAME (VINSN_TYPE (vi)));
if (flags & DUMP_VINSN_COUNT)
sel_print ("count:%d;", VINSN_COUNT (vi));
if (flags & DUMP_VINSN_COST)
{
int cost = vi->cost;
if (cost != -1)
sel_print ("cost:%d;", cost);
}
sel_print (")");
}
/* Dump vinsn VI with default flags. */
void
dump_vinsn (vinsn_t vi)
{
dump_vinsn_1 (vi, dump_vinsn_flags);
}
DEBUG_FUNCTION void
debug (vinsn_def &ref)
{
switch_dump (stderr);
dump_vinsn_1 (&ref, dump_vinsn_flags);
sel_print ("\n");
restore_dump ();
}
DEBUG_FUNCTION void
debug (vinsn_def *ptr)
{
if (ptr)
debug (*ptr);
else
fprintf (stderr, "<nil>\n");
}
DEBUG_FUNCTION void
debug_verbose (vinsn_def &ref)
{
switch_dump (stderr);
dump_vinsn_1 (&ref, debug_vinsn_flags);
sel_print ("\n");
restore_dump ();
}
DEBUG_FUNCTION void
debug_verbose (vinsn_def *ptr)
{
if (ptr)
debug (*ptr);
else
fprintf (stderr, "<nil>\n");
}
/* Dump vinsn VI to stderr. */
DEBUG_FUNCTION void
debug_vinsn (vinsn_t vi)
{
switch_dump (stderr);
dump_vinsn_1 (vi, debug_vinsn_flags);
sel_print ("\n");
restore_dump ();
}
/* Dump EXPR honoring flags. */
void
dump_expr_1 (expr_t expr, int flags)
{
int all;
/* flags == -1 also means dumping all. */
all = flags & 1;
if (all)
flags |= DUMP_EXPR_ALL;
sel_print ("[");
if (flags & DUMP_EXPR_VINSN)
dump_vinsn_1 (EXPR_VINSN (expr), dump_vinsn_flags | all);
if (flags & DUMP_EXPR_SPEC)
{
int spec = EXPR_SPEC (expr);
if (spec != 0)
sel_print ("spec:%d;", spec);
}
if (flags & DUMP_EXPR_USEFULNESS)
{
int use = EXPR_USEFULNESS (expr);
if (use != REG_BR_PROB_BASE)
sel_print ("use:%d;", use);
}
if (flags & DUMP_EXPR_PRIORITY)
sel_print ("prio:%d;", EXPR_PRIORITY (expr));
if (flags & DUMP_EXPR_SCHED_TIMES)
{
int times = EXPR_SCHED_TIMES (expr);
if (times != 0)
sel_print ("times:%d;", times);
}
if (flags & DUMP_EXPR_SPEC_DONE_DS)
{
ds_t spec_done_ds = EXPR_SPEC_DONE_DS (expr);
if (spec_done_ds != 0)
sel_print ("ds:%d;", spec_done_ds);
}
if (flags & DUMP_EXPR_ORIG_BB)
{
int orig_bb = EXPR_ORIG_BB_INDEX (expr);
if (orig_bb != 0)
sel_print ("orig_bb:%d;", orig_bb);
}
if (EXPR_TARGET_AVAILABLE (expr) < 1)
sel_print ("target:%d;", EXPR_TARGET_AVAILABLE (expr));
sel_print ("]");
}
/* Dump expression EXPR with default flags. */
void
dump_expr (expr_t expr)
{
dump_expr_1 (expr, dump_expr_flags);
}
/* Dump expression EXPR to stderr. */
DEBUG_FUNCTION void
debug_expr (expr_t expr)
{
switch_dump (stderr);
dump_expr_1 (expr, debug_expr_flags);
sel_print ("\n");
restore_dump ();
}
/* Dump expression REF. */
DEBUG_FUNCTION void
debug (expr_def &ref)
{
switch_dump (stderr);
dump_expr_1 (&ref, 0);
sel_print ("\n");
restore_dump ();
}
DEBUG_FUNCTION void
debug (expr_def *ptr)
{
if (ptr)
debug (*ptr);
else
fprintf (stderr, "<nil>\n");
}
/* Dump expression REF verbosely. */
DEBUG_FUNCTION void
debug_verbose (expr_def &ref)
{
switch_dump (stderr);
dump_expr_1 (&ref, DUMP_EXPR_ALL);
sel_print ("\n");
restore_dump ();
}
DEBUG_FUNCTION void
debug_verbose (expr_def *ptr)
{
if (ptr)
debug_verbose (*ptr);
else
fprintf (stderr, "<nil>\n");
}
/* Dump insn I honoring FLAGS. */
void
dump_insn_1 (insn_t i, int flags)
{
int all;
all = flags & 1;
if (all)
flags |= DUMP_INSN_ALL;
if (!sched_dump_to_dot_p)
sel_print ("(");
if (flags & DUMP_INSN_EXPR)
{
dump_expr_1 (INSN_EXPR (i), dump_expr_flags | all);
sel_print (";");
}
else if (flags & DUMP_INSN_PATTERN)
{
dump_insn_rtx_1 (i, DUMP_INSN_RTX_PATTERN | all);
sel_print (";");
}
else if (flags & DUMP_INSN_UID)
sel_print ("uid:%d;", INSN_UID (i));
if (flags & DUMP_INSN_SEQNO)
sel_print ("seqno:%d;", INSN_SEQNO (i));
if (flags & DUMP_INSN_SCHED_CYCLE)
{
int cycle = INSN_SCHED_CYCLE (i);
if (cycle != 0)
sel_print ("cycle:%d;", cycle);
}
if (!sched_dump_to_dot_p)
sel_print (")");
}
/* Dump insn I with default flags. */
void
dump_insn (insn_t i)
{
dump_insn_1 (i, DUMP_INSN_EXPR | DUMP_INSN_SCHED_CYCLE);
}
/* Dump INSN to stderr. */
DEBUG_FUNCTION void
debug_insn (insn_t insn)
{
switch_dump (stderr);
dump_insn_1 (insn, debug_insn_flags);
sel_print ("\n");
restore_dump ();
}
/* Dumps av_set AV. */
void
dump_av_set (av_set_t av)
{
av_set_iterator i;
expr_t expr;
if (!sched_dump_to_dot_p)
sel_print ("{");
FOR_EACH_EXPR (expr, i, av)
{
dump_expr (expr);
if (!sched_dump_to_dot_p)
sel_print (" ");
else
sel_print ("\n");
}
if (!sched_dump_to_dot_p)
sel_print ("}");
}
/* Dumps lvset LV. */
void
dump_lv_set (regset lv)
{
sel_print ("{");
/* This code was adapted from cfg.c: dump_regset (). */
if (lv == NULL)
sel_print ("nil");
else
{
unsigned i;
reg_set_iterator rsi;
int count = 0;
EXECUTE_IF_SET_IN_REG_SET (lv, 0, i, rsi)
{
sel_print (" %d", i);
if (i < FIRST_PSEUDO_REGISTER)
{
sel_print (" [%s]", reg_names[i]);
++count;
}
++count;
if (sched_dump_to_dot_p && count == 12)
{
count = 0;
sel_print ("\n");
}
}
}
sel_print ("}\n");
}
/* Dumps a list of instructions pointed to by P. */
static void
dump_ilist (ilist_t p)
{
while (p)
{
dump_insn (ILIST_INSN (p));
p = ILIST_NEXT (p);
}
}
/* Dumps a list of boundaries pointed to by BNDS. */
void
dump_blist (blist_t bnds)
{
for (; bnds; bnds = BLIST_NEXT (bnds))
{
bnd_t bnd = BLIST_BND (bnds);
sel_print ("[to: %d; ptr: ", INSN_UID (BND_TO (bnd)));
dump_ilist (BND_PTR (bnd));
sel_print ("] ");
}
}
/* Dumps a list of fences pointed to by L. */
void
dump_flist (flist_t l)
{
while (l)
{
dump_insn_1 (FENCE_INSN (FLIST_FENCE (l)), dump_flist_insn_flags);
sel_print (" ");
l = FLIST_NEXT (l);
}
}
/* Dumps an insn vector SUCCS. */
void
dump_insn_vector (rtx_vec_t succs)
{
int i;
rtx succ;
FOR_EACH_VEC_ELT (succs, i, succ)
if (succ)
dump_insn (succ);
else
sel_print ("NULL ");
}
/* Dumps a hard reg set SET to FILE using PREFIX. */
static void
print_hard_reg_set (FILE *file, const char *prefix, HARD_REG_SET set)
{
int i;
fprintf (file, "%s{ ", prefix);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
if (TEST_HARD_REG_BIT (set, i))
fprintf (file, "%d ", i);
}
fprintf (file, "}\n");
}
/* Dumps a hard reg set SET using PREFIX. */
void
dump_hard_reg_set (const char *prefix, HARD_REG_SET set)
{
print_hard_reg_set (sched_dump, prefix, set);
}
/* Pretty print INSN. This is used as a hook. */
const char *
sel_print_insn (const_rtx insn, int aligned ATTRIBUTE_UNUSED)
{
static char buf[80];
/* '+' before insn means it is a new cycle start and it's not been
scheduled yet. '>' - has been scheduled. */
if (s_i_d.exists () && INSN_LUID (insn) > 0)
if (GET_MODE (insn) == TImode)
sprintf (buf, "%s %4d",
INSN_SCHED_TIMES (insn) > 0 ? "> " : "< ",
INSN_UID (insn));
else
sprintf (buf, "%s %4d",
INSN_SCHED_TIMES (insn) > 0 ? "! " : " ",
INSN_UID (insn));
else
if (GET_MODE (insn) == TImode)
sprintf (buf, "+ %4d", INSN_UID (insn));
else
sprintf (buf, " %4d", INSN_UID (insn));
return buf;
}
/* Functions for pretty printing of CFG. */
/* FIXME: Using pretty-print here could simplify this stuff. */
/* Replace all occurencies of STR1 to STR2 in BUF.
The BUF must be large enough to hold the result. */
static void
replace_str_in_buf (char *buf, const char *str1, const char *str2)
{
int buf_len = strlen (buf);
int str1_len = strlen (str1);
int str2_len = strlen (str2);
int diff = str2_len - str1_len;
char *p = buf;
do
{
p = strstr (p, str1);
if (p)
{
char *p1 = p + str1_len;
/* Copy the rest of buf and '\0'. */
int n = buf + buf_len - p1;
int i;
/* Shift str by DIFF chars. */
if (diff > 0)
for (i = n; i >= 0; i--)
p1[i + diff] = p1[i];
else
for (i = 0; i <= n; i++)
p1[i + diff] = p1[i];
/* Copy str2. */
for (i = 0; i < str2_len; i++)
p[i] = str2[i];
p += str2_len;
buf_len += diff;
}
}
while (p);
}
/* Replace characters in BUF that have special meaning in .dot file.
Similar to pp_write_text_as_dot_label_to_stream. */
static void
sel_prepare_string_for_dot_label (char *buf)
{
static char specials_from[7][2] = { "<", ">", "{", "|", "}", "\"",
"\n" };
static char specials_to[7][3] = { "\\<", "\\>", "\\{", "\\|", "\\}",
"\\\"", "\\l" };
unsigned i;
for (i = 0; i < 7; i++)
replace_str_in_buf (buf, specials_from[i], specials_to[i]);
}
/* This function acts like printf but dumps to the sched_dump file. */
void
sel_print (const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
if (sched_dump_to_dot_p)
{
char *message;
if (vasprintf (&message, fmt, ap) >= 0 && message != NULL)
{
message = (char *) xrealloc (message, 2 * strlen (message) + 1);
sel_prepare_string_for_dot_label (message);
fprintf (sched_dump, "%s", message);
free (message);
}
}
else
vfprintf (sched_dump, fmt, ap);
va_end (ap);
}
/* Dump INSN with FLAGS. */
static void
sel_dump_cfg_insn (insn_t insn, int flags)
{
int insn_flags = DUMP_INSN_UID | DUMP_INSN_PATTERN;
if (sched_luids.exists () && INSN_LUID (insn) > 0)
{
if (flags & SEL_DUMP_CFG_INSN_SEQNO)
insn_flags |= DUMP_INSN_SEQNO | DUMP_INSN_SCHED_CYCLE | DUMP_INSN_EXPR;
}
dump_insn_1 (insn, insn_flags);
}
/* Dump E to the dot file F. */
static void
sel_dump_cfg_edge (FILE *f, edge e)
{
int w;
const char *color;
if (e->flags & EDGE_FALLTHRU)
{
w = 10;
color = ", color = red";
}
else if (e->src->next_bb == e->dest)
{
w = 3;
color = ", color = blue";
}
else
{
w = 1;
color = "";
}
fprintf (f, "\tbb%d -> bb%d [weight = %d%s];\n",
e->src->index, e->dest->index, w, color);
}
/* Return true if BB has a predesessor from current region.
TODO: Either make this function to trace back through empty block
or just remove those empty blocks. */
static bool
has_preds_in_current_region_p (basic_block bb)
{
edge e;
edge_iterator ei;
gcc_assert (!in_current_region_p (bb));
FOR_EACH_EDGE (e, ei, bb->preds)
if (in_current_region_p (e->src))
return true;
return false;
}
/* Dump a cfg region to the dot file F honoring FLAGS. */
static void
sel_dump_cfg_2 (FILE *f, int flags)
{
basic_block bb;
sched_dump_to_dot_p = true;
switch_dump (f);
fprintf (f, "digraph G {\n"
"\tratio = 2.25;\n"
"\tnode [shape = record, fontsize = 9];\n");
if (flags & SEL_DUMP_CFG_FUNCTION_NAME)
fprintf (f, "function [label = \"%s\"];\n", current_function_name ());
FOR_EACH_BB (bb)
{
insn_t insn = BB_HEAD (bb);
insn_t next_tail = NEXT_INSN (BB_END (bb));
edge e;
edge_iterator ei;
bool in_region_p = ((flags & SEL_DUMP_CFG_CURRENT_REGION)
&& in_current_region_p (bb));
bool full_p = (!(flags & SEL_DUMP_CFG_CURRENT_REGION)
|| in_region_p);
bool some_p = full_p || has_preds_in_current_region_p (bb);
const char *color;
const char *style;
if (!some_p)
continue;
if ((flags & SEL_DUMP_CFG_CURRENT_REGION)
&& in_current_region_p (bb)
&& BLOCK_TO_BB (bb->index) == 0)
color = "color = green, ";
else
color = "";
if ((flags & SEL_DUMP_CFG_FENCES)
&& in_region_p)
{
style = "";
if (!sel_bb_empty_p (bb))
{
bool first_p = true;
insn_t tail = BB_END (bb);
insn_t cur_insn;
cur_insn = bb_note (bb);
do
{
fence_t fence;
cur_insn = NEXT_INSN (cur_insn);
fence = flist_lookup (fences, cur_insn);
if (fence != NULL)
{
if (!FENCE_SCHEDULED_P (fence))
{
if (first_p)
color = "color = red, ";
else
color = "color = yellow, ";
}
else
color = "color = blue, ";
}
first_p = false;
}
while (cur_insn != tail);
}
}
else if (!full_p)
style = "style = dashed, ";
else
style = "";
fprintf (f, "\tbb%d [%s%slabel = \"{Basic block %d", bb->index,
style, color, bb->index);
if ((flags & SEL_DUMP_CFG_BB_LOOP)
&& bb->loop_father != NULL)
fprintf (f, ", loop %d", bb->loop_father->num);
if (full_p
&& (flags & SEL_DUMP_CFG_BB_NOTES_LIST))
{
insn_t notes = BB_NOTE_LIST (bb);
if (notes != NULL_RTX)
{
fprintf (f, "|");
/* For simplicity, we dump notes from note_list in reversed order
to that what they will appear in the code. */
while (notes != NULL_RTX)
{
sel_dump_cfg_insn (notes, flags);
fprintf (f, "\\l");
notes = PREV_INSN (notes);
}
}
}
if (full_p
&& (flags & SEL_DUMP_CFG_AV_SET)
&& in_current_region_p (bb)
&& !sel_bb_empty_p (bb))
{
fprintf (f, "|");
if (BB_AV_SET_VALID_P (bb))
dump_av_set (BB_AV_SET (bb));
else if (BB_AV_LEVEL (bb) == -1)
fprintf (f, "AV_SET needs update");
}
if ((flags & SEL_DUMP_CFG_LV_SET)
&& !sel_bb_empty_p (bb))
{
fprintf (f, "|");
if (BB_LV_SET_VALID_P (bb))
dump_lv_set (BB_LV_SET (bb));
else
fprintf (f, "LV_SET needs update");
}
if (full_p
&& (flags & SEL_DUMP_CFG_BB_INSNS))
{
fprintf (f, "|");
while (insn != next_tail)
{
sel_dump_cfg_insn (insn, flags);
fprintf (f, "\\l");
insn = NEXT_INSN (insn);
}
}
fprintf (f, "}\"];\n");
FOR_EACH_EDGE (e, ei, bb->succs)
if (full_p || in_current_region_p (e->dest))
sel_dump_cfg_edge (f, e);
}
fprintf (f, "}");
restore_dump ();
sched_dump_to_dot_p = false;
}
/* Dump a cfg region to the file specified by TAG honoring flags.
The file is created by the function. */
static void
sel_dump_cfg_1 (const char *tag, int flags)
{
char *buf;
int i;
FILE *f;
++sel_dump_cfg_fileno;
if (!sel_dump_cfg_p)
return;
i = 1 + snprintf (NULL, 0, "%s/%s%05d-%s.dot", sel_debug_cfg_root,
sel_debug_cfg_root_postfix, sel_dump_cfg_fileno, tag);
buf = XNEWVEC (char, i);
snprintf (buf, i, "%s/%s%05d-%s.dot", sel_debug_cfg_root,
sel_debug_cfg_root_postfix, sel_dump_cfg_fileno, tag);
f = fopen (buf, "w");
if (f == NULL)
fprintf (stderr, "Can't create file: %s.\n", buf);
else
{
sel_dump_cfg_2 (f, flags);
fclose (f);
}
free (buf);
}
/* Setup cfg dumping flags. Used for debugging. */
void
setup_dump_cfg_params (void)
{
sel_dump_cfg_flags = SEL_DUMP_CFG_FLAGS;
sel_dump_cfg_p = 0;
sel_debug_cfg_root_postfix = sel_debug_cfg_root_postfix_default;
}
/* Debug a cfg region with FLAGS. */
void
sel_debug_cfg_1 (int flags)
{
bool t1 = sel_dump_cfg_p;
int t2 = sel_dump_cfg_fileno;
sel_dump_cfg_p = true;
sel_dump_cfg_fileno = ++sel_debug_cfg_fileno;
sel_dump_cfg_1 ("sel-debug-cfg", flags);
sel_dump_cfg_fileno = t2;
sel_dump_cfg_p = t1;
}
/* Dumps av_set AV to stderr. */
DEBUG_FUNCTION void
debug_av_set (av_set_t av)
{
switch_dump (stderr);
dump_av_set (av);
sel_print ("\n");
restore_dump ();
}
/* Dump LV to stderr. */
DEBUG_FUNCTION void
debug_lv_set (regset lv)
{
switch_dump (stderr);
dump_lv_set (lv);
sel_print ("\n");
restore_dump ();
}
/* Dump an instruction list P to stderr. */
DEBUG_FUNCTION void
debug_ilist (ilist_t p)
{
switch_dump (stderr);
dump_ilist (p);
sel_print ("\n");
restore_dump ();
}
/* Dump a boundary list BNDS to stderr. */
DEBUG_FUNCTION void
debug_blist (blist_t bnds)
{
switch_dump (stderr);
dump_blist (bnds);
sel_print ("\n");
restore_dump ();
}
/* Dump a rtx vector REF. */
DEBUG_FUNCTION void
debug (vec<rtx> &ref)
{
switch_dump (stderr);
dump_insn_vector (ref);
sel_print ("\n");
restore_dump ();
}
DEBUG_FUNCTION void
debug (vec<rtx> *ptr)
{
if (ptr)
debug (*ptr);
else
fprintf (stderr, "<nil>\n");
}
/* Dump an insn vector SUCCS. */
DEBUG_FUNCTION void
debug_insn_vector (rtx_vec_t succs)
{
switch_dump (stderr);
dump_insn_vector (succs);
sel_print ("\n");
restore_dump ();
}
/* Dump a hard reg set SET to stderr. */
DEBUG_FUNCTION void
debug_hard_reg_set (HARD_REG_SET set)
{
switch_dump (stderr);
dump_hard_reg_set ("", set);
sel_print ("\n");
restore_dump ();
}
/* Debug a cfg region with default flags. */
void
sel_debug_cfg (void)
{
sel_debug_cfg_1 (sel_debug_cfg_flags);
}
/* Print a current cselib value for X's address to stderr. */
DEBUG_FUNCTION rtx
debug_mem_addr_value (rtx x)
{
rtx t, addr;
enum machine_mode address_mode;
gcc_assert (MEM_P (x));
address_mode = get_address_mode (x);
t = shallow_copy_rtx (x);
if (cselib_lookup (XEXP (t, 0), address_mode, 0, GET_MODE (t)))
XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0), GET_MODE (t));
t = canon_rtx (t);
addr = get_addr (XEXP (t, 0));
debug_rtx (t);
debug_rtx (addr);
return t;
}
#endif