
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
1064 lines
22 KiB
C
1064 lines
22 KiB
C
/* 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
|
||
|