Move scheduling visualization code to separate file.
authorBernd Schmidt <bernds@redhat.co.uk>
Sun, 3 Dec 2000 14:35:17 +0000 (14:35 +0000)
committerBernd Schmidt <bernds@gcc.gnu.org>
Sun, 3 Dec 2000 14:35:17 +0000 (14:35 +0000)
From-SVN: r37974

gcc/ChangeLog
gcc/Makefile.in
gcc/haifa-sched.c
gcc/sched-vis.c [new file with mode: 0644]

index fe83a48df9bf0aafe0dcfab164a51149f1dbed5d..efabdb459f592d5acff9a144a720b10136b31c1a 100644 (file)
@@ -1,5 +1,26 @@
 2000-12-03  Bernd Schmidt  <bernds@redhat.co.uk>
 
+       * 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.
index 7071c88dc788f6bcf2100cec23da64533ec44df3..6cb0d77a0c70e6aa05dc9c931959d34e3cbe5b59 100644 (file)
@@ -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 \
index 6a07f3cea27e05d0c881f4361ce9c0fd5fd2a805..f89f2a1dd777aac4e22251c2fcc65b7025ac4bd8 100644 (file)
@@ -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  <What?>", 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;
 }
 \f
 /* 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 (file)
index 0000000..9bbc435
--- /dev/null
@@ -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.  */
+\f
+#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  <What?>", 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);
+}