Patchwork RFA: Add a SLIM_RTX_STRING macro

login
register
mail settings
Submitter Richard Sandiford
Date Nov. 3, 2012, 7:52 p.m.
Message ID <87a9uyea6v.fsf@talisman.home>
Download mbox | patch
Permalink /patch/196932/
State New
Headers show

Comments

Richard Sandiford - Nov. 3, 2012, 7:52 p.m.
This patch rewrites sched-vis.c to use obstacks rather than fixed-length
buffers.  It then uses that file to provide a SLIM_RTX_STRING macro,
so that dump routines can do something like:

    fprintf (dump_file, "convert from %s to %s",
	     SLIM_RTX_STRING (from, 1), SLIM_RTX_STRING (to, 1));

I used a class to track the lifetime of the strings; hope that's OK.

An alternative to obstacks would have been to use <sstream>,
but obstacks should be pretty well tuned to this kind of thing and
if anything might be more efficient.  The new helper routines ought
to make it easier to change implementation details like that in future.

There are some deliberate changes in output here:

- adding a utility function for printing the insn prefix means that
  we now consistently use "<id>: ", whereas before we used a mixture
  of "<id> ", "<id>: " and "i<id>: ".

- jumps don't include "jump", whereas previously they did sometimes
  and didn't other times.  Consistently using "jump" would be OK with
  me too, but the structure forced consistency one way or the other.

- call patterns are always printed, even if they aren't a PARALLEL.

- I removed the printing of unspec and unspec_volatile at the *_pattern
  level and left it to the *_exp routine.  This is because the latter
  prints the unspec type whereas the former didn't.

I also merged some cases based on GET_RTX_NAME, which was easier than
updating the copies individually.

Tested on x86_64-linux-gnu, and by inspecting the -fsched-verbose=5
-fsched-pressure --param sched-pressure-algorithm=2 output, the
-fselective-scheduling output and the LRA output.  OK to install?

I have a follow-on change I'd like to make to the LRA dumps if this is OK.

Richard


gcc/
	* rtl.h (printed_rtl_count, slim_rtx_string): Declare.
	(printed_rtl): New class.
	(SLIM_RTX_STRING, SLIM_RTX_STRINGN): New macros.
	* sched-int.h (print_insn, print_pattern, print_value): Delete.
	* sched-vis.c (safe_concat): Delete.
	(obstack vis_obstack, printed_rtl_count): New variables.
	(printed_rtl::str, start_print, finish_print, add_char, add_string)
	(add_signed, add_unsigned, add_hex, add_real, add_fixed)
	(add_insn_uid_prefix): New functions.
	(print_exp, print_value, print_pattern, print_insn): Rename to...
	(add_exp, add_value, add_pattern, add_insn): ...these.  Remove buffer
	parameters and buffer temporaries.  Use above functions to build the
	string instead.
	(slim_rtx_string): New function.
	(print_value_string, dump_insn_slim): Use SLIM_RTX_STRING.
	* haifa-sched.c (model_recompute, model_record_pressures)
	(schedule_insn): Likewise.
	* sel-sched-dump.c (dump_insn_rtx_1): Likewise.
Steven Bosscher - Nov. 3, 2012, 9:44 p.m.
On Sat, Nov 3, 2012 at 8:52 PM, Richard Sandiford wrote:
> This patch rewrites sched-vis.c to use obstacks rather than fixed-length
> buffers.

Hmm, nice but...

I have some patches for GCC 4.9 to use the pretty-print infrastructure
instead (and also some half-finished ones for the non-slim RTL dumps).
I would like to make all middle-end IR dumps use pretty-print, and
then teach pretty-print about dump_for_graph.

Obviously these patches clash with this one.

It seemed like a good idea, using pretty-print and concentrating the
dump_for_graph stuff there. What do you think about this?

Ciao!
Steven
Richard Sandiford - Nov. 4, 2012, 9:19 a.m.
Steven Bosscher <stevenb.gcc@gmail.com> writes:
> On Sat, Nov 3, 2012 at 8:52 PM, Richard Sandiford wrote:
>> This patch rewrites sched-vis.c to use obstacks rather than fixed-length
>> buffers.
>
> Hmm, nice but...
>
> I have some patches for GCC 4.9 to use the pretty-print infrastructure
> instead (and also some half-finished ones for the non-slim RTL dumps).
> I would like to make all middle-end IR dumps use pretty-print, and
> then teach pretty-print about dump_for_graph.
>
> Obviously these patches clash with this one.
>
> It seemed like a good idea, using pretty-print and concentrating the
> dump_for_graph stuff there. What do you think about this?

