diff gcc/genrecog.c @ 0:a06113de4d67

first commit
author kent <kent@cr.ie.u-ryukyu.ac.jp>
date Fri, 17 Jul 2009 14:47:48 +0900
parents
children 77e2b8dfacca
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gcc/genrecog.c	Fri Jul 17 14:47:48 2009 +0900
@@ -0,0 +1,2911 @@
+/* Generate code from machine description to recognize rtl as insns.
+   Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1997, 1998,
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
+   Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC 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 GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+
+/* This program is used to produce insn-recog.c, which contains a
+   function called `recog' plus its subroutines.  These functions
+   contain a decision tree that recognizes whether an rtx, the
+   argument given to recog, is a valid instruction.
+
+   recog returns -1 if the rtx is not valid.  If the rtx is valid,
+   recog returns a nonnegative number which is the insn code number
+   for the pattern that matched.  This is the same as the order in the
+   machine description of the entry that matched.  This number can be
+   used as an index into various insn_* tables, such as insn_template,
+   insn_outfun, and insn_n_operands (found in insn-output.c).
+
+   The third argument to recog is an optional pointer to an int.  If
+   present, recog will accept a pattern if it matches except for
+   missing CLOBBER expressions at the end.  In that case, the value
+   pointed to by the optional pointer will be set to the number of
+   CLOBBERs that need to be added (it should be initialized to zero by
+   the caller).  If it is set nonzero, the caller should allocate a
+   PARALLEL of the appropriate size, copy the initial entries, and
+   call add_clobbers (found in insn-emit.c) to fill in the CLOBBERs.
+
+   This program also generates the function `split_insns', which
+   returns 0 if the rtl could not be split, or it returns the split
+   rtl as an INSN list.
+
+   This program also generates the function `peephole2_insns', which
+   returns 0 if the rtl could not be matched.  If there was a match,
+   the new rtl is returned in an INSN list, and LAST_INSN will point
+   to the last recognized insn in the old sequence.  */
+
+#include "bconfig.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "rtl.h"
+#include "errors.h"
+#include "gensupport.h"
+
+#define OUTPUT_LABEL(INDENT_STRING, LABEL_NUMBER) \
+  printf("%sL%d: ATTRIBUTE_UNUSED_LABEL\n", (INDENT_STRING), (LABEL_NUMBER))
+
+/* A listhead of decision trees.  The alternatives to a node are kept
+   in a doubly-linked list so we can easily add nodes to the proper
+   place when merging.  */
+
+struct decision_head
+{
+  struct decision *first;
+  struct decision *last;
+};
+
+/* A single test.  The two accept types aren't tests per-se, but
+   their equality (or lack thereof) does affect tree merging so
+   it is convenient to keep them here.  */
+
+struct decision_test
+{
+  /* A linked list through the tests attached to a node.  */
+  struct decision_test *next;
+
+  /* These types are roughly in the order in which we'd like to test them.  */
+  enum decision_type
+    {
+      DT_num_insns,
+      DT_mode, DT_code, DT_veclen,
+      DT_elt_zero_int, DT_elt_one_int, DT_elt_zero_wide, DT_elt_zero_wide_safe,
+      DT_const_int,
+      DT_veclen_ge, DT_dup, DT_pred, DT_c_test,
+      DT_accept_op, DT_accept_insn
+    } type;
+
+  union
+  {
+    int num_insns;		/* Number if insn in a define_peephole2.  */
+    enum machine_mode mode;	/* Machine mode of node.  */
+    RTX_CODE code;		/* Code to test.  */
+
+    struct
+    {
+      const char *name;		/* Predicate to call.  */
+      const struct pred_data *data;
+                                /* Optimization hints for this predicate.  */
+      enum machine_mode mode;	/* Machine mode for node.  */
+    } pred;
+
+    const char *c_test;		/* Additional test to perform.  */
+    int veclen;			/* Length of vector.  */
+    int dup;			/* Number of operand to compare against.  */
+    HOST_WIDE_INT intval;	/* Value for XINT for XWINT.  */
+    int opno;			/* Operand number matched.  */
+
+    struct {
+      int code_number;		/* Insn number matched.  */
+      int lineno;		/* Line number of the insn.  */
+      int num_clobbers_to_add;	/* Number of CLOBBERs to be added.  */
+    } insn;
+  } u;
+};
+
+/* Data structure for decision tree for recognizing legitimate insns.  */
+
+struct decision
+{
+  struct decision_head success;	/* Nodes to test on success.  */
+  struct decision *next;	/* Node to test on failure.  */
+  struct decision *prev;	/* Node whose failure tests us.  */
+  struct decision *afterward;	/* Node to test on success,
+				   but failure of successor nodes.  */
+
+  const char *position;		/* String denoting position in pattern.  */
+
+  struct decision_test *tests;	/* The tests for this node.  */
+
+  int number;			/* Node number, used for labels */
+  int subroutine_number;	/* Number of subroutine this node starts */
+  int need_label;		/* Label needs to be output.  */
+};
+
+#define SUBROUTINE_THRESHOLD	100
+
+static int next_subroutine_number;
+
+/* We can write three types of subroutines: One for insn recognition,
+   one to split insns, and one for peephole-type optimizations.  This
+   defines which type is being written.  */
+
+enum routine_type {
+  RECOG, SPLIT, PEEPHOLE2
+};
+
+#define IS_SPLIT(X) ((X) != RECOG)
+
+/* Next available node number for tree nodes.  */
+
+static int next_number;
+
+/* Next number to use as an insn_code.  */
+
+static int next_insn_code;
+
+/* Record the highest depth we ever have so we know how many variables to
+   allocate in each subroutine we make.  */
+
+static int max_depth;
+
+/* The line number of the start of the pattern currently being processed.  */
+static int pattern_lineno;
+
+/* Count of errors.  */
+static int error_count;
+
+/* Predicate handling.
+
+   We construct from the machine description a table mapping each
+   predicate to a list of the rtl codes it can possibly match.  The
+   function 'maybe_both_true' uses it to deduce that there are no
+   expressions that can be matches by certain pairs of tree nodes.
+   Also, if a predicate can match only one code, we can hardwire that
+   code into the node testing the predicate.
+
+   Some predicates are flagged as special.  validate_pattern will not
+   warn about modeless match_operand expressions if they have a
+   special predicate.  Predicates that allow only constants are also
+   treated as special, for this purpose.
+
+   validate_pattern will warn about predicates that allow non-lvalues
+   when they appear in destination operands.
+
+   Calculating the set of rtx codes that can possibly be accepted by a
+   predicate expression EXP requires a three-state logic: any given
+   subexpression may definitively accept a code C (Y), definitively
+   reject a code C (N), or may have an indeterminate effect (I).  N
+   and I is N; Y or I is Y; Y and I, N or I are both I.  Here are full
+   truth tables.
+
+     a b  a&b  a|b
+     Y Y   Y    Y
+     N Y   N    Y
+     N N   N    N
+     I Y   I    Y
+     I N   N    I
+     I I   I    I
+
+   We represent Y with 1, N with 0, I with 2.  If any code is left in
+   an I state by the complete expression, we must assume that that
+   code can be accepted.  */
+
+#define N 0
+#define Y 1
+#define I 2
+
+#define TRISTATE_AND(a,b)			\
+  ((a) == I ? ((b) == N ? N : I) :		\
+   (b) == I ? ((a) == N ? N : I) :		\
+   (a) && (b))
+
+#define TRISTATE_OR(a,b)			\
+  ((a) == I ? ((b) == Y ? Y : I) :		\
+   (b) == I ? ((a) == Y ? Y : I) :		\
+   (a) || (b))
+
+#define TRISTATE_NOT(a)				\
+  ((a) == I ? I : !(a))
+
+/* 0 means no warning about that code yet, 1 means warned.  */
+static char did_you_mean_codes[NUM_RTX_CODE];
+
+/* Recursively calculate the set of rtx codes accepted by the
+   predicate expression EXP, writing the result to CODES.  */
+static void
+compute_predicate_codes (rtx exp, char codes[NUM_RTX_CODE])
+{
+  char op0_codes[NUM_RTX_CODE];
+  char op1_codes[NUM_RTX_CODE];
+  char op2_codes[NUM_RTX_CODE];
+  int i;
+
+  switch (GET_CODE (exp))
+    {
+    case AND:
+      compute_predicate_codes (XEXP (exp, 0), op0_codes);
+      compute_predicate_codes (XEXP (exp, 1), op1_codes);
+      for (i = 0; i < NUM_RTX_CODE; i++)
+	codes[i] = TRISTATE_AND (op0_codes[i], op1_codes[i]);
+      break;
+
+    case IOR:
+      compute_predicate_codes (XEXP (exp, 0), op0_codes);
+      compute_predicate_codes (XEXP (exp, 1), op1_codes);
+      for (i = 0; i < NUM_RTX_CODE; i++)
+	codes[i] = TRISTATE_OR (op0_codes[i], op1_codes[i]);
+      break;
+    case NOT:
+      compute_predicate_codes (XEXP (exp, 0), op0_codes);
+      for (i = 0; i < NUM_RTX_CODE; i++)
+	codes[i] = TRISTATE_NOT (op0_codes[i]);
+      break;
+
+    case IF_THEN_ELSE:
+      /* a ? b : c  accepts the same codes as (a & b) | (!a & c).  */
+      compute_predicate_codes (XEXP (exp, 0), op0_codes);
+      compute_predicate_codes (XEXP (exp, 1), op1_codes);
+      compute_predicate_codes (XEXP (exp, 2), op2_codes);
+      for (i = 0; i < NUM_RTX_CODE; i++)
+	codes[i] = TRISTATE_OR (TRISTATE_AND (op0_codes[i], op1_codes[i]),
+				TRISTATE_AND (TRISTATE_NOT (op0_codes[i]),
+					      op2_codes[i]));
+      break;
+
+    case MATCH_CODE:
+      /* MATCH_CODE allows a specified list of codes.  However, if it
+	 does not apply to the top level of the expression, it does not
+	 constrain the set of codes for the top level.  */
+      if (XSTR (exp, 1)[0] != '\0')
+	{
+	  memset (codes, Y, NUM_RTX_CODE);
+	  break;
+	}
+
+      memset (codes, N, NUM_RTX_CODE);
+      {
+	const char *next_code = XSTR (exp, 0);
+	const char *code;
+
+	if (*next_code == '\0')
+	  {
+	    message_with_line (pattern_lineno, "empty match_code expression");
+	    error_count++;
+	    break;
+	  }
+
+	while ((code = scan_comma_elt (&next_code)) != 0)
+	  {
+	    size_t n = next_code - code;
+	    int found_it = 0;
+
+	    for (i = 0; i < NUM_RTX_CODE; i++)
+	      if (!strncmp (code, GET_RTX_NAME (i), n)
+		  && GET_RTX_NAME (i)[n] == '\0')
+		{
+		  codes[i] = Y;
+		  found_it = 1;
+		  break;
+		}
+	    if (!found_it)
+	      {
+		message_with_line (pattern_lineno, "match_code \"%.*s\" matches nothing",
+				   (int) n, code);
+		error_count ++;
+		for (i = 0; i < NUM_RTX_CODE; i++)
+		  if (!strncasecmp (code, GET_RTX_NAME (i), n)
+		      && GET_RTX_NAME (i)[n] == '\0'
+		      && !did_you_mean_codes[i])
+		    {
+		      did_you_mean_codes[i] = 1;
+		      message_with_line (pattern_lineno, "(did you mean \"%s\"?)", GET_RTX_NAME (i));
+		    }
+	      }
+
+	  }
+      }
+      break;
+
+    case MATCH_OPERAND:
+      /* MATCH_OPERAND disallows the set of codes that the named predicate
+	 disallows, and is indeterminate for the codes that it does allow.  */
+      {
+	struct pred_data *p = lookup_predicate (XSTR (exp, 1));
+	if (!p)
+	  {
+	    message_with_line (pattern_lineno,
+			       "reference to unknown predicate '%s'",
+			       XSTR (exp, 1));
+	    error_count++;
+	    break;
+	  }
+	for (i = 0; i < NUM_RTX_CODE; i++)
+	  codes[i] = p->codes[i] ? I : N;
+      }
+      break;
+
+
+    case MATCH_TEST:
+      /* (match_test WHATEVER) is completely indeterminate.  */
+      memset (codes, I, NUM_RTX_CODE);
+      break;
+
+    default:
+      message_with_line (pattern_lineno,
+	 "'%s' cannot be used in a define_predicate expression",
+	 GET_RTX_NAME (GET_CODE (exp)));
+      error_count++;
+      memset (codes, I, NUM_RTX_CODE);
+      break;
+    }
+}
+
+#undef TRISTATE_OR
+#undef TRISTATE_AND
+#undef TRISTATE_NOT
+
+/* Process a define_predicate expression: compute the set of predicates
+   that can be matched, and record this as a known predicate.  */
+static void
+process_define_predicate (rtx desc)
+{
+  struct pred_data *pred = XCNEW (struct pred_data);
+  char codes[NUM_RTX_CODE];
+  int i;
+
+  pred->name = XSTR (desc, 0);
+  if (GET_CODE (desc) == DEFINE_SPECIAL_PREDICATE)
+    pred->special = 1;
+
+  compute_predicate_codes (XEXP (desc, 1), codes);
+
+  for (i = 0; i < NUM_RTX_CODE; i++)
+    if (codes[i] != N)
+      add_predicate_code (pred, i);
+
+  add_predicate (pred);
+}
+#undef I
+#undef N
+#undef Y
+
+
+static struct decision *new_decision
+  (const char *, struct decision_head *);
+static struct decision_test *new_decision_test
+  (enum decision_type, struct decision_test ***);
+static rtx find_operand
+  (rtx, int, rtx);
+static rtx find_matching_operand
+  (rtx, int);
+static void validate_pattern
+  (rtx, rtx, rtx, int);
+static struct decision *add_to_sequence
+  (rtx, struct decision_head *, const char *, enum routine_type, int);
+
+static int maybe_both_true_2
+  (struct decision_test *, struct decision_test *);
+static int maybe_both_true_1
+  (struct decision_test *, struct decision_test *);
+static int maybe_both_true
+  (struct decision *, struct decision *, int);
+
+static int nodes_identical_1
+  (struct decision_test *, struct decision_test *);
+static int nodes_identical
+  (struct decision *, struct decision *);
+static void merge_accept_insn
+  (struct decision *, struct decision *);
+static void merge_trees
+  (struct decision_head *, struct decision_head *);
+
+static void factor_tests
+  (struct decision_head *);
+static void simplify_tests
+  (struct decision_head *);
+static int break_out_subroutines
+  (struct decision_head *, int);
+static void find_afterward
+  (struct decision_head *, struct decision *);
+
+static void change_state
+  (const char *, const char *, const char *);
+static void print_code
+  (enum rtx_code);
+static void write_afterward
+  (struct decision *, struct decision *, const char *);
+static struct decision *write_switch
+  (struct decision *, int);
+static void write_cond
+  (struct decision_test *, int, enum routine_type);
+static void write_action
+  (struct decision *, struct decision_test *, int, int,
+   struct decision *, enum routine_type);
+static int is_unconditional
+  (struct decision_test *, enum routine_type);
+static int write_node
+  (struct decision *, int, enum routine_type);
+static void write_tree_1
+  (struct decision_head *, int, enum routine_type);
+static void write_tree
+  (struct decision_head *, const char *, enum routine_type, int);
+static void write_subroutine
+  (struct decision_head *, enum routine_type);
+static void write_subroutines
+  (struct decision_head *, enum routine_type);
+static void write_header
+  (void);
+
+static struct decision_head make_insn_sequence
+  (rtx, enum routine_type);
+static void process_tree
+  (struct decision_head *, enum routine_type);
+
+static void debug_decision_0
+  (struct decision *, int, int);
+static void debug_decision_1
+  (struct decision *, int);
+static void debug_decision_2
+  (struct decision_test *);
+extern void debug_decision
+  (struct decision *);
+extern void debug_decision_list
+  (struct decision *);
+
+/* Create a new node in sequence after LAST.  */
+
+static struct decision *
+new_decision (const char *position, struct decision_head *last)
+{
+  struct decision *new_decision = XCNEW (struct decision);
+
+  new_decision->success = *last;
+  new_decision->position = xstrdup (position);
+  new_decision->number = next_number++;
+
+  last->first = last->last = new_decision;
+  return new_decision;
+}
+
+/* Create a new test and link it in at PLACE.  */
+
+static struct decision_test *
+new_decision_test (enum decision_type type, struct decision_test ***pplace)
+{
+  struct decision_test **place = *pplace;
+  struct decision_test *test;
+
+  test = XNEW (struct decision_test);
+  test->next = *place;
+  test->type = type;
+  *place = test;
+
+  place = &test->next;
+  *pplace = place;
+
+  return test;
+}
+
+/* Search for and return operand N, stop when reaching node STOP.  */
+
+static rtx
+find_operand (rtx pattern, int n, rtx stop)
+{
+  const char *fmt;
+  RTX_CODE code;
+  int i, j, len;
+  rtx r;
+
+  if (pattern == stop)
+    return stop;
+
+  code = GET_CODE (pattern);
+  if ((code == MATCH_SCRATCH
+       || code == MATCH_OPERAND
+       || code == MATCH_OPERATOR
+       || code == MATCH_PARALLEL)
+      && XINT (pattern, 0) == n)
+    return pattern;
+
+  fmt = GET_RTX_FORMAT (code);
+  len = GET_RTX_LENGTH (code);
+  for (i = 0; i < len; i++)
+    {
+      switch (fmt[i])
+	{
+	case 'e': case 'u':
+	  if ((r = find_operand (XEXP (pattern, i), n, stop)) != NULL_RTX)
+	    return r;
+	  break;
+
+	case 'V':
+	  if (! XVEC (pattern, i))
+	    break;
+	  /* Fall through.  */
+
+	case 'E':
+	  for (j = 0; j < XVECLEN (pattern, i); j++)
+	    if ((r = find_operand (XVECEXP (pattern, i, j), n, stop))
+		!= NULL_RTX)
+	      return r;
+	  break;
+
+	case 'i': case 'w': case '0': case 's':
+	  break;
+
+	default:
+	  gcc_unreachable ();
+	}
+    }
+
+  return NULL;
+}
+
+/* Search for and return operand M, such that it has a matching
+   constraint for operand N.  */
+
+static rtx
+find_matching_operand (rtx pattern, int n)
+{
+  const char *fmt;
+  RTX_CODE code;
+  int i, j, len;
+  rtx r;
+
+  code = GET_CODE (pattern);
+  if (code == MATCH_OPERAND
+      && (XSTR (pattern, 2)[0] == '0' + n
+	  || (XSTR (pattern, 2)[0] == '%'
+	      && XSTR (pattern, 2)[1] == '0' + n)))
+    return pattern;
+
+  fmt = GET_RTX_FORMAT (code);
+  len = GET_RTX_LENGTH (code);
+  for (i = 0; i < len; i++)
+    {
+      switch (fmt[i])
+	{
+	case 'e': case 'u':
+	  if ((r = find_matching_operand (XEXP (pattern, i), n)))
+	    return r;
+	  break;
+
+	case 'V':
+	  if (! XVEC (pattern, i))
+	    break;
+	  /* Fall through.  */
+
+	case 'E':
+	  for (j = 0; j < XVECLEN (pattern, i); j++)
+	    if ((r = find_matching_operand (XVECEXP (pattern, i, j), n)))
+	      return r;
+	  break;
+
+	case 'i': case 'w': case '0': case 's':
+	  break;
+
+	default:
+	  gcc_unreachable ();
+	}
+    }
+
+  return NULL;
+}
+
+
+/* Check for various errors in patterns.  SET is nonnull for a destination,
+   and is the complete set pattern.  SET_CODE is '=' for normal sets, and
+   '+' within a context that requires in-out constraints.  */
+
+static void
+validate_pattern (rtx pattern, rtx insn, rtx set, int set_code)
+{
+  const char *fmt;
+  RTX_CODE code;
+  size_t i, len;
+  int j;
+
+  code = GET_CODE (pattern);
+  switch (code)
+    {
+    case MATCH_SCRATCH:
+      return;
+    case MATCH_DUP:
+    case MATCH_OP_DUP:
+    case MATCH_PAR_DUP:
+      if (find_operand (insn, XINT (pattern, 0), pattern) == pattern)
+	{
+	  message_with_line (pattern_lineno,
+			     "operand %i duplicated before defined",
+			     XINT (pattern, 0));
+          error_count++;
+	}
+      break;
+    case MATCH_OPERAND:
+    case MATCH_OPERATOR:
+      {
+	const char *pred_name = XSTR (pattern, 1);
+	const struct pred_data *pred;
+	const char *c_test;
+
+	if (GET_CODE (insn) == DEFINE_INSN)
+	  c_test = XSTR (insn, 2);
+	else
+	  c_test = XSTR (insn, 1);
+
+	if (pred_name[0] != 0)
+	  {
+	    pred = lookup_predicate (pred_name);
+	    if (!pred)
+	      message_with_line (pattern_lineno,
+				 "warning: unknown predicate '%s'",
+				 pred_name);
+	  }
+	else
+	  pred = 0;
+
+	if (code == MATCH_OPERAND)
+	  {
+	    const char constraints0 = XSTR (pattern, 2)[0];
+
+	    /* In DEFINE_EXPAND, DEFINE_SPLIT, and DEFINE_PEEPHOLE2, we
+	       don't use the MATCH_OPERAND constraint, only the predicate.
+	       This is confusing to folks doing new ports, so help them
+	       not make the mistake.  */
+	    if (GET_CODE (insn) == DEFINE_EXPAND
+		|| GET_CODE (insn) == DEFINE_SPLIT
+		|| GET_CODE (insn) == DEFINE_PEEPHOLE2)
+	      {
+		if (constraints0)
+		  message_with_line (pattern_lineno,
+				     "warning: constraints not supported in %s",
+				     rtx_name[GET_CODE (insn)]);
+	      }
+
+	    /* A MATCH_OPERAND that is a SET should have an output reload.  */
+	    else if (set && constraints0)
+	      {
+		if (set_code == '+')
+		  {
+		    if (constraints0 == '+')
+		      ;
+		    /* If we've only got an output reload for this operand,
+		       we'd better have a matching input operand.  */
+		    else if (constraints0 == '='
+			     && find_matching_operand (insn, XINT (pattern, 0)))
+		      ;
+		    else
+		      {
+			message_with_line (pattern_lineno,
+					   "operand %d missing in-out reload",
+					   XINT (pattern, 0));
+			error_count++;
+		      }
+		  }
+		else if (constraints0 != '=' && constraints0 != '+')
+		  {
+		    message_with_line (pattern_lineno,
+				       "operand %d missing output reload",
+				       XINT (pattern, 0));
+		    error_count++;
+		  }
+	      }
+	  }
+
+	/* Allowing non-lvalues in destinations -- particularly CONST_INT --
+	   while not likely to occur at runtime, results in less efficient
+	   code from insn-recog.c.  */
+	if (set && pred && pred->allows_non_lvalue)
+	  message_with_line (pattern_lineno,
+			     "warning: destination operand %d "
+			     "allows non-lvalue",
+			     XINT (pattern, 0));
+
+	/* A modeless MATCH_OPERAND can be handy when we can check for
+	   multiple modes in the c_test.  In most other cases, it is a
+	   mistake.  Only DEFINE_INSN is eligible, since SPLIT and
+	   PEEP2 can FAIL within the output pattern.  Exclude special
+	   predicates, which check the mode themselves.  Also exclude
+	   predicates that allow only constants.  Exclude the SET_DEST
+	   of a call instruction, as that is a common idiom.  */
+
+	if (GET_MODE (pattern) == VOIDmode
+	    && code == MATCH_OPERAND
+	    && GET_CODE (insn) == DEFINE_INSN
+	    && pred
+	    && !pred->special
+	    && pred->allows_non_const
+	    && strstr (c_test, "operands") == NULL
+	    && ! (set
+		  && GET_CODE (set) == SET
+		  && GET_CODE (SET_SRC (set)) == CALL))
+	  message_with_line (pattern_lineno,
+			     "warning: operand %d missing mode?",
+			     XINT (pattern, 0));
+	return;
+      }
+
+    case SET:
+      {
+	enum machine_mode dmode, smode;
+	rtx dest, src;
+
+	dest = SET_DEST (pattern);
+	src = SET_SRC (pattern);
+
+	/* STRICT_LOW_PART is a wrapper.  Its argument is the real
+	   destination, and it's mode should match the source.  */
+	if (GET_CODE (dest) == STRICT_LOW_PART)
+	  dest = XEXP (dest, 0);
+
+	/* Find the referent for a DUP.  */
+
+	if (GET_CODE (dest) == MATCH_DUP
+	    || GET_CODE (dest) == MATCH_OP_DUP
+	    || GET_CODE (dest) == MATCH_PAR_DUP)
+	  dest = find_operand (insn, XINT (dest, 0), NULL);
+
+	if (GET_CODE (src) == MATCH_DUP
+	    || GET_CODE (src) == MATCH_OP_DUP
+	    || GET_CODE (src) == MATCH_PAR_DUP)
+	  src = find_operand (insn, XINT (src, 0), NULL);
+
+	dmode = GET_MODE (dest);
+	smode = GET_MODE (src);
+
+	/* The mode of an ADDRESS_OPERAND is the mode of the memory
+	   reference, not the mode of the address.  */
+	if (GET_CODE (src) == MATCH_OPERAND
+	    && ! strcmp (XSTR (src, 1), "address_operand"))
+	  ;
+
+        /* The operands of a SET must have the same mode unless one
+	   is VOIDmode.  */
+        else if (dmode != VOIDmode && smode != VOIDmode && dmode != smode)
+	  {
+	    message_with_line (pattern_lineno,
+			       "mode mismatch in set: %smode vs %smode",
+			       GET_MODE_NAME (dmode), GET_MODE_NAME (smode));
+	    error_count++;
+	  }
+
+	/* If only one of the operands is VOIDmode, and PC or CC0 is
+	   not involved, it's probably a mistake.  */
+	else if (dmode != smode
+		 && GET_CODE (dest) != PC
+		 && GET_CODE (dest) != CC0
+		 && GET_CODE (src) != PC
+		 && GET_CODE (src) != CC0
+		 && GET_CODE (src) != CONST_INT)
+	  {
+	    const char *which;
+	    which = (dmode == VOIDmode ? "destination" : "source");
+	    message_with_line (pattern_lineno,
+			       "warning: %s missing a mode?", which);
+	  }
+
+	if (dest != SET_DEST (pattern))
+	  validate_pattern (dest, insn, pattern, '=');
+	validate_pattern (SET_DEST (pattern), insn, pattern, '=');
+        validate_pattern (SET_SRC (pattern), insn, NULL_RTX, 0);
+        return;
+      }
+
+    case CLOBBER:
+      validate_pattern (SET_DEST (pattern), insn, pattern, '=');
+      return;
+
+    case ZERO_EXTRACT:
+      validate_pattern (XEXP (pattern, 0), insn, set, set ? '+' : 0);
+      validate_pattern (XEXP (pattern, 1), insn, NULL_RTX, 0);
+      validate_pattern (XEXP (pattern, 2), insn, NULL_RTX, 0);
+      return;
+
+    case STRICT_LOW_PART:
+      validate_pattern (XEXP (pattern, 0), insn, set, set ? '+' : 0);
+      return;
+
+    case LABEL_REF:
+      if (GET_MODE (XEXP (pattern, 0)) != VOIDmode)
+	{
+	  message_with_line (pattern_lineno,
+			     "operand to label_ref %smode not VOIDmode",
+			     GET_MODE_NAME (GET_MODE (XEXP (pattern, 0))));
+	  error_count++;
+	}
+      break;
+
+    default:
+      break;
+    }
+
+  fmt = GET_RTX_FORMAT (code);
+  len = GET_RTX_LENGTH (code);
+  for (i = 0; i < len; i++)
+    {
+      switch (fmt[i])
+	{
+	case 'e': case 'u':
+	  validate_pattern (XEXP (pattern, i), insn, NULL_RTX, 0);
+	  break;
+
+	case 'E':
+	  for (j = 0; j < XVECLEN (pattern, i); j++)
+	    validate_pattern (XVECEXP (pattern, i, j), insn, NULL_RTX, 0);
+	  break;
+
+	case 'i': case 'w': case '0': case 's':
+	  break;
+
+	default:
+	  gcc_unreachable ();
+	}
+    }
+}
+
+/* Create a chain of nodes to verify that an rtl expression matches
+   PATTERN.
+
+   LAST is a pointer to the listhead in the previous node in the chain (or
+   in the calling function, for the first node).
+
+   POSITION is the string representing the current position in the insn.
+
+   INSN_TYPE is the type of insn for which we are emitting code.
+
+   A pointer to the final node in the chain is returned.  */
+
+static struct decision *
+add_to_sequence (rtx pattern, struct decision_head *last, const char *position,
+		 enum routine_type insn_type, int top)
+{
+  RTX_CODE code;
+  struct decision *this_decision, *sub;
+  struct decision_test *test;
+  struct decision_test **place;
+  char *subpos;
+  size_t i;
+  const char *fmt;
+  int depth = strlen (position);
+  int len;
+  enum machine_mode mode;
+
+  if (depth > max_depth)
+    max_depth = depth;
+
+  subpos = XNEWVAR (char, depth + 2);
+  strcpy (subpos, position);
+  subpos[depth + 1] = 0;
+
+  sub = this_decision = new_decision (position, last);
+  place = &this_decision->tests;
+
+ restart:
+  mode = GET_MODE (pattern);
+  code = GET_CODE (pattern);
+
+  switch (code)
+    {
+    case PARALLEL:
+      /* Toplevel peephole pattern.  */
+      if (insn_type == PEEPHOLE2 && top)
+	{
+	  int num_insns;
+
+	  /* Check we have sufficient insns.  This avoids complications
+	     because we then know peep2_next_insn never fails.  */
+	  num_insns = XVECLEN (pattern, 0);
+	  if (num_insns > 1)
+	    {
+	      test = new_decision_test (DT_num_insns, &place);
+	      test->u.num_insns = num_insns;
+	      last = &sub->success;
+	    }
+	  else
+	    {
+	      /* We don't need the node we just created -- unlink it.  */
+	      last->first = last->last = NULL;
+	    }
+
+	  for (i = 0; i < (size_t) XVECLEN (pattern, 0); i++)
+	    {
+	      /* Which insn we're looking at is represented by A-Z. We don't
+	         ever use 'A', however; it is always implied.  */
+
+	      subpos[depth] = (i > 0 ? 'A' + i : 0);
+	      sub = add_to_sequence (XVECEXP (pattern, 0, i),
+				     last, subpos, insn_type, 0);
+	      last = &sub->success;
+	    }
+	  goto ret;
+	}
+
+      /* Else nothing special.  */
+      break;
+
+    case MATCH_PARALLEL:
+      /* The explicit patterns within a match_parallel enforce a minimum
+	 length on the vector.  The match_parallel predicate may allow
+	 for more elements.  We do need to check for this minimum here
+	 or the code generated to match the internals may reference data
+	 beyond the end of the vector.  */
+      test = new_decision_test (DT_veclen_ge, &place);
+      test->u.veclen = XVECLEN (pattern, 2);
+      /* Fall through.  */
+
+    case MATCH_OPERAND:
+    case MATCH_SCRATCH:
+    case MATCH_OPERATOR:
+      {
+	RTX_CODE was_code = code;
+	const char *pred_name;
+	bool allows_const_int = true;
+
+	if (code == MATCH_SCRATCH)
+	  {
+	    pred_name = "scratch_operand";
+	    code = UNKNOWN;
+	  }
+	else
+	  {
+	    pred_name = XSTR (pattern, 1);
+	    if (code == MATCH_PARALLEL)
+	      code = PARALLEL;
+	    else
+	      code = UNKNOWN;
+	  }
+
+	if (pred_name[0] != 0)
+	  {
+	    const struct pred_data *pred;
+
+	    test = new_decision_test (DT_pred, &place);
+	    test->u.pred.name = pred_name;
+	    test->u.pred.mode = mode;
+
+	    /* See if we know about this predicate.
+	       If we do, remember it for use below.
+
+	       We can optimize the generated code a little if either
+	       (a) the predicate only accepts one code, or (b) the
+	       predicate does not allow CONST_INT, in which case it
+	       can match only if the modes match.  */
+	    pred = lookup_predicate (pred_name);
+	    if (pred)
+	      {
+		test->u.pred.data = pred;
+		allows_const_int = pred->codes[CONST_INT];
+		if (was_code == MATCH_PARALLEL
+		    && pred->singleton != PARALLEL)
+		  message_with_line (pattern_lineno,
+			"predicate '%s' used in match_parallel "
+			"does not allow only PARALLEL", pred->name);
+		else
+		  code = pred->singleton;
+	      }
+	    else
+	      message_with_line (pattern_lineno,
+			"warning: unknown predicate '%s' in '%s' expression",
+			pred_name, GET_RTX_NAME (was_code));
+	  }
+
+	/* Can't enforce a mode if we allow const_int.  */
+	if (allows_const_int)
+	  mode = VOIDmode;
+
+	/* Accept the operand, i.e. record it in `operands'.  */
+	test = new_decision_test (DT_accept_op, &place);
+	test->u.opno = XINT (pattern, 0);
+
+	if (was_code == MATCH_OPERATOR || was_code == MATCH_PARALLEL)
+	  {
+	    char base = (was_code == MATCH_OPERATOR ? '0' : 'a');
+	    for (i = 0; i < (size_t) XVECLEN (pattern, 2); i++)
+	      {
+		subpos[depth] = i + base;
+		sub = add_to_sequence (XVECEXP (pattern, 2, i),
+				       &sub->success, subpos, insn_type, 0);
+	      }
+	  }
+	goto fini;
+      }
+
+    case MATCH_OP_DUP:
+      code = UNKNOWN;
+
+      test = new_decision_test (DT_dup, &place);
+      test->u.dup = XINT (pattern, 0);
+
+      test = new_decision_test (DT_accept_op, &place);
+      test->u.opno = XINT (pattern, 0);
+
+      for (i = 0; i < (size_t) XVECLEN (pattern, 1); i++)
+	{
+	  subpos[depth] = i + '0';
+	  sub = add_to_sequence (XVECEXP (pattern, 1, i),
+				 &sub->success, subpos, insn_type, 0);
+	}
+      goto fini;
+
+    case MATCH_DUP:
+    case MATCH_PAR_DUP:
+      code = UNKNOWN;
+
+      test = new_decision_test (DT_dup, &place);
+      test->u.dup = XINT (pattern, 0);
+      goto fini;
+
+    case ADDRESS:
+      pattern = XEXP (pattern, 0);
+      goto restart;
+
+    default:
+      break;
+    }
+
+  fmt = GET_RTX_FORMAT (code);
+  len = GET_RTX_LENGTH (code);
+
+  /* Do tests against the current node first.  */
+  for (i = 0; i < (size_t) len; i++)
+    {
+      if (fmt[i] == 'i')
+	{
+	  gcc_assert (i < 2);
+
+	  if (!i)
+	    {
+	      test = new_decision_test (DT_elt_zero_int, &place);
+	      test->u.intval = XINT (pattern, i);
+	    }
+	  else
+	    {
+	      test = new_decision_test (DT_elt_one_int, &place);
+	      test->u.intval = XINT (pattern, i);
+	    }
+	}
+      else if (fmt[i] == 'w')
+	{
+	  /* If this value actually fits in an int, we can use a switch
+	     statement here, so indicate that.  */
+	  enum decision_type type
+	    = ((int) XWINT (pattern, i) == XWINT (pattern, i))
+	      ? DT_elt_zero_wide_safe : DT_elt_zero_wide;
+
+	  gcc_assert (!i);
+
+	  test = new_decision_test (type, &place);
+	  test->u.intval = XWINT (pattern, i);
+	}
+      else if (fmt[i] == 'E')
+	{
+	  gcc_assert (!i);
+
+	  test = new_decision_test (DT_veclen, &place);
+	  test->u.veclen = XVECLEN (pattern, i);
+	}
+    }
+
+  /* Now test our sub-patterns.  */
+  for (i = 0; i < (size_t) len; i++)
+    {
+      switch (fmt[i])
+	{
+	case 'e': case 'u':
+	  subpos[depth] = '0' + i;
+	  sub = add_to_sequence (XEXP (pattern, i), &sub->success,
+				 subpos, insn_type, 0);
+	  break;
+
+	case 'E':
+	  {
+	    int j;
+	    for (j = 0; j < XVECLEN (pattern, i); j++)
+	      {
+		subpos[depth] = 'a' + j;
+		sub = add_to_sequence (XVECEXP (pattern, i, j),
+				       &sub->success, subpos, insn_type, 0);
+	      }
+	    break;
+	  }
+
+	case 'i': case 'w':
+	  /* Handled above.  */
+	  break;
+	case '0':
+	  break;
+
+	default:
+	  gcc_unreachable ();
+	}
+    }
+
+ fini:
+  /* Insert nodes testing mode and code, if they're still relevant,
+     before any of the nodes we may have added above.  */
+  if (code != UNKNOWN)
+    {
+      place = &this_decision->tests;
+      test = new_decision_test (DT_code, &place);
+      test->u.code = code;
+    }
+
+  if (mode != VOIDmode)
+    {
+      place = &this_decision->tests;
+      test = new_decision_test (DT_mode, &place);
+      test->u.mode = mode;
+    }
+
+  /* If we didn't insert any tests or accept nodes, hork.  */
+  gcc_assert (this_decision->tests);
+
+ ret:
+  free (subpos);
+  return sub;
+}
+
+/* A subroutine of maybe_both_true; examines only one test.
+   Returns > 0 for "definitely both true" and < 0 for "maybe both true".  */
+
+static int
+maybe_both_true_2 (struct decision_test *d1, struct decision_test *d2)
+{
+  if (d1->type == d2->type)
+    {
+      switch (d1->type)
+	{
+	case DT_num_insns:
+	  if (d1->u.num_insns == d2->u.num_insns)
+	    return 1;
+	  else
+	    return -1;
+
+	case DT_mode:
+	  return d1->u.mode == d2->u.mode;
+
+	case DT_code:
+	  return d1->u.code == d2->u.code;
+
+	case DT_veclen:
+	  return d1->u.veclen == d2->u.veclen;
+
+	case DT_elt_zero_int:
+	case DT_elt_one_int:
+	case DT_elt_zero_wide:
+	case DT_elt_zero_wide_safe:
+	  return d1->u.intval == d2->u.intval;
+
+	default:
+	  break;
+	}
+    }
+
+  /* If either has a predicate that we know something about, set
+     things up so that D1 is the one that always has a known
+     predicate.  Then see if they have any codes in common.  */
+
+  if (d1->type == DT_pred || d2->type == DT_pred)
+    {
+      if (d2->type == DT_pred)
+	{
+	  struct decision_test *tmp;
+	  tmp = d1, d1 = d2, d2 = tmp;
+	}
+
+      /* If D2 tests a mode, see if it matches D1.  */
+      if (d1->u.pred.mode != VOIDmode)
+	{
+	  if (d2->type == DT_mode)
+	    {
+	      if (d1->u.pred.mode != d2->u.mode
+		  /* The mode of an address_operand predicate is the
+		     mode of the memory, not the operand.  It can only
+		     be used for testing the predicate, so we must
+		     ignore it here.  */
+		  && strcmp (d1->u.pred.name, "address_operand") != 0)
+		return 0;
+	    }
+	  /* Don't check two predicate modes here, because if both predicates
+	     accept CONST_INT, then both can still be true even if the modes
+	     are different.  If they don't accept CONST_INT, there will be a
+	     separate DT_mode that will make maybe_both_true_1 return 0.  */
+	}
+
+      if (d1->u.pred.data)
+	{
+	  /* If D2 tests a code, see if it is in the list of valid
+	     codes for D1's predicate.  */
+	  if (d2->type == DT_code)
+	    {
+	      if (!d1->u.pred.data->codes[d2->u.code])
+		return 0;
+	    }
+
+	  /* Otherwise see if the predicates have any codes in common.  */
+	  else if (d2->type == DT_pred && d2->u.pred.data)
+	    {
+	      bool common = false;
+	      enum rtx_code c;
+
+	      for (c = 0; c < NUM_RTX_CODE; c++)
+		if (d1->u.pred.data->codes[c] && d2->u.pred.data->codes[c])
+		  {
+		    common = true;
+		    break;
+		  }
+
+	      if (!common)
+		return 0;
+	    }
+	}
+    }
+
+  /* Tests vs veclen may be known when strict equality is involved.  */
+  if (d1->type == DT_veclen && d2->type == DT_veclen_ge)
+    return d1->u.veclen >= d2->u.veclen;
+  if (d1->type == DT_veclen_ge && d2->type == DT_veclen)
+    return d2->u.veclen >= d1->u.veclen;
+
+  return -1;
+}
+
+/* A subroutine of maybe_both_true; examines all the tests for a given node.
+   Returns > 0 for "definitely both true" and < 0 for "maybe both true".  */
+
+static int
+maybe_both_true_1 (struct decision_test *d1, struct decision_test *d2)
+{
+  struct decision_test *t1, *t2;
+
+  /* A match_operand with no predicate can match anything.  Recognize
+     this by the existence of a lone DT_accept_op test.  */
+  if (d1->type == DT_accept_op || d2->type == DT_accept_op)
+    return 1;
+
+  /* Eliminate pairs of tests while they can exactly match.  */
+  while (d1 && d2 && d1->type == d2->type)
+    {
+      if (maybe_both_true_2 (d1, d2) == 0)
+	return 0;
+      d1 = d1->next, d2 = d2->next;
+    }
+
+  /* After that, consider all pairs.  */
+  for (t1 = d1; t1 ; t1 = t1->next)
+    for (t2 = d2; t2 ; t2 = t2->next)
+      if (maybe_both_true_2 (t1, t2) == 0)
+	return 0;
+
+  return -1;
+}
+
+/* Return 0 if we can prove that there is no RTL that can match both
+   D1 and D2.  Otherwise, return 1 (it may be that there is an RTL that
+   can match both or just that we couldn't prove there wasn't such an RTL).
+
+   TOPLEVEL is nonzero if we are to only look at the top level and not
+   recursively descend.  */
+
+static int
+maybe_both_true (struct decision *d1, struct decision *d2,
+		 int toplevel)
+{
+  struct decision *p1, *p2;
+  int cmp;
+
+  /* Don't compare strings on the different positions in insn.  Doing so
+     is incorrect and results in false matches from constructs like
+
+	[(set (subreg:HI (match_operand:SI "register_operand" "r") 0)
+	      (subreg:HI (match_operand:SI "register_operand" "r") 0))]
+     vs
+	[(set (match_operand:HI "register_operand" "r")
+	      (match_operand:HI "register_operand" "r"))]
+
+     If we are presented with such, we are recursing through the remainder
+     of a node's success nodes (from the loop at the end of this function).
+     Skip forward until we come to a position that matches.
+
+     Due to the way position strings are constructed, we know that iterating
+     forward from the lexically lower position (e.g. "00") will run into
+     the lexically higher position (e.g. "1") and not the other way around.
+     This saves a bit of effort.  */
+
+  cmp = strcmp (d1->position, d2->position);
+  if (cmp != 0)
+    {
+      gcc_assert (!toplevel);
+
+      /* If the d2->position was lexically lower, swap.  */
+      if (cmp > 0)
+	p1 = d1, d1 = d2, d2 = p1;
+
+      if (d1->success.first == 0)
+	return 1;
+      for (p1 = d1->success.first; p1; p1 = p1->next)
+	if (maybe_both_true (p1, d2, 0))
+	  return 1;
+
+      return 0;
+    }
+
+  /* Test the current level.  */
+  cmp = maybe_both_true_1 (d1->tests, d2->tests);
+  if (cmp >= 0)
+    return cmp;
+
+  /* We can't prove that D1 and D2 cannot both be true.  If we are only
+     to check the top level, return 1.  Otherwise, see if we can prove
+     that all choices in both successors are mutually exclusive.  If
+     either does not have any successors, we can't prove they can't both
+     be true.  */
+
+  if (toplevel || d1->success.first == 0 || d2->success.first == 0)
+    return 1;
+
+  for (p1 = d1->success.first; p1; p1 = p1->next)
+    for (p2 = d2->success.first; p2; p2 = p2->next)
+      if (maybe_both_true (p1, p2, 0))
+	return 1;
+
+  return 0;
+}
+
+/* A subroutine of nodes_identical.  Examine two tests for equivalence.  */
+
+static int
+nodes_identical_1 (struct decision_test *d1, struct decision_test *d2)
+{
+  switch (d1->type)
+    {
+    case DT_num_insns:
+      return d1->u.num_insns == d2->u.num_insns;
+
+    case DT_mode:
+      return d1->u.mode == d2->u.mode;
+
+    case DT_code:
+      return d1->u.code == d2->u.code;
+
+    case DT_pred:
+      return (d1->u.pred.mode == d2->u.pred.mode
+	      && strcmp (d1->u.pred.name, d2->u.pred.name) == 0);
+
+    case DT_c_test:
+      return strcmp (d1->u.c_test, d2->u.c_test) == 0;
+
+    case DT_veclen:
+    case DT_veclen_ge:
+      return d1->u.veclen == d2->u.veclen;
+
+    case DT_dup:
+      return d1->u.dup == d2->u.dup;
+
+    case DT_elt_zero_int:
+    case DT_elt_one_int:
+    case DT_elt_zero_wide:
+    case DT_elt_zero_wide_safe:
+      return d1->u.intval == d2->u.intval;
+
+    case DT_accept_op:
+      return d1->u.opno == d2->u.opno;
+
+    case DT_accept_insn:
+      /* Differences will be handled in merge_accept_insn.  */
+      return 1;
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* True iff the two nodes are identical (on one level only).  Due
+   to the way these lists are constructed, we shouldn't have to
+   consider different orderings on the tests.  */
+
+static int
+nodes_identical (struct decision *d1, struct decision *d2)
+{
+  struct decision_test *t1, *t2;
+
+  for (t1 = d1->tests, t2 = d2->tests; t1 && t2; t1 = t1->next, t2 = t2->next)
+    {
+      if (t1->type != t2->type)
+	return 0;
+      if (! nodes_identical_1 (t1, t2))
+	return 0;
+    }
+
+  /* For success, they should now both be null.  */
+  if (t1 != t2)
+    return 0;
+
+  /* Check that their subnodes are at the same position, as any one set
+     of sibling decisions must be at the same position.  Allowing this
+     requires complications to find_afterward and when change_state is
+     invoked.  */
+  if (d1->success.first
+      && d2->success.first
+      && strcmp (d1->success.first->position, d2->success.first->position))
+    return 0;
+
+  return 1;
+}
+
+/* A subroutine of merge_trees; given two nodes that have been declared
+   identical, cope with two insn accept states.  If they differ in the
+   number of clobbers, then the conflict was created by make_insn_sequence
+   and we can drop the with-clobbers version on the floor.  If both
+   nodes have no additional clobbers, we have found an ambiguity in the
+   source machine description.  */
+
+static void
+merge_accept_insn (struct decision *oldd, struct decision *addd)
+{
+  struct decision_test *old, *add;
+
+  for (old = oldd->tests; old; old = old->next)
+    if (old->type == DT_accept_insn)
+      break;
+  if (old == NULL)
+    return;
+
+  for (add = addd->tests; add; add = add->next)
+    if (add->type == DT_accept_insn)
+      break;
+  if (add == NULL)
+    return;
+
+  /* If one node is for a normal insn and the second is for the base
+     insn with clobbers stripped off, the second node should be ignored.  */
+
+  if (old->u.insn.num_clobbers_to_add == 0
+      && add->u.insn.num_clobbers_to_add > 0)
+    {
+      /* Nothing to do here.  */
+    }
+  else if (old->u.insn.num_clobbers_to_add > 0
+	   && add->u.insn.num_clobbers_to_add == 0)
+    {
+      /* In this case, replace OLD with ADD.  */
+      old->u.insn = add->u.insn;
+    }
+  else
+    {
+      message_with_line (add->u.insn.lineno, "`%s' matches `%s'",
+			 get_insn_name (add->u.insn.code_number),
+			 get_insn_name (old->u.insn.code_number));
+      message_with_line (old->u.insn.lineno, "previous definition of `%s'",
+			 get_insn_name (old->u.insn.code_number));
+      error_count++;
+    }
+}
+
+/* Merge two decision trees OLDH and ADDH, modifying OLDH destructively.  */
+
+static void
+merge_trees (struct decision_head *oldh, struct decision_head *addh)
+{
+  struct decision *next, *add;
+
+  if (addh->first == 0)
+    return;
+  if (oldh->first == 0)
+    {
+      *oldh = *addh;
+      return;
+    }
+
+  /* Trying to merge bits at different positions isn't possible.  */
+  gcc_assert (!strcmp (oldh->first->position, addh->first->position));
+
+  for (add = addh->first; add ; add = next)
+    {
+      struct decision *old, *insert_before = NULL;
+
+      next = add->next;
+
+      /* The semantics of pattern matching state that the tests are
+	 done in the order given in the MD file so that if an insn
+	 matches two patterns, the first one will be used.  However,
+	 in practice, most, if not all, patterns are unambiguous so
+	 that their order is independent.  In that case, we can merge
+	 identical tests and group all similar modes and codes together.
+
+	 Scan starting from the end of OLDH until we reach a point
+	 where we reach the head of the list or where we pass a
+	 pattern that could also be true if NEW is true.  If we find
+	 an identical pattern, we can merge them.  Also, record the
+	 last node that tests the same code and mode and the last one
+	 that tests just the same mode.
+
+	 If we have no match, place NEW after the closest match we found.  */
+
+      for (old = oldh->last; old; old = old->prev)
+	{
+	  if (nodes_identical (old, add))
+	    {
+	      merge_accept_insn (old, add);
+	      merge_trees (&old->success, &add->success);
+	      goto merged_nodes;
+	    }
+
+	  if (maybe_both_true (old, add, 0))
+	    break;
+
+	  /* Insert the nodes in DT test type order, which is roughly
+	     how expensive/important the test is.  Given that the tests
+	     are also ordered within the list, examining the first is
+	     sufficient.  */
+	  if ((int) add->tests->type < (int) old->tests->type)
+	    insert_before = old;
+	}
+
+      if (insert_before == NULL)
+	{
+	  add->next = NULL;
+	  add->prev = oldh->last;
+	  oldh->last->next = add;
+	  oldh->last = add;
+	}
+      else
+	{
+	  if ((add->prev = insert_before->prev) != NULL)
+	    add->prev->next = add;
+	  else
+	    oldh->first = add;
+	  add->next = insert_before;
+	  insert_before->prev = add;
+	}
+
+    merged_nodes:;
+    }
+}
+
+/* Walk the tree looking for sub-nodes that perform common tests.
+   Factor out the common test into a new node.  This enables us
+   (depending on the test type) to emit switch statements later.  */
+
+static void
+factor_tests (struct decision_head *head)
+{
+  struct decision *first, *next;
+
+  for (first = head->first; first && first->next; first = next)
+    {
+      enum decision_type type;
+      struct decision *new_dec, *old_last;
+
+      type = first->tests->type;
+      next = first->next;
+
+      /* Want at least two compatible sequential nodes.  */
+      if (next->tests->type != type)
+	continue;
+
+      /* Don't want all node types, just those we can turn into
+	 switch statements.  */
+      if (type != DT_mode
+	  && type != DT_code
+	  && type != DT_veclen
+	  && type != DT_elt_zero_int
+	  && type != DT_elt_one_int
+	  && type != DT_elt_zero_wide_safe)
+	continue;
+
+      /* If we'd been performing more than one test, create a new node
+         below our first test.  */
+      if (first->tests->next != NULL)
+	{
+	  new_dec = new_decision (first->position, &first->success);
+	  new_dec->tests = first->tests->next;
+	  first->tests->next = NULL;
+	}
+
+      /* Crop the node tree off after our first test.  */
+      first->next = NULL;
+      old_last = head->last;
+      head->last = first;
+
+      /* For each compatible test, adjust to perform only one test in
+	 the top level node, then merge the node back into the tree.  */
+      do
+	{
+	  struct decision_head h;
+
+	  if (next->tests->next != NULL)
+	    {
+	      new_dec = new_decision (next->position, &next->success);
+	      new_dec->tests = next->tests->next;
+	      next->tests->next = NULL;
+	    }
+	  new_dec = next;
+	  next = next->next;
+	  new_dec->next = NULL;
+	  h.first = h.last = new_dec;
+
+	  merge_trees (head, &h);
+	}
+      while (next && next->tests->type == type);
+
+      /* After we run out of compatible tests, graft the remaining nodes
+	 back onto the tree.  */
+      if (next)
+	{
+	  next->prev = head->last;
+	  head->last->next = next;
+	  head->last = old_last;
+	}
+    }
+
+  /* Recurse.  */
+  for (first = head->first; first; first = first->next)
+    factor_tests (&first->success);
+}
+
+/* After factoring, try to simplify the tests on any one node.
+   Tests that are useful for switch statements are recognizable
+   by having only a single test on a node -- we'll be manipulating
+   nodes with multiple tests:
+
+   If we have mode tests or code tests that are redundant with
+   predicates, remove them.  */
+
+static void
+simplify_tests (struct decision_head *head)
+{
+  struct decision *tree;
+
+  for (tree = head->first; tree; tree = tree->next)
+    {
+      struct decision_test *a, *b;
+
+      a = tree->tests;
+      b = a->next;
+      if (b == NULL)
+	continue;
+
+      /* Find a predicate node.  */
+      while (b && b->type != DT_pred)
+	b = b->next;
+      if (b)
+	{
+	  /* Due to how these tests are constructed, we don't even need
+	     to check that the mode and code are compatible -- they were
+	     generated from the predicate in the first place.  */
+	  while (a->type == DT_mode || a->type == DT_code)
+	    a = a->next;
+	  tree->tests = a;
+	}
+    }
+
+  /* Recurse.  */
+  for (tree = head->first; tree; tree = tree->next)
+    simplify_tests (&tree->success);
+}
+
+/* Count the number of subnodes of HEAD.  If the number is high enough,
+   make the first node in HEAD start a separate subroutine in the C code
+   that is generated.  */
+
+static int
+break_out_subroutines (struct decision_head *head, int initial)
+{
+  int size = 0;
+  struct decision *sub;
+
+  for (sub = head->first; sub; sub = sub->next)
+    size += 1 + break_out_subroutines (&sub->success, 0);
+
+  if (size > SUBROUTINE_THRESHOLD && ! initial)
+    {
+      head->first->subroutine_number = ++next_subroutine_number;
+      size = 1;
+    }
+  return size;
+}
+
+/* For each node p, find the next alternative that might be true
+   when p is true.  */
+
+static void
+find_afterward (struct decision_head *head, struct decision *real_afterward)
+{
+  struct decision *p, *q, *afterward;
+
+  /* We can't propagate alternatives across subroutine boundaries.
+     This is not incorrect, merely a minor optimization loss.  */
+
+  p = head->first;
+  afterward = (p->subroutine_number > 0 ? NULL : real_afterward);
+
+  for ( ; p ; p = p->next)
+    {
+      /* Find the next node that might be true if this one fails.  */
+      for (q = p->next; q ; q = q->next)
+	if (maybe_both_true (p, q, 1))
+	  break;
+
+      /* If we reached the end of the list without finding one,
+	 use the incoming afterward position.  */
+      if (!q)
+	q = afterward;
+      p->afterward = q;
+      if (q)
+	q->need_label = 1;
+    }
+
+  /* Recurse.  */
+  for (p = head->first; p ; p = p->next)
+    if (p->success.first)
+      find_afterward (&p->success, p->afterward);
+
+  /* When we are generating a subroutine, record the real afterward
+     position in the first node where write_tree can find it, and we
+     can do the right thing at the subroutine call site.  */
+  p = head->first;
+  if (p->subroutine_number > 0)
+    p->afterward = real_afterward;
+}
+
+/* Assuming that the state of argument is denoted by OLDPOS, take whatever
+   actions are necessary to move to NEWPOS.  If we fail to move to the
+   new state, branch to node AFTERWARD if nonzero, otherwise return.
+
+   Failure to move to the new state can only occur if we are trying to
+   match multiple insns and we try to step past the end of the stream.  */
+
+static void
+change_state (const char *oldpos, const char *newpos, const char *indent)
+{
+  int odepth = strlen (oldpos);
+  int ndepth = strlen (newpos);
+  int depth;
+  int old_has_insn, new_has_insn;
+
+  /* Pop up as many levels as necessary.  */
+  for (depth = odepth; strncmp (oldpos, newpos, depth) != 0; --depth)
+    continue;
+
+  /* Hunt for the last [A-Z] in both strings.  */
+  for (old_has_insn = odepth - 1; old_has_insn >= 0; --old_has_insn)
+    if (ISUPPER (oldpos[old_has_insn]))
+      break;
+  for (new_has_insn = ndepth - 1; new_has_insn >= 0; --new_has_insn)
+    if (ISUPPER (newpos[new_has_insn]))
+      break;
+
+  /* Go down to desired level.  */
+  while (depth < ndepth)
+    {
+      /* It's a different insn from the first one.  */
+      if (ISUPPER (newpos[depth]))
+	{
+	  printf ("%stem = peep2_next_insn (%d);\n",
+		  indent, newpos[depth] - 'A');
+	  printf ("%sx%d = PATTERN (tem);\n", indent, depth + 1);
+	}
+      else if (ISLOWER (newpos[depth]))
+	printf ("%sx%d = XVECEXP (x%d, 0, %d);\n",
+		indent, depth + 1, depth, newpos[depth] - 'a');
+      else
+	printf ("%sx%d = XEXP (x%d, %c);\n",
+		indent, depth + 1, depth, newpos[depth]);
+      ++depth;
+    }
+}
+
+/* Print the enumerator constant for CODE -- the upcase version of
+   the name.  */
+
+static void
+print_code (enum rtx_code code)
+{
+  const char *p;
+  for (p = GET_RTX_NAME (code); *p; p++)
+    putchar (TOUPPER (*p));
+}
+
+/* Emit code to cross an afterward link -- change state and branch.  */
+
+static void
+write_afterward (struct decision *start, struct decision *afterward,
+		 const char *indent)
+{
+  if (!afterward || start->subroutine_number > 0)
+    printf("%sgoto ret0;\n", indent);
+  else
+    {
+      change_state (start->position, afterward->position, indent);
+      printf ("%sgoto L%d;\n", indent, afterward->number);
+    }
+}
+
+/* Emit a HOST_WIDE_INT as an integer constant expression.  We need to take
+   special care to avoid "decimal constant is so large that it is unsigned"
+   warnings in the resulting code.  */
+
+static void
+print_host_wide_int (HOST_WIDE_INT val)
+{
+  HOST_WIDE_INT min = (unsigned HOST_WIDE_INT)1 << (HOST_BITS_PER_WIDE_INT-1);
+  if (val == min)
+    printf ("(" HOST_WIDE_INT_PRINT_DEC_C "-1)", val + 1);
+  else
+    printf (HOST_WIDE_INT_PRINT_DEC_C, val);
+}
+
+/* Emit a switch statement, if possible, for an initial sequence of
+   nodes at START.  Return the first node yet untested.  */
+
+static struct decision *
+write_switch (struct decision *start, int depth)
+{
+  struct decision *p = start;
+  enum decision_type type = p->tests->type;
+  struct decision *needs_label = NULL;
+
+  /* If we have two or more nodes in sequence that test the same one
+     thing, we may be able to use a switch statement.  */
+
+  if (!p->next
+      || p->tests->next
+      || p->next->tests->type != type
+      || p->next->tests->next
+      || nodes_identical_1 (p->tests, p->next->tests))
+    return p;
+
+  /* DT_code is special in that we can do interesting things with
+     known predicates at the same time.  */
+  if (type == DT_code)
+    {
+      char codemap[NUM_RTX_CODE];
+      struct decision *ret;
+      RTX_CODE code;
+
+      memset (codemap, 0, sizeof(codemap));
+
+      printf ("  switch (GET_CODE (x%d))\n    {\n", depth);
+      code = p->tests->u.code;
+      do
+	{
+	  if (p != start && p->need_label && needs_label == NULL)
+	    needs_label = p;
+
+	  printf ("    case ");
+	  print_code (code);
+	  printf (":\n      goto L%d;\n", p->success.first->number);
+	  p->success.first->need_label = 1;
+
+	  codemap[code] = 1;
+	  p = p->next;
+	}
+      while (p
+	     && ! p->tests->next
+	     && p->tests->type == DT_code
+	     && ! codemap[code = p->tests->u.code]);
+
+      /* If P is testing a predicate that we know about and we haven't
+	 seen any of the codes that are valid for the predicate, we can
+	 write a series of "case" statement, one for each possible code.
+	 Since we are already in a switch, these redundant tests are very
+	 cheap and will reduce the number of predicates called.  */
+
+      /* Note that while we write out cases for these predicates here,
+	 we don't actually write the test here, as it gets kinda messy.
+	 It is trivial to leave this to later by telling our caller that
+	 we only processed the CODE tests.  */
+      if (needs_label != NULL)
+	ret = needs_label;
+      else
+	ret = p;
+
+      while (p && p->tests->type == DT_pred && p->tests->u.pred.data)
+	{
+	  const struct pred_data *data = p->tests->u.pred.data;
+	  RTX_CODE c;
+	  for (c = 0; c < NUM_RTX_CODE; c++)
+	    if (codemap[c] && data->codes[c])
+	      goto pred_done;
+
+	  for (c = 0; c < NUM_RTX_CODE; c++)
+	    if (data->codes[c])
+	      {
+		fputs ("    case ", stdout);
+		print_code (c);
+		fputs (":\n", stdout);
+		codemap[c] = 1;
+	      }
+
+	  printf ("      goto L%d;\n", p->number);
+	  p->need_label = 1;
+	  p = p->next;
+	}
+
+    pred_done:
+      /* Make the default case skip the predicates we managed to match.  */
+
+      printf ("    default:\n");
+      if (p != ret)
+	{
+	  if (p)
+	    {
+	      printf ("      goto L%d;\n", p->number);
+	      p->need_label = 1;
+	    }
+	  else
+	    write_afterward (start, start->afterward, "      ");
+	}
+      else
+	printf ("     break;\n");
+      printf ("   }\n");
+
+      return ret;
+    }
+  else if (type == DT_mode
+	   || type == DT_veclen
+	   || type == DT_elt_zero_int
+	   || type == DT_elt_one_int
+	   || type == DT_elt_zero_wide_safe)
+    {
+      const char *indent = "";
+
+      /* We cast switch parameter to integer, so we must ensure that the value
+	 fits.  */
+      if (type == DT_elt_zero_wide_safe)
+	{
+	  indent = "  ";
+	  printf("  if ((int) XWINT (x%d, 0) == XWINT (x%d, 0))\n", depth, depth);
+	}
+      printf ("%s  switch (", indent);
+      switch (type)
+	{
+	case DT_mode:
+	  printf ("GET_MODE (x%d)", depth);
+	  break;
+	case DT_veclen:
+	  printf ("XVECLEN (x%d, 0)", depth);
+	  break;
+	case DT_elt_zero_int:
+	  printf ("XINT (x%d, 0)", depth);
+	  break;
+	case DT_elt_one_int:
+	  printf ("XINT (x%d, 1)", depth);
+	  break;
+	case DT_elt_zero_wide_safe:
+	  /* Convert result of XWINT to int for portability since some C
+	     compilers won't do it and some will.  */
+	  printf ("(int) XWINT (x%d, 0)", depth);
+	  break;
+	default:
+	  gcc_unreachable ();
+	}
+      printf (")\n%s    {\n", indent);
+
+      do
+	{
+	  /* Merge trees will not unify identical nodes if their
+	     sub-nodes are at different levels.  Thus we must check
+	     for duplicate cases.  */
+	  struct decision *q;
+	  for (q = start; q != p; q = q->next)
+	    if (nodes_identical_1 (p->tests, q->tests))
+	      goto case_done;
+
+	  if (p != start && p->need_label && needs_label == NULL)
+	    needs_label = p;
+
+	  printf ("%s    case ", indent);
+	  switch (type)
+	    {
+	    case DT_mode:
+	      printf ("%smode", GET_MODE_NAME (p->tests->u.mode));
+	      break;
+	    case DT_veclen:
+	      printf ("%d", p->tests->u.veclen);
+	      break;
+	    case DT_elt_zero_int:
+	    case DT_elt_one_int:
+	    case DT_elt_zero_wide:
+	    case DT_elt_zero_wide_safe:
+	      print_host_wide_int (p->tests->u.intval);
+	      break;
+	    default:
+	      gcc_unreachable ();
+	    }
+	  printf (":\n%s      goto L%d;\n", indent, p->success.first->number);
+	  p->success.first->need_label = 1;
+
+	  p = p->next;
+	}
+      while (p && p->tests->type == type && !p->tests->next);
+
+    case_done:
+      printf ("%s    default:\n%s      break;\n%s    }\n",
+	      indent, indent, indent);
+
+      return needs_label != NULL ? needs_label : p;
+    }
+  else
+    {
+      /* None of the other tests are amenable.  */
+      return p;
+    }
+}
+
+/* Emit code for one test.  */
+
+static void
+write_cond (struct decision_test *p, int depth,
+	    enum routine_type subroutine_type)
+{
+  switch (p->type)
+    {
+    case DT_num_insns:
+      printf ("peep2_current_count >= %d", p->u.num_insns);
+      break;
+
+    case DT_mode:
+      printf ("GET_MODE (x%d) == %smode", depth, GET_MODE_NAME (p->u.mode));
+      break;
+
+    case DT_code:
+      printf ("GET_CODE (x%d) == ", depth);
+      print_code (p->u.code);
+      break;
+
+    case DT_veclen:
+      printf ("XVECLEN (x%d, 0) == %d", depth, p->u.veclen);
+      break;
+
+    case DT_elt_zero_int:
+      printf ("XINT (x%d, 0) == %d", depth, (int) p->u.intval);
+      break;
+
+    case DT_elt_one_int:
+      printf ("XINT (x%d, 1) == %d", depth, (int) p->u.intval);
+      break;
+
+    case DT_elt_zero_wide:
+    case DT_elt_zero_wide_safe:
+      printf ("XWINT (x%d, 0) == ", depth);
+      print_host_wide_int (p->u.intval);
+      break;
+
+    case DT_const_int:
+      printf ("x%d == const_int_rtx[MAX_SAVED_CONST_INT + (%d)]",
+	      depth, (int) p->u.intval);
+      break;
+
+    case DT_veclen_ge:
+      printf ("XVECLEN (x%d, 0) >= %d", depth, p->u.veclen);
+      break;
+
+    case DT_dup:
+      printf ("rtx_equal_p (x%d, operands[%d])", depth, p->u.dup);
+      break;
+
+    case DT_pred:
+      printf ("%s (x%d, %smode)", p->u.pred.name, depth,
+	      GET_MODE_NAME (p->u.pred.mode));
+      break;
+
+    case DT_c_test:
+      print_c_condition (p->u.c_test);
+      break;
+
+    case DT_accept_insn:
+      gcc_assert (subroutine_type == RECOG);
+      gcc_assert (p->u.insn.num_clobbers_to_add);
+      printf ("pnum_clobbers != NULL");
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Emit code for one action.  The previous tests have succeeded;
+   TEST is the last of the chain.  In the normal case we simply
+   perform a state change.  For the `accept' tests we must do more work.  */
+
+static void
+write_action (struct decision *p, struct decision_test *test,
+	      int depth, int uncond, struct decision *success,
+	      enum routine_type subroutine_type)
+{
+  const char *indent;
+  int want_close = 0;
+
+  if (uncond)
+    indent = "  ";
+  else if (test->type == DT_accept_op || test->type == DT_accept_insn)
+    {
+      fputs ("    {\n", stdout);
+      indent = "      ";
+      want_close = 1;
+    }
+  else
+    indent = "    ";
+
+  if (test->type == DT_accept_op)
+    {
+      printf("%soperands[%d] = x%d;\n", indent, test->u.opno, depth);
+
+      /* Only allow DT_accept_insn to follow.  */
+      if (test->next)
+	{
+	  test = test->next;
+	  gcc_assert (test->type == DT_accept_insn);
+	}
+    }
+
+  /* Sanity check that we're now at the end of the list of tests.  */
+  gcc_assert (!test->next);
+
+  if (test->type == DT_accept_insn)
+    {
+      switch (subroutine_type)
+	{
+	case RECOG:
+	  if (test->u.insn.num_clobbers_to_add != 0)
+	    printf ("%s*pnum_clobbers = %d;\n",
+		    indent, test->u.insn.num_clobbers_to_add);
+	  printf ("%sreturn %d;  /* %s */\n", indent,
+		  test->u.insn.code_number,
+		  get_insn_name (test->u.insn.code_number));
+	  break;
+
+	case SPLIT:
+	  printf ("%sreturn gen_split_%d (insn, operands);\n",
+		  indent, test->u.insn.code_number);
+	  break;
+
+	case PEEPHOLE2:
+	  {
+	    int match_len = 0, i;
+
+	    for (i = strlen (p->position) - 1; i >= 0; --i)
+	      if (ISUPPER (p->position[i]))
+		{
+		  match_len = p->position[i] - 'A';
+		  break;
+		}
+	    printf ("%s*_pmatch_len = %d;\n", indent, match_len);
+	    printf ("%stem = gen_peephole2_%d (insn, operands);\n",
+		    indent, test->u.insn.code_number);
+	    printf ("%sif (tem != 0)\n%s  return tem;\n", indent, indent);
+	  }
+	  break;
+
+	default:
+	  gcc_unreachable ();
+	}
+    }
+  else
+    {
+      printf("%sgoto L%d;\n", indent, success->number);
+      success->need_label = 1;
+    }
+
+  if (want_close)
+    fputs ("    }\n", stdout);
+}
+
+/* Return 1 if the test is always true and has no fallthru path.  Return -1
+   if the test does have a fallthru path, but requires that the condition be
+   terminated.  Otherwise return 0 for a normal test.  */
+/* ??? is_unconditional is a stupid name for a tri-state function.  */
+
+static int
+is_unconditional (struct decision_test *t, enum routine_type subroutine_type)
+{
+  if (t->type == DT_accept_op)
+    return 1;
+
+  if (t->type == DT_accept_insn)
+    {
+      switch (subroutine_type)
+	{
+	case RECOG:
+	  return (t->u.insn.num_clobbers_to_add == 0);
+	case SPLIT:
+	  return 1;
+	case PEEPHOLE2:
+	  return -1;
+	default:
+	  gcc_unreachable ();
+	}
+    }
+
+  return 0;
+}
+
+/* Emit code for one node -- the conditional and the accompanying action.
+   Return true if there is no fallthru path.  */
+
+static int
+write_node (struct decision *p, int depth,
+	    enum routine_type subroutine_type)
+{
+  struct decision_test *test, *last_test;
+  int uncond;
+
+  /* Scan the tests and simplify comparisons against small
+     constants.  */
+  for (test = p->tests; test; test = test->next)
+    {
+      if (test->type == DT_code
+	  && test->u.code == CONST_INT
+	  && test->next
+	  && test->next->type == DT_elt_zero_wide_safe
+	  && -MAX_SAVED_CONST_INT <= test->next->u.intval
+	  && test->next->u.intval <= MAX_SAVED_CONST_INT)
+	{
+	  test->type = DT_const_int;
+	  test->u.intval = test->next->u.intval;
+	  test->next = test->next->next;
+	}
+    }
+
+  last_test = test = p->tests;
+  uncond = is_unconditional (test, subroutine_type);
+  if (uncond == 0)
+    {
+      printf ("  if (");
+      write_cond (test, depth, subroutine_type);
+
+      while ((test = test->next) != NULL)
+	{
+	  last_test = test;
+	  if (is_unconditional (test, subroutine_type))
+	    break;
+
+	  printf ("\n      && ");
+	  write_cond (test, depth, subroutine_type);
+	}
+
+      printf (")\n");
+    }
+
+  write_action (p, last_test, depth, uncond, p->success.first, subroutine_type);
+
+  return uncond > 0;
+}
+
+/* Emit code for all of the sibling nodes of HEAD.  */
+
+static void
+write_tree_1 (struct decision_head *head, int depth,
+	      enum routine_type subroutine_type)
+{
+  struct decision *p, *next;
+  int uncond = 0;
+
+  for (p = head->first; p ; p = next)
+    {
+      /* The label for the first element was printed in write_tree.  */
+      if (p != head->first && p->need_label)
+	OUTPUT_LABEL (" ", p->number);
+
+      /* Attempt to write a switch statement for a whole sequence.  */
+      next = write_switch (p, depth);
+      if (p != next)
+	uncond = 0;
+      else
+	{
+	  /* Failed -- fall back and write one node.  */
+	  uncond = write_node (p, depth, subroutine_type);
+	  next = p->next;
+	}
+    }
+
+  /* Finished with this chain.  Close a fallthru path by branching
+     to the afterward node.  */
+  if (! uncond)
+    write_afterward (head->last, head->last->afterward, "  ");
+}
+
+/* Write out the decision tree starting at HEAD.  PREVPOS is the
+   position at the node that branched to this node.  */
+
+static void
+write_tree (struct decision_head *head, const char *prevpos,
+	    enum routine_type type, int initial)
+{
+  struct decision *p = head->first;
+
+  putchar ('\n');
+  if (p->need_label)
+    OUTPUT_LABEL (" ", p->number);
+
+  if (! initial && p->subroutine_number > 0)
+    {
+      static const char * const name_prefix[] = {
+	  "recog", "split", "peephole2"
+      };
+
+      static const char * const call_suffix[] = {
+	  ", pnum_clobbers", "", ", _pmatch_len"
+      };
+
+      /* This node has been broken out into a separate subroutine.
+	 Call it, test the result, and branch accordingly.  */
+
+      if (p->afterward)
+	{
+	  printf ("  tem = %s_%d (x0, insn%s);\n",
+		  name_prefix[type], p->subroutine_number, call_suffix[type]);
+	  if (IS_SPLIT (type))
+	    printf ("  if (tem != 0)\n    return tem;\n");
+	  else
+	    printf ("  if (tem >= 0)\n    return tem;\n");
+
+	  change_state (p->position, p->afterward->position, "  ");
+	  printf ("  goto L%d;\n", p->afterward->number);
+	}
+      else
+	{
+	  printf ("  return %s_%d (x0, insn%s);\n",
+		  name_prefix[type], p->subroutine_number, call_suffix[type]);
+	}
+    }
+  else
+    {
+      int depth = strlen (p->position);
+
+      change_state (prevpos, p->position, "  ");
+      write_tree_1 (head, depth, type);
+
+      for (p = head->first; p; p = p->next)
+        if (p->success.first)
+          write_tree (&p->success, p->position, type, 0);
+    }
+}
+
+/* Write out a subroutine of type TYPE to do comparisons starting at
+   node TREE.  */
+
+static void
+write_subroutine (struct decision_head *head, enum routine_type type)
+{
+  int subfunction = head->first ? head->first->subroutine_number : 0;
+  const char *s_or_e;
+  char extension[32];
+  int i;
+
+  s_or_e = subfunction ? "static " : "";
+
+  if (subfunction)
+    sprintf (extension, "_%d", subfunction);
+  else if (type == RECOG)
+    extension[0] = '\0';
+  else
+    strcpy (extension, "_insns");
+
+  switch (type)
+    {
+    case RECOG:
+      printf ("%sint\n\
+recog%s (rtx x0 ATTRIBUTE_UNUSED,\n\trtx insn ATTRIBUTE_UNUSED,\n\tint *pnum_clobbers ATTRIBUTE_UNUSED)\n", s_or_e, extension);
+      break;
+    case SPLIT:
+      printf ("%srtx\n\
+split%s (rtx x0 ATTRIBUTE_UNUSED, rtx insn ATTRIBUTE_UNUSED)\n",
+	      s_or_e, extension);
+      break;
+    case PEEPHOLE2:
+      printf ("%srtx\n\
+peephole2%s (rtx x0 ATTRIBUTE_UNUSED,\n\trtx insn ATTRIBUTE_UNUSED,\n\tint *_pmatch_len ATTRIBUTE_UNUSED)\n",
+	      s_or_e, extension);
+      break;
+    }
+
+  printf ("{\n  rtx * const operands ATTRIBUTE_UNUSED = &recog_data.operand[0];\n");
+  for (i = 1; i <= max_depth; i++)
+    printf ("  rtx x%d ATTRIBUTE_UNUSED;\n", i);
+
+  printf ("  %s tem ATTRIBUTE_UNUSED;\n", IS_SPLIT (type) ? "rtx" : "int");
+
+  if (!subfunction)
+    printf ("  recog_data.insn = NULL_RTX;\n");
+
+  if (head->first)
+    write_tree (head, "", type, 1);
+  else
+    printf ("  goto ret0;\n");
+
+  printf (" ret0:\n  return %d;\n}\n\n", IS_SPLIT (type) ? 0 : -1);
+}
+
+/* In break_out_subroutines, we discovered the boundaries for the
+   subroutines, but did not write them out.  Do so now.  */
+
+static void
+write_subroutines (struct decision_head *head, enum routine_type type)
+{
+  struct decision *p;
+
+  for (p = head->first; p ; p = p->next)
+    if (p->success.first)
+      write_subroutines (&p->success, type);
+
+  if (head->first->subroutine_number > 0)
+    write_subroutine (head, type);
+}
+
+/* Begin the output file.  */
+
+static void
+write_header (void)
+{
+  puts ("\
+/* Generated automatically by the program `genrecog' from the target\n\
+   machine description file.  */\n\
+\n\
+#include \"config.h\"\n\
+#include \"system.h\"\n\
+#include \"coretypes.h\"\n\
+#include \"tm.h\"\n\
+#include \"rtl.h\"\n\
+#include \"tm_p.h\"\n\
+#include \"function.h\"\n\
+#include \"insn-config.h\"\n\
+#include \"recog.h\"\n\
+#include \"real.h\"\n\
+#include \"output.h\"\n\
+#include \"flags.h\"\n\
+#include \"hard-reg-set.h\"\n\
+#include \"resource.h\"\n\
+#include \"toplev.h\"\n\
+#include \"reload.h\"\n\
+#include \"regs.h\"\n\
+#include \"tm-constrs.h\"\n\
+\n");
+
+  puts ("\n\
+/* `recog' contains a decision tree that recognizes whether the rtx\n\
+   X0 is a valid instruction.\n\
+\n\
+   recog returns -1 if the rtx is not valid.  If the rtx is valid, recog\n\
+   returns a nonnegative number which is the insn code number for the\n\
+   pattern that matched.  This is the same as the order in the machine\n\
+   description of the entry that matched.  This number can be used as an\n\
+   index into `insn_data' and other tables.\n");
+  puts ("\
+   The third argument to recog is an optional pointer to an int.  If\n\
+   present, recog will accept a pattern if it matches except for missing\n\
+   CLOBBER expressions at the end.  In that case, the value pointed to by\n\
+   the optional pointer will be set to the number of CLOBBERs that need\n\
+   to be added (it should be initialized to zero by the caller).  If it");
+  puts ("\
+   is set nonzero, the caller should allocate a PARALLEL of the\n\
+   appropriate size, copy the initial entries, and call add_clobbers\n\
+   (found in insn-emit.c) to fill in the CLOBBERs.\n\
+");
+
+  puts ("\n\
+   The function split_insns returns 0 if the rtl could not\n\
+   be split or the split rtl as an INSN list if it can be.\n\
+\n\
+   The function peephole2_insns returns 0 if the rtl could not\n\
+   be matched. If there was a match, the new rtl is returned in an INSN list,\n\
+   and LAST_INSN will point to the last recognized insn in the old sequence.\n\
+*/\n\n");
+}
+
+
+/* Construct and return a sequence of decisions
+   that will recognize INSN.
+
+   TYPE says what type of routine we are recognizing (RECOG or SPLIT).  */
+
+static struct decision_head
+make_insn_sequence (rtx insn, enum routine_type type)
+{
+  rtx x;
+  const char *c_test = XSTR (insn, type == RECOG ? 2 : 1);
+  int truth = maybe_eval_c_test (c_test);
+  struct decision *last;
+  struct decision_test *test, **place;
+  struct decision_head head;
+  char c_test_pos[2];
+
+  /* We should never see an insn whose C test is false at compile time.  */
+  gcc_assert (truth);
+
+  c_test_pos[0] = '\0';
+  if (type == PEEPHOLE2)
+    {
+      int i, j;
+
+      /* peephole2 gets special treatment:
+	 - X always gets an outer parallel even if it's only one entry
+	 - we remove all traces of outer-level match_scratch and match_dup
+           expressions here.  */
+      x = rtx_alloc (PARALLEL);
+      PUT_MODE (x, VOIDmode);
+      XVEC (x, 0) = rtvec_alloc (XVECLEN (insn, 0));
+      for (i = j = 0; i < XVECLEN (insn, 0); i++)
+	{
+	  rtx tmp = XVECEXP (insn, 0, i);
+	  if (GET_CODE (tmp) != MATCH_SCRATCH && GET_CODE (tmp) != MATCH_DUP)
+	    {
+	      XVECEXP (x, 0, j) = tmp;
+	      j++;
+	    }
+	}
+      XVECLEN (x, 0) = j;
+
+      c_test_pos[0] = 'A' + j - 1;
+      c_test_pos[1] = '\0';
+    }
+  else if (XVECLEN (insn, type == RECOG) == 1)
+    x = XVECEXP (insn, type == RECOG, 0);
+  else
+    {
+      x = rtx_alloc (PARALLEL);
+      XVEC (x, 0) = XVEC (insn, type == RECOG);
+      PUT_MODE (x, VOIDmode);
+    }
+
+  validate_pattern (x, insn, NULL_RTX, 0);
+
+  memset(&head, 0, sizeof(head));
+  last = add_to_sequence (x, &head, "", type, 1);
+
+  /* Find the end of the test chain on the last node.  */
+  for (test = last->tests; test->next; test = test->next)
+    continue;
+  place = &test->next;
+
+  /* Skip the C test if it's known to be true at compile time.  */
+  if (truth == -1)
+    {
+      /* Need a new node if we have another test to add.  */
+      if (test->type == DT_accept_op)
+	{
+	  last = new_decision (c_test_pos, &last->success);
+	  place = &last->tests;
+	}
+      test = new_decision_test (DT_c_test, &place);
+      test->u.c_test = c_test;
+    }
+
+  test = new_decision_test (DT_accept_insn, &place);
+  test->u.insn.code_number = next_insn_code;
+  test->u.insn.lineno = pattern_lineno;
+  test->u.insn.num_clobbers_to_add = 0;
+
+  switch (type)
+    {
+    case RECOG:
+      /* If this is a DEFINE_INSN and X is a PARALLEL, see if it ends
+	 with a group of CLOBBERs of (hard) registers or MATCH_SCRATCHes.
+	 If so, set up to recognize the pattern without these CLOBBERs.  */
+
+      if (GET_CODE (x) == PARALLEL)
+	{
+	  int i;
+
+	  /* Find the last non-clobber in the parallel.  */
+	  for (i = XVECLEN (x, 0); i > 0; i--)
+	    {
+	      rtx y = XVECEXP (x, 0, i - 1);
+	      if (GET_CODE (y) != CLOBBER
+		  || (!REG_P (XEXP (y, 0))
+		      && GET_CODE (XEXP (y, 0)) != MATCH_SCRATCH))
+		break;
+	    }
+
+	  if (i != XVECLEN (x, 0))
+	    {
+	      rtx new_rtx;
+	      struct decision_head clobber_head;
+
+	      /* Build a similar insn without the clobbers.  */
+	      if (i == 1)
+		new_rtx = XVECEXP (x, 0, 0);
+	      else
+		{
+		  int j;
+
+		  new_rtx = rtx_alloc (PARALLEL);
+		  XVEC (new_rtx, 0) = rtvec_alloc (i);
+		  for (j = i - 1; j >= 0; j--)
+		    XVECEXP (new_rtx, 0, j) = XVECEXP (x, 0, j);
+		}
+
+	      /* Recognize it.  */
+	      memset (&clobber_head, 0, sizeof(clobber_head));
+	      last = add_to_sequence (new_rtx, &clobber_head, "", type, 1);
+
+	      /* Find the end of the test chain on the last node.  */
+	      for (test = last->tests; test->next; test = test->next)
+		continue;
+
+	      /* We definitely have a new test to add -- create a new
+		 node if needed.  */
+	      place = &test->next;
+	      if (test->type == DT_accept_op)
+		{
+		  last = new_decision ("", &last->success);
+		  place = &last->tests;
+		}
+
+	      /* Skip the C test if it's known to be true at compile
+                 time.  */
+	      if (truth == -1)
+		{
+		  test = new_decision_test (DT_c_test, &place);
+		  test->u.c_test = c_test;
+		}
+
+	      test = new_decision_test (DT_accept_insn, &place);
+	      test->u.insn.code_number = next_insn_code;
+	      test->u.insn.lineno = pattern_lineno;
+	      test->u.insn.num_clobbers_to_add = XVECLEN (x, 0) - i;
+
+	      merge_trees (&head, &clobber_head);
+	    }
+	}
+      break;
+
+    case SPLIT:
+      /* Define the subroutine we will call below and emit in genemit.  */
+      printf ("extern rtx gen_split_%d (rtx, rtx *);\n", next_insn_code);
+      break;
+
+    case PEEPHOLE2:
+      /* Define the subroutine we will call below and emit in genemit.  */
+      printf ("extern rtx gen_peephole2_%d (rtx, rtx *);\n",
+	      next_insn_code);
+      break;
+    }
+
+  return head;
+}
+
+static void
+process_tree (struct decision_head *head, enum routine_type subroutine_type)
+{
+  if (head->first == NULL)
+    {
+      /* We can elide peephole2_insns, but not recog or split_insns.  */
+      if (subroutine_type == PEEPHOLE2)
+	return;
+    }
+  else
+    {
+      factor_tests (head);
+
+      next_subroutine_number = 0;
+      break_out_subroutines (head, 1);
+      find_afterward (head, NULL);
+
+      /* We run this after find_afterward, because find_afterward needs
+	 the redundant DT_mode tests on predicates to determine whether
+	 two tests can both be true or not.  */
+      simplify_tests(head);
+
+      write_subroutines (head, subroutine_type);
+    }
+
+  write_subroutine (head, subroutine_type);
+}
+
+extern int main (int, char **);
+
+int
+main (int argc, char **argv)
+{
+  rtx desc;
+  struct decision_head recog_tree, split_tree, peephole2_tree, h;
+
+  progname = "genrecog";
+
+  memset (&recog_tree, 0, sizeof recog_tree);
+  memset (&split_tree, 0, sizeof split_tree);
+  memset (&peephole2_tree, 0, sizeof peephole2_tree);
+
+  if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE)
+    return (FATAL_EXIT_CODE);
+
+  next_insn_code = 0;
+
+  write_header ();
+
+  /* Read the machine description.  */
+
+  while (1)
+    {
+      desc = read_md_rtx (&pattern_lineno, &next_insn_code);
+      if (desc == NULL)
+	break;
+
+      switch (GET_CODE (desc))
+	{
+	case DEFINE_PREDICATE:
+	case DEFINE_SPECIAL_PREDICATE:
+	  process_define_predicate (desc);
+	  break;
+
+	case DEFINE_INSN:
+	  h = make_insn_sequence (desc, RECOG);
+	  merge_trees (&recog_tree, &h);
+	  break;
+
+	case DEFINE_SPLIT:
+	  h = make_insn_sequence (desc, SPLIT);
+	  merge_trees (&split_tree, &h);
+	  break;
+
+	case DEFINE_PEEPHOLE2:
+	  h = make_insn_sequence (desc, PEEPHOLE2);
+	  merge_trees (&peephole2_tree, &h);
+
+	default:
+	  /* do nothing */;
+	}
+    }
+
+  if (error_count || have_error)
+    return FATAL_EXIT_CODE;
+
+  puts ("\n\n");
+
+  process_tree (&recog_tree, RECOG);
+  process_tree (&split_tree, SPLIT);
+  process_tree (&peephole2_tree, PEEPHOLE2);
+
+  fflush (stdout);
+  return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
+}
+
+static void
+debug_decision_2 (struct decision_test *test)
+{
+  switch (test->type)
+    {
+    case DT_num_insns:
+      fprintf (stderr, "num_insns=%d", test->u.num_insns);
+      break;
+    case DT_mode:
+      fprintf (stderr, "mode=%s", GET_MODE_NAME (test->u.mode));
+      break;
+    case DT_code:
+      fprintf (stderr, "code=%s", GET_RTX_NAME (test->u.code));
+      break;
+    case DT_veclen:
+      fprintf (stderr, "veclen=%d", test->u.veclen);
+      break;
+    case DT_elt_zero_int:
+      fprintf (stderr, "elt0_i=%d", (int) test->u.intval);
+      break;
+    case DT_elt_one_int:
+      fprintf (stderr, "elt1_i=%d", (int) test->u.intval);
+      break;
+    case DT_elt_zero_wide:
+      fprintf (stderr, "elt0_w=" HOST_WIDE_INT_PRINT_DEC, test->u.intval);
+      break;
+    case DT_elt_zero_wide_safe:
+      fprintf (stderr, "elt0_ws=" HOST_WIDE_INT_PRINT_DEC, test->u.intval);
+      break;
+    case DT_veclen_ge:
+      fprintf (stderr, "veclen>=%d", test->u.veclen);
+      break;
+    case DT_dup:
+      fprintf (stderr, "dup=%d", test->u.dup);
+      break;
+    case DT_pred:
+      fprintf (stderr, "pred=(%s,%s)",
+	       test->u.pred.name, GET_MODE_NAME(test->u.pred.mode));
+      break;
+    case DT_c_test:
+      {
+	char sub[16+4];
+	strncpy (sub, test->u.c_test, sizeof(sub));
+	memcpy (sub+16, "...", 4);
+	fprintf (stderr, "c_test=\"%s\"", sub);
+      }
+      break;
+    case DT_accept_op:
+      fprintf (stderr, "A_op=%d", test->u.opno);
+      break;
+    case DT_accept_insn:
+      fprintf (stderr, "A_insn=(%d,%d)",
+	       test->u.insn.code_number, test->u.insn.num_clobbers_to_add);
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
+static void
+debug_decision_1 (struct decision *d, int indent)
+{
+  int i;
+  struct decision_test *test;
+
+  if (d == NULL)
+    {
+      for (i = 0; i < indent; ++i)
+	putc (' ', stderr);
+      fputs ("(nil)\n", stderr);
+      return;
+    }
+
+  for (i = 0; i < indent; ++i)
+    putc (' ', stderr);
+
+  putc ('{', stderr);
+  test = d->tests;
+  if (test)
+    {
+      debug_decision_2 (test);
+      while ((test = test->next) != NULL)
+	{
+	  fputs (" + ", stderr);
+	  debug_decision_2 (test);
+	}
+    }
+  fprintf (stderr, "} %d n %d a %d\n", d->number,
+	   (d->next ? d->next->number : -1),
+	   (d->afterward ? d->afterward->number : -1));
+}
+
+static void
+debug_decision_0 (struct decision *d, int indent, int maxdepth)
+{
+  struct decision *n;
+  int i;
+
+  if (maxdepth < 0)
+    return;
+  if (d == NULL)
+    {
+      for (i = 0; i < indent; ++i)
+	putc (' ', stderr);
+      fputs ("(nil)\n", stderr);
+      return;
+    }
+
+  debug_decision_1 (d, indent);
+  for (n = d->success.first; n ; n = n->next)
+    debug_decision_0 (n, indent + 2, maxdepth - 1);
+}
+
+void
+debug_decision (struct decision *d)
+{
+  debug_decision_0 (d, 0, 1000000);
+}
+
+void
+debug_decision_list (struct decision *d)
+{
+  while (d)
+    {
+      debug_decision_0 (d, 0, 0);
+      d = d->next;
+    }
+}