#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 "hard-reg-set.h"
#include "basic-block.h"
#include "insn-attr.h"
#include "real.h"
#include "sched-int.h"
#include "target.h"
#ifdef INSN_SCHEDULING
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);
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, "]");
}
}
#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];
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);
}
}
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;
}
s = alloca (INSN_LEN + 6);
sprintf (s, " %33s", "uname");
n1 = strlen (s);
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;
return (MAX_VISUAL_LINES * n);
}
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;
int c;
if (cur > end)
{
*end = '\0';
return end;
}
while (cur < end && (c = *str++) != '\0')
*cur++ = c;
*cur = '\0';
return cur;
}
static void
print_exp (char *buf, rtx x, int verbose)
{
char tmp[BUF_LEN];
const char *st[4];
char *cur = buf;
const char *fun = (char *) 0;
const char *sep;
rtx op[4];
int i;
for (i = 0; i < 4; i++)
{
st[i] = (char *) 0;
op[i] = NULL_RTX;
}
switch (GET_CODE (x))
{
case PLUS:
op[0] = XEXP (x, 0);
if (GET_CODE (XEXP (x, 1)) == CONST_INT
&& INTVAL (XEXP (x, 1)) < 0)
{
st[1] = "-";
op[1] = GEN_INT (-INTVAL (XEXP (x, 1)));
}
else
{
st[1] = "+";
op[1] = XEXP (x, 1);
}
break;
case LO_SUM:
op[0] = XEXP (x, 0);
st[1] = "+low(";
op[1] = XEXP (x, 1);
st[2] = ")";
break;
case MINUS:
op[0] = XEXP (x, 0);
st[1] = "-";
op[1] = XEXP (x, 1);
break;
case COMPARE:
fun = "cmp";
op[0] = XEXP (x, 0);
op[1] = XEXP (x, 1);
break;
case NEG:
st[0] = "-";
op[0] = XEXP (x, 0);
break;
case MULT:
op[0] = XEXP (x, 0);
st[1] = "*";
op[1] = XEXP (x, 1);
break;
case DIV:
op[0] = XEXP (x, 0);
st[1] = "/";
op[1] = XEXP (x, 1);
break;
case UDIV:
fun = "udiv";
op[0] = XEXP (x, 0);
op[1] = XEXP (x, 1);
break;
case MOD:
op[0] = XEXP (x, 0);
st[1] = "%";
op[1] = XEXP (x, 1);
break;
case UMOD:
fun = "umod";
op[0] = XEXP (x, 0);
op[1] = XEXP (x, 1);
break;
case SMIN:
fun = "smin";
op[0] = XEXP (x, 0);
op[1] = XEXP (x, 1);
break;
case SMAX:
fun = "smax";
op[0] = XEXP (x, 0);
op[1] = XEXP (x, 1);
break;
case UMIN:
fun = "umin";
op[0] = XEXP (x, 0);
op[1] = XEXP (x, 1);
break;
case UMAX:
fun = "umax";
op[0] = XEXP (x, 0);
op[1] = XEXP (x, 1);
break;
case NOT:
st[0] = "!";
op[0] = XEXP (x, 0);
break;
case AND:
op[0] = XEXP (x, 0);
st[1] = "&";
op[1] = XEXP (x, 1);
break;
case IOR:
op[0] = XEXP (x, 0);
st[1] = "|";
op[1] = XEXP (x, 1);
break;
case XOR:
op[0] = XEXP (x, 0);
st[1] = "^";
op[1] = XEXP (x, 1);
break;
case ASHIFT:
op[0] = XEXP (x, 0);
st[1] = "<<";
op[1] = XEXP (x, 1);
break;
case LSHIFTRT:
op[0] = XEXP (x, 0);
st[1] = " 0>>";
op[1] = XEXP (x, 1);
break;
case ASHIFTRT:
op[0] = XEXP (x, 0);
st[1] = ">>";
op[1] = XEXP (x, 1);
break;
case ROTATE:
op[0] = XEXP (x, 0);
st[1] = "<-<";
op[1] = XEXP (x, 1);
break;
case ROTATERT:
op[0] = XEXP (x, 0);
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";
op[0] = XEXP (x, 0);
op[1] = XEXP (x, 1);
break;
case GE:
op[0] = XEXP (x, 0);
st[1] = ">=";
op[1] = XEXP (x, 1);
break;
case GEU:
fun = "geu";
op[0] = XEXP (x, 0);
op[1] = XEXP (x, 1);
break;
case LE:
op[0] = XEXP (x, 0);
st[1] = "<=";
op[1] = XEXP (x, 1);
break;
case LEU:
fun = "leu";
op[0] = XEXP (x, 0);
op[1] = XEXP (x, 1);
break;
case SIGN_EXTRACT:
fun = (verbose) ? "sign_extract" : "sxt";
op[0] = XEXP (x, 0);
op[1] = XEXP (x, 1);
op[2] = XEXP (x, 2);
break;
case ZERO_EXTRACT:
fun = (verbose) ? "zero_extract" : "zxt";
op[0] = XEXP (x, 0);
op[1] = XEXP (x, 1);
op[2] = XEXP (x, 2);
break;
case SIGN_EXTEND:
fun = (verbose) ? "sign_extend" : "sxn";
op[0] = XEXP (x, 0);
break;
case ZERO_EXTEND:
fun = (verbose) ? "zero_extend" : "zxn";
op[0] = XEXP (x, 0);
break;
case FLOAT_EXTEND:
fun = (verbose) ? "float_extend" : "fxn";
op[0] = XEXP (x, 0);
break;
case TRUNCATE:
fun = (verbose) ? "trunc" : "trn";
op[0] = XEXP (x, 0);
break;
case FLOAT_TRUNCATE:
fun = (verbose) ? "float_trunc" : "ftr";
op[0] = XEXP (x, 0);
break;
case FLOAT:
fun = (verbose) ? "float" : "flt";
op[0] = XEXP (x, 0);
break;
case UNSIGNED_FLOAT:
fun = (verbose) ? "uns_float" : "ufl";
op[0] = XEXP (x, 0);
break;
case FIX:
fun = "fix";
op[0] = XEXP (x, 0);
break;
case UNSIGNED_FIX:
fun = (verbose) ? "uns_fix" : "ufx";
op[0] = XEXP (x, 0);
break;
case PRE_DEC:
st[0] = "--";
op[0] = XEXP (x, 0);
break;
case PRE_INC:
st[0] = "++";
op[0] = XEXP (x, 0);
break;
case POST_DEC:
op[0] = XEXP (x, 0);
st[1] = "--";
break;
case POST_INC:
op[0] = XEXP (x, 0);
st[1] = "++";
break;
case CALL:
st[0] = "call ";
op[0] = XEXP (x, 0);
if (verbose)
{
st[1] = " argc:";
op[1] = XEXP (x, 1);
}
break;
case IF_THEN_ELSE:
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 TRAP_IF:
fun = "trap_if";
op[0] = TRAP_CONDITION (x);
break;
case PREFETCH:
fun = "prefetch";
op[0] = XEXP (x, 0);
op[1] = XEXP (x, 1);
op[2] = XEXP (x, 2);
break;
case UNSPEC:
case UNSPEC_VOLATILE:
{
cur = safe_concat (buf, cur, "unspec");
if (GET_CODE (x) == UNSPEC_VOLATILE)
cur = safe_concat (buf, cur, "/v");
cur = safe_concat (buf, cur, "[");
sep = "";
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 = ",";
}
cur = safe_concat (buf, cur, "] ");
sprintf (tmp, "%d", XINT (x, 1));
cur = safe_concat (buf, cur, tmp);
}
break;
default:
st[0] = GET_RTX_NAME (GET_CODE (x));
break;
}
if (fun)
{
cur = safe_concat (buf, cur, fun);
cur = safe_concat (buf, cur, "(");
}
for (i = 0; i < 4; i++)
{
if (st[i])
cur = safe_concat (buf, cur, 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);
}
}
if (fun)
cur = safe_concat (buf, cur, ")");
}
static void
print_value (char *buf, rtx x, int verbose)
{
char t[BUF_LEN];
char *cur = buf;
switch (GET_CODE (x))
{
case CONST_INT:
sprintf (t, HOST_WIDE_INT_PRINT_HEX, INTVAL (x));
cur = safe_concat (buf, cur, t);
break;
case CONST_DOUBLE:
if (FLOAT_MODE_P (GET_MODE (x)))
real_to_decimal (t, CONST_DOUBLE_REAL_VALUE (x), sizeof (t), 0, 1);
else
sprintf (t, "<0x%lx,0x%lx>", (long) XWINT (x, 2), (long) XWINT (x, 3));
cur = safe_concat (buf, cur, t);
break;
case CONST_STRING:
cur = safe_concat (buf, cur, "\"");
cur = safe_concat (buf, cur, XSTR (x, 0));
cur = safe_concat (buf, cur, "\"");
break;
case SYMBOL_REF:
cur = safe_concat (buf, cur, "`");
cur = safe_concat (buf, cur, XSTR (x, 0));
cur = safe_concat (buf, cur, "'");
break;
case LABEL_REF:
sprintf (t, "L%d", INSN_UID (XEXP (x, 0)));
cur = safe_concat (buf, cur, t);
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, ")");
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)]);
}
else
{
sprintf (t, "r%d", REGNO (x));
cur = safe_concat (buf, cur, t);
}
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);
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");
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, "]");
break;
default:
print_exp (t, x, verbose);
cur = safe_concat (buf, cur, t);
break;
}
}
static void
print_pattern (char *buf, rtx x, int verbose)
{
char t1[BUF_LEN], t2[BUF_LEN], t3[BUF_LEN];
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);
break;
case RETURN:
sprintf (buf, "return");
break;
case CALL:
print_exp (buf, 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);
break;
case COND_EXEC:
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);
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);
}
else
print_value (t1, COND_EXEC_TEST (x), verbose);
print_pattern (t2, COND_EXEC_CODE (x), verbose);
sprintf (buf, "(%s) %s", t1, t2);
break;
case PARALLEL:
{
int i;
sprintf (t1, "{");
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 SEQUENCE:
abort ();
break;
case ASM_INPUT:
sprintf (buf, "asm {%s}", XSTR (x, 0));
break;
case ADDR_VEC:
break;
case ADDR_DIFF_VEC:
print_value (buf, XEXP (x, 0), verbose);
break;
case TRAP_IF:
print_value (t1, TRAP_CONDITION (x), verbose);
sprintf (buf, "trap_if %s", t1);
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;
default:
print_value (buf, x, verbose);
}
}
void
print_insn (char *buf, rtx x, int verbose)
{
char t[BUF_LEN];
rtx insn = x;
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);
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);
break;
case CALL_INSN:
x = PATTERN (insn);
if (GET_CODE (x) == PARALLEL)
{
x = XVECEXP (x, 0, 0);
print_pattern (t, x, 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);
break;
case CODE_LABEL:
sprintf (buf, "L%d:", INSN_UID (x));
break;
case BARRIER:
sprintf (buf, "i% 4d: barrier", INSN_UID (x));
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;
default:
if (verbose)
{
sprintf (buf, "Not an INSN at all\n");
debug_rtx (x);
}
else
sprintf (buf, "i%-4d <What?>", INSN_UID (x));
}
}
void
print_block_visualization (const char *s)
{
int unit, i;
fprintf (sched_dump, "\n;; ==================== scheduling visualization %s \n", s);
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", "=======");
fprintf (sched_dump, "%s\n", visual_tbl);
}
void
visualize_no_unit (rtx insn)
{
if (n_vis_no_unit < MAX_VISUAL_NO_UNIT)
{
vis_no_unit[n_vis_no_unit] = insn;
n_vis_no_unit++;
}
}
void
visualize_scheduled_insns (int clock)
{
int i, unit;
if (n_visual_lines >= MAX_VISUAL_LINES)
{
print_block_visualization ("(incomplete)");
init_block_visualization ();
}
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);
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", "------------------------------");
}
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");
}
void
visualize_stall_cycles (int stalls)
{
static const char *const prefix = ";; ";
const char *suffix = "\n";
char *p;
if (n_visual_lines >= MAX_VISUAL_LINES)
{
print_block_visualization ("(incomplete)");
init_block_visualization ();
}
n_visual_lines++;
p = visual_tbl + strlen (visual_tbl);
strcpy (p, prefix);
p += strlen (prefix);
if ((unsigned) stalls >
visual_tbl_line_length - strlen (prefix) - strlen (suffix))
{
suffix = "[...]\n";
stalls = visual_tbl_line_length - strlen (prefix) - strlen (suffix);
}
memset (p, '.', stalls);
p += stalls;
strcpy (p, suffix);
}
void
visualize_alloc (void)
{
visual_tbl = xmalloc (get_visual_tbl_length ());
}
void
visualize_free (void)
{
free (visual_tbl);
}
#endif