OK, fair enough.  I certainly don't mind dropping this patch.

Richard

Patch

Index: gcc/rtl.h
===================================================================
--- gcc/rtl.h	2012-11-03 19:12:42.026369032 +0000
+++ gcc/rtl.h	2012-11-03 19:13:13.019368954 +0000
@@ -2573,6 +2573,41 @@  extern rtx make_compound_operation (rtx,
 extern void delete_dead_jumptables (void);
 
 /* In sched-vis.c.  */
+extern int printed_rtl_count;
+
+/* Represents an obstack-allocated rtl debugging string.  The global
+   printed_rtl_count variable counts the number of strings still in use.  */
+class printed_rtl {
+public:
+  printed_rtl (char *string)
+  : string_ (string)
+  {
+    printed_rtl_count++;
+  }
+
+  printed_rtl (const printed_rtl &other)
+  : string_ ((&other)->string_)
+  {
+    printed_rtl_count++;
+  }
+
+  ~printed_rtl ()
+  {
+    printed_rtl_count--;
+  }
+
+  const char *str () const
+  {
+    return string_;
+  }
+
+  const char *str (size_t limit);
+
+private:
+  char *string_;
+};
+
+extern printed_rtl slim_rtx_string (const_rtx, int);
 extern void debug_bb_n_slim (int);
 extern void debug_bb_slim (struct basic_block_def *);
 extern void print_value_slim (FILE *, const_rtx, int);
@@ -2580,6 +2615,13 @@  extern void debug_rtl_slim (FILE *, cons
 extern void dump_insn_slim (FILE *f, const_rtx x);
 extern void debug_insn_slim (const_rtx x);
 
+/* A "slim" string represention of X, for debugging purposes.
+   V selects between verbose and terse output.  */
+#define SLIM_RTX_STRING(X, V) (slim_rtx_string (X, V).str ())
+
+/* Like SLIM_RTX_STRING, but limit the string to LIMIT characters.  */
+#define SLIM_RTX_STRINGN(X, V, LIMIT) (slim_rtx_string (X, V).str (LIMIT))
+
 /* In sched-rgn.c.  */
 extern void schedule_insns (void);
 
Index: gcc/sched-int.h
===================================================================
--- gcc/sched-int.h	2012-11-03 19:12:42.026369032 +0000
+++ gcc/sched-int.h	2012-11-03 19:13:13.111368956 +0000
@@ -1587,11 +1587,5 @@  extern void sd_debug_lists (rtx, sd_list
 
 #endif /* INSN_SCHEDULING */
 
-/* Functions in sched-vis.c.  These must be outside INSN_SCHEDULING as
-   sched-vis.c is compiled always.  */
-extern void print_insn (char *, const_rtx, int);
-extern void print_pattern (char *, const_rtx, int);
-extern void print_value (char *, const_rtx, int);
-
 #endif /* GCC_SCHED_INT_H */
 
Index: gcc/sched-vis.c
===================================================================
--- gcc/sched-vis.c	2012-11-03 19:12:42.026369032 +0000
+++ gcc/sched-vis.c	2012-11-03 19:46:49.300364022 +0000
@@ -34,27 +34,133 @@  Software Foundation; either version 3, o
 #include "sched-int.h"
 #include "dumpfile.h"	/* for the TDF_* flags */
 
-static char *safe_concat (char *, char *, const char *);
+/* An obstack used for allocating debug strings.  */
+static obstack vis_obstack;
 
-#define BUF_LEN 2048
+/* The number of debug strings still in use.  */
+int printed_rtl_count;
 
-static char *
-safe_concat (char *buf, char *cur, const char *str)
+/* Trim the string to LIMIT characters and return it.  */
+
+const char *
+printed_rtl::str (size_t limit)
 {
-  char *end = buf + BUF_LEN - 2;	/* Leave room for null.  */
-  int c;
+  if (limit < strlen (string_))
+    string_[limit] = 0;
+  return string_;
+}
 
-  if (cur > end)
-    {
-      *end = '\0';
-      return end;
-    }
+/* Start a new debugging string.  */
+
+static void
+start_print (void)
+{
+  static bool initialized = false;
+  if (!initialized)
+    gcc_obstack_init (&vis_obstack);
+  else if (printed_rtl_count == 0)
+    obstack_free (&vis_obstack, NULL);
+}
+
+/* Finish the current debugging string.  */
+
+static printed_rtl
+finish_print (void)
+{
+  obstack_1grow (&vis_obstack, 0);
+  return printed_rtl ((char *) obstack_finish (&vis_obstack));
+}
+
+static void add_value (const_rtx, int);
+static void add_pattern (const_rtx, int);
+
+/* Add CH to the current debugging string.  */
+
+static inline void
+add_char (char ch)
+{
+  obstack_1grow (&vis_obstack, ch);
+}
+
+/* Add STRING to the current debugging string.  */
+
+static inline void
+add_string (const char *string)
+{
+  obstack_grow (&vis_obstack, string, strlen (string));
+}
+
+/* Add VALUE to the current debugging string, printing it as a signed
+   decimal number.  */
+
+static void
+add_signed (HOST_WIDE_INT value)
+{
+  char tmp[HOST_BITS_PER_WIDE_INT + sizeof (HOST_WIDE_INT_PRINT_DEC)];
+  sprintf (tmp, HOST_WIDE_INT_PRINT_DEC, value);
+  add_string (tmp);
+}
+
+/* Add VALUE to the current debugging string, printing it as an unsigned
+   decimal number.  */
+
+static void
+add_unsigned (unsigned HOST_WIDE_INT value)
+{
+  char tmp[HOST_BITS_PER_WIDE_INT + sizeof (HOST_WIDE_INT_PRINT_UNSIGNED)];
+  sprintf (tmp, HOST_WIDE_INT_PRINT_UNSIGNED, value);
+  add_string (tmp);
+}
+
+/* Add VALUE to the current debugging string, printing it in hex.  */
+
+static void
+add_hex (unsigned HOST_WIDE_INT value)
+{
+  char tmp[HOST_BITS_PER_WIDE_INT + sizeof (HOST_WIDE_INT_PRINT_HEX)];
+  sprintf (tmp, HOST_WIDE_INT_PRINT_HEX, value);
+  add_string (tmp);
+}
+
+/* Add VALUE to the current debugging string.  */
+
+static void
+add_real (const REAL_VALUE_TYPE *value)
+{
+  char buf[100];
+  real_to_decimal (buf, value, sizeof (buf), 0, 1);
+  add_string (buf);
+}
+
+/* Add VALUE to the current debugging string.  */
+
+static void
+add_fixed (const FIXED_VALUE_TYPE *value)
+{
+  char buf[100];
+  fixed_to_decimal (buf, value, sizeof (buf));
+  add_string (buf);
+}
 
-  while (cur < end && (c = *str++) != '\0')
-    *cur++ = c;
+/* Add a prefix for instruction INSN to the current debugging string.
+   VERBOSE says whether we want extra information to be printed.  */
 
-  *cur = '\0';
-  return cur;
+static void
+add_insn_uid_prefix (const_rtx insn, int verbose)
+{
+#ifdef INSN_SCHEDULING
+  if (verbose && current_sched_info && NONDEBUG_INSN_P (insn))
+    {
+      add_string ((*current_sched_info->print_insn) (insn, 1));
+      add_string (": ");
+    }
+  else
+#endif
+    {
+      char buf[HOST_BITS_PER_INT + sizeof (" : ")];
+      sprintf (buf, " %4d: ", INSN_UID (insn));
+      add_string (buf);
+    }
 }
 
 /* This recognizes rtx, I classified as expressions.  These are always
@@ -62,11 +168,9 @@  safe_concat (char *buf, char *cur, const
    may be stored in objects representing values.  */
 
 static void
-print_exp (char *buf, const_rtx x, int verbose)
+add_exp (const_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];
@@ -349,21 +453,19 @@  print_exp (char *buf, const_rtx x, int v
     case UNSPEC:
     case UNSPEC_VOLATILE:
       {
-	cur = safe_concat (buf, cur, "unspec");
+	add_string ("unspec");
 	if (GET_CODE (x) == UNSPEC_VOLATILE)
-	  cur = safe_concat (buf, cur, "/v");
-	cur = safe_concat (buf, cur, "[");
+	  add_string ("/v");
+	add_char ('[');
 	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);
+	    add_string (sep);
+	    add_pattern (XVECEXP (x, 0, i), verbose);
 	    sep = ",";
 	  }
-	cur = safe_concat (buf, cur, "] ");
-	sprintf (tmp, "%d", XINT (x, 1));
-	cur = safe_concat (buf, cur, tmp);
+	add_string ("] ");
+	add_signed (XINT (x, 1));
       }
       break;
     default:
@@ -400,103 +502,92 @@  print_exp (char *buf, const_rtx x, int v
   /* Print this as a function?  */
   if (fun)
     {
-      cur = safe_concat (buf, cur, fun);
-      cur = safe_concat (buf, cur, "(");
+      add_string (fun);
+      add_char ('(');
     }
 
   for (i = 0; i < 4; i++)
     {
       if (st[i])
-	cur = safe_concat (buf, cur, st[i]);
+	add_string (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);
+	    add_char (',');
+	  add_value (op[i], verbose);
 	}
     }
 
   if (fun)
-    cur = safe_concat (buf, cur, ")");
-}		/* print_exp */
+    add_char (')');
+}
 
 /* Prints rtxes, I customarily classified as values.  They're constants,
    registers, labels, symbols and memory accesses.  */
 
