-/* Instruction scheduling pass.
- Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
+/* Printing of RTL in "slim", mnemonic like form.
+ Copyright (C) 1992-2015 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com) Enhanced by,
and currently maintained by, Jim Wilson (wilson@cygnus.com)
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 2, or (at your option) any later
+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
for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+/* Historically this form of RTL dumping was introduced along with
+ the Haifa instruction scheduling pass, hence the name of this file.
+ But there is nothing in this file left that is scheduler-specific. */
\f
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
-#include "toplev.h"
#include "rtl.h"
-#include "tm_p.h"
-#include "regs.h"
+#include "alias.h"
+#include "symtab.h"
+#include "tree.h" /* FIXME: To dump INSN_VAR_LOCATION_DECL. */
+#include "predict.h"
#include "hard-reg-set.h"
+#include "function.h"
+#include "dominance.h"
+#include "cfg.h"
#include "basic-block.h"
-#include "insn-attr.h"
-#include "real.h"
-#include "sched-int.h"
-#include "target.h"
-
-#ifdef INSN_SCHEDULING
-/* target_units bitmask has 1 for each unit in the cpu. It should be
- possible to compute this variable from the machine description.
- But currently it is computed by examining the insn list. Since
- this is only needed for visualization, it seems an acceptable
- solution. (For understanding the mapping of bits to units, see
- definition of function_units[] in "insn-attrtab.c".) The scheduler
- using only DFA description should never use the following variable. */
-
-static int target_units = 0;
-
-static char *safe_concat (char *, char *, const char *);
-static int get_visual_tbl_length (void);
-static void print_exp (char *, rtx, int);
-static void print_value (char *, rtx, int);
-static void print_pattern (char *, rtx, int);
-
-/* Print names of units on which insn can/should execute, for debugging. */
-
-void
-insn_print_units (rtx insn)
-{
- int i;
- int unit = insn_unit (insn);
-
- if (unit == -1)
- fprintf (sched_dump, "none");
- else if (unit >= 0)
- fprintf (sched_dump, "%s", function_units[unit].name);
- else
- {
- fprintf (sched_dump, "[");
- for (i = 0, unit = ~unit; unit; i++, unit >>= 1)
- if (unit & 1)
- {
- fprintf (sched_dump, "%s", function_units[i].name);
- if (unit != 1)
- fprintf (sched_dump, " ");
- }
- fprintf (sched_dump, "]");
- }
-}
-
-/* MAX_VISUAL_LINES is the maximum number of lines in visualization table
- of a basic block. If more lines are needed, table is split to two.
- n_visual_lines is the number of lines printed so far for a block.
- visual_tbl contains the block visualization info.
- vis_no_unit holds insns in a cycle that are not mapped to any unit. */
-#define MAX_VISUAL_LINES 100
-#define INSN_LEN 30
-int n_visual_lines;
-static unsigned visual_tbl_line_length;
-char *visual_tbl;
-int n_vis_no_unit;
-#define MAX_VISUAL_NO_UNIT 20
-rtx vis_no_unit[MAX_VISUAL_NO_UNIT];
-
-/* Finds units that are in use in this function. Required only
- for visualization. */
-
-void
-init_target_units (void)
-{
- rtx insn;
- int unit;
-
- for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
- {
- if (! INSN_P (insn))
- continue;
-
- unit = insn_unit (insn);
-
- if (unit < 0)
- target_units |= ~unit;
- else
- target_units |= (1 << unit);
- }
-}
-
-/* Return the length of the visualization table. */
-
-static int
-get_visual_tbl_length (void)
-{
- int unit, i;
- int n, n1;
- char *s;
-
- if (targetm.sched.use_dfa_pipeline_interface
- && (*targetm.sched.use_dfa_pipeline_interface) ())
- {
- visual_tbl_line_length = 1;
- return 1; /* Can't return 0 because that will cause problems
- with alloca. */
- }
-
- /* Compute length of one field in line. */
- s = alloca (INSN_LEN + 6);
- sprintf (s, " %33s", "uname");
- n1 = strlen (s);
-
- /* Compute length of one line. */
- n = strlen (";; ");
- n += n1;
- for (unit = 0; unit < FUNCTION_UNITS_SIZE; unit++)
- if (function_units[unit].bitmask & target_units)
- for (i = 0; i < function_units[unit].multiplicity; i++)
- n += n1;
- n += n1;
- n += strlen ("\n") + 2;
-
- visual_tbl_line_length = n;
-
- /* Compute length of visualization string. */
- return (MAX_VISUAL_LINES * n);
-}
-
-/* Init block visualization debugging info. */
-
-void
-init_block_visualization (void)
-{
- strcpy (visual_tbl, "");
- n_visual_lines = 0;
- n_vis_no_unit = 0;
-}
-
-#define BUF_LEN 2048
-
-static char *
-safe_concat (char *buf, char *cur, const char *str)
-{
- char *end = buf + BUF_LEN - 2; /* Leave room for null. */
- int c;
-
- if (cur > end)
- {
- *end = '\0';
- return end;
- }
-
- while (cur < end && (c = *str++) != '\0')
- *cur++ = c;
-
- *cur = '\0';
- return cur;
-}
-
-/* This recognizes rtx, I classified as expressions. These are always
+#include "dumpfile.h" /* for the TDF_* flags */
+#include "pretty-print.h"
+
+/* The functions in this file try to print RTL in a form resembling assembler
+ mnemonics. Because this form is more concise than the "traditional" form
+ of RTL printing in Lisp-style, the form printed by this file is called
+ "slim". RTL dumps in slim format can be obtained by appending the "-slim"
+ option to -fdump-rtl-<pass>. Control flow graph output as a DOT file is
+ always printed in slim form.
+
+ The normal interface to the functionality provided in this pretty-printer
+ is through the dump_*_slim functions to print to a stream, or via the
+ print_*_slim functions to print into a user's pretty-printer.
+
+ It is also possible to obtain a string for a single pattern as a string
+ pointer, via str_pattern_slim, but this usage is discouraged. */
+
+/* For insns we print patterns, and for some patterns we print insns... */
+static void print_insn_with_notes (pretty_printer *, const rtx_insn *);
+
+/* This recognizes rtx'en classified as expressions. These are always
represent some action on values or results of other expression, that
may be stored in objects representing values. */
static void
-print_exp (char *buf, rtx x, int verbose)
+print_exp (pretty_printer *pp, const_rtx x, int verbose)
{
- char tmp[BUF_LEN];
const char *st[4];
- char *cur = buf;
- const char *fun = (char *) 0;
- const char *sep;
+ const char *fun;
rtx op[4];
int i;
+ fun = (char *) 0;
for (i = 0; i < 4; i++)
{
st[i] = (char *) 0;
{
case PLUS:
op[0] = XEXP (x, 0);
- if (GET_CODE (XEXP (x, 1)) == CONST_INT
+ if (CONST_INT_P (XEXP (x, 1))
&& INTVAL (XEXP (x, 1)) < 0)
{
st[1] = "-";
st[0] = "-";
op[0] = XEXP (x, 0);
break;
+ case FMA:
+ st[0] = "{";
+ op[0] = XEXP (x, 0);
+ st[1] = "*";
+ op[1] = XEXP (x, 1);
+ st[2] = "+";
+ op[2] = XEXP (x, 2);
+ st[3] = "}";
+ break;
case MULT:
op[0] = XEXP (x, 0);
st[1] = "*";
st[1] = ">->";
op[1] = XEXP (x, 1);
break;
- case ABS:
- fun = "abs";
- op[0] = XEXP (x, 0);
- break;
- case SQRT:
- fun = "sqrt";
- op[0] = XEXP (x, 0);
- break;
- case FFS:
- fun = "ffs";
- op[0] = XEXP (x, 0);
- break;
- case EQ:
- op[0] = XEXP (x, 0);
- st[1] = "==";
- op[1] = XEXP (x, 1);
- break;
case NE:
op[0] = XEXP (x, 0);
st[1] = "!=";
op[1] = XEXP (x, 1);
break;
- case GT:
- op[0] = XEXP (x, 0);
- st[1] = ">";
- op[1] = XEXP (x, 1);
- break;
- case GTU:
- fun = "gtu";
- op[0] = XEXP (x, 0);
- op[1] = XEXP (x, 1);
- break;
- case LT:
- op[0] = XEXP (x, 0);
- st[1] = "<";
- op[1] = XEXP (x, 1);
- break;
- case LTU:
- fun = "ltu";
+ case EQ:
op[0] = XEXP (x, 0);
+ st[1] = "==";
op[1] = XEXP (x, 1);
break;
case GE:
st[1] = ">=";
op[1] = XEXP (x, 1);
break;
- case GEU:
- fun = "geu";
+ case GT:
op[0] = XEXP (x, 0);
+ st[1] = ">";
op[1] = XEXP (x, 1);
break;
case LE:
st[1] = "<=";
op[1] = XEXP (x, 1);
break;
- case LEU:
- fun = "leu";
+ case LT:
op[0] = XEXP (x, 0);
+ st[1] = "<";
op[1] = XEXP (x, 1);
break;
case SIGN_EXTRACT:
op[0] = XEXP (x, 0);
st[1] = "++";
break;
+ case PRE_MODIFY:
+ st[0] = "pre ";
+ op[0] = XEXP (XEXP (x, 1), 0);
+ st[1] = "+=";
+ op[1] = XEXP (XEXP (x, 1), 1);
+ break;
+ case POST_MODIFY:
+ st[0] = "post ";
+ op[0] = XEXP (XEXP (x, 1), 0);
+ st[1] = "+=";
+ op[1] = XEXP (XEXP (x, 1), 1);
+ break;
case CALL:
st[0] = "call ";
op[0] = XEXP (x, 0);
case UNSPEC:
case UNSPEC_VOLATILE:
{
- cur = safe_concat (buf, cur, "unspec");
+ pp_string (pp, "unspec");
if (GET_CODE (x) == UNSPEC_VOLATILE)
- cur = safe_concat (buf, cur, "/v");
- cur = safe_concat (buf, cur, "[");
- sep = "";
+ pp_string (pp, "/v");
+ pp_left_bracket (pp);
for (i = 0; i < XVECLEN (x, 0); i++)
{
- print_pattern (tmp, XVECEXP (x, 0, i), verbose);
- cur = safe_concat (buf, cur, sep);
- cur = safe_concat (buf, cur, tmp);
- sep = ",";
+ if (i != 0)
+ pp_comma (pp);
+ print_pattern (pp, XVECEXP (x, 0, i), verbose);
}
- cur = safe_concat (buf, cur, "] ");
- sprintf (tmp, "%d", XINT (x, 1));
- cur = safe_concat (buf, cur, tmp);
+ pp_string (pp, "] ");
+ pp_decimal_int (pp, XINT (x, 1));
}
break;
default:
- /* If (verbose) debug_rtx (x); */
- st[0] = GET_RTX_NAME (GET_CODE (x));
+ {
+ /* Most unhandled codes can be printed as pseudo-functions. */
+ if (GET_RTX_CLASS (GET_CODE (x)) == RTX_UNARY)
+ {
+ fun = GET_RTX_NAME (GET_CODE (x));
+ op[0] = XEXP (x, 0);
+ }
+ else if (GET_RTX_CLASS (GET_CODE (x)) == RTX_COMPARE
+ || GET_RTX_CLASS (GET_CODE (x)) == RTX_COMM_COMPARE
+ || GET_RTX_CLASS (GET_CODE (x)) == RTX_BIN_ARITH
+ || GET_RTX_CLASS (GET_CODE (x)) == RTX_COMM_ARITH)
+ {
+ fun = GET_RTX_NAME (GET_CODE (x));
+ op[0] = XEXP (x, 0);
+ op[1] = XEXP (x, 1);
+ }
+ else if (GET_RTX_CLASS (GET_CODE (x)) == RTX_TERNARY)
+ {
+ fun = GET_RTX_NAME (GET_CODE (x));
+ op[0] = XEXP (x, 0);
+ op[1] = XEXP (x, 1);
+ op[2] = XEXP (x, 2);
+ }
+ else
+ /* Give up, just print the RTX name. */
+ st[0] = GET_RTX_NAME (GET_CODE (x));
+ }
break;
}
/* Print this as a function? */
if (fun)
{
- cur = safe_concat (buf, cur, fun);
- cur = safe_concat (buf, cur, "(");
+ pp_string (pp, fun);
+ pp_left_paren (pp);
}
for (i = 0; i < 4; i++)
{
if (st[i])
- cur = safe_concat (buf, cur, st[i]);
+ pp_string (pp, st[i]);
if (op[i])
{
if (fun && i != 0)
- cur = safe_concat (buf, cur, ",");
-
- print_value (tmp, op[i], verbose);
- cur = safe_concat (buf, cur, tmp);
+ pp_comma (pp);
+ print_value (pp, op[i], verbose);
}
}
if (fun)
- cur = safe_concat (buf, cur, ")");
+ pp_right_paren (pp);
} /* print_exp */
/* Prints rtxes, I customarily classified as values. They're constants,
registers, labels, symbols and memory accesses. */
-static void
-print_value (char *buf, rtx x, int verbose)
+void
+print_value (pretty_printer *pp, const_rtx x, int verbose)
{
- char t[BUF_LEN];
- char *cur = buf;
+ char tmp[1024];
+ if (!x)
+ {
+ pp_string (pp, "(nil)");
+ return;
+ }
switch (GET_CODE (x))
{
case CONST_INT:
- sprintf (t, HOST_WIDE_INT_PRINT_HEX, INTVAL (x));
- cur = safe_concat (buf, cur, t);
+ pp_scalar (pp, HOST_WIDE_INT_PRINT_HEX,
+ (unsigned HOST_WIDE_INT) INTVAL (x));
break;
+
+ case CONST_WIDE_INT:
+ {
+ const char *sep = "<";
+ int i;
+ for (i = CONST_WIDE_INT_NUNITS (x) - 1; i >= 0; i--)
+ {
+ pp_string (pp, sep);
+ sep = ",";
+ sprintf (tmp, HOST_WIDE_INT_PRINT_HEX,
+ (unsigned HOST_WIDE_INT) CONST_WIDE_INT_ELT (x, i));
+ pp_string (pp, tmp);
+ }
+ pp_greater (pp);
+ }
+ break;
+
case CONST_DOUBLE:
if (FLOAT_MODE_P (GET_MODE (x)))
- real_to_decimal (t, CONST_DOUBLE_REAL_VALUE (x), sizeof (t), 0, 1);
+ {
+ real_to_decimal (tmp, CONST_DOUBLE_REAL_VALUE (x),
+ sizeof (tmp), 0, 1);
+ pp_string (pp, tmp);
+ }
else
- sprintf (t, "<0x%lx,0x%lx>", (long) XWINT (x, 2), (long) XWINT (x, 3));
- cur = safe_concat (buf, cur, t);
+ pp_printf (pp, "<%wx,%wx>",
+ (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (x),
+ (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (x));
+ break;
+ case CONST_FIXED:
+ fixed_to_decimal (tmp, CONST_FIXED_VALUE (x), sizeof (tmp));
+ pp_string (pp, tmp);
break;
case CONST_STRING:
- cur = safe_concat (buf, cur, "\"");
- cur = safe_concat (buf, cur, XSTR (x, 0));
- cur = safe_concat (buf, cur, "\"");
+ pp_printf (pp, "\"%s\"", XSTR (x, 0));
break;
case SYMBOL_REF:
- cur = safe_concat (buf, cur, "`");
- cur = safe_concat (buf, cur, XSTR (x, 0));
- cur = safe_concat (buf, cur, "'");
+ pp_printf (pp, "`%s'", XSTR (x, 0));
break;
case LABEL_REF:
- sprintf (t, "L%d", INSN_UID (XEXP (x, 0)));
- cur = safe_concat (buf, cur, t);
+ pp_printf (pp, "L%d", INSN_UID (LABEL_REF_LABEL (x)));
break;
case CONST:
- print_value (t, XEXP (x, 0), verbose);
- cur = safe_concat (buf, cur, "const(");
- cur = safe_concat (buf, cur, t);
- cur = safe_concat (buf, cur, ")");
- break;
case HIGH:
- print_value (t, XEXP (x, 0), verbose);
- cur = safe_concat (buf, cur, "high(");
- cur = safe_concat (buf, cur, t);
- cur = safe_concat (buf, cur, ")");
+ case STRICT_LOW_PART:
+ pp_printf (pp, "%s(", GET_RTX_NAME (GET_CODE (x)));
+ print_value (pp, XEXP (x, 0), verbose);
+ pp_right_paren (pp);
break;
case REG:
if (REGNO (x) < FIRST_PSEUDO_REGISTER)
{
- int c = reg_names[REGNO (x)][0];
- if (ISDIGIT (c))
- cur = safe_concat (buf, cur, "%");
-
- cur = safe_concat (buf, cur, reg_names[REGNO (x)]);
+ if (ISDIGIT (reg_names[REGNO (x)][0]))
+ pp_modulo (pp);
+ pp_string (pp, reg_names[REGNO (x)]);
}
else
- {
- sprintf (t, "r%d", REGNO (x));
- cur = safe_concat (buf, cur, t);
- }
+ pp_printf (pp, "r%d", REGNO (x));
+ if (verbose)
+ pp_printf (pp, ":%s", GET_MODE_NAME (GET_MODE (x)));
break;
case SUBREG:
- print_value (t, SUBREG_REG (x), verbose);
- cur = safe_concat (buf, cur, t);
- sprintf (t, "#%d", SUBREG_BYTE (x));
- cur = safe_concat (buf, cur, t);
+ print_value (pp, SUBREG_REG (x), verbose);
+ pp_printf (pp, "#%d", SUBREG_BYTE (x));
break;
case SCRATCH:
- cur = safe_concat (buf, cur, "scratch");
- break;
case CC0:
- cur = safe_concat (buf, cur, "cc0");
- break;
case PC:
- cur = safe_concat (buf, cur, "pc");
+ pp_string (pp, GET_RTX_NAME (GET_CODE (x)));
break;
case MEM:
- print_value (t, XEXP (x, 0), verbose);
- cur = safe_concat (buf, cur, "[");
- cur = safe_concat (buf, cur, t);
- cur = safe_concat (buf, cur, "]");
+ pp_left_bracket (pp);
+ print_value (pp, XEXP (x, 0), verbose);
+ pp_right_bracket (pp);
+ break;
+ case DEBUG_EXPR:
+ pp_printf (pp, "D#%i", DEBUG_TEMP_UID (DEBUG_EXPR_TREE_DECL (x)));
break;
default:
- print_exp (t, x, verbose);
- cur = safe_concat (buf, cur, t);
+ print_exp (pp, x, verbose);
break;
}
} /* print_value */
/* The next step in insn detalization, its pattern recognition. */
-static void
-print_pattern (char *buf, rtx x, int verbose)
+void
+print_pattern (pretty_printer *pp, const_rtx x, int verbose)
{
- char t1[BUF_LEN], t2[BUF_LEN], t3[BUF_LEN];
+ if (! x)
+ {
+ pp_string (pp, "(nil)");
+ return;
+ }
switch (GET_CODE (x))
{
case SET:
- print_value (t1, SET_DEST (x), verbose);
- print_value (t2, SET_SRC (x), verbose);
- sprintf (buf, "%s=%s", t1, t2);
+ print_value (pp, SET_DEST (x), verbose);
+ pp_equal (pp);
+ print_value (pp, SET_SRC (x), verbose);
break;
case RETURN:
- sprintf (buf, "return");
+ case SIMPLE_RETURN:
+ case EH_RETURN:
+ pp_string (pp, GET_RTX_NAME (GET_CODE (x)));
break;
case CALL:
- print_exp (buf, x, verbose);
+ print_exp (pp, x, verbose);
break;
case CLOBBER:
- print_value (t1, XEXP (x, 0), verbose);
- sprintf (buf, "clobber %s", t1);
- break;
case USE:
- print_value (t1, XEXP (x, 0), verbose);
- sprintf (buf, "use %s", t1);
+ pp_printf (pp, "%s ", GET_RTX_NAME (GET_CODE (x)));
+ print_value (pp, XEXP (x, 0), verbose);
+ break;
+ case VAR_LOCATION:
+ pp_string (pp, "loc ");
+ print_value (pp, PAT_VAR_LOCATION_LOC (x), verbose);
break;
case COND_EXEC:
+ pp_left_paren (pp);
if (GET_CODE (COND_EXEC_TEST (x)) == NE
&& XEXP (COND_EXEC_TEST (x), 1) == const0_rtx)
- print_value (t1, XEXP (COND_EXEC_TEST (x), 0), verbose);
+ print_value (pp, XEXP (COND_EXEC_TEST (x), 0), verbose);
else if (GET_CODE (COND_EXEC_TEST (x)) == EQ
&& XEXP (COND_EXEC_TEST (x), 1) == const0_rtx)
{
- t1[0] = '!';
- print_value (t1 + 1, XEXP (COND_EXEC_TEST (x), 0), verbose);
+ pp_exclamation (pp);
+ print_value (pp, XEXP (COND_EXEC_TEST (x), 0), verbose);
}
else
- print_value (t1, COND_EXEC_TEST (x), verbose);
- print_pattern (t2, COND_EXEC_CODE (x), verbose);
- sprintf (buf, "(%s) %s", t1, t2);
+ print_value (pp, COND_EXEC_TEST (x), verbose);
+ pp_string (pp, ") ");
+ print_pattern (pp, COND_EXEC_CODE (x), verbose);
break;
case PARALLEL:
{
int i;
- sprintf (t1, "{");
+ pp_left_brace (pp);
for (i = 0; i < XVECLEN (x, 0); i++)
{
- print_pattern (t2, XVECEXP (x, 0, i), verbose);
- sprintf (t3, "%s%s;", t1, t2);
- strcpy (t1, t3);
+ print_pattern (pp, XVECEXP (x, 0, i), verbose);
+ pp_semicolon (pp);
}
- sprintf (buf, "%s}", t1);
+ pp_right_brace (pp);
}
break;
case SEQUENCE:
- /* Should never see SEQUENCE codes until after reorg. */
- abort ();
+ {
+ const rtx_sequence *seq = as_a <const rtx_sequence *> (x);
+ pp_string (pp, "sequence{");
+ if (INSN_P (seq->element (0)))
+ {
+ /* Print the sequence insns indented. */
+ const char * save_print_rtx_head = print_rtx_head;
+ char indented_print_rtx_head[32];
+
+ pp_newline (pp);
+ gcc_assert (strlen (print_rtx_head) < sizeof (indented_print_rtx_head) - 4);
+ snprintf (indented_print_rtx_head,
+ sizeof (indented_print_rtx_head),
+ "%s ", print_rtx_head);
+ print_rtx_head = indented_print_rtx_head;
+ for (int i = 0; i < seq->len (); i++)
+ print_insn_with_notes (pp, seq->insn (i));
+ pp_printf (pp, "%s ", save_print_rtx_head);
+ print_rtx_head = save_print_rtx_head;
+ }
+ else
+ {
+ for (int i = 0; i < seq->len (); i++)
+ {
+ print_pattern (pp, seq->element (i), verbose);
+ pp_semicolon (pp);
+ }
+ }
+ pp_right_brace (pp);
+ }
break;
case ASM_INPUT:
- sprintf (buf, "asm {%s}", XSTR (x, 0));
+ pp_printf (pp, "asm {%s}", XSTR (x, 0));
break;
case ADDR_VEC:
+ for (int i = 0; i < XVECLEN (x, 0); i++)
+ {
+ print_value (pp, XVECEXP (x, 0, i), verbose);
+ pp_semicolon (pp);
+ }
break;
case ADDR_DIFF_VEC:
- print_value (buf, XEXP (x, 0), verbose);
+ for (int i = 0; i < XVECLEN (x, 1); i++)
+ {
+ print_value (pp, XVECEXP (x, 1, i), verbose);
+ pp_semicolon (pp);
+ }
break;
case TRAP_IF:
- print_value (t1, TRAP_CONDITION (x), verbose);
- sprintf (buf, "trap_if %s", t1);
+ pp_string (pp, "trap_if ");
+ print_value (pp, TRAP_CONDITION (x), verbose);
break;
case UNSPEC:
- {
- int i;
-
- sprintf (t1, "unspec{");
- for (i = 0; i < XVECLEN (x, 0); i++)
- {
- print_pattern (t2, XVECEXP (x, 0, i), verbose);
- sprintf (t3, "%s%s;", t1, t2);
- strcpy (t1, t3);
- }
- sprintf (buf, "%s}", t1);
- }
- break;
case UNSPEC_VOLATILE:
- {
- int i;
-
- sprintf (t1, "unspec/v{");
- for (i = 0; i < XVECLEN (x, 0); i++)
- {
- print_pattern (t2, XVECEXP (x, 0, i), verbose);
- sprintf (t3, "%s%s;", t1, t2);
- strcpy (t1, t3);
- }
- sprintf (buf, "%s}", t1);
- }
- break;
+ /* Fallthru -- leave UNSPECs to print_exp. */
default:
- print_value (buf, x, verbose);
+ print_value (pp, x, verbose);
}
} /* print_pattern */
-/* This is the main function in rtl visualization mechanism. It
- accepts an rtx and tries to recognize it as an insn, then prints it
- properly in human readable form, resembling assembler mnemonics.
- For every insn it prints its UID and BB the insn belongs too.
- (Probably the last "option" should be extended somehow, since it
- depends now on sched.c inner variables ...) */
+/* This is the main function in slim rtl visualization mechanism.
+
+ X is an insn, to be printed into PP.
+
+ This function tries to print it properly in human-readable form,
+ resembling assembler mnemonics (instead of the older Lisp-style
+ form).
+
+ If VERBOSE is TRUE, insns are printed with more complete (but
+ longer) pattern names and with extra information, and prefixed
+ with their INSN_UIDs. */
void
-print_insn (char *buf, rtx x, int verbose)
+print_insn (pretty_printer *pp, const rtx_insn *x, int verbose)
{
- char t[BUF_LEN];
- rtx insn = x;
+ if (verbose)
+ {
+ /* Blech, pretty-print can't print integers with a specified width. */
+ char uid_prefix[32];
+ snprintf (uid_prefix, sizeof uid_prefix, " %4d: ", INSN_UID (x));
+ pp_string (pp, uid_prefix);
+ }
switch (GET_CODE (x))
{
case INSN:
- print_pattern (t, PATTERN (x), verbose);
- if (verbose)
- sprintf (buf, "%s: %s", (*current_sched_info->print_insn) (x, 1),
- t);
- else
- sprintf (buf, "%-4d %s", INSN_UID (x), t);
+ print_pattern (pp, PATTERN (x), verbose);
break;
+
+ case DEBUG_INSN:
+ {
+ const char *name = "?";
+
+ if (DECL_P (INSN_VAR_LOCATION_DECL (x)))
+ {
+ tree id = DECL_NAME (INSN_VAR_LOCATION_DECL (x));
+ char idbuf[32];
+ if (id)
+ name = IDENTIFIER_POINTER (id);
+ else if (TREE_CODE (INSN_VAR_LOCATION_DECL (x))
+ == DEBUG_EXPR_DECL)
+ {
+ sprintf (idbuf, "D#%i",
+ DEBUG_TEMP_UID (INSN_VAR_LOCATION_DECL (x)));
+ name = idbuf;
+ }
+ else
+ {
+ sprintf (idbuf, "D.%i",
+ DECL_UID (INSN_VAR_LOCATION_DECL (x)));
+ name = idbuf;
+ }
+ }
+ pp_printf (pp, "debug %s => ", name);
+ if (VAR_LOC_UNKNOWN_P (INSN_VAR_LOCATION_LOC (x)))
+ pp_string (pp, "optimized away");
+ else
+ print_pattern (pp, INSN_VAR_LOCATION_LOC (x), verbose);
+ }
+ break;
+
case JUMP_INSN:
- print_pattern (t, PATTERN (x), verbose);
- if (verbose)
- sprintf (buf, "%s: jump %s", (*current_sched_info->print_insn) (x, 1),
- t);
- else
- sprintf (buf, "%-4d %s", INSN_UID (x), t);
+ print_pattern (pp, PATTERN (x), verbose);
break;
case CALL_INSN:
- x = PATTERN (insn);
- if (GET_CODE (x) == PARALLEL)
- {
- x = XVECEXP (x, 0, 0);
- print_pattern (t, x, verbose);
- }
+ if (GET_CODE (PATTERN (x)) == PARALLEL)
+ print_pattern (pp, XVECEXP (PATTERN (x), 0, 0), verbose);
else
- strcpy (t, "call <...>");
- if (verbose)
- sprintf (buf, "%s: %s", (*current_sched_info->print_insn) (x, 1), t);
- else
- sprintf (buf, "%-4d %s", INSN_UID (insn), t);
+ print_pattern (pp, PATTERN (x), verbose);
break;
case CODE_LABEL:
- sprintf (buf, "L%d:", INSN_UID (x));
+ pp_printf (pp, "L%d:", INSN_UID (x));
+ break;
+ case JUMP_TABLE_DATA:
+ pp_string (pp, "jump_table_data{\n");
+ print_pattern (pp, PATTERN (x), verbose);
+ pp_right_brace (pp);
break;
case BARRIER:
- sprintf (buf, "i% 4d: barrier", INSN_UID (x));
+ pp_string (pp, "barrier");
break;
case NOTE:
- if (NOTE_LINE_NUMBER (x) > 0)
- sprintf (buf, "%4d note \"%s\" %d", INSN_UID (x),
- NOTE_SOURCE_FILE (x), NOTE_LINE_NUMBER (x));
- else
- sprintf (buf, "%4d %s", INSN_UID (x),
- GET_NOTE_INSN_NAME (NOTE_LINE_NUMBER (x)));
- break;
+ {
+ pp_string (pp, GET_NOTE_INSN_NAME (NOTE_KIND (x)));
+ switch (NOTE_KIND (x))
+ {
+ case NOTE_INSN_EH_REGION_BEG:
+ case NOTE_INSN_EH_REGION_END:
+ pp_printf (pp, " %d", NOTE_EH_HANDLER (x));
+ break;
+
+ case NOTE_INSN_BLOCK_BEG:
+ case NOTE_INSN_BLOCK_END:
+ pp_printf (pp, " %d", BLOCK_NUMBER (NOTE_BLOCK (x)));
+ break;
+
+ case NOTE_INSN_BASIC_BLOCK:
+ pp_printf (pp, " %d", NOTE_BASIC_BLOCK (x)->index);
+ break;
+
+ case NOTE_INSN_DELETED_LABEL:
+ case NOTE_INSN_DELETED_DEBUG_LABEL:
+ {
+ const char *label = NOTE_DELETED_LABEL_NAME (x);
+ if (label == NULL)
+ label = "";
+ pp_printf (pp, " (\"%s\")", label);
+ }
+ break;
+
+ case NOTE_INSN_VAR_LOCATION:
+ case NOTE_INSN_CALL_ARG_LOCATION:
+ pp_left_brace (pp);
+ print_pattern (pp, NOTE_VAR_LOCATION (x), verbose);
+ pp_right_brace (pp);
+ break;
+
+ default:
+ break;
+ }
+ break;
+ }
default:
- if (verbose)
- {
- sprintf (buf, "Not an INSN at all\n");
- debug_rtx (x);
- }
- else
- sprintf (buf, "i%-4d <What?>", INSN_UID (x));
+ gcc_unreachable ();
}
} /* print_insn */
-/* Print visualization debugging info. The scheduler using only DFA
- description should never use the following function. */
+/* Pretty-print a slim dump of X (an insn) to PP, including any register
+ note attached to the instruction. */
-void
-print_block_visualization (const char *s)
+static void
+print_insn_with_notes (pretty_printer *pp, const rtx_insn *x)
{
- int unit, i;
-
- /* Print header. */
- fprintf (sched_dump, "\n;; ==================== scheduling visualization %s \n", s);
-
- /* Print names of units. */
- fprintf (sched_dump, ";; %-8s", "clock");
- for (unit = 0; unit < FUNCTION_UNITS_SIZE; unit++)
- if (function_units[unit].bitmask & target_units)
- for (i = 0; i < function_units[unit].multiplicity; i++)
- fprintf (sched_dump, " %-33s", function_units[unit].name);
- fprintf (sched_dump, " %-8s\n", "no-unit");
-
- fprintf (sched_dump, ";; %-8s", "=====");
- for (unit = 0; unit < FUNCTION_UNITS_SIZE; unit++)
- if (function_units[unit].bitmask & target_units)
- for (i = 0; i < function_units[unit].multiplicity; i++)
- fprintf (sched_dump, " %-33s", "==============================");
- fprintf (sched_dump, " %-8s\n", "=======");
-
- /* Print insns in each cycle. */
- fprintf (sched_dump, "%s\n", visual_tbl);
+ pp_string (pp, print_rtx_head);
+ print_insn (pp, x, 1);
+ pp_newline (pp);
+ if (INSN_P (x) && REG_NOTES (x))
+ for (rtx note = REG_NOTES (x); note; note = XEXP (note, 1))
+ {
+ pp_printf (pp, "%s %s ", print_rtx_head,
+ GET_REG_NOTE_NAME (REG_NOTE_KIND (note)));
+ if (GET_CODE (note) == INT_LIST)
+ pp_printf (pp, "%d", XINT (note, 0));
+ else
+ print_pattern (pp, XEXP (note, 0), 1);
+ pp_newline (pp);
+ }
}
-/* Print insns in the 'no_unit' column of visualization. */
+/* Print X, an RTL value node, to file F in slim format. Include
+ additional information if VERBOSE is nonzero.
+
+ Value nodes are constants, registers, labels, symbols and
+ memory. */
void
-visualize_no_unit (rtx insn)
+dump_value_slim (FILE *f, const_rtx x, int verbose)
{
- if (n_vis_no_unit < MAX_VISUAL_NO_UNIT)
- {
- vis_no_unit[n_vis_no_unit] = insn;
- n_vis_no_unit++;
- }
+ pretty_printer rtl_slim_pp;
+ rtl_slim_pp.buffer->stream = f;
+ print_value (&rtl_slim_pp, x, verbose);
+ pp_flush (&rtl_slim_pp);
}
-/* Print insns scheduled in clock, for visualization. */
-
+/* Emit a slim dump of X (an insn) to the file F, including any register
+ note attached to the instruction. */
void
-visualize_scheduled_insns (int clock)
+dump_insn_slim (FILE *f, const rtx_insn *x)
{
- int i, unit;
+ pretty_printer rtl_slim_pp;
+ rtl_slim_pp.buffer->stream = f;
+ print_insn_with_notes (&rtl_slim_pp, x);
+ pp_flush (&rtl_slim_pp);
+}
+
+/* Same as above, but stop at LAST or when COUNT == 0.
+ If COUNT < 0 it will stop only at LAST or NULL rtx. */
- /* If no more room, split table into two. */
- if (n_visual_lines >= MAX_VISUAL_LINES)
+void
+dump_rtl_slim (FILE *f, const rtx_insn *first, const rtx_insn *last,
+ int count, int flags ATTRIBUTE_UNUSED)
+{
+ const rtx_insn *insn, *tail;
+ pretty_printer rtl_slim_pp;
+ rtl_slim_pp.buffer->stream = f;
+
+ tail = last ? NEXT_INSN (last) : NULL;
+ for (insn = first;
+ (insn != NULL) && (insn != tail) && (count != 0);
+ insn = NEXT_INSN (insn))
{
- print_block_visualization ("(incomplete)");
- init_block_visualization ();
+ print_insn_with_notes (&rtl_slim_pp, insn);
+ if (count > 0)
+ count--;
}
- n_visual_lines++;
-
- sprintf (visual_tbl + strlen (visual_tbl), ";; %-8d", clock);
- for (unit = 0; unit < FUNCTION_UNITS_SIZE; unit++)
- if (function_units[unit].bitmask & target_units)
- for (i = 0; i < function_units[unit].multiplicity; i++)
- {
- int instance = unit + i * FUNCTION_UNITS_SIZE;
- rtx insn = get_unit_last_insn (instance);
-
- /* Print insns that still keep the unit busy. */
- if (insn
- && actual_hazard_this_instance (unit, instance, insn, clock, 0))
- {
- char str[BUF_LEN];
- print_insn (str, insn, 0);
- str[INSN_LEN] = '\0';
- sprintf (visual_tbl + strlen (visual_tbl), " %-33s", str);
- }
- else
- sprintf (visual_tbl + strlen (visual_tbl), " %-33s", "------------------------------");
- }
-
- /* Print insns that are not assigned to any unit. */
- for (i = 0; i < n_vis_no_unit; i++)
- sprintf (visual_tbl + strlen (visual_tbl), " %-8d",
- INSN_UID (vis_no_unit[i]));
- n_vis_no_unit = 0;
-
- sprintf (visual_tbl + strlen (visual_tbl), "\n");
+ pp_flush (&rtl_slim_pp);
}
-/* Print stalled cycles. */
+/* Dumps basic block BB to pretty-printer PP in slim form and without and
+ no indentation, for use as a label of a DOT graph record-node. */
void
-visualize_stall_cycles (int stalls)
+rtl_dump_bb_for_graph (pretty_printer *pp, basic_block bb)
{
- static const char *const prefix = ";; ";
- const char *suffix = "\n";
- char *p;
+ rtx_insn *insn;
+ bool first = true;
- /* If no more room, split table into two. */
- if (n_visual_lines >= MAX_VISUAL_LINES)
+ /* TODO: inter-bb stuff. */
+ FOR_BB_INSNS (bb, insn)
{
- print_block_visualization ("(incomplete)");
- init_block_visualization ();
+ if (! first)
+ {
+ pp_bar (pp);
+ pp_write_text_to_stream (pp);
+ }
+ first = false;
+ print_insn_with_notes (pp, insn);
+ pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/true);
}
+}
- n_visual_lines++;
-
- p = visual_tbl + strlen (visual_tbl);
- strcpy (p, prefix);
- p += strlen (prefix);
+/* Pretty-print pattern X of some insn in non-verbose mode.
+ Return a string pointer to the pretty-printer buffer.
- if ((unsigned) stalls >
- visual_tbl_line_length - strlen (prefix) - strlen (suffix))
- {
- suffix = "[...]\n";
- stalls = visual_tbl_line_length - strlen (prefix) - strlen (suffix);
- }
+ This function is only exported exists only to accommodate some older users
+ of the slim RTL pretty printers. Please do not use it for new code. */
- memset (p, '.', stalls);
- p += stalls;
-
- strcpy (p, suffix);
+const char *
+str_pattern_slim (const_rtx x)
+{
+ pretty_printer rtl_slim_pp;
+ print_pattern (&rtl_slim_pp, x, 0);
+ return ggc_strdup (pp_formatted_text (&rtl_slim_pp));
}
-/* Allocate data used for visualization during scheduling. */
+/* Emit a slim dump of X (an insn) to stderr. */
+extern void debug_insn_slim (const rtx_insn *);
+DEBUG_FUNCTION void
+debug_insn_slim (const rtx_insn *x)
+{
+ dump_insn_slim (stderr, x);
+}
-void
-visualize_alloc (void)
+/* Same as above, but using dump_rtl_slim. */
+extern void debug_rtl_slim (FILE *, const rtx_insn *, const rtx_insn *,
+ int, int);
+DEBUG_FUNCTION void
+debug_rtl_slim (const rtx_insn *first, const rtx_insn *last, int count,
+ int flags)
{
- visual_tbl = xmalloc (get_visual_tbl_length ());
+ dump_rtl_slim (stderr, first, last, count, flags);
}
-/* Free data used for visualization. */
+extern void debug_bb_slim (basic_block);
+DEBUG_FUNCTION void
+debug_bb_slim (basic_block bb)
+{
+ dump_bb (stderr, bb, 0, TDF_SLIM | TDF_BLOCKS);
+}
-void
-visualize_free (void)
+extern void debug_bb_n_slim (int);
+DEBUG_FUNCTION void
+debug_bb_n_slim (int n)
{
- free (visual_tbl);
+ basic_block bb = BASIC_BLOCK_FOR_FN (cfun, n);
+ debug_bb_slim (bb);
}
-#endif
+