From c62c265908370049de8565fe666386a33e35e73a Mon Sep 17 00:00:00 2001 From: Bernd Schmidt Date: Sun, 3 Dec 2000 14:35:17 +0000 Subject: [PATCH] Move scheduling visualization code to separate file. From-SVN: r37974 --- gcc/ChangeLog | 21 ++ gcc/Makefile.in | 4 +- gcc/haifa-sched.c | 917 +-------------------------------------------- gcc/sched-vis.c | 929 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 970 insertions(+), 901 deletions(-) create mode 100644 gcc/sched-vis.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index fe83a48df9b..efabdb459f5 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,26 @@ 2000-12-03 Bernd Schmidt + * Makefile.in (OBJS): Add sched-vis.o. + (sched-vis.o): New rule. + * haifa-sched.c (get_unit_last_insn): New function. + (sched_dump, insn_unit, actual_hazard_this_instance): No longer + static. + (schedule_block): Call visualize_alloc and visualize_free. Delete + spurious return statement. + (init_target_units, insn_print_units, get_visual_tbl_length, + init_block_visualization, print_block_visualization, safe_concat, + visualize_scheduled_inns, visualize_no_unit, visualize_stall_cycles, + print_exp, print_value, print_pattern, print_insn, target_units, + MAX_VISUAL_LINES, INSN_LEN, n_visual_lines, visual_tbl, + n_vis_no_unit, vis_no_unit): Move scheduling visualization + functions/variables... + * sched-vis.c: ...here. New file. + (visualize_alloc, visualize_free): New functions. + (visualize_scheduled_insns, visualize_stall_cycles, + print_block_visualization): Lose basic block argument. All callers + changed. + (visualize_scheduled_insns): Use new function get_unit_last_insn. + * sched-int.h: New file. * Makefile.in (haifa-sched.o): Depend on it. * haifa-sched.c: Include it. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 7071c88dc78..6cb0d77a0c7 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -737,7 +737,7 @@ OBJS = diagnostic.o version.o tree.o print-tree.o stor-layout.o fold-const.o \ mbchar.o splay-tree.o graph.o sbitmap.o resource.o hash.o predict.o \ lists.o ggc-common.o $(GGC) stringpool.o simplify-rtx.o ssa.o bb-reorder.o \ sibcall.o conflict.o timevar.o ifcvt.o dominance.o dependence.o dce.o \ - hashtab.o + sched-vis.o hashtab.o BACKEND = toplev.o libbackend.a @@ -1455,6 +1455,8 @@ regmove.o : regmove.c $(CONFIG_H) system.h $(RTL_H) insn-config.h \ haifa-sched.o : haifa-sched.c $(CONFIG_H) system.h $(RTL_H) sched-int.h \ $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h flags.h insn-config.h function.h \ $(INSN_ATTR_H) toplev.h $(RECOG_H) except.h +sched-vis.o : sched-vis.c $(CONFIG_H) system.h $(RTL_H) sched-int.h \ + $(INSN_ATTR_H) $(REGS_H) final.o : final.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h intl.h \ $(REGS_H) $(RECOG_H) conditions.h insn-config.h $(INSN_ATTR_H) function.h \ real.h output.h hard-reg-set.h insn-flags.h insn-codes.h gstab.h except.h \ diff --git a/gcc/haifa-sched.c b/gcc/haifa-sched.c index 6a07f3cea27..f89f2a1dd77 100644 --- a/gcc/haifa-sched.c +++ b/gcc/haifa-sched.c @@ -177,15 +177,6 @@ extern rtx *reg_known_value; #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".) */ - -static int target_units = 0; - /* issue_rate is the number of insns that can be scheduled in the same machine cycle. It can be defined in the config/mach/mach.h file, otherwise we set it to 1. */ @@ -216,7 +207,7 @@ static int nr_inter, nr_spec; /* Debugging file. All printouts are sent to dump, which is always set, either to stderr, or to the dump listing file (-dRS). */ -static FILE *sched_dump = 0; +FILE *sched_dump = 0; /* Highest uid before scheduling. */ static int old_max_uid; @@ -502,10 +493,8 @@ static void add_dependence PARAMS ((rtx, rtx, enum reg_note)); static void remove_dependence PARAMS ((rtx, rtx)); static rtx find_insn_list PARAMS ((rtx, rtx)); static void set_sched_group_p PARAMS ((rtx)); -static int insn_unit PARAMS ((rtx)); static unsigned int blockage_range PARAMS ((int, rtx)); static void clear_units PARAMS ((void)); -static int actual_hazard_this_instance PARAMS ((int, int, rtx, int, int)); static void schedule_unit PARAMS ((int, rtx, int)); static int actual_hazard PARAMS ((int, rtx, int, int)); static int potential_hazard PARAMS ((int, rtx, int)); @@ -525,7 +514,6 @@ static void queue_insn PARAMS ((rtx, int)); static void schedule_insn PARAMS ((rtx, struct ready_list *, int)); static void find_insn_reg_weight PARAMS ((int)); static void schedule_block PARAMS ((int, int)); -static char *safe_concat PARAMS ((char *, char *, const char *)); static int insn_issue_delay PARAMS ((rtx)); static void adjust_priority PARAMS ((rtx)); @@ -802,18 +790,6 @@ static rtx ready_remove_first PARAMS ((struct ready_list *)); static void queue_to_ready PARAMS ((struct ready_list *)); static void debug_ready_list PARAMS ((struct ready_list *)); -static void init_target_units PARAMS ((void)); -static void insn_print_units PARAMS ((rtx)); -static int get_visual_tbl_length PARAMS ((void)); -static void init_block_visualization PARAMS ((void)); -static void print_block_visualization PARAMS ((int, const char *)); -static void visualize_scheduled_insns PARAMS ((int, int)); -static void visualize_no_unit PARAMS ((rtx)); -static void visualize_stall_cycles PARAMS ((int, int)); -static void print_exp PARAMS ((char *, rtx, int)); -static void print_value PARAMS ((char *, rtx, int)); -static void print_pattern PARAMS ((char *, rtx, int)); -static void print_insn PARAMS ((char *, rtx, int)); void debug_reg_vector PARAMS ((regset)); static rtx move_insn1 PARAMS ((rtx, rtx)); @@ -2914,7 +2890,7 @@ find_insn_mem_list (insn, x, list, list1) mask if the value is negative. A function unit index is the non-negative encoding. */ -HAIFA_INLINE static int +HAIFA_INLINE int insn_unit (insn) rtx insn; { @@ -2986,6 +2962,15 @@ static int unit_tick[FUNCTION_UNITS_SIZE * MAX_MULTIPLICITY]; that remain to use the unit. */ static int unit_n_insns[FUNCTION_UNITS_SIZE]; +/* Access the unit_last_insn array. Used by the visualization code. */ + +rtx +get_unit_last_insn (instance) + int instance; +{ + return unit_last_insn[instance]; +} + /* Reset the function unit state to the null state. */ static void @@ -3028,7 +3013,7 @@ insn_issue_delay (insn) instance INSTANCE at time CLOCK if the previous actual hazard cost was COST. */ -HAIFA_INLINE static int +HAIFA_INLINE int actual_hazard_this_instance (unit, instance, insn, clock, cost) int unit, instance, clock, cost; rtx insn; @@ -4899,7 +4884,7 @@ queue_to_ready (ready) } if (sched_verbose && stalls) - visualize_stall_cycles (BB_TO_BLOCK (target_bb), stalls); + visualize_stall_cycles (stalls); q_ptr = NEXT_Q_AFTER (q_ptr, stalls); clock_var += stalls; } @@ -4923,873 +4908,6 @@ debug_ready_list (ready) fprintf (sched_dump, "\n"); } -/* Print names of units on which insn can/should execute, for debugging. */ - -static void -insn_print_units (insn) - 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 splitted 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; -char *visual_tbl; -int n_vis_no_unit; -rtx vis_no_unit[10]; - -/* Finds units that are in use in this fuction. Required only - for visualization. */ - -static void -init_target_units () -{ - 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 () -{ - int unit, i; - int n, n1; - char *s; - - /* Compute length of one field in line. */ - s = (char *) 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; - - /* Compute length of visualization string. */ - return (MAX_VISUAL_LINES * n); -} - -/* Init block visualization debugging info. */ - -static void -init_block_visualization () -{ - strcpy (visual_tbl, ""); - n_visual_lines = 0; - n_vis_no_unit = 0; -} - -#define BUF_LEN 2048 - -static char * -safe_concat (buf, cur, str) - 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 - represent some action on values or results of other expression, that - may be stored in objects representing values. */ - -static void -print_exp (buf, x, verbose) - 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 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: - /* If (verbose) debug_rtx (x); */ - 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, "("); - } - - 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, ")"); -} /* print_exp */ - -/* Prints rtxes, I customly classified as values. They're constants, - registers, labels, symbols and memory accesses. */ - -static void -print_value (buf, x, verbose) - 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: - 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 (c >= '0' && c <= '9') - 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_WORD (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; - } -} /* print_value */ - -/* The next step in insn detalization, its pattern recognition. */ - -static void -print_pattern (buf, x, verbose) - 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: - { - int i; - - sprintf (t1, "%%{"); - for (i = 0; i < XVECLEN (x, 0); i++) - { - print_insn (t2, XVECEXP (x, 0, i), verbose); - sprintf (t3, "%s%s;", t1, t2); - strcpy (t1, t3); - } - sprintf (buf, "%s%%}", t1); - } - 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); - } -} /* 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 ...) */ - -static void -print_insn (buf, x, verbose) - 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 ", INSN_UID (x)); - } -} /* print_insn */ - -/* Print visualization debugging info. */ - -static void -print_block_visualization (b, s) - int b; - const char *s; -{ - int unit, i; - - /* Print header. */ - fprintf (sched_dump, "\n;; ==================== scheduling visualization for block %d %s \n", b, 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); -} - -/* Print insns in the 'no_unit' column of visualization. */ - -static void -visualize_no_unit (insn) - rtx insn; -{ - vis_no_unit[n_vis_no_unit] = insn; - n_vis_no_unit++; -} - -/* Print insns scheduled in clock, for visualization. */ - -static void -visualize_scheduled_insns (b, clock) - int b, clock; -{ - int i, unit; - - /* If no more room, split table into two. */ - if (n_visual_lines >= MAX_VISUAL_LINES) - { - print_block_visualization (b, "(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 = 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"); -} - -/* Print stalled cycles. */ - -static void -visualize_stall_cycles (b, stalls) - int b, stalls; -{ - int i; - - /* If no more room, split table into two. */ - if (n_visual_lines >= MAX_VISUAL_LINES) - { - print_block_visualization (b, "(incomplete)"); - init_block_visualization (); - } - - n_visual_lines++; - - sprintf (visual_tbl + strlen (visual_tbl), ";; "); - for (i = 0; i < stalls; i++) - sprintf (visual_tbl + strlen (visual_tbl), "."); - sprintf (visual_tbl + strlen (visual_tbl), "\n"); -} - /* The number of insns from the current block scheduled so far. */ static int sched_target_n_insns; /* The number of insns from the current block to be scheduled in total. */ @@ -6248,7 +5366,7 @@ schedule_block (bb, rgn_n_insns) fprintf (sched_dump, ";; ======================================================\n"); fprintf (sched_dump, "\n"); - visual_tbl = (char *) alloca (get_visual_tbl_length ()); + visualize_alloc (); init_block_visualization (); } @@ -6356,7 +5474,7 @@ schedule_block (bb, rgn_n_insns) /* Debug info. */ if (sched_verbose) - visualize_scheduled_insns (b, clock_var); + visualize_scheduled_insns (clock_var); } /* Debug info. */ @@ -6364,7 +5482,7 @@ schedule_block (bb, rgn_n_insns) { fprintf (sched_dump, ";;\tReady list (final): "); debug_ready_list (&ready); - print_block_visualization (b, ""); + print_block_visualization (""); } /* Sanity check -- queue must be empty now. Meaningless if region has @@ -6402,14 +5520,13 @@ schedule_block (bb, rgn_n_insns) clock_var, INSN_UID (head)); fprintf (sched_dump, ";; new tail = %d\n\n", INSN_UID (tail)); + visualize_free (); } current_sched_info->head = head; current_sched_info->tail = tail; free (ready.vec); - - return 1; } /* Print the bit-set of registers, S, callable from debugger. */ diff --git a/gcc/sched-vis.c b/gcc/sched-vis.c new file mode 100644 index 00000000000..9bbc4357d7c --- /dev/null +++ b/gcc/sched-vis.c @@ -0,0 +1,929 @@ +/* Instruction scheduling pass. + Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000 Free Software Foundation, Inc. + Contributed by Michael Tiemann (tiemann@cygnus.com) Enhanced by, + and currently maintained by, Jim Wilson (wilson@cygnus.com) + +This file is part of GNU CC. + +GNU CC 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 version. + +GNU CC 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 GNU CC; see the file COPYING. If not, write to the Free +the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "toplev.h" +#include "rtl.h" +#include "tm_p.h" +#include "regs.h" +#include "insn-attr.h" +#include "sched-int.h" + +/* 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".) */ + +static int target_units = 0; + +static char *safe_concat PARAMS ((char *, char *, const char *)); +static int get_visual_tbl_length PARAMS ((void)); +static void print_exp PARAMS ((char *, rtx, int)); +static void print_value PARAMS ((char *, rtx, int)); +static void print_pattern PARAMS ((char *, rtx, int)); +static void print_insn PARAMS ((char *, rtx, int)); + +/* Print names of units on which insn can/should execute, for debugging. */ + +void +insn_print_units (insn) + 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 splitted 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; +char *visual_tbl; +int n_vis_no_unit; +rtx vis_no_unit[10]; + +/* Finds units that are in use in this fuction. Required only + for visualization. */ + +void +init_target_units () +{ + 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 () +{ + int unit, i; + int n, n1; + char *s; + + /* Compute length of one field in line. */ + s = (char *) 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; + + /* Compute length of visualization string. */ + return (MAX_VISUAL_LINES * n); +} + +/* Init block visualization debugging info. */ + +void +init_block_visualization () +{ + strcpy (visual_tbl, ""); + n_visual_lines = 0; + n_vis_no_unit = 0; +} + +#define BUF_LEN 2048 + +static char * +safe_concat (buf, cur, str) + 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 + represent some action on values or results of other expression, that + may be stored in objects representing values. */ + +static void +print_exp (buf, x, verbose) + 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 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: + /* If (verbose) debug_rtx (x); */ + 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, "("); + } + + 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, ")"); +} /* print_exp */ + +/* Prints rtxes, I customly classified as values. They're constants, + registers, labels, symbols and memory accesses. */ + +static void +print_value (buf, x, verbose) + 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: + 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 (c >= '0' && c <= '9') + 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_WORD (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; + } +} /* print_value */ + +/* The next step in insn detalization, its pattern recognition. */ + +static void +print_pattern (buf, x, verbose) + 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: + { + int i; + + sprintf (t1, "%%{"); + for (i = 0; i < XVECLEN (x, 0); i++) + { + print_insn (t2, XVECEXP (x, 0, i), verbose); + sprintf (t3, "%s%s;", t1, t2); + strcpy (t1, t3); + } + sprintf (buf, "%s%%}", t1); + } + 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); + } +} /* 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 ...) */ + +static void +print_insn (buf, x, verbose) + 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 ", INSN_UID (x)); + } +} /* print_insn */ + +/* Print visualization debugging info. */ + +void +print_block_visualization (s) + const char *s; +{ + 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); +} + +/* Print insns in the 'no_unit' column of visualization. */ + +void +visualize_no_unit (insn) + rtx insn; +{ + vis_no_unit[n_vis_no_unit] = insn; + n_vis_no_unit++; +} + +/* Print insns scheduled in clock, for visualization. */ + +void +visualize_scheduled_insns (clock) + int clock; +{ + int i, unit; + + /* If no more room, split table into two. */ + 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); + + /* 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"); +} + +/* Print stalled cycles. */ + +void +visualize_stall_cycles (stalls) + int stalls; +{ + int i; + + /* If no more room, split table into two. */ + if (n_visual_lines >= MAX_VISUAL_LINES) + { + print_block_visualization ("(incomplete)"); + init_block_visualization (); + } + + n_visual_lines++; + + sprintf (visual_tbl + strlen (visual_tbl), ";; "); + for (i = 0; i < stalls; i++) + sprintf (visual_tbl + strlen (visual_tbl), "."); + sprintf (visual_tbl + strlen (visual_tbl), "\n"); +} + +/* Allocate data used for visualization during scheduling. */ + +void +visualize_alloc () +{ + visual_tbl = xmalloc (get_visual_tbl_length ()); +} + +/* Free data used for visualization. */ + +void +visualize_free () +{ + free (visual_tbl); +} -- 2.30.2