-void
-print_value (char *buf, const_rtx x, int verbose)
+static void
+add_value (const_rtx x, int verbose)
 {
-  char t[BUF_LEN];
-  char *cur = buf;
-
   if (!x)
     {
-      safe_concat (buf, buf, "(nil)");
+      add_string ("(nil)");
       return;
     }
   switch (GET_CODE (x))
     {
     case CONST_INT:
-      sprintf (t, HOST_WIDE_INT_PRINT_HEX,
-	       (unsigned HOST_WIDE_INT) INTVAL (x));
-      cur = safe_concat (buf, cur, t);
+      add_hex (INTVAL (x));
       break;
     case CONST_DOUBLE:
       if (FLOAT_MODE_P (GET_MODE (x)))
-	real_to_decimal (t, CONST_DOUBLE_REAL_VALUE (x), sizeof (t), 0, 1);
+	add_real (CONST_DOUBLE_REAL_VALUE (x));
       else
-	sprintf (t,
-		 "<" HOST_WIDE_INT_PRINT_HEX "," HOST_WIDE_INT_PRINT_HEX ">",
-		 (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (x),
-		 (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (x));
-      cur = safe_concat (buf, cur, t);
+	{
+	  add_char ('<');
+	  add_hex (CONST_DOUBLE_LOW (x));
+	  add_char (',');
+	  add_hex (CONST_DOUBLE_HIGH (x));
+	  add_char ('>');
+	}
       break;
     case CONST_FIXED:
-      fixed_to_decimal (t, CONST_FIXED_VALUE (x), sizeof (t));
-      cur = safe_concat (buf, cur, t);
+      add_fixed (CONST_FIXED_VALUE (x));
       break;
     case CONST_STRING:
-      cur = safe_concat (buf, cur, "\"");
-      cur = safe_concat (buf, cur, XSTR (x, 0));
-      cur = safe_concat (buf, cur, "\"");
+      add_char ('"');
+      add_string (XSTR (x, 0));
+      add_char ('"');
       break;
     case SYMBOL_REF:
-      cur = safe_concat (buf, cur, "`");
-      cur = safe_concat (buf, cur, XSTR (x, 0));
-      cur = safe_concat (buf, cur, "'");
+      add_char ('`');
+      add_string (XSTR (x, 0));
+      add_char ('\'');
       break;
     case LABEL_REF:
-      sprintf (t, "L%d", INSN_UID (XEXP (x, 0)));
-      cur = safe_concat (buf, cur, t);
+      add_char ('L');
+      add_unsigned (INSN_UID (XEXP (x, 0)));
       break;
     case CONST:
-      print_value (t, XEXP (x, 0), verbose);
-      cur = safe_concat (buf, cur, "const(");
-      cur = safe_concat (buf, cur, t);
-      cur = safe_concat (buf, cur, ")");
-      break;
     case HIGH:
-      print_value (t, XEXP (x, 0), verbose);
-      cur = safe_concat (buf, cur, "high(");
-      cur = safe_concat (buf, cur, t);
-      cur = safe_concat (buf, cur, ")");
+    case STRICT_LOW_PART:
+      add_string (GET_RTX_NAME (GET_CODE (x)));
+      add_char ('(');
+      add_value (XEXP (x, 0), verbose);
+      add_char (')');
       break;
     case REG:
       if (REGNO (x) < FIRST_PSEUDO_REGISTER)
 	{
 	  int c = reg_names[REGNO (x)][0];
 	  if (ISDIGIT (c))
-	    cur = safe_concat (buf, cur, "%");
-
-	  cur = safe_concat (buf, cur, reg_names[REGNO (x)]);
+	    add_char ('%');
+	  add_string (reg_names[REGNO (x)]);
 	}
       else
 	{
-	  sprintf (t, "r%d", REGNO (x));
-	  cur = safe_concat (buf, cur, t);
+	  add_char ('r');
+	  add_unsigned (REGNO (x));
 	}
       if (verbose
 #ifdef INSN_SCHEDULING
@@ -504,184 +595,117 @@  print_value (char *buf, const_rtx x, int
 #endif
 	 )
 	{
-	  sprintf (t, ":%s", GET_MODE_NAME (GET_MODE (x)));
-	  cur = safe_concat (buf, cur, t);
+	  add_char (':');
+	  add_string (GET_MODE_NAME (GET_MODE (x)));
 	}
       break;
     case SUBREG:
-      print_value (t, SUBREG_REG (x), verbose);
-      cur = safe_concat (buf, cur, t);
-      sprintf (t, "#%d", SUBREG_BYTE (x));
-      cur = safe_concat (buf, cur, t);
-      break;
-    case STRICT_LOW_PART:
-      print_value (t, XEXP (x, 0), verbose);
-      cur = safe_concat (buf, cur, "strict_low_part(");
-      cur = safe_concat (buf, cur, t);
-      cur = safe_concat (buf, cur, ")");
+      add_value (SUBREG_REG (x), verbose);
+      add_char ('#');
+      add_signed (SUBREG_BYTE (x));
       break;
     case SCRATCH:
-      cur = safe_concat (buf, cur, "scratch");
-      break;
     case CC0:
-      cur = safe_concat (buf, cur, "cc0");
-      break;
     case PC:
-      cur = safe_concat (buf, cur, "pc");
+      add_string (GET_RTX_NAME (GET_CODE (x)));
       break;
     case MEM:
-      print_value (t, XEXP (x, 0), verbose);
-      cur = safe_concat (buf, cur, "[");
-      cur = safe_concat (buf, cur, t);
-      cur = safe_concat (buf, cur, "]");
+      add_char ('[');
+      add_value (XEXP (x, 0), verbose);
+      add_char (']');
       break;
     case DEBUG_EXPR:
-      sprintf (t, "D#%i", DEBUG_TEMP_UID (DEBUG_EXPR_TREE_DECL (x)));
-      cur = safe_concat (buf, cur, t);
+      add_string ("D#");
+      add_unsigned (DEBUG_TEMP_UID (DEBUG_EXPR_TREE_DECL (x)));
       break;
     default:
-      print_exp (t, x, verbose);
-      cur = safe_concat (buf, cur, t);
+      add_exp (x, verbose);
       break;
     }
-}				/* print_value */
-
-/* Print X, an RTL value node, to file F in slim format.  Include
-   additional information if VERBOSE is nonzero.
-
-   Value nodes are constants, registers, labels, symbols and
-   memory.  */
-
-void
-print_value_slim (FILE *f, const_rtx x, int verbose)
-{
-  char buf[BUF_LEN];
-
-  print_value (buf, x, verbose);
-  fprintf (f, "%s", buf);
 }
 
 /* The next step in insn detalization, its pattern recognition.  */
 
-void
-print_pattern (char *buf, const_rtx x, int verbose)
+static void
+add_pattern (const_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);
+      add_value (SET_DEST (x), verbose);
+      add_char ('=');
+      add_value (SET_SRC (x), verbose);
       break;
     case RETURN:
     case SIMPLE_RETURN:
     case EH_RETURN:
-      sprintf (buf, GET_RTX_NAME (GET_CODE (x)));
+      add_string (GET_RTX_NAME (GET_CODE (x)));
       break;
     case CALL:
-      print_exp (buf, x, verbose);
+      add_exp (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);
+      add_string (GET_RTX_NAME (GET_CODE (x)));
+      add_char (' ');
+      add_value (XEXP (x, 0), verbose);
       break;
     case VAR_LOCATION:
-      print_value (t1, PAT_VAR_LOCATION_LOC (x), verbose);
-      sprintf (buf, "loc %s", t1);
+      add_string ("loc ");
+      add_value (PAT_VAR_LOCATION_LOC (x), verbose);
       break;
     case COND_EXEC:
+      add_char ('(');
       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);
+	add_value (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);
+	  add_char ('!');
+	  add_value (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);
+	add_value (COND_EXEC_TEST (x), verbose);
+      add_string (") ");
+      add_pattern (COND_EXEC_CODE (x), verbose);
       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);
-      }
+      add_char ('{');
+      for (int i = 0; i < XVECLEN (x, 0); i++)
+	{
+	  add_pattern (XVECEXP (x, 0, i), verbose);
+	  add_char (';');
+	}
+      add_char ('}');
       break;
     case SEQUENCE:
-      {
-	int i;
-
-	sprintf (t1, "sequence{");
-	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);
-      }
+      add_string ("sequence{");
+      for (int i = 0; i < XVECLEN (x, 0); i++)
+	{
+	  add_pattern (XVECEXP (x, 0, i), verbose);
+	  add_char (';');
+	}
+      add_char ('}');
       break;
     case ASM_INPUT:
-      sprintf (buf, "asm {%s}", XSTR (x, 0));
+      add_string ("asm {");
+      add_string (XSTR (x, 0));
+      add_char ('}');
       break;
     case ADDR_VEC:
-      /* Fall through.  */
     case ADDR_DIFF_VEC:
-      print_value (buf, XEXP (x, 0), verbose);
+      add_value (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);
-      }
+      add_string ("trap_if ");
+      add_value (TRAP_CONDITION (x), verbose);
       break;
     default:
-      print_value (buf, x, verbose);
+      add_value (x, verbose);
+      break;
     }
-}				/* 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
@@ -690,120 +714,108 @@  print_pattern (char *buf, const_rtx x, i
    (Probably the last "option" should be extended somehow, since it
    depends now on sched.c inner variables ...)  */
 
-void
-print_insn (char *buf, const_rtx x, int verbose)
+static void
+add_insn (const_rtx x, int verbose)
 {
-  char t[BUF_LEN];
-  const_rtx insn = x;
-
   switch (GET_CODE (x))
     {
     case INSN:
-      print_pattern (t, PATTERN (x), verbose);
-#ifdef INSN_SCHEDULING
-      if (verbose && current_sched_info)
-	sprintf (buf, "%s: %s", (*current_sched_info->print_insn) (x, 1),
-		 t);
-      else
-#endif
-	sprintf (buf, " %4d %s", INSN_UID (x), t);
-      break;
-
-    case DEBUG_INSN:
-      {
-	const char *name = "?";
-
-	if (DECL_P (INSN_VAR_LOCATION_DECL (insn)))
-	  {
-	    tree id = DECL_NAME (INSN_VAR_LOCATION_DECL (insn));
-	    char idbuf[32];
-	    if (id)
-	      name = IDENTIFIER_POINTER (id);
-	    else if (TREE_CODE (INSN_VAR_LOCATION_DECL (insn))
-		     == DEBUG_EXPR_DECL)
-	      {
-		sprintf (idbuf, "D#%i",
-			 DEBUG_TEMP_UID (INSN_VAR_LOCATION_DECL (insn)));
-		name = idbuf;
-	      }
-	    else
-	      {
-		sprintf (idbuf, "D.%i",
-			 DECL_UID (INSN_VAR_LOCATION_DECL (insn)));
-		name = idbuf;
-	      }
-	  }
-	if (VAR_LOC_UNKNOWN_P (INSN_VAR_LOCATION_LOC (insn)))
-	  sprintf (buf, " %4d: debug %s optimized away", INSN_UID (insn), name);
-	else
-	  {
-	    print_pattern (t, INSN_VAR_LOCATION_LOC (insn), verbose);
-	    sprintf (buf, " %4d: debug %s => %s", INSN_UID (insn), name, t);
-	  }
-      }
-      break;
-
     case JUMP_INSN:
-      print_pattern (t, PATTERN (x), verbose);
-#ifdef INSN_SCHEDULING
-      if (verbose && current_sched_info)
-	sprintf (buf, "%s: jump %s", (*current_sched_info->print_insn) (x, 1),
-		 t);
-      else
-#endif
-	sprintf (buf, " %4d %s", INSN_UID (x), t);
+      add_insn_uid_prefix (x, verbose);
+      add_pattern (PATTERN (x), verbose);
       break;
-    case CALL_INSN:
-      x = PATTERN (insn);
-      if (GET_CODE (x) == PARALLEL)
+    case DEBUG_INSN:
+      add_insn_uid_prefix (x, verbose);
+      add_string ("debug ");
+      if (DECL_P (INSN_VAR_LOCATION_DECL (x)))
 	{
-	  x = XVECEXP (x, 0, 0);
-	  print_pattern (t, x, verbose);
+	  tree id = DECL_NAME (INSN_VAR_LOCATION_DECL (x));
+	  if (id)
+	    add_string (IDENTIFIER_POINTER (id));
+	  else if (TREE_CODE (INSN_VAR_LOCATION_DECL (x)) == DEBUG_EXPR_DECL)
+	    {
+	      add_string ("D#");
+	      add_unsigned (DEBUG_TEMP_UID (INSN_VAR_LOCATION_DECL (x)));
+	    }
+	  else
+	    {
+	      add_string ("D.");
+	      add_unsigned (DECL_UID (INSN_VAR_LOCATION_DECL (x)));
+	    }
 	}
       else
-	strcpy (t, "call <...>");
-#ifdef INSN_SCHEDULING
-      if (verbose && current_sched_info)
-	sprintf (buf, "%s: %s", (*current_sched_info->print_insn) (insn, 1), t);
+	add_char ('?');
+      if (VAR_LOC_UNKNOWN_P (INSN_VAR_LOCATION_LOC (x)))
+	add_string (" optimized away");
       else
-#endif
-	sprintf (buf, " %4d %s", INSN_UID (insn), t);
+	{
+	  add_string (" => ");
+	  add_pattern (INSN_VAR_LOCATION_LOC (x), verbose);
+	}
+      break;
+    case CALL_INSN:
+      add_insn_uid_prefix (x, verbose);
+      x = PATTERN (x);
+      if (GET_CODE (x) == PARALLEL)
+	x = XVECEXP (x, 0, 0);
+      add_pattern (x, verbose);
       break;
     case CODE_LABEL:
-      sprintf (buf, "L%d:", INSN_UID (x));
+      add_char ('L');
+      add_unsigned (INSN_UID (x));
+      add_char (':');
       break;
     case BARRIER:
-      sprintf (buf, "i%4d: barrier", INSN_UID (x));
+      add_insn_uid_prefix (x, verbose);
+      add_string ("barrier");
       break;
     case NOTE:
-      sprintf (buf, " %4d %s", INSN_UID (x),
-	       GET_NOTE_INSN_NAME (NOTE_KIND (x)));
+      add_insn_uid_prefix (x, verbose);
+      add_string (GET_NOTE_INSN_NAME (NOTE_KIND (x)));
       break;
     default:
-      sprintf (buf, "i%4d  <What %s?>", INSN_UID (x),
-	       GET_RTX_NAME (GET_CODE (x)));
+      add_pattern (x, verbose);
+      break;
     }
-}				/* print_insn */
+}
+
+/* Return a string representation of X, for debugging purposes.
+   Include additional information if VERBOSE is nonzero.  */
+
+printed_rtl
+slim_rtx_string (const_rtx x, int verbose)
+{
+  start_print ();
+  add_insn (x, verbose);
+  return finish_print ();
+}
+
+/* Print X, an RTL value node, to file F in slim format.  Include
+   additional information if VERBOSE is nonzero.  */
+
+void
+print_value_slim (FILE *f, const_rtx x, int verbose)
+{
+  fprintf (f, "%s", SLIM_RTX_STRING (x, verbose));
+}
 
 /* Emit a slim dump of X (an insn) to the file F, including any register
    note attached to the instruction.  */
 void
 dump_insn_slim (FILE *f, const_rtx x)
 {
-  char t[BUF_LEN + 32];
   rtx note;
 
-  print_insn (t, x, 1);
   fputs (print_rtx_head, f);
-  fputs (t, f);
+  fputs (SLIM_RTX_STRING (x, 1), f);
   putc ('\n', f);
   if (INSN_P (x) && REG_NOTES (x))
     for (note = REG_NOTES (x); note; note = XEXP (note, 1))
       {
 	fputs (print_rtx_head, f);
-        print_pattern (t, XEXP (note, 0), 1);
 	fprintf (f, "      %s: %s\n",
-		 GET_REG_NOTE_NAME (REG_NOTE_KIND (note)), t);
+		 GET_REG_NOTE_NAME (REG_NOTE_KIND (note)),
+		 SLIM_RTX_STRING (XEXP (note, 0), 1));
       }
 }
 
Index: gcc/haifa-sched.c
===================================================================
--- gcc/haifa-sched.c	2012-11-03 19:12:42.026369032 +0000
+++ gcc/haifa-sched.c	2012-11-03 19:13:13.914368953 +0000
@@ -2171,8 +2171,6 @@  model_recompute (rtx insn)
 
 	    if (sched_verbose >= 5)
 	      {
-		char buf[2048];
-
 		if (!print_p)
 		  {
 		    fprintf (sched_dump, MODEL_BAR);
@@ -2182,9 +2180,9 @@  model_recompute (rtx insn)
 		    print_p = true;
 		  }
 
-		print_pattern (buf, PATTERN (insn), 0);
 		fprintf (sched_dump, ";;\t\t| %3d %4d %-30s ",
-			 point, INSN_UID (insn), buf);
+			 point, INSN_UID (insn),
+			 SLIM_RTX_STRING (PATTERN (insn), 0));
 		for (pci = 0; pci < ira_pressure_classes_num; pci++)
 		  {
 		    cl = ira_pressure_classes[pci];
@@ -3346,18 +3344,16 @@  model_record_pressures (struct model_ins
   point = model_index (insn->insn);
   if (sched_verbose >= 2)
     {
-      char buf[2048];
-
       if (point == 0)
 	{
 	  fprintf (sched_dump, "\n;;\tModel schedule:\n;;\n");
 	  fprintf (sched_dump, ";;\t| idx insn | mpri hght dpth prio |\n");
 	}
-      print_pattern (buf, PATTERN (insn->insn), 0);
       fprintf (sched_dump, ";;\t| %3d %4d | %4d %4d %4d %4d | %-30s ",
 	       point, INSN_UID (insn->insn), insn->model_priority,
 	       insn->depth + insn->alap, insn->depth,
-	       INSN_PRIORITY (insn->insn), buf);
+	       INSN_PRIORITY (insn->insn),
+	       SLIM_RTX_STRING (PATTERN (insn->insn), 0));
     }
   calculate_reg_deaths (insn->insn, death);
   reg_pressure = INSN_REG_PRESSURE (insn->insn);
@@ -3718,11 +3714,9 @@  schedule_insn (rtx insn)
   if (sched_verbose >= 1)
     {
       struct reg_pressure_data *pressure_info;
-      char buf[2048];
 
-      print_insn (buf, insn, 0);
-      buf[40] = 0;
-      fprintf (sched_dump, ";;\t%3i--> %-40s:", clock_var, buf);
+      fprintf (sched_dump, ";;\t%3i--> %-40s:", clock_var,
+	       SLIM_RTX_STRINGN (insn, 0, 40));
 
       if (recog_memoized (insn) < 0)
 	fprintf (sched_dump, "nothing");
Index: gcc/sel-sched-dump.c
===================================================================
--- gcc/sel-sched-dump.c	2012-11-03 19:12:42.025369032 +0000
+++ gcc/sel-sched-dump.c	2012-11-03 19:13:14.211368950 +0000
@@ -136,12 +136,7 @@  dump_insn_rtx_1 (rtx insn, int flags)
     sel_print ("%d;", INSN_UID (insn));
 
   if (flags & DUMP_INSN_RTX_PATTERN)
-    {
-      char buf[2048];
-
-      print_insn (buf, insn, 0);
-      sel_print ("%s;", buf);
-    }
+    sel_print ("%s;", SLIM_RTX_STRING (insn, 0));
 
   if (flags & DUMP_INSN_RTX_BBN)
     {