OSDN Git Service

PR target/21723
[pf3gnuchains/gcc-fork.git] / gcc / genattrtab.c
index 7024c01..c284f86 100644 (file)
@@ -1,6 +1,6 @@
 /* Generate code from machine description to compute values of attributes.
    Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2002, 2003 Free Software Foundation, Inc.
+   1999, 2000, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
    Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
 
 This file is part of GCC.
@@ -17,11 +17,11 @@ for more details.
 
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 /* This program handles insn attributes and the DEFINE_DELAY and
-   DEFINE_FUNCTION_UNIT definitions.
+   DEFINE_INSN_RESERVATION definitions.
 
    It produces a series of functions named `get_attr_...', one for each insn
    attribute.  Each of these is given the rtx for an insn and returns a member
@@ -54,7 +54,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
    used.
 
    Internal attributes are defined to handle DEFINE_DELAY and
-   DEFINE_FUNCTION_UNIT.  Special routines are output for these cases.
+   DEFINE_INSN_RESERVATION.  Special routines are output for these cases.
 
    This program works by keeping a list of possible values for each attribute.
    These include the basic attribute choices, default values for attribute, and
@@ -70,9 +70,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
    indicates when the attribute has the specified value for the insn.  This
    avoids recursive calls during compilation.
 
-   The strategy used when processing DEFINE_DELAY and DEFINE_FUNCTION_UNIT
-   definitions is to create arbitrarily complex expressions and have the
-   optimization simplify them.
+   The strategy used when processing DEFINE_DELAY definitions is to create
+   arbitrarily complex expressions and have the optimization simplify them.
 
    Once optimization is complete, any required routines and definitions
    will be written.
@@ -90,15 +89,20 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
       independent of the insn code.
    `in_struct' (ATTR_CURR_SIMPLIFIED_P): This rtx is fully simplified
       for the insn code currently being processed (see optimize_attrs).
-   `integrated' (ATTR_PERMANENT_P): This rtx is permanent and unique
-      (see attr_rtx).
-   `volatil' (ATTR_EQ_ATTR_P): During simplify_by_exploding the value of an
-      EQ_ATTR rtx is true if !volatil and false if volatil.  */
+   `return_val' (ATTR_PERMANENT_P): This rtx is permanent and unique
+      (see attr_rtx).  */
 
 #define ATTR_IND_SIMPLIFIED_P(RTX) (RTX_FLAG((RTX), unchanging))
 #define ATTR_CURR_SIMPLIFIED_P(RTX) (RTX_FLAG((RTX), in_struct))
-#define ATTR_PERMANENT_P(RTX) (RTX_FLAG((RTX), integrated))
-#define ATTR_EQ_ATTR_P(RTX) (RTX_FLAG((RTX), volatil))
+#define ATTR_PERMANENT_P(RTX) (RTX_FLAG((RTX), return_val))
+
+#if 0
+#define strcmp_check(S1, S2) ((S1) == (S2)             \
+                             ? 0                       \
+                             : (gcc_assert (strcmp ((S1), (S2))), 1))
+#else
+#define strcmp_check(S1, S2) ((S1) != (S2))
+#endif
 
 #include "bconfig.h"
 #include "system.h"
@@ -151,9 +155,7 @@ struct insn_def
 struct insn_ent
 {
   struct insn_ent *next;       /* Next in chain.  */
-  int insn_code;               /* Instruction number.  */
-  int insn_index;              /* Index of definition in file */
-  int lineno;                  /* Line number.  */
+  struct insn_def *def;                /* Instruction definition.  */
 };
 
 /* Each value of an attribute (either constant or computed) is assigned a
@@ -179,25 +181,11 @@ struct attr_desc
   struct attr_value *default_val; /* Default value for this attribute.  */
   int lineno : 24;             /* Line number.  */
   unsigned is_numeric  : 1;    /* Values of this attribute are numeric.  */
-  unsigned negative_ok : 1;    /* Allow negative numeric values.  */
-  unsigned unsigned_p  : 1;    /* Make the output function unsigned int.  */
   unsigned is_const    : 1;    /* Attribute value constant for each run.  */
   unsigned is_special  : 1;    /* Don't call `write_attr_set'.  */
-  unsigned func_units_p        : 1;    /* This is the function_units attribute.  */
-  unsigned blockage_p  : 1;    /* This is the blockage range function.  */
   unsigned static_p    : 1;    /* Make the output function static.  */
 };
 
-#define NULL_ATTR (struct attr_desc *) NULL
-
-/* A range of values.  */
-
-struct range
-{
-  int min;
-  int max;
-};
-
 /* Structure for each DEFINE_DELAY.  */
 
 struct delay_desc
@@ -208,43 +196,6 @@ struct delay_desc
   int lineno;                  /* Line number.  */
 };
 
-/* Record information about each DEFINE_FUNCTION_UNIT.  */
-
-struct function_unit_op
-{
-  rtx condexp;                 /* Expression TRUE for applicable insn.  */
-  struct function_unit_op *next; /* Next operation for this function unit.  */
-  int num;                     /* Ordinal for this operation type in unit.  */
-  int ready;                   /* Cost until data is ready.  */
-  int issue_delay;             /* Cost until unit can accept another insn.  */
-  rtx conflict_exp;            /* Expression TRUE for insns incurring issue delay.  */
-  rtx issue_exp;               /* Expression computing issue delay.  */
-  int lineno;                  /* Line number.  */
-};
-
-/* Record information about each function unit mentioned in a
-   DEFINE_FUNCTION_UNIT.  */
-
-struct function_unit
-{
-  const char *name;            /* Function unit name.  */
-  struct function_unit *next;  /* Next function unit.  */
-  int num;                     /* Ordinal of this unit type.  */
-  int multiplicity;            /* Number of units of this type.  */
-  int simultaneity;            /* Maximum number of simultaneous insns
-                                  on this function unit or 0 if unlimited.  */
-  rtx condexp;                 /* Expression TRUE for insn needing unit.  */
-  int num_opclasses;           /* Number of different operation types.  */
-  struct function_unit_op *ops;        /* Pointer to first operation type.  */
-  int needs_conflict_function; /* Nonzero if a conflict function required.  */
-  int needs_blockage_function; /* Nonzero if a blockage function required.  */
-  int needs_range_function;    /* Nonzero if blockage range function needed.  */
-  rtx default_cost;            /* Conflict cost, if constant.  */
-  struct range issue_delay;    /* Range of issue delay values.  */
-  int max_blockage;            /* Maximum time an insn blocks the unit.  */
-  int first_lineno;            /* First seen line number.  */
-};
-
 /* Listheads of above structures.  */
 
 /* This one is indexed by the first character of the attribute name.  */
@@ -252,50 +203,6 @@ struct function_unit
 static struct attr_desc *attrs[MAX_ATTRS_INDEX];
 static struct insn_def *defs;
 static struct delay_desc *delays;
-static struct function_unit *units;
-
-/* An expression where all the unknown terms are EQ_ATTR tests can be
-   rearranged into a COND provided we can enumerate all possible
-   combinations of the unknown values.  The set of combinations become the
-   tests of the COND; the value of the expression given that combination is
-   computed and becomes the corresponding value.  To do this, we must be
-   able to enumerate all values for each attribute used in the expression
-   (currently, we give up if we find a numeric attribute).
-
-   If the set of EQ_ATTR tests used in an expression tests the value of N
-   different attributes, the list of all possible combinations can be made
-   by walking the N-dimensional attribute space defined by those
-   attributes.  We record each of these as a struct dimension.
-
-   The algorithm relies on sharing EQ_ATTR nodes: if two nodes in an
-   expression are the same, the will also have the same address.  We find
-   all the EQ_ATTR nodes by marking them ATTR_EQ_ATTR_P.  This bit later
-   represents the value of an EQ_ATTR node, so once all nodes are marked,
-   they are also given an initial value of FALSE.
-
-   We then separate the set of EQ_ATTR nodes into dimensions for each
-   attribute and put them on the VALUES list.  Terms are added as needed by
-   `add_values_to_cover' so that all possible values of the attribute are
-   tested.
-
-   Each dimension also has a current value.  This is the node that is
-   currently considered to be TRUE.  If this is one of the nodes added by
-   `add_values_to_cover', all the EQ_ATTR tests in the original expression
-   will be FALSE.  Otherwise, only the CURRENT_VALUE will be true.
-
-   NUM_VALUES is simply the length of the VALUES list and is there for
-   convenience.
-
-   Once the dimensions are created, the algorithm enumerates all possible
-   values and computes the current value of the given expression.  */
-
-struct dimension
-{
-  struct attr_desc *attr;      /* Attribute for this dimension.  */
-  rtx values;                  /* List of attribute values used.  */
-  rtx current_value;           /* Position in the list for the TRUE value.  */
-  int num_values;              /* Length of the values list.  */
-};
 
 /* Other variables.  */
 
@@ -308,15 +215,10 @@ static int address_used;
 static int length_used;
 static int num_delays;
 static int have_annul_true, have_annul_false;
-static int num_units, num_unit_opclasses;
 static int num_insn_ents;
 
 int num_dfa_decls;
 
-/* Used as operand to `operate_exp':  */
-
-enum operator {PLUS_OP, MINUS_OP, POS_MINUS_OP, EQ_OP, OR_OP, ORX_OP, MAX_OP, MIN_OP, RANGE_OP};
-
 /* Stores, for each insn code, the number of constraint alternatives.  */
 
 static int *insn_n_alternatives;
@@ -339,6 +241,10 @@ static rtx true_rtx, false_rtx;
 /* Used to reduce calls to `strcmp' */
 
 static char *alternative_name;
+static const char *length_str;
+static const char *delay_type_str;
+static const char *delay_1_0_str;
+static const char *num_delay_slots_str;
 
 /* Indicate that REG_DEAD notes are valid if dead_or_set_p is ever
    called.  */
@@ -365,6 +271,8 @@ int optimize = 0;
     (EXP) = (XSTR ((EXP), 1) == current_alternative_string     \
            ? true_rtx : false_rtx);
 
+#define DEF_ATTR_STRING(S) (attr_string ((S), strlen (S)))
+
 /* These are referenced by rtlanal.c and hence need to be defined somewhere.
    They won't actually be used.  */
 
@@ -385,10 +293,6 @@ static struct attr_value *get_attr_value (rtx, struct attr_desc *, int);
 static rtx copy_rtx_unchanging (rtx);
 static rtx copy_boolean                (rtx);
 static void expand_delays      (void);
-static rtx operate_exp         (enum operator, rtx, rtx);
-static void expand_units       (void);
-static rtx simplify_knowing    (rtx, rtx);
-static rtx encode_units_mask   (rtx);
 static void fill_attr          (struct attr_desc *);
 static rtx substitute_address  (rtx, rtx (*) (rtx), rtx (*) (rtx));
 static void make_length_attrs  (void);
@@ -398,16 +302,7 @@ static rtx one_fn          (rtx);
 static rtx max_fn              (rtx);
 static void write_length_unit_log (void);
 static rtx simplify_cond       (rtx, int, int);
-static rtx simplify_by_exploding (rtx);
-static int find_and_mark_used_attributes (rtx, rtx *, int *);
-static void unmark_used_attributes (rtx, struct dimension *, int);
-static int add_values_to_cover (struct dimension *);
-static int increment_current_value (struct dimension *, int);
-static rtx test_for_current_value (struct dimension *, int);
-static rtx simplify_with_current_value (rtx, struct dimension *, int);
-static rtx simplify_with_current_value_aux (rtx);
 static void clear_struct_flag (rtx);
-static int count_sub_rtxs    (rtx, int);
 static void remove_insn_ent  (struct attr_value *, struct insn_ent *);
 static void insert_insn_ent  (struct attr_value *, struct insn_ent *);
 static rtx insert_right_side   (enum rtx_code, rtx, rtx, int, int);
@@ -425,7 +320,6 @@ static int compares_alternatives_p (rtx);
 static int contained_in_p      (rtx, rtx);
 static void gen_insn           (rtx, int);
 static void gen_delay          (rtx, int);
-static void gen_unit           (rtx, int);
 static void write_test_expr    (rtx, int);
 static int max_attr_value      (rtx, int*);
 static int or_attr_value       (rtx, int*);
@@ -435,30 +329,31 @@ static rtx eliminate_known_true (rtx, rtx, int, int);
 static void write_attr_set     (struct attr_desc *, int, rtx,
                                 const char *, const char *, rtx,
                                 int, int);
+static void write_insn_cases   (struct insn_ent *, int);
 static void write_attr_case    (struct attr_desc *, struct attr_value *,
                                 int, const char *, const char *, int, rtx);
-static void write_unit_name    (const char *, int, const char *);
 static void write_attr_valueq  (struct attr_desc *, const char *);
 static void write_attr_value   (struct attr_desc *, rtx);
 static void write_upcase       (const char *);
 static void write_indent       (int);
 static void write_eligible_delay (const char *);
-static void write_function_unit_info (void);
-static void write_complex_function (struct function_unit *, const char *,
-                                   const char *);
 static int write_expr_attr_cache (rtx, struct attr_desc *);
-static void write_toplevel_expr        (rtx);
 static void write_const_num_delay_slots (void);
 static char *next_comma_elt    (const char **);
-static struct attr_desc *find_attr (const char *, int);
+static struct attr_desc *find_attr (const char **, int);
 static struct attr_value *find_most_used  (struct attr_desc *);
-static rtx find_single_value   (struct attr_desc *);
-static void extend_range       (struct range *, int, int);
 static rtx attr_eq             (const char *, const char *);
 static const char *attr_numeral        (int);
 static int attr_equal_p                (rtx, rtx);
 static rtx attr_copy_rtx       (rtx);
 static int attr_rtx_cost       (rtx);
+static bool attr_alt_subset_p (rtx, rtx);
+static bool attr_alt_subset_of_compl_p (rtx, rtx);
+static rtx attr_alt_intersection (rtx, rtx);
+static rtx attr_alt_union (rtx, rtx);
+static rtx attr_alt_complement (rtx);
+static bool attr_alt_bit_p (rtx, int);
+static rtx mk_attr_alt (int);
 
 #define oballoc(size) obstack_alloc (hash_obstack, size)
 
@@ -527,7 +422,7 @@ attr_hash_add_string (int hashcode, char *str)
    In some cases we cannot uniquify; then we return an ordinary
    impermanent rtx with ATTR_PERMANENT_P clear.
 
-   Args are like gen_rtx, but without the mode:
+   Args are as follows:
 
    rtx attr_rtx (code, [element1, ..., elementn])  */
 
@@ -543,7 +438,7 @@ attr_rtx_1 (enum rtx_code code, va_list p)
      Use that entry if one is found; otherwise create a new RTL and add it
      to the table.  */
 
-  if (GET_RTX_CLASS (code) == '1')
+  if (GET_RTX_CLASS (code) == RTX_UNARY)
     {
       rtx arg0 = va_arg (p, rtx);
 
@@ -569,9 +464,10 @@ attr_rtx_1 (enum rtx_code code, va_list p)
          XEXP (rt_val, 0) = arg0;
        }
     }
-  else if (GET_RTX_CLASS (code) == 'c'
-          || GET_RTX_CLASS (code) == '2'
-          || GET_RTX_CLASS (code) == '<')
+  else if (GET_RTX_CLASS (code) == RTX_BIN_ARITH
+          || GET_RTX_CLASS (code) == RTX_COMM_ARITH
+          || GET_RTX_CLASS (code) == RTX_COMPARE
+          || GET_RTX_CLASS (code) == RTX_COMM_COMPARE)
     {
       rtx arg0 = va_arg (p, rtx);
       rtx arg1 = va_arg (p, rtx);
@@ -606,8 +502,7 @@ attr_rtx_1 (enum rtx_code code, va_list p)
     {
       char *arg0 = va_arg (p, char *);
 
-      if (code == SYMBOL_REF)
-       arg0 = attr_string (arg0, strlen (arg0));
+      arg0 = DEF_ATTR_STRING (arg0);
 
       hashcode = ((HOST_WIDE_INT) code + RTL_HASH (arg0));
       for (h = attr_hash_table[hashcode % RTL_HASH_SIZE]; h; h = h->next)
@@ -693,7 +588,7 @@ attr_rtx_1 (enum rtx_code code, va_list p)
              break;
 
            default:
-             abort ();
+             gcc_unreachable ();
            }
        }
       return rt_val;
@@ -730,20 +625,18 @@ attr_printf (unsigned int len, const char *fmt, ...)
 
   va_start (p, fmt);
 
-  if (len > sizeof str - 1) /* Leave room for \0.  */
-    abort ();
+  gcc_assert (len < sizeof str); /* Leave room for \0.  */
 
   vsprintf (str, fmt, p);
   va_end (p);
 
-  return attr_string (str, strlen (str));
+  return DEF_ATTR_STRING (str);
 }
 
 static rtx
 attr_eq (const char *name, const char *value)
 {
-  return attr_rtx (EQ_ATTR, attr_string (name, strlen (name)),
-                  attr_string (value, strlen (value)));
+  return attr_rtx (EQ_ATTR, DEF_ATTR_STRING (name), DEF_ATTR_STRING (value));
 }
 
 static const char *
@@ -817,7 +710,6 @@ attr_copy_rtx (rtx orig)
   switch (code)
     {
     case REG:
-    case QUEUED:
     case CONST_INT:
     case CONST_DOUBLE:
     case CONST_VECTOR:
@@ -836,7 +728,6 @@ attr_copy_rtx (rtx orig)
   ATTR_IND_SIMPLIFIED_P (copy) = ATTR_IND_SIMPLIFIED_P (orig);
   ATTR_CURR_SIMPLIFIED_P (copy) = ATTR_CURR_SIMPLIFIED_P (orig);
   ATTR_PERMANENT_P (copy) = ATTR_PERMANENT_P (orig);
-  ATTR_EQ_ATTR_P (copy) = ATTR_EQ_ATTR_P (orig);
 
   format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
 
@@ -876,7 +767,7 @@ attr_copy_rtx (rtx orig)
          break;
 
        default:
-         abort ();
+         gcc_unreachable ();
        }
     }
   return copy;
@@ -916,16 +807,11 @@ check_attr_test (rtx exp, int is_const, int lineno)
 
       else if (n_comma_elts (XSTR (exp, 1)) == 1)
        {
-         attr = find_attr (XSTR (exp, 0), 0);
+         attr = find_attr (&XSTR (exp, 0), 0);
          if (attr == NULL)
            {
              if (! strcmp (XSTR (exp, 0), "alternative"))
-               {
-                 XSTR (exp, 0) = alternative_name;
-                 /* This can't be simplified any further.  */
-                 ATTR_IND_SIMPLIFIED_P (exp) = 1;
-                 return exp;
-               }
+               return mk_attr_alt (1 << atoi (XSTR (exp, 1)));
              else
                fatal ("unknown attribute `%s' in EQ_ATTR", XSTR (exp, 0));
            }
@@ -965,16 +851,29 @@ check_attr_test (rtx exp, int is_const, int lineno)
        }
       else
        {
-         /* Make an IOR tree of the possible values.  */
-         orexp = false_rtx;
-         name_ptr = XSTR (exp, 1);
-         while ((p = next_comma_elt (&name_ptr)) != NULL)
+         if (! strcmp (XSTR (exp, 0), "alternative"))
            {
-             newexp = attr_eq (XSTR (exp, 0), p);
-             orexp = insert_right_side (IOR, orexp, newexp, -2, -2);
+             int set = 0;
+
+             name_ptr = XSTR (exp, 1);
+             while ((p = next_comma_elt (&name_ptr)) != NULL)
+               set |= 1 << atoi (p);
+
+             return mk_attr_alt (set);
            }
+         else
+           {
+             /* Make an IOR tree of the possible values.  */
+             orexp = false_rtx;
+             name_ptr = XSTR (exp, 1);
+             while ((p = next_comma_elt (&name_ptr)) != NULL)
+               {
+                 newexp = attr_eq (XSTR (exp, 0), p);
+                 orexp = insert_right_side (IOR, orexp, newexp, -2, -2);
+               }
 
-         return check_attr_test (orexp, is_const, lineno);
+             return check_attr_test (orexp, is_const, lineno);
+           }
        }
       break;
 
@@ -998,7 +897,6 @@ check_attr_test (rtx exp, int is_const, int lineno)
       XEXP (exp, 0) = check_attr_test (XEXP (exp, 0), is_const, lineno);
       break;
 
-    case MATCH_INSN:
     case MATCH_OPERAND:
       if (is_const)
        fatal ("RTL operator \"%s\" not valid in constant attribute test",
@@ -1061,7 +959,7 @@ check_attr_value (rtx exp, struct attr_desc *attr)
          break;
        }
 
-      if (INTVAL (exp) < 0 && ! attr->negative_ok)
+      if (INTVAL (exp) < 0)
        {
          message_with_line (attr->lineno,
                             "negative numeric value specified for attribute %s",
@@ -1078,8 +976,6 @@ check_attr_value (rtx exp, struct attr_desc *attr)
       if (attr == 0 || attr->is_numeric)
        {
          p = XSTR (exp, 0);
-         if (attr && attr->negative_ok && *p == '-')
-           p++;
          for (; *p; p++)
            if (! ISDIGIT (*p))
              {
@@ -1127,7 +1023,7 @@ check_attr_value (rtx exp, struct attr_desc *attr)
          have_error = 1;
          break;
        }
-      /* FALLTHRU */
+      /* Fall through.  */
 
     case IOR:
     case AND:
@@ -1166,7 +1062,7 @@ check_attr_value (rtx exp, struct attr_desc *attr)
 
     case ATTR:
       {
-       struct attr_desc *attr2 = find_attr (XSTR (exp, 0), 0);
+       struct attr_desc *attr2 = find_attr (&XSTR (exp, 0), 0);
        if (attr2 == NULL)
          {
            message_with_line (attr ? attr->lineno : 0,
@@ -1182,8 +1078,7 @@ check_attr_value (rtx exp, struct attr_desc *attr)
            have_error = 1;
          }
        else if (attr
-                && (attr->is_numeric != attr2->is_numeric
-                    || (! attr->negative_ok && attr2->negative_ok)))
+                && attr->is_numeric != attr2->is_numeric)
          {
            message_with_line (attr->lineno,
                "numeric attribute mismatch calling `%s' from `%s'",
@@ -1326,7 +1221,7 @@ check_defs (void)
          if (value == NULL_RTX)
            continue;
 
-         if ((attr = find_attr (XSTR (XEXP (value, 0), 0), 0)) == NULL)
+         if ((attr = find_attr (&XSTR (XEXP (value, 0), 0), 0)) == NULL)
            {
              message_with_line (id->lineno, "unknown attribute %s",
                                 XSTR (XEXP (value, 0), 0));
@@ -1364,6 +1259,8 @@ make_canonical (struct attr_desc *attr, rtx exp)
            fatal ("(attr_value \"*\") used in invalid context");
          exp = attr->default_val->value;
        }
+      else
+       XSTR (exp, 0) = DEF_ATTR_STRING (XSTR (exp, 0));
 
       break;
 
@@ -1424,6 +1321,17 @@ copy_boolean (rtx exp)
   if (GET_CODE (exp) == AND || GET_CODE (exp) == IOR)
     return attr_rtx (GET_CODE (exp), copy_boolean (XEXP (exp, 0)),
                     copy_boolean (XEXP (exp, 1)));
+  if (GET_CODE (exp) == MATCH_OPERAND)
+    {
+      XSTR (exp, 1) = DEF_ATTR_STRING (XSTR (exp, 1));
+      XSTR (exp, 2) = DEF_ATTR_STRING (XSTR (exp, 2));
+    }
+  else if (GET_CODE (exp) == EQ_ATTR)
+    {
+      XSTR (exp, 0) = DEF_ATTR_STRING (XSTR (exp, 0));
+      XSTR (exp, 1) = DEF_ATTR_STRING (XSTR (exp, 1));
+    }
+
   return exp;
 }
 
@@ -1454,7 +1362,7 @@ get_attr_value (rtx value, struct attr_desc *attr, int insn_code)
   for (av = attr->first_value; av; av = av->next)
     if (rtx_equal_p (value, av->value)
        && (num_alt == 0 || av->first_insn == NULL
-           || insn_alternatives[av->first_insn->insn_code]))
+           || insn_alternatives[av->first_insn->def->insn_code]))
       return av;
 
   av = oballoc (sizeof (struct attr_value));
@@ -1504,7 +1412,7 @@ expand_delays (void)
        = make_numeric_value (XVECLEN (delay->def, 1) / 3);
     }
 
-  make_internal_attr ("*num_delay_slots", condexp, ATTR_NONE);
+  make_internal_attr (num_delay_slots_str, condexp, ATTR_NONE);
 
   /* If more than one delay type, do the same for computing the delay type.  */
   if (num_delays > 1)
@@ -1519,7 +1427,7 @@ expand_delays (void)
          XVECEXP (condexp, 0, i + 1) = make_numeric_value (delay->num);
        }
 
-      make_internal_attr ("*delay_type", condexp, ATTR_SPECIAL);
+      make_internal_attr (delay_type_str, condexp, ATTR_SPECIAL);
     }
 
   /* For each delay possibility and delay slot, compute an eligibility
@@ -1566,1291 +1474,779 @@ expand_delays (void)
     }
 }
 
-/* This function is given a left and right side expression and an operator.
-   Each side is a conditional expression, each alternative of which has a
-   numerical value.  The function returns another conditional expression
-   which, for every possible set of condition values, returns a value that is
-   the operator applied to the values of the two sides.
-
-   Since this is called early, it must also support IF_THEN_ELSE.  */
+/* Once all attributes and insns have been read and checked, we construct for
+   each attribute value a list of all the insns that have that value for
+   the attribute.  */
 
-static rtx
-operate_exp (enum operator op, rtx left, rtx right)
+static void
+fill_attr (struct attr_desc *attr)
 {
-  int left_value, right_value;
-  rtx newexp;
+  struct attr_value *av;
+  struct insn_ent *ie;
+  struct insn_def *id;
   int i;
+  rtx value;
 
-  /* If left is a string, apply operator to it and the right side.  */
-  if (GET_CODE (left) == CONST_STRING)
-    {
-      /* If right is also a string, just perform the operation.  */
-      if (GET_CODE (right) == CONST_STRING)
-       {
-         left_value = atoi (XSTR (left, 0));
-         right_value = atoi (XSTR (right, 0));
-         switch (op)
-           {
-           case PLUS_OP:
-             i = left_value + right_value;
-             break;
-
-           case MINUS_OP:
-             i = left_value - right_value;
-             break;
-
-           case POS_MINUS_OP:  /* The positive part of LEFT - RIGHT.  */
-             if (left_value > right_value)
-               i = left_value - right_value;
-             else
-               i = 0;
-             break;
-
-           case OR_OP:
-           case ORX_OP:
-             i = left_value | right_value;
-             break;
-
-           case EQ_OP:
-             i = left_value == right_value;
-             break;
-
-           case RANGE_OP:
-             i = (left_value << (HOST_BITS_PER_INT / 2)) | right_value;
-             break;
-
-           case MAX_OP:
-             if (left_value > right_value)
-               i = left_value;
-             else
-               i = right_value;
-             break;
-
-           case MIN_OP:
-             if (left_value < right_value)
-               i = left_value;
-             else
-               i = right_value;
-             break;
-
-           default:
-             abort ();
-           }
+  /* Don't fill constant attributes.  The value is independent of
+     any particular insn.  */
+  if (attr->is_const)
+    return;
 
-         if (i == left_value)
-           return left;
-         if (i == right_value)
-           return right;
-         return make_numeric_value (i);
-       }
-      else if (GET_CODE (right) == IF_THEN_ELSE)
-       {
-         /* Apply recursively to all values within.  */
-         rtx newleft = operate_exp (op, left, XEXP (right, 1));
-         rtx newright = operate_exp (op, left, XEXP (right, 2));
-         if (rtx_equal_p (newleft, newright))
-           return newleft;
-         return attr_rtx (IF_THEN_ELSE, XEXP (right, 0), newleft, newright);
-       }
-      else if (GET_CODE (right) == COND)
-       {
-         int allsame = 1;
-         rtx defval;
+  for (id = defs; id; id = id->next)
+    {
+      /* If no value is specified for this insn for this attribute, use the
+        default.  */
+      value = NULL;
+      if (XVEC (id->def, id->vec_idx))
+       for (i = 0; i < XVECLEN (id->def, id->vec_idx); i++)
+         if (! strcmp_check (XSTR (XEXP (XVECEXP (id->def, id->vec_idx, i), 0), 0),
+                             attr->name))
+           value = XEXP (XVECEXP (id->def, id->vec_idx, i), 1);
 
-         newexp = rtx_alloc (COND);
-         XVEC (newexp, 0) = rtvec_alloc (XVECLEN (right, 0));
-         defval = XEXP (newexp, 1) = operate_exp (op, left, XEXP (right, 1));
+      if (value == NULL)
+       av = attr->default_val;
+      else
+       av = get_attr_value (value, attr, id->insn_code);
 
-         for (i = 0; i < XVECLEN (right, 0); i += 2)
-           {
-             XVECEXP (newexp, 0, i) = XVECEXP (right, 0, i);
-             XVECEXP (newexp, 0, i + 1)
-               = operate_exp (op, left, XVECEXP (right, 0, i + 1));
-             if (! rtx_equal_p (XVECEXP (newexp, 0, i + 1),
-                                defval))
-               allsame = 0;
-           }
+      ie = oballoc (sizeof (struct insn_ent));
+      ie->def = id;
+      insert_insn_ent (av, ie);
+    }
+}
 
-         /* If the resulting cond is trivial (all alternatives
-            give the same value), optimize it away.  */
-         if (allsame)
-           return operate_exp (op, left, XEXP (right, 1));
+/* Given an expression EXP, see if it is a COND or IF_THEN_ELSE that has a
+   test that checks relative positions of insns (uses MATCH_DUP or PC).
+   If so, replace it with what is obtained by passing the expression to
+   ADDRESS_FN.  If not but it is a COND or IF_THEN_ELSE, call this routine
+   recursively on each value (including the default value).  Otherwise,
+   return the value returned by NO_ADDRESS_FN applied to EXP.  */
 
-         return newexp;
-       }
-      else
-       fatal ("badly formed attribute value");
-    }
+static rtx
+substitute_address (rtx exp, rtx (*no_address_fn) (rtx),
+                   rtx (*address_fn) (rtx))
+{
+  int i;
+  rtx newexp;
 
-  /* A hack to prevent expand_units from completely blowing up: ORX_OP does
-     not associate through IF_THEN_ELSE.  */
-  else if (op == ORX_OP && GET_CODE (right) == IF_THEN_ELSE)
+  if (GET_CODE (exp) == COND)
     {
-      return attr_rtx (IOR, left, right);
-    }
+      /* See if any tests use addresses.  */
+      address_used = 0;
+      for (i = 0; i < XVECLEN (exp, 0); i += 2)
+       walk_attr_value (XVECEXP (exp, 0, i));
 
-  /* Otherwise, do recursion the other way.  */
-  else if (GET_CODE (left) == IF_THEN_ELSE)
-    {
-      rtx newleft = operate_exp (op, XEXP (left, 1), right);
-      rtx newright = operate_exp (op, XEXP (left, 2), right);
-      if (rtx_equal_p (newleft, newright))
-       return newleft;
-      return attr_rtx (IF_THEN_ELSE, XEXP (left, 0), newleft, newright);
-    }
-  else if (GET_CODE (left) == COND)
-    {
-      int allsame = 1;
-      rtx defval;
+      if (address_used)
+       return (*address_fn) (exp);
 
+      /* Make a new copy of this COND, replacing each element.  */
       newexp = rtx_alloc (COND);
-      XVEC (newexp, 0) = rtvec_alloc (XVECLEN (left, 0));
-      defval = XEXP (newexp, 1) = operate_exp (op, XEXP (left, 1), right);
-
-      for (i = 0; i < XVECLEN (left, 0); i += 2)
+      XVEC (newexp, 0) = rtvec_alloc (XVECLEN (exp, 0));
+      for (i = 0; i < XVECLEN (exp, 0); i += 2)
        {
-         XVECEXP (newexp, 0, i) = XVECEXP (left, 0, i);
+         XVECEXP (newexp, 0, i) = XVECEXP (exp, 0, i);
          XVECEXP (newexp, 0, i + 1)
-           = operate_exp (op, XVECEXP (left, 0, i + 1), right);
-         if (! rtx_equal_p (XVECEXP (newexp, 0, i + 1),
-                            defval))
-           allsame = 0;
+           = substitute_address (XVECEXP (exp, 0, i + 1),
+                                 no_address_fn, address_fn);
        }
 
-      /* If the cond is trivial (all alternatives give the same value),
-        optimize it away.  */
-      if (allsame)
-       return operate_exp (op, XEXP (left, 1), right);
-
-      /* If the result is the same as the LEFT operand,
-        just use that.  */
-      if (rtx_equal_p (newexp, left))
-       return left;
+      XEXP (newexp, 1) = substitute_address (XEXP (exp, 1),
+                                            no_address_fn, address_fn);
 
       return newexp;
     }
 
-  else
-    fatal ("badly formed attribute value");
-  /* NOTREACHED */
-  return NULL;
-}
-
-/* Once all attributes and DEFINE_FUNCTION_UNITs have been read, we
-   construct a number of attributes.
-
-   The first produces a function `function_units_used' which is given an
-   insn and produces an encoding showing which function units are required
-   for the execution of that insn.  If the value is non-negative, the insn
-   uses that unit; otherwise, the value is a one's complement mask of units
-   used.
-
-   The second produces a function `result_ready_cost' which is used to
-   determine the time that the result of an insn will be ready and hence
-   a worst-case schedule.
-
-   Both of these produce quite complex expressions which are then set as the
-   default value of internal attributes.  Normal attribute simplification
-   should produce reasonable expressions.
-
-   For each unit, a `<name>_unit_ready_cost' function will take an
-   insn and give the delay until that unit will be ready with the result
-   and a `<name>_unit_conflict_cost' function is given an insn already
-   executing on the unit and a candidate to execute and will give the
-   cost from the time the executing insn started until the candidate
-   can start (ignore limitations on the number of simultaneous insns).
-
-   For each unit, a `<name>_unit_blockage' function is given an insn
-   already executing on the unit and a candidate to execute and will
-   give the delay incurred due to function unit conflicts.  The range of
-   blockage cost values for a given executing insn is given by the
-   `<name>_unit_blockage_range' function.  These values are encoded in
-   an int where the upper half gives the minimum value and the lower
-   half gives the maximum value.  */
-
-static void
-expand_units (void)
-{
-  struct function_unit *unit, **unit_num;
-  struct function_unit_op *op, **op_array, ***unit_ops;
-  rtx unitsmask;
-  rtx readycost;
-  rtx newexp;
-  const char *str;
-  int i, j, u, num, nvalues;
-
-  /* Rebuild the condition for the unit to share the RTL expressions.
-     Sharing is required by simplify_by_exploding.  Build the issue delay
-     expressions.  Validate the expressions we were given for the conditions
-     and conflict vector.  Then make attributes for use in the conflict
-     function.  */
-
-  for (unit = units; unit; unit = unit->next)
+  else if (GET_CODE (exp) == IF_THEN_ELSE)
     {
-      unit->condexp = check_attr_test (unit->condexp, 0, unit->first_lineno);
-
-      for (op = unit->ops; op; op = op->next)
-       {
-         rtx issue_delay = make_numeric_value (op->issue_delay);
-         rtx issue_exp = issue_delay;
-
-         /* Build, validate, and simplify the issue delay expression.  */
-         if (op->conflict_exp != true_rtx)
-           issue_exp = attr_rtx (IF_THEN_ELSE, op->conflict_exp,
-                                 issue_exp, make_numeric_value (0));
-         issue_exp = check_attr_value (make_canonical (NULL_ATTR,
-                                                       issue_exp),
-                                       NULL_ATTR);
-         issue_exp = simplify_knowing (issue_exp, unit->condexp);
-         op->issue_exp = issue_exp;
-
-         /* Make an attribute for use in the conflict function if needed.  */
-         unit->needs_conflict_function = (unit->issue_delay.min
-                                          != unit->issue_delay.max);
-         if (unit->needs_conflict_function)
-           {
-             str = attr_printf ((strlen (unit->name) + sizeof "*_cost_"
-                                 + MAX_DIGITS),
-                                "*%s_cost_%d", unit->name, op->num);
-             make_internal_attr (str, issue_exp, ATTR_SPECIAL);
-           }
+      address_used = 0;
+      walk_attr_value (XEXP (exp, 0));
+      if (address_used)
+       return (*address_fn) (exp);
 
-         /* Validate the condition.  */
-         op->condexp = check_attr_test (op->condexp, 0, op->lineno);
-       }
+      return attr_rtx (IF_THEN_ELSE,
+                      substitute_address (XEXP (exp, 0),
+                                          no_address_fn, address_fn),
+                      substitute_address (XEXP (exp, 1),
+                                          no_address_fn, address_fn),
+                      substitute_address (XEXP (exp, 2),
+                                          no_address_fn, address_fn));
     }
 
-  /* Compute the mask of function units used.  Initially, the unitsmask is
-     zero.   Set up a conditional to compute each unit's contribution.  */
-  unitsmask = make_numeric_value (0);
-  newexp = rtx_alloc (IF_THEN_ELSE);
-  XEXP (newexp, 2) = make_numeric_value (0);
+  return (*no_address_fn) (exp);
+}
 
-  /* If we have just a few units, we may be all right expanding the whole
-     thing.  But the expansion is 2**N in space on the number of opclasses,
-     so we can't do this for very long -- Alpha and MIPS in particular have
-     problems with this.  So in that situation, we fall back on an alternate
-     implementation method.  */
-#define NUM_UNITOP_CUTOFF 20
+/* Make new attributes from the `length' attribute.  The following are made,
+   each corresponding to a function called from `shorten_branches' or
+   `get_attr_length':
 
-  if (num_unit_opclasses < NUM_UNITOP_CUTOFF)
-    {
-      /* Merge each function unit into the unit mask attributes.  */
-      for (unit = units; unit; unit = unit->next)
-       {
-         XEXP (newexp, 0) = unit->condexp;
-         XEXP (newexp, 1) = make_numeric_value (1 << unit->num);
-         unitsmask = operate_exp (OR_OP, unitsmask, newexp);
-       }
-    }
-  else
-    {
-      /* Merge each function unit into the unit mask attributes.  */
-      for (unit = units; unit; unit = unit->next)
-       {
-         XEXP (newexp, 0) = unit->condexp;
-         XEXP (newexp, 1) = make_numeric_value (1 << unit->num);
-         unitsmask = operate_exp (ORX_OP, unitsmask, attr_copy_rtx (newexp));
-       }
-    }
+   *insn_default_length                This is the length of the insn to be returned
+                               by `get_attr_length' before `shorten_branches'
+                               has been called.  In each case where the length
+                               depends on relative addresses, the largest
+                               possible is used.  This routine is also used
+                               to compute the initial size of the insn.
 
-  /* Simplify the unit mask expression, encode it, and make an attribute
-     for the function_units_used function.  */
-  unitsmask = simplify_by_exploding (unitsmask);
+   *insn_variable_length_p     This returns 1 if the insn's length depends
+                               on relative addresses, zero otherwise.
 
-  if (num_unit_opclasses < NUM_UNITOP_CUTOFF)
-    unitsmask = encode_units_mask (unitsmask);
-  else
+   *insn_current_length                This is only called when it is known that the
+                               insn has a variable length and returns the
+                               current length, based on relative addresses.
+  */
+
+static void
+make_length_attrs (void)
+{
+  static const char *new_names[] =
     {
-      /* We can no longer encode unitsmask at compile time, so emit code to
-         calculate it at runtime.  Rather, put a marker for where we'd do
-        the code, and actually output it in write_attr_get().  */
-      unitsmask = attr_rtx (FFS, unitsmask);
-    }
+      "*insn_default_length",
+      "*insn_variable_length_p",
+      "*insn_current_length"
+    };
+  static rtx (*const no_address_fn[]) (rtx) = {identity_fn, zero_fn, zero_fn};
+  static rtx (*const address_fn[]) (rtx) = {max_fn, one_fn, identity_fn};
+  size_t i;
+  struct attr_desc *length_attr, *new_attr;
+  struct attr_value *av, *new_av;
+  struct insn_ent *ie, *new_ie;
 
-  make_internal_attr ("*function_units_used", unitsmask,
-                     (ATTR_NEGATIVE_OK | ATTR_FUNC_UNITS));
+  /* See if length attribute is defined.  If so, it must be numeric.  Make
+     it special so we don't output anything for it.  */
+  length_attr = find_attr (&length_str, 0);
+  if (length_attr == 0)
+    return;
 
-  /* Create an array of ops for each unit.  Add an extra unit for the
-     result_ready_cost function that has the ops of all other units.  */
-  unit_ops = xmalloc ((num_units + 1) * sizeof (struct function_unit_op **));
-  unit_num = xmalloc ((num_units + 1) * sizeof (struct function_unit *));
+  if (! length_attr->is_numeric)
+    fatal ("length attribute must be numeric");
 
-  unit_num[num_units] = unit = xmalloc (sizeof (struct function_unit));
-  unit->num = num_units;
-  unit->num_opclasses = 0;
+  length_attr->is_const = 0;
+  length_attr->is_special = 1;
 
-  for (unit = units; unit; unit = unit->next)
+  /* Make each new attribute, in turn.  */
+  for (i = 0; i < ARRAY_SIZE (new_names); i++)
     {
-      unit_num[num_units]->num_opclasses += unit->num_opclasses;
-      unit_num[unit->num] = unit;
-      unit_ops[unit->num] = op_array =
-       xmalloc (unit->num_opclasses * sizeof (struct function_unit_op *));
-
-      for (op = unit->ops; op; op = op->next)
-       op_array[op->num] = op;
+      make_internal_attr (new_names[i],
+                         substitute_address (length_attr->default_val->value,
+                                             no_address_fn[i], address_fn[i]),
+                         ATTR_NONE);
+      new_attr = find_attr (&new_names[i], 0);
+      for (av = length_attr->first_value; av; av = av->next)
+       for (ie = av->first_insn; ie; ie = ie->next)
+         {
+           new_av = get_attr_value (substitute_address (av->value,
+                                                        no_address_fn[i],
+                                                        address_fn[i]),
+                                    new_attr, ie->def->insn_code);
+           new_ie = oballoc (sizeof (struct insn_ent));
+           new_ie->def = ie->def;
+           insert_insn_ent (new_av, new_ie);
+         }
     }
+}
 
-  /* Compose the array of ops for the extra unit.  */
-  unit_ops[num_units] = op_array =
-    xmalloc (unit_num[num_units]->num_opclasses
-           * sizeof (struct function_unit_op *));
+/* Utility functions called from above routine.  */
 
-  for (unit = units, i = 0; unit; i += unit->num_opclasses, unit = unit->next)
-    memcpy (&op_array[i], unit_ops[unit->num],
-           unit->num_opclasses * sizeof (struct function_unit_op *));
+static rtx
+identity_fn (rtx exp)
+{
+  return exp;
+}
 
-  /* Compute the ready cost function for each unit by computing the
-     condition for each non-default value.  */
-  for (u = 0; u <= num_units; u++)
-    {
-      rtx orexp;
-      int value;
+static rtx
+zero_fn (rtx exp ATTRIBUTE_UNUSED)
+{
+  return make_numeric_value (0);
+}
 
-      unit = unit_num[u];
-      op_array = unit_ops[unit->num];
-      num = unit->num_opclasses;
+static rtx
+one_fn (rtx exp ATTRIBUTE_UNUSED)
+{
+  return make_numeric_value (1);
+}
 
-      /* Sort the array of ops into increasing ready cost order.  */
-      for (i = 0; i < num; i++)
-       for (j = num - 1; j > i; j--)
-         if (op_array[j - 1]->ready < op_array[j]->ready)
-           {
-             op = op_array[j];
-             op_array[j] = op_array[j - 1];
-             op_array[j - 1] = op;
-           }
+static rtx
+max_fn (rtx exp)
+{
+  int unknown;
+  return make_numeric_value (max_attr_value (exp, &unknown));
+}
 
-      /* Determine how many distinct non-default ready cost values there
-        are.  We use a default ready cost value of 1.  */
-      nvalues = 0; value = 1;
-      for (i = num - 1; i >= 0; i--)
-       if (op_array[i]->ready > value)
-         {
-           value = op_array[i]->ready;
-           nvalues++;
-         }
-
-      if (nvalues == 0)
-       readycost = make_numeric_value (1);
-      else
-       {
-         /* Construct the ready cost expression as a COND of each value from
-            the largest to the smallest.  */
-         readycost = rtx_alloc (COND);
-         XVEC (readycost, 0) = rtvec_alloc (nvalues * 2);
-         XEXP (readycost, 1) = make_numeric_value (1);
-
-         nvalues = 0;
-         orexp = false_rtx;
-         value = op_array[0]->ready;
-         for (i = 0; i < num; i++)
-           {
-             op = op_array[i];
-             if (op->ready <= 1)
-               break;
-             else if (op->ready == value)
-               orexp = insert_right_side (IOR, orexp, op->condexp, -2, -2);
-             else
-               {
-                 XVECEXP (readycost, 0, nvalues * 2) = orexp;
-                 XVECEXP (readycost, 0, nvalues * 2 + 1)
-                   = make_numeric_value (value);
-                 nvalues++;
-                 value = op->ready;
-                 orexp = op->condexp;
-               }
-           }
-         XVECEXP (readycost, 0, nvalues * 2) = orexp;
-         XVECEXP (readycost, 0, nvalues * 2 + 1) = make_numeric_value (value);
-       }
+static void
+write_length_unit_log (void)
+{
+  struct attr_desc *length_attr = find_attr (&length_str, 0);
+  struct attr_value *av;
+  struct insn_ent *ie;
+  unsigned int length_unit_log, length_or;
+  int unknown = 0;
 
-      if (u < num_units)
-       {
-         rtx max_blockage = 0, min_blockage = 0;
+  if (length_attr == 0)
+    return;
+  length_or = or_attr_value (length_attr->default_val->value, &unknown);
+  for (av = length_attr->first_value; av; av = av->next)
+    for (ie = av->first_insn; ie; ie = ie->next)
+      length_or |= or_attr_value (av->value, &unknown);
 
-         /* Simplify the readycost expression by only considering insns
-            that use the unit.  */
-         readycost = simplify_knowing (readycost, unit->condexp);
+  if (unknown)
+    length_unit_log = 0;
+  else
+    {
+      length_or = ~length_or;
+      for (length_unit_log = 0; length_or & 1; length_or >>= 1)
+       length_unit_log++;
+    }
+  printf ("int length_unit_log = %u;\n", length_unit_log);
+}
 
-         /* Determine the blockage cost the executing insn (E) given
-            the candidate insn (C).  This is the maximum of the issue
-            delay, the pipeline delay, and the simultaneity constraint.
-            Each function_unit_op represents the characteristics of the
-            candidate insn, so in the expressions below, C is a known
-            term and E is an unknown term.
+/* Take a COND expression and see if any of the conditions in it can be
+   simplified.  If any are known true or known false for the particular insn
+   code, the COND can be further simplified.
 
-            We compute the blockage cost for each E for every possible C.
-            Thus OP represents E, and READYCOST is a list of values for
-            every possible C.
+   Also call ourselves on any COND operations that are values of this COND.
 
-            The issue delay function for C is op->issue_exp and is used to
-            write the `<name>_unit_conflict_cost' function.  Symbolically
-            this is "ISSUE-DELAY (E,C)".
+   We do not modify EXP; rather, we make and return a new rtx.  */
 
-            The pipeline delay results form the FIFO constraint on the
-            function unit and is "READY-COST (E) + 1 - READY-COST (C)".
+static rtx
+simplify_cond (rtx exp, int insn_code, int insn_index)
+{
+  int i, j;
+  /* We store the desired contents here,
+     then build a new expression if they don't match EXP.  */
+  rtx defval = XEXP (exp, 1);
+  rtx new_defval = XEXP (exp, 1);
+  int len = XVECLEN (exp, 0);
+  rtx *tests = xmalloc (len * sizeof (rtx));
+  int allsame = 1;
+  rtx ret;
 
-            The simultaneity constraint is based on how long it takes to
-            fill the unit given the minimum issue delay.  FILL-TIME is the
-            constant "MIN (ISSUE-DELAY (*,*)) * (SIMULTANEITY - 1)", and
-            the simultaneity constraint is "READY-COST (E) - FILL-TIME"
-            if SIMULTANEITY is nonzero and zero otherwise.
+  /* This lets us free all storage allocated below, if appropriate.  */
+  obstack_finish (rtl_obstack);
 
-            Thus, BLOCKAGE (E,C) when SIMULTANEITY is zero is
+  memcpy (tests, XVEC (exp, 0)->elem, len * sizeof (rtx));
 
-                MAX (ISSUE-DELAY (E,C),
-                     READY-COST (E) - (READY-COST (C) - 1))
+  /* See if default value needs simplification.  */
+  if (GET_CODE (defval) == COND)
+    new_defval = simplify_cond (defval, insn_code, insn_index);
 
-            and otherwise
+  /* Simplify the subexpressions, and see what tests we can get rid of.  */
 
-                MAX (ISSUE-DELAY (E,C),
-                     READY-COST (E) - (READY-COST (C) - 1),
-                     READY-COST (E) - FILL-TIME)
+  for (i = 0; i < len; i += 2)
+    {
+      rtx newtest, newval;
 
-            The `<name>_unit_blockage' function is computed by determining
-            this value for each candidate insn.  As these values are
-            computed, we also compute the upper and lower bounds for
-            BLOCKAGE (E,*).  These are combined to form the function
-            `<name>_unit_blockage_range'.  Finally, the maximum blockage
-            cost, MAX (BLOCKAGE (*,*)), is computed.  */
+      /* Simplify this test.  */
+      newtest = simplify_test_exp_in_temp (tests[i], insn_code, insn_index);
+      tests[i] = newtest;
 
-         for (op = unit->ops; op; op = op->next)
-           {
-             rtx blockage = op->issue_exp;
-             blockage = simplify_knowing (blockage, unit->condexp);
+      newval = tests[i + 1];
+      /* See if this value may need simplification.  */
+      if (GET_CODE (newval) == COND)
+       newval = simplify_cond (newval, insn_code, insn_index);
 
-             /* Add this op's contribution to MAX (BLOCKAGE (E,*)) and
-                MIN (BLOCKAGE (E,*)).  */
-             if (max_blockage == 0)
-               max_blockage = min_blockage = blockage;
-             else
-               {
-                 max_blockage
-                   = simplify_knowing (operate_exp (MAX_OP, max_blockage,
-                                                    blockage),
-                                       unit->condexp);
-                 min_blockage
-                   = simplify_knowing (operate_exp (MIN_OP, min_blockage,
-                                                    blockage),
-                                       unit->condexp);
-               }
+      /* Look for ways to delete or combine this test.  */
+      if (newtest == true_rtx)
+       {
+         /* If test is true, make this value the default
+            and discard this + any following tests.  */
+         len = i;
+         defval = tests[i + 1];
+         new_defval = newval;
+       }
 
-             /* Make an attribute for use in the blockage function.  */
-             str = attr_printf ((strlen (unit->name) + sizeof "*_block_"
-                                 + MAX_DIGITS),
-                                "*%s_block_%d", unit->name, op->num);
-             make_internal_attr (str, blockage, ATTR_SPECIAL);
-           }
+      else if (newtest == false_rtx)
+       {
+         /* If test is false, discard it and its value.  */
+         for (j = i; j < len - 2; j++)
+           tests[j] = tests[j + 2];
+         i -= 2;
+         len -= 2;
+       }
 
-         /* Record MAX (BLOCKAGE (*,*)).  */
-         {
-           int unknown;
-           unit->max_blockage = max_attr_value (max_blockage, &unknown);
-         }
+      else if (i > 0 && attr_equal_p (newval, tests[i - 1]))
+       {
+         /* If this value and the value for the prev test are the same,
+            merge the tests.  */
 
-         /* See if the upper and lower bounds of BLOCKAGE (E,*) are the
-            same.  If so, the blockage function carries no additional
-            information and is not written.  */
-         newexp = operate_exp (EQ_OP, max_blockage, min_blockage);
-         newexp = simplify_knowing (newexp, unit->condexp);
-         unit->needs_blockage_function
-           = (GET_CODE (newexp) != CONST_STRING
-              || atoi (XSTR (newexp, 0)) != 1);
-
-         /* If the all values of BLOCKAGE (E,C) have the same value,
-            neither blockage function is written.  */
-         unit->needs_range_function
-           = (unit->needs_blockage_function
-              || GET_CODE (max_blockage) != CONST_STRING);
-
-         if (unit->needs_range_function)
-           {
-             /* Compute the blockage range function and make an attribute
-                for writing its value.  */
-             newexp = operate_exp (RANGE_OP, min_blockage, max_blockage);
-             newexp = simplify_knowing (newexp, unit->condexp);
-
-             str = attr_printf ((strlen (unit->name)
-                                 + sizeof "*_unit_blockage_range"),
-                                "*%s_unit_blockage_range", unit->name);
-             make_internal_attr (str, newexp, (ATTR_STATIC|ATTR_BLOCKAGE|ATTR_UNSIGNED));
-           }
+         tests[i - 2]
+           = insert_right_side (IOR, tests[i - 2], newtest,
+                                insn_code, insn_index);
 
-         str = attr_printf (strlen (unit->name) + sizeof "*_unit_ready_cost",
-                            "*%s_unit_ready_cost", unit->name);
-         make_internal_attr (str, readycost, ATTR_STATIC);
+         /* Delete this test/value.  */
+         for (j = i; j < len - 2; j++)
+           tests[j] = tests[j + 2];
+         len -= 2;
+         i -= 2;
        }
+
       else
-        {
-         /* Make an attribute for the ready_cost function.  Simplifying
-            further with simplify_by_exploding doesn't win.  */
-         str = "*result_ready_cost";
-         make_internal_attr (str, readycost, ATTR_NONE);
-       }
+       tests[i + 1] = newval;
     }
 
-  /* For each unit that requires a conflict cost function, make an attribute
-     that maps insns to the operation number.  */
-  for (unit = units; unit; unit = unit->next)
-    {
-      rtx caseexp;
-
-      if (! unit->needs_conflict_function
-         && ! unit->needs_blockage_function)
-       continue;
+  /* If the last test in a COND has the same value
+     as the default value, that test isn't needed.  */
 
-      caseexp = rtx_alloc (COND);
-      XVEC (caseexp, 0) = rtvec_alloc ((unit->num_opclasses - 1) * 2);
+  while (len > 0 && attr_equal_p (tests[len - 1], new_defval))
+    len -= 2;
 
-      for (op = unit->ops; op; op = op->next)
+  /* See if we changed anything.  */
+  if (len != XVECLEN (exp, 0) || new_defval != XEXP (exp, 1))
+    allsame = 0;
+  else
+    for (i = 0; i < len; i++)
+      if (! attr_equal_p (tests[i], XVECEXP (exp, 0, i)))
        {
-         /* Make our adjustment to the COND being computed.  If we are the
-            last operation class, place our values into the default of the
-            COND.  */
-         if (op->num == unit->num_opclasses - 1)
-           {
-             XEXP (caseexp, 1) = make_numeric_value (op->num);
-           }
-         else
-           {
-             XVECEXP (caseexp, 0, op->num * 2) = op->condexp;
-             XVECEXP (caseexp, 0, op->num * 2 + 1)
-               = make_numeric_value (op->num);
-           }
+         allsame = 0;
+         break;
        }
 
-      /* Simplifying caseexp with simplify_by_exploding doesn't win.  */
-      str = attr_printf (strlen (unit->name) + sizeof "*_cases",
-                        "*%s_cases", unit->name);
-      make_internal_attr (str, caseexp, ATTR_SPECIAL);
+  if (len == 0)
+    {
+      if (GET_CODE (defval) == COND)
+       ret = simplify_cond (defval, insn_code, insn_index);
+      else
+       ret = defval;
     }
-}
-
-/* Simplify EXP given KNOWN_TRUE.  */
-
-static rtx
-simplify_knowing (rtx exp, rtx known_true)
-{
-  if (GET_CODE (exp) != CONST_STRING)
+  else if (allsame)
+    ret = exp;
+  else
     {
-      int unknown = 0, max;
-      max = max_attr_value (exp, &unknown);
-      if (! unknown)
-       {
-         exp = attr_rtx (IF_THEN_ELSE, known_true, exp,
-                         make_numeric_value (max));
-         exp = simplify_by_exploding (exp);
-       }
+      rtx newexp = rtx_alloc (COND);
+
+      XVEC (newexp, 0) = rtvec_alloc (len);
+      memcpy (XVEC (newexp, 0)->elem, tests, len * sizeof (rtx));
+      XEXP (newexp, 1) = new_defval;
+      ret = newexp;
     }
-  return exp;
+  free (tests);
+  return ret;
 }
 
-/* Translate the CONST_STRING expressions in X to change the encoding of
-   value.  On input, the value is a bitmask with a one bit for each unit
-   used; on output, the value is the unit number (zero based) if one
-   and only one unit is used or the one's complement of the bitmask.  */
+/* Remove an insn entry from an attribute value.  */
 
-static rtx
-encode_units_mask (rtx x)
+static void
+remove_insn_ent (struct attr_value *av, struct insn_ent *ie)
 {
-  int i;
-  int j;
-  enum rtx_code code;
-  const char *fmt;
-
-  code = GET_CODE (x);
+  struct insn_ent *previe;
 
-  switch (code)
+  if (av->first_insn == ie)
+    av->first_insn = ie->next;
+  else
     {
-    case CONST_STRING:
-      i = atoi (XSTR (x, 0));
-      if (i < 0)
-       /* The sign bit encodes a one's complement mask.  */
-       abort ();
-      else if (i != 0 && i == (i & -i))
-       /* Only one bit is set, so yield that unit number.  */
-       for (j = 0; (i >>= 1) != 0; j++)
-         ;
-      else
-       j = ~i;
-      return attr_rtx (CONST_STRING, attr_printf (MAX_DIGITS, "%d", j));
-
-    case REG:
-    case QUEUED:
-    case CONST_INT:
-    case CONST_DOUBLE:
-    case CONST_VECTOR:
-    case SYMBOL_REF:
-    case CODE_LABEL:
-    case PC:
-    case CC0:
-    case EQ_ATTR:
-      return x;
-
-    default:
-      break;
+      for (previe = av->first_insn; previe->next != ie; previe = previe->next)
+       ;
+      previe->next = ie->next;
     }
 
-  /* Compare the elements.  If any pair of corresponding elements
-     fail to match, return 0 for the whole things.  */
-
-  fmt = GET_RTX_FORMAT (code);
-  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
-    {
-      switch (fmt[i])
-       {
-       case 'V':
-       case 'E':
-         for (j = 0; j < XVECLEN (x, i); j++)
-           XVECEXP (x, i, j) = encode_units_mask (XVECEXP (x, i, j));
-         break;
+  av->num_insns--;
+  if (ie->def->insn_code == -1)
+    av->has_asm_insn = 0;
 
-       case 'e':
-         XEXP (x, i) = encode_units_mask (XEXP (x, i));
-         break;
-       }
-    }
-  return x;
+  num_insn_ents--;
 }
 
-/* Once all attributes and insns have been read and checked, we construct for
-   each attribute value a list of all the insns that have that value for
-   the attribute.  */
+/* Insert an insn entry in an attribute value list.  */
 
 static void
-fill_attr (struct attr_desc *attr)
+insert_insn_ent (struct attr_value *av, struct insn_ent *ie)
 {
-  struct attr_value *av;
-  struct insn_ent *ie;
-  struct insn_def *id;
-  int i;
-  rtx value;
-
-  /* Don't fill constant attributes.  The value is independent of
-     any particular insn.  */
-  if (attr->is_const)
-    return;
-
-  for (id = defs; id; id = id->next)
-    {
-      /* If no value is specified for this insn for this attribute, use the
-        default.  */
-      value = NULL;
-      if (XVEC (id->def, id->vec_idx))
-       for (i = 0; i < XVECLEN (id->def, id->vec_idx); i++)
-         if (! strcmp (XSTR (XEXP (XVECEXP (id->def, id->vec_idx, i), 0), 0),
-                       attr->name))
-           value = XEXP (XVECEXP (id->def, id->vec_idx, i), 1);
-
-      if (value == NULL)
-       av = attr->default_val;
-      else
-       av = get_attr_value (value, attr, id->insn_code);
+  ie->next = av->first_insn;
+  av->first_insn = ie;
+  av->num_insns++;
+  if (ie->def->insn_code == -1)
+    av->has_asm_insn = 1;
 
-      ie = oballoc (sizeof (struct insn_ent));
-      ie->insn_code = id->insn_code;
-      ie->insn_index = id->insn_code;
-      insert_insn_ent (av, ie);
-    }
+  num_insn_ents++;
 }
 
-/* Given an expression EXP, see if it is a COND or IF_THEN_ELSE that has a
-   test that checks relative positions of insns (uses MATCH_DUP or PC).
-   If so, replace it with what is obtained by passing the expression to
-   ADDRESS_FN.  If not but it is a COND or IF_THEN_ELSE, call this routine
-   recursively on each value (including the default value).  Otherwise,
-   return the value returned by NO_ADDRESS_FN applied to EXP.  */
+/* This is a utility routine to take an expression that is a tree of either
+   AND or IOR expressions and insert a new term.  The new term will be
+   inserted at the right side of the first node whose code does not match
+   the root.  A new node will be created with the root's code.  Its left
+   side will be the old right side and its right side will be the new
+   term.
+
+   If the `term' is itself a tree, all its leaves will be inserted.  */
 
 static rtx
-substitute_address (rtx exp, rtx (*no_address_fn) (rtx),
-                   rtx (*address_fn) (rtx))
+insert_right_side (enum rtx_code code, rtx exp, rtx term, int insn_code, int insn_index)
 {
-  int i;
   rtx newexp;
 
-  if (GET_CODE (exp) == COND)
-    {
-      /* See if any tests use addresses.  */
-      address_used = 0;
-      for (i = 0; i < XVECLEN (exp, 0); i += 2)
-       walk_attr_value (XVECEXP (exp, 0, i));
-
-      if (address_used)
-       return (*address_fn) (exp);
-
-      /* Make a new copy of this COND, replacing each element.  */
-      newexp = rtx_alloc (COND);
-      XVEC (newexp, 0) = rtvec_alloc (XVECLEN (exp, 0));
-      for (i = 0; i < XVECLEN (exp, 0); i += 2)
-       {
-         XVECEXP (newexp, 0, i) = XVECEXP (exp, 0, i);
-         XVECEXP (newexp, 0, i + 1)
-           = substitute_address (XVECEXP (exp, 0, i + 1),
-                                 no_address_fn, address_fn);
-       }
+  /* Avoid consing in some special cases.  */
+  if (code == AND && term == true_rtx)
+    return exp;
+  if (code == AND && term == false_rtx)
+    return false_rtx;
+  if (code == AND && exp == true_rtx)
+    return term;
+  if (code == AND && exp == false_rtx)
+    return false_rtx;
+  if (code == IOR && term == true_rtx)
+    return true_rtx;
+  if (code == IOR && term == false_rtx)
+    return exp;
+  if (code == IOR && exp == true_rtx)
+    return true_rtx;
+  if (code == IOR && exp == false_rtx)
+    return term;
+  if (attr_equal_p (exp, term))
+    return exp;
 
-      XEXP (newexp, 1) = substitute_address (XEXP (exp, 1),
-                                            no_address_fn, address_fn);
+  if (GET_CODE (term) == code)
+    {
+      exp = insert_right_side (code, exp, XEXP (term, 0),
+                              insn_code, insn_index);
+      exp = insert_right_side (code, exp, XEXP (term, 1),
+                              insn_code, insn_index);
 
-      return newexp;
+      return exp;
     }
 
-  else if (GET_CODE (exp) == IF_THEN_ELSE)
+  if (GET_CODE (exp) == code)
     {
-      address_used = 0;
-      walk_attr_value (XEXP (exp, 0));
-      if (address_used)
-       return (*address_fn) (exp);
-
-      return attr_rtx (IF_THEN_ELSE,
-                      substitute_address (XEXP (exp, 0),
-                                          no_address_fn, address_fn),
-                      substitute_address (XEXP (exp, 1),
-                                          no_address_fn, address_fn),
-                      substitute_address (XEXP (exp, 2),
-                                          no_address_fn, address_fn));
+      rtx new = insert_right_side (code, XEXP (exp, 1),
+                                  term, insn_code, insn_index);
+      if (new != XEXP (exp, 1))
+       /* Make a copy of this expression and call recursively.  */
+       newexp = attr_rtx (code, XEXP (exp, 0), new);
+      else
+       newexp = exp;
+    }
+  else
+    {
+      /* Insert the new term.  */
+      newexp = attr_rtx (code, exp, term);
     }
 
-  return (*no_address_fn) (exp);
+  return simplify_test_exp_in_temp (newexp, insn_code, insn_index);
 }
 
-/* Make new attributes from the `length' attribute.  The following are made,
-   each corresponding to a function called from `shorten_branches' or
-   `get_attr_length':
-
-   *insn_default_length                This is the length of the insn to be returned
-                               by `get_attr_length' before `shorten_branches'
-                               has been called.  In each case where the length
-                               depends on relative addresses, the largest
-                               possible is used.  This routine is also used
-                               to compute the initial size of the insn.
-
-   *insn_variable_length_p     This returns 1 if the insn's length depends
-                               on relative addresses, zero otherwise.
+/* If we have an expression which AND's a bunch of
+       (not (eq_attrq "alternative" "n"))
+   terms, we may have covered all or all but one of the possible alternatives.
+   If so, we can optimize.  Similarly for IOR's of EQ_ATTR.
 
-   *insn_current_length                This is only called when it is known that the
-                               insn has a variable length and returns the
-                               current length, based on relative addresses.
-  */
+   This routine is passed an expression and either AND or IOR.  It returns a
+   bitmask indicating which alternatives are mentioned within EXP.  */
 
-static void
-make_length_attrs (void)
+static int
+compute_alternative_mask (rtx exp, enum rtx_code code)
 {
-  static const char *const new_names[] = {"*insn_default_length",
-                                     "*insn_variable_length_p",
-                                     "*insn_current_length"};
-  static rtx (*const no_address_fn[]) (rtx) = {identity_fn, zero_fn, zero_fn};
-  static rtx (*const address_fn[]) (rtx) = {max_fn, one_fn, identity_fn};
-  size_t i;
-  struct attr_desc *length_attr, *new_attr;
-  struct attr_value *av, *new_av;
-  struct insn_ent *ie, *new_ie;
-
-  /* See if length attribute is defined.  If so, it must be numeric.  Make
-     it special so we don't output anything for it.  */
-  length_attr = find_attr ("length", 0);
-  if (length_attr == 0)
-    return;
+  const char *string;
+  if (GET_CODE (exp) == code)
+    return compute_alternative_mask (XEXP (exp, 0), code)
+          | compute_alternative_mask (XEXP (exp, 1), code);
 
-  if (! length_attr->is_numeric)
-    fatal ("length attribute must be numeric");
+  else if (code == AND && GET_CODE (exp) == NOT
+          && GET_CODE (XEXP (exp, 0)) == EQ_ATTR
+          && XSTR (XEXP (exp, 0), 0) == alternative_name)
+    string = XSTR (XEXP (exp, 0), 1);
 
-  length_attr->is_const = 0;
-  length_attr->is_special = 1;
+  else if (code == IOR && GET_CODE (exp) == EQ_ATTR
+          && XSTR (exp, 0) == alternative_name)
+    string = XSTR (exp, 1);
 
-  /* Make each new attribute, in turn.  */
-  for (i = 0; i < ARRAY_SIZE (new_names); i++)
+  else if (GET_CODE (exp) == EQ_ATTR_ALT)
     {
-      make_internal_attr (new_names[i],
-                         substitute_address (length_attr->default_val->value,
-                                             no_address_fn[i], address_fn[i]),
-                         ATTR_NONE);
-      new_attr = find_attr (new_names[i], 0);
-      for (av = length_attr->first_value; av; av = av->next)
-       for (ie = av->first_insn; ie; ie = ie->next)
-         {
-           new_av = get_attr_value (substitute_address (av->value,
-                                                        no_address_fn[i],
-                                                        address_fn[i]),
-                                    new_attr, ie->insn_code);
-           new_ie = oballoc (sizeof (struct insn_ent));
-           new_ie->insn_code = ie->insn_code;
-           new_ie->insn_index = ie->insn_index;
-           insert_insn_ent (new_av, new_ie);
-         }
+      if (code == AND && XINT (exp, 1))
+       return XINT (exp, 0);
+
+      if (code == IOR && !XINT (exp, 1))
+       return XINT (exp, 0);
+
+      return 0;
     }
+  else
+    return 0;
+
+  if (string[1] == 0)
+    return 1 << (string[0] - '0');
+  return 1 << atoi (string);
 }
 
-/* Utility functions called from above routine.  */
+/* Given I, a single-bit mask, return RTX to compare the `alternative'
+   attribute with the value represented by that bit.  */
 
 static rtx
-identity_fn (rtx exp)
+make_alternative_compare (int mask)
 {
-  return exp;
+  return mk_attr_alt (mask);
 }
 
-static rtx
-zero_fn (rtx exp ATTRIBUTE_UNUSED)
-{
-  return make_numeric_value (0);
-}
+/* If we are processing an (eq_attr "attr" "value") test, we find the value
+   of "attr" for this insn code.  From that value, we can compute a test
+   showing when the EQ_ATTR will be true.  This routine performs that
+   computation.  If a test condition involves an address, we leave the EQ_ATTR
+   intact because addresses are only valid for the `length' attribute.
 
-static rtx
-one_fn (rtx exp ATTRIBUTE_UNUSED)
-{
-  return make_numeric_value (1);
-}
+   EXP is the EQ_ATTR expression and VALUE is the value of that attribute
+   for the insn corresponding to INSN_CODE and INSN_INDEX.  */
 
 static rtx
-max_fn (rtx exp)
-{
-  int unknown;
-  return make_numeric_value (max_attr_value (exp, &unknown));
-}
-
-static void
-write_length_unit_log (void)
+evaluate_eq_attr (rtx exp, rtx value, int insn_code, int insn_index)
 {
-  struct attr_desc *length_attr = find_attr ("length", 0);
-  struct attr_value *av;
-  struct insn_ent *ie;
-  unsigned int length_unit_log, length_or;
-  int unknown = 0;
-
-  if (length_attr == 0)
-    return;
-  length_or = or_attr_value (length_attr->default_val->value, &unknown);
-  for (av = length_attr->first_value; av; av = av->next)
-    for (ie = av->first_insn; ie; ie = ie->next)
-      length_or |= or_attr_value (av->value, &unknown);
+  rtx orexp, andexp;
+  rtx right;
+  rtx newexp;
+  int i;
 
-  if (unknown)
-    length_unit_log = 0;
-  else
+  switch (GET_CODE (value))
     {
-      length_or = ~length_or;
-      for (length_unit_log = 0; length_or & 1; length_or >>= 1)
-       length_unit_log++;
-    }
-  printf ("int length_unit_log = %u;\n", length_unit_log);
-}
+    case CONST_STRING:
+      if (! strcmp_check (XSTR (value, 0), XSTR (exp, 1)))
+       newexp = true_rtx;
+      else
+       newexp = false_rtx;
+      break;
+      
+    case SYMBOL_REF:
+      {
+       char *p;
+       char string[256];
+       
+       gcc_assert (GET_CODE (exp) == EQ_ATTR);
+       gcc_assert (strlen (XSTR (exp, 0)) + strlen (XSTR (exp, 1)) + 2
+                   <= 256);
+       
+       strcpy (string, XSTR (exp, 0));
+       strcat (string, "_");
+       strcat (string, XSTR (exp, 1));
+       for (p = string; *p; p++)
+         *p = TOUPPER (*p);
+       
+       newexp = attr_rtx (EQ, value,
+                          attr_rtx (SYMBOL_REF,
+                                    DEF_ATTR_STRING (string)));
+       break;
+      }
 
-/* Take a COND expression and see if any of the conditions in it can be
-   simplified.  If any are known true or known false for the particular insn
-   code, the COND can be further simplified.
+    case COND:
+      /* We construct an IOR of all the cases for which the
+        requested attribute value is present.  Since we start with
+        FALSE, if it is not present, FALSE will be returned.
+         
+        Each case is the AND of the NOT's of the previous conditions with the
+        current condition; in the default case the current condition is TRUE.
+         
+        For each possible COND value, call ourselves recursively.
+         
+        The extra TRUE and FALSE expressions will be eliminated by another
+        call to the simplification routine.  */
 
-   Also call ourselves on any COND operations that are values of this COND.
+      orexp = false_rtx;
+      andexp = true_rtx;
 
-   We do not modify EXP; rather, we make and return a new rtx.  */
+      if (current_alternative_string)
+       clear_struct_flag (value);
 
-static rtx
-simplify_cond (rtx exp, int insn_code, int insn_index)
-{
-  int i, j;
-  /* We store the desired contents here,
-     then build a new expression if they don't match EXP.  */
-  rtx defval = XEXP (exp, 1);
-  rtx new_defval = XEXP (exp, 1);
-  int len = XVECLEN (exp, 0);
-  rtx *tests = xmalloc (len * sizeof (rtx));
-  int allsame = 1;
-  rtx ret;
+      for (i = 0; i < XVECLEN (value, 0); i += 2)
+       {
+         rtx this = simplify_test_exp_in_temp (XVECEXP (value, 0, i),
+                                               insn_code, insn_index);
 
-  /* This lets us free all storage allocated below, if appropriate.  */
-  obstack_finish (rtl_obstack);
+         SIMPLIFY_ALTERNATIVE (this);
 
-  memcpy (tests, XVEC (exp, 0)->elem, len * sizeof (rtx));
+         right = insert_right_side (AND, andexp, this,
+                                    insn_code, insn_index);
+         right = insert_right_side (AND, right,
+                                    evaluate_eq_attr (exp,
+                                                      XVECEXP (value, 0,
+                                                               i + 1),
+                                                      insn_code, insn_index),
+                                    insn_code, insn_index);
+         orexp = insert_right_side (IOR, orexp, right,
+                                    insn_code, insn_index);
 
-  /* See if default value needs simplification.  */
-  if (GET_CODE (defval) == COND)
-    new_defval = simplify_cond (defval, insn_code, insn_index);
+         /* Add this condition into the AND expression.  */
+         newexp = attr_rtx (NOT, this);
+         andexp = insert_right_side (AND, andexp, newexp,
+                                     insn_code, insn_index);
+       }
 
-  /* Simplify the subexpressions, and see what tests we can get rid of.  */
+      /* Handle the default case.  */
+      right = insert_right_side (AND, andexp,
+                                evaluate_eq_attr (exp, XEXP (value, 1),
+                                                  insn_code, insn_index),
+                                insn_code, insn_index);
+      newexp = insert_right_side (IOR, orexp, right, insn_code, insn_index);
+      break;
 
-  for (i = 0; i < len; i += 2)
+    default:
+      gcc_unreachable ();
+    }
+
+  /* If uses an address, must return original expression.  But set the
+     ATTR_IND_SIMPLIFIED_P bit so we don't try to simplify it again.  */
+
+  address_used = 0;
+  walk_attr_value (newexp);
+
+  if (address_used)
     {
-      rtx newtest, newval;
+      /* This had `&& current_alternative_string', which seems to be wrong.  */
+      if (! ATTR_IND_SIMPLIFIED_P (exp))
+       return copy_rtx_unchanging (exp);
+      return exp;
+    }
+  else
+    return newexp;
+}
 
-      /* Simplify this test.  */
-      newtest = simplify_test_exp_in_temp (tests[i], insn_code, insn_index);
-      tests[i] = newtest;
+/* This routine is called when an AND of a term with a tree of AND's is
+   encountered.  If the term or its complement is present in the tree, it
+   can be replaced with TRUE or FALSE, respectively.
 
-      newval = tests[i + 1];
-      /* See if this value may need simplification.  */
-      if (GET_CODE (newval) == COND)
-       newval = simplify_cond (newval, insn_code, insn_index);
+   Note that (eq_attr "att" "v1") and (eq_attr "att" "v2") cannot both
+   be true and hence are complementary.
 
-      /* Look for ways to delete or combine this test.  */
-      if (newtest == true_rtx)
+   There is one special case:  If we see
+       (and (not (eq_attr "att" "v1"))
+            (eq_attr "att" "v2"))
+   this can be replaced by (eq_attr "att" "v2").  To do this we need to
+   replace the term, not anything in the AND tree.  So we pass a pointer to
+   the term.  */
+
+static rtx
+simplify_and_tree (rtx exp, rtx *pterm, int insn_code, int insn_index)
+{
+  rtx left, right;
+  rtx newexp;
+  rtx temp;
+  int left_eliminates_term, right_eliminates_term;
+
+  if (GET_CODE (exp) == AND)
+    {
+      left  = simplify_and_tree (XEXP (exp, 0), pterm, insn_code, insn_index);
+      right = simplify_and_tree (XEXP (exp, 1), pterm, insn_code, insn_index);
+      if (left != XEXP (exp, 0) || right != XEXP (exp, 1))
        {
-         /* If test is true, make this value the default
-            and discard this + any following tests.  */
-         len = i;
-         defval = tests[i + 1];
-         new_defval = newval;
+         newexp = attr_rtx (AND, left, right);
+
+         exp = simplify_test_exp_in_temp (newexp, insn_code, insn_index);
        }
+    }
 
-      else if (newtest == false_rtx)
+  else if (GET_CODE (exp) == IOR)
+    {
+      /* For the IOR case, we do the same as above, except that we can
+         only eliminate `term' if both sides of the IOR would do so.  */
+      temp = *pterm;
+      left = simplify_and_tree (XEXP (exp, 0), &temp, insn_code, insn_index);
+      left_eliminates_term = (temp == true_rtx);
+
+      temp = *pterm;
+      right = simplify_and_tree (XEXP (exp, 1), &temp, insn_code, insn_index);
+      right_eliminates_term = (temp == true_rtx);
+
+      if (left_eliminates_term && right_eliminates_term)
+       *pterm = true_rtx;
+
+      if (left != XEXP (exp, 0) || right != XEXP (exp, 1))
        {
-         /* If test is false, discard it and its value.  */
-         for (j = i; j < len - 2; j++)
-           tests[j] = tests[j + 2];
-         len -= 2;
+         newexp = attr_rtx (IOR, left, right);
+
+         exp = simplify_test_exp_in_temp (newexp, insn_code, insn_index);
        }
+    }
 
-      else if (i > 0 && attr_equal_p (newval, tests[i - 1]))
-       {
-         /* If this value and the value for the prev test are the same,
-            merge the tests.  */
+  /* Check for simplifications.  Do some extra checking here since this
+     routine is called so many times.  */
 
-         tests[i - 2]
-           = insert_right_side (IOR, tests[i - 2], newtest,
-                                insn_code, insn_index);
+  if (exp == *pterm)
+    return true_rtx;
 
-         /* Delete this test/value.  */
-         for (j = i; j < len - 2; j++)
-           tests[j] = tests[j + 2];
-         len -= 2;
-       }
+  else if (GET_CODE (exp) == NOT && XEXP (exp, 0) == *pterm)
+    return false_rtx;
 
-      else
-       tests[i + 1] = newval;
-    }
+  else if (GET_CODE (*pterm) == NOT && exp == XEXP (*pterm, 0))
+    return false_rtx;
 
-  /* If the last test in a COND has the same value
-     as the default value, that test isn't needed.  */
+  else if (GET_CODE (exp) == EQ_ATTR_ALT && GET_CODE (*pterm) == EQ_ATTR_ALT)
+    {
+      if (attr_alt_subset_p (*pterm, exp))
+       return true_rtx;
 
-  while (len > 0 && attr_equal_p (tests[len - 1], new_defval))
-    len -= 2;
+      if (attr_alt_subset_of_compl_p (*pterm, exp))
+       return false_rtx;
 
-  /* See if we changed anything.  */
-  if (len != XVECLEN (exp, 0) || new_defval != XEXP (exp, 1))
-    allsame = 0;
-  else
-    for (i = 0; i < len; i++)
-      if (! attr_equal_p (tests[i], XVECEXP (exp, 0, i)))
-       {
-         allsame = 0;
-         break;
-       }
+      if (attr_alt_subset_p (exp, *pterm))
+       *pterm = true_rtx;
+       
+      return exp;
+    }
 
-  if (len == 0)
+  else if (GET_CODE (exp) == EQ_ATTR && GET_CODE (*pterm) == EQ_ATTR)
     {
-      if (GET_CODE (defval) == COND)
-       ret = simplify_cond (defval, insn_code, insn_index);
+      if (XSTR (exp, 0) != XSTR (*pterm, 0))
+       return exp;
+
+      if (! strcmp_check (XSTR (exp, 1), XSTR (*pterm, 1)))
+       return true_rtx;
       else
-       ret = defval;
+       return false_rtx;
     }
-  else if (allsame)
-    ret = exp;
-  else
+
+  else if (GET_CODE (*pterm) == EQ_ATTR && GET_CODE (exp) == NOT
+          && GET_CODE (XEXP (exp, 0)) == EQ_ATTR)
     {
-      rtx newexp = rtx_alloc (COND);
+      if (XSTR (*pterm, 0) != XSTR (XEXP (exp, 0), 0))
+       return exp;
 
-      XVEC (newexp, 0) = rtvec_alloc (len);
-      memcpy (XVEC (newexp, 0)->elem, tests, len * sizeof (rtx));
-      XEXP (newexp, 1) = new_defval;
-      ret = newexp;
+      if (! strcmp_check (XSTR (*pterm, 1), XSTR (XEXP (exp, 0), 1)))
+       return false_rtx;
+      else
+       return true_rtx;
     }
-  free (tests);
-  return ret;
-}
 
-/* Remove an insn entry from an attribute value.  */
+  else if (GET_CODE (exp) == EQ_ATTR && GET_CODE (*pterm) == NOT
+          && GET_CODE (XEXP (*pterm, 0)) == EQ_ATTR)
+    {
+      if (XSTR (exp, 0) != XSTR (XEXP (*pterm, 0), 0))
+       return exp;
 
-static void
-remove_insn_ent (struct attr_value *av, struct insn_ent *ie)
-{
-  struct insn_ent *previe;
+      if (! strcmp_check (XSTR (exp, 1), XSTR (XEXP (*pterm, 0), 1)))
+       return false_rtx;
+      else
+       *pterm = true_rtx;
+    }
 
-  if (av->first_insn == ie)
-    av->first_insn = ie->next;
-  else
+  else if (GET_CODE (exp) == NOT && GET_CODE (*pterm) == NOT)
     {
-      for (previe = av->first_insn; previe->next != ie; previe = previe->next)
-       ;
-      previe->next = ie->next;
+      if (attr_equal_p (XEXP (exp, 0), XEXP (*pterm, 0)))
+       return true_rtx;
     }
 
-  av->num_insns--;
-  if (ie->insn_code == -1)
-    av->has_asm_insn = 0;
-
-  num_insn_ents--;
-}
+  else if (GET_CODE (exp) == NOT)
+    {
+      if (attr_equal_p (XEXP (exp, 0), *pterm))
+       return false_rtx;
+    }
 
-/* Insert an insn entry in an attribute value list.  */
+  else if (GET_CODE (*pterm) == NOT)
+    {
+      if (attr_equal_p (XEXP (*pterm, 0), exp))
+       return false_rtx;
+    }
 
-static void
-insert_insn_ent (struct attr_value *av, struct insn_ent *ie)
-{
-  ie->next = av->first_insn;
-  av->first_insn = ie;
-  av->num_insns++;
-  if (ie->insn_code == -1)
-    av->has_asm_insn = 1;
+  else if (attr_equal_p (exp, *pterm))
+    return true_rtx;
 
-  num_insn_ents++;
+  return exp;
 }
 
-/* This is a utility routine to take an expression that is a tree of either
-   AND or IOR expressions and insert a new term.  The new term will be
-   inserted at the right side of the first node whose code does not match
-   the root.  A new node will be created with the root's code.  Its left
-   side will be the old right side and its right side will be the new
-   term.
-
-   If the `term' is itself a tree, all its leaves will be inserted.  */
+/* Similar to `simplify_and_tree', but for IOR trees.  */
 
 static rtx
-insert_right_side (enum rtx_code code, rtx exp, rtx term, int insn_code, int insn_index)
+simplify_or_tree (rtx exp, rtx *pterm, int insn_code, int insn_index)
 {
+  rtx left, right;
   rtx newexp;
+  rtx temp;
+  int left_eliminates_term, right_eliminates_term;
 
-  /* Avoid consing in some special cases.  */
-  if (code == AND && term == true_rtx)
-    return exp;
-  if (code == AND && term == false_rtx)
-    return false_rtx;
-  if (code == AND && exp == true_rtx)
-    return term;
-  if (code == AND && exp == false_rtx)
-    return false_rtx;
-  if (code == IOR && term == true_rtx)
-    return true_rtx;
-  if (code == IOR && term == false_rtx)
-    return exp;
-  if (code == IOR && exp == true_rtx)
-    return true_rtx;
-  if (code == IOR && exp == false_rtx)
-    return term;
-  if (attr_equal_p (exp, term))
-    return exp;
-
-  if (GET_CODE (term) == code)
-    {
-      exp = insert_right_side (code, exp, XEXP (term, 0),
-                              insn_code, insn_index);
-      exp = insert_right_side (code, exp, XEXP (term, 1),
-                              insn_code, insn_index);
-
-      return exp;
-    }
-
-  if (GET_CODE (exp) == code)
-    {
-      rtx new = insert_right_side (code, XEXP (exp, 1),
-                                  term, insn_code, insn_index);
-      if (new != XEXP (exp, 1))
-       /* Make a copy of this expression and call recursively.  */
-       newexp = attr_rtx (code, XEXP (exp, 0), new);
-      else
-       newexp = exp;
-    }
-  else
-    {
-      /* Insert the new term.  */
-      newexp = attr_rtx (code, exp, term);
-    }
-
-  return simplify_test_exp_in_temp (newexp, insn_code, insn_index);
-}
-
-/* If we have an expression which AND's a bunch of
-       (not (eq_attrq "alternative" "n"))
-   terms, we may have covered all or all but one of the possible alternatives.
-   If so, we can optimize.  Similarly for IOR's of EQ_ATTR.
-
-   This routine is passed an expression and either AND or IOR.  It returns a
-   bitmask indicating which alternatives are mentioned within EXP.  */
-
-static int
-compute_alternative_mask (rtx exp, enum rtx_code code)
-{
-  const char *string;
-  if (GET_CODE (exp) == code)
-    return compute_alternative_mask (XEXP (exp, 0), code)
-          | compute_alternative_mask (XEXP (exp, 1), code);
-
-  else if (code == AND && GET_CODE (exp) == NOT
-          && GET_CODE (XEXP (exp, 0)) == EQ_ATTR
-          && XSTR (XEXP (exp, 0), 0) == alternative_name)
-    string = XSTR (XEXP (exp, 0), 1);
-
-  else if (code == IOR && GET_CODE (exp) == EQ_ATTR
-          && XSTR (exp, 0) == alternative_name)
-    string = XSTR (exp, 1);
-
-  else
-    return 0;
-
-  if (string[1] == 0)
-    return 1 << (string[0] - '0');
-  return 1 << atoi (string);
-}
-
-/* Given I, a single-bit mask, return RTX to compare the `alternative'
-   attribute with the value represented by that bit.  */
-
-static rtx
-make_alternative_compare (int mask)
-{
-  rtx newexp;
-  int i;
-
-  /* Find the bit.  */
-  for (i = 0; (mask & (1 << i)) == 0; i++)
-    ;
-
-  newexp = attr_rtx (EQ_ATTR, alternative_name, attr_numeral (i));
-  ATTR_IND_SIMPLIFIED_P (newexp) = 1;
-
-  return newexp;
-}
-
-/* If we are processing an (eq_attr "attr" "value") test, we find the value
-   of "attr" for this insn code.  From that value, we can compute a test
-   showing when the EQ_ATTR will be true.  This routine performs that
-   computation.  If a test condition involves an address, we leave the EQ_ATTR
-   intact because addresses are only valid for the `length' attribute.
-
-   EXP is the EQ_ATTR expression and VALUE is the value of that attribute
-   for the insn corresponding to INSN_CODE and INSN_INDEX.  */
-
-static rtx
-evaluate_eq_attr (rtx exp, rtx value, int insn_code, int insn_index)
-{
-  rtx orexp, andexp;
-  rtx right;
-  rtx newexp;
-  int i;
-
-  if (GET_CODE (value) == CONST_STRING)
-    {
-      if (! strcmp (XSTR (value, 0), XSTR (exp, 1)))
-       newexp = true_rtx;
-      else
-       newexp = false_rtx;
-    }
-  else if (GET_CODE (value) == SYMBOL_REF)
-    {
-      char *p;
-      char string[256];
-
-      if (GET_CODE (exp) != EQ_ATTR)
-       abort ();
-
-      if (strlen (XSTR (exp, 0)) + strlen (XSTR (exp, 1)) + 2 > 256)
-       abort ();
-
-      strcpy (string, XSTR (exp, 0));
-      strcat (string, "_");
-      strcat (string, XSTR (exp, 1));
-      for (p = string; *p; p++)
-       *p = TOUPPER (*p);
-
-      newexp = attr_rtx (EQ, value,
-                        attr_rtx (SYMBOL_REF,
-                                  attr_string (string, strlen (string))));
-    }
-  else if (GET_CODE (value) == COND)
-    {
-      /* We construct an IOR of all the cases for which the requested attribute
-        value is present.  Since we start with FALSE, if it is not present,
-        FALSE will be returned.
-
-        Each case is the AND of the NOT's of the previous conditions with the
-        current condition; in the default case the current condition is TRUE.
-
-        For each possible COND value, call ourselves recursively.
-
-        The extra TRUE and FALSE expressions will be eliminated by another
-        call to the simplification routine.  */
-
-      orexp = false_rtx;
-      andexp = true_rtx;
-
-      if (current_alternative_string)
-       clear_struct_flag (value);
-
-      for (i = 0; i < XVECLEN (value, 0); i += 2)
-       {
-         rtx this = simplify_test_exp_in_temp (XVECEXP (value, 0, i),
-                                               insn_code, insn_index);
-
-         SIMPLIFY_ALTERNATIVE (this);
-
-         right = insert_right_side (AND, andexp, this,
-                                    insn_code, insn_index);
-         right = insert_right_side (AND, right,
-                                    evaluate_eq_attr (exp,
-                                                      XVECEXP (value, 0,
-                                                               i + 1),
-                                                      insn_code, insn_index),
-                                    insn_code, insn_index);
-         orexp = insert_right_side (IOR, orexp, right,
-                                    insn_code, insn_index);
-
-         /* Add this condition into the AND expression.  */
-         newexp = attr_rtx (NOT, this);
-         andexp = insert_right_side (AND, andexp, newexp,
-                                     insn_code, insn_index);
-       }
-
-      /* Handle the default case.  */
-      right = insert_right_side (AND, andexp,
-                                evaluate_eq_attr (exp, XEXP (value, 1),
-                                                  insn_code, insn_index),
-                                insn_code, insn_index);
-      newexp = insert_right_side (IOR, orexp, right, insn_code, insn_index);
-    }
-  else
-    abort ();
-
-  /* If uses an address, must return original expression.  But set the
-     ATTR_IND_SIMPLIFIED_P bit so we don't try to simplify it again.  */
-
-  address_used = 0;
-  walk_attr_value (newexp);
-
-  if (address_used)
-    {
-      /* This had `&& current_alternative_string', which seems to be wrong.  */
-      if (! ATTR_IND_SIMPLIFIED_P (exp))
-       return copy_rtx_unchanging (exp);
-      return exp;
-    }
-  else
-    return newexp;
-}
-
-/* This routine is called when an AND of a term with a tree of AND's is
-   encountered.  If the term or its complement is present in the tree, it
-   can be replaced with TRUE or FALSE, respectively.
-
-   Note that (eq_attr "att" "v1") and (eq_attr "att" "v2") cannot both
-   be true and hence are complementary.
-
-   There is one special case:  If we see
-       (and (not (eq_attr "att" "v1"))
-            (eq_attr "att" "v2"))
-   this can be replaced by (eq_attr "att" "v2").  To do this we need to
-   replace the term, not anything in the AND tree.  So we pass a pointer to
-   the term.  */
-
-static rtx
-simplify_and_tree (rtx exp, rtx *pterm, int insn_code, int insn_index)
-{
-  rtx left, right;
-  rtx newexp;
-  rtx temp;
-  int left_eliminates_term, right_eliminates_term;
-
-  if (GET_CODE (exp) == AND)
+  if (GET_CODE (exp) == IOR)
     {
-      left  = simplify_and_tree (XEXP (exp, 0), pterm, insn_code, insn_index);
-      right = simplify_and_tree (XEXP (exp, 1), pterm, insn_code, insn_index);
+      left  = simplify_or_tree (XEXP (exp, 0), pterm, insn_code, insn_index);
+      right = simplify_or_tree (XEXP (exp, 1), pterm, insn_code, insn_index);
       if (left != XEXP (exp, 0) || right != XEXP (exp, 1))
        {
          newexp = attr_rtx (GET_CODE (exp), left, right);
@@ -2859,20 +2255,20 @@ simplify_and_tree (rtx exp, rtx *pterm, int insn_code, int insn_index)
        }
     }
 
-  else if (GET_CODE (exp) == IOR)
+  else if (GET_CODE (exp) == AND)
     {
-      /* For the IOR case, we do the same as above, except that we can
-         only eliminate `term' if both sides of the IOR would do so.  */
+      /* For the AND case, we do the same as above, except that we can
+         only eliminate `term' if both sides of the AND would do so.  */
       temp = *pterm;
-      left = simplify_and_tree (XEXP (exp, 0), &temp, insn_code, insn_index);
-      left_eliminates_term = (temp == true_rtx);
+      left = simplify_or_tree (XEXP (exp, 0), &temp, insn_code, insn_index);
+      left_eliminates_term = (temp == false_rtx);
 
       temp = *pterm;
-      right = simplify_and_tree (XEXP (exp, 1), &temp, insn_code, insn_index);
-      right_eliminates_term = (temp == true_rtx);
+      right = simplify_or_tree (XEXP (exp, 1), &temp, insn_code, insn_index);
+      right_eliminates_term = (temp == false_rtx);
 
       if (left_eliminates_term && right_eliminates_term)
-       *pterm = true_rtx;
+       *pterm = false_rtx;
 
       if (left != XEXP (exp, 0) || right != XEXP (exp, 1))
        {
@@ -2882,143 +2278,27 @@ simplify_and_tree (rtx exp, rtx *pterm, int insn_code, int insn_index)
        }
     }
 
-  /* Check for simplifications.  Do some extra checking here since this
-     routine is called so many times.  */
+  if (attr_equal_p (exp, *pterm))
+    return false_rtx;
 
-  if (exp == *pterm)
+  else if (GET_CODE (exp) == NOT && attr_equal_p (XEXP (exp, 0), *pterm))
     return true_rtx;
 
-  else if (GET_CODE (exp) == NOT && XEXP (exp, 0) == *pterm)
-    return false_rtx;
+  else if (GET_CODE (*pterm) == NOT && attr_equal_p (XEXP (*pterm, 0), exp))
+    return true_rtx;
 
-  else if (GET_CODE (*pterm) == NOT && exp == XEXP (*pterm, 0))
+  else if (GET_CODE (*pterm) == EQ_ATTR && GET_CODE (exp) == NOT
+          && GET_CODE (XEXP (exp, 0)) == EQ_ATTR
+          && XSTR (*pterm, 0) == XSTR (XEXP (exp, 0), 0))
+    *pterm = false_rtx;
+
+  else if (GET_CODE (exp) == EQ_ATTR && GET_CODE (*pterm) == NOT
+          && GET_CODE (XEXP (*pterm, 0)) == EQ_ATTR
+          && XSTR (exp, 0) == XSTR (XEXP (*pterm, 0), 0))
     return false_rtx;
 
-  else if (GET_CODE (exp) == EQ_ATTR && GET_CODE (*pterm) == EQ_ATTR)
-    {
-      if (XSTR (exp, 0) != XSTR (*pterm, 0))
-       return exp;
-
-      if (! strcmp (XSTR (exp, 1), XSTR (*pterm, 1)))
-       return true_rtx;
-      else
-       return false_rtx;
-    }
-
-  else if (GET_CODE (*pterm) == EQ_ATTR && GET_CODE (exp) == NOT
-          && GET_CODE (XEXP (exp, 0)) == EQ_ATTR)
-    {
-      if (XSTR (*pterm, 0) != XSTR (XEXP (exp, 0), 0))
-       return exp;
-
-      if (! strcmp (XSTR (*pterm, 1), XSTR (XEXP (exp, 0), 1)))
-       return false_rtx;
-      else
-       return true_rtx;
-    }
-
-  else if (GET_CODE (exp) == EQ_ATTR && GET_CODE (*pterm) == NOT
-          && GET_CODE (XEXP (*pterm, 0)) == EQ_ATTR)
-    {
-      if (XSTR (exp, 0) != XSTR (XEXP (*pterm, 0), 0))
-       return exp;
-
-      if (! strcmp (XSTR (exp, 1), XSTR (XEXP (*pterm, 0), 1)))
-       return false_rtx;
-      else
-       *pterm = true_rtx;
-    }
-
-  else if (GET_CODE (exp) == NOT && GET_CODE (*pterm) == NOT)
-    {
-      if (attr_equal_p (XEXP (exp, 0), XEXP (*pterm, 0)))
-       return true_rtx;
-    }
-
-  else if (GET_CODE (exp) == NOT)
-    {
-      if (attr_equal_p (XEXP (exp, 0), *pterm))
-       return false_rtx;
-    }
-
-  else if (GET_CODE (*pterm) == NOT)
-    {
-      if (attr_equal_p (XEXP (*pterm, 0), exp))
-       return false_rtx;
-    }
-
-  else if (attr_equal_p (exp, *pterm))
-    return true_rtx;
-
-  return exp;
-}
-
-/* Similar to `simplify_and_tree', but for IOR trees.  */
-
-static rtx
-simplify_or_tree (rtx exp, rtx *pterm, int insn_code, int insn_index)
-{
-  rtx left, right;
-  rtx newexp;
-  rtx temp;
-  int left_eliminates_term, right_eliminates_term;
-
-  if (GET_CODE (exp) == IOR)
-    {
-      left  = simplify_or_tree (XEXP (exp, 0), pterm, insn_code, insn_index);
-      right = simplify_or_tree (XEXP (exp, 1), pterm, insn_code, insn_index);
-      if (left != XEXP (exp, 0) || right != XEXP (exp, 1))
-       {
-         newexp = attr_rtx (GET_CODE (exp), left, right);
-
-         exp = simplify_test_exp_in_temp (newexp, insn_code, insn_index);
-       }
-    }
-
-  else if (GET_CODE (exp) == AND)
-    {
-      /* For the AND case, we do the same as above, except that we can
-         only eliminate `term' if both sides of the AND would do so.  */
-      temp = *pterm;
-      left = simplify_or_tree (XEXP (exp, 0), &temp, insn_code, insn_index);
-      left_eliminates_term = (temp == false_rtx);
-
-      temp = *pterm;
-      right = simplify_or_tree (XEXP (exp, 1), &temp, insn_code, insn_index);
-      right_eliminates_term = (temp == false_rtx);
-
-      if (left_eliminates_term && right_eliminates_term)
-       *pterm = false_rtx;
-
-      if (left != XEXP (exp, 0) || right != XEXP (exp, 1))
-       {
-         newexp = attr_rtx (GET_CODE (exp), left, right);
-
-         exp = simplify_test_exp_in_temp (newexp, insn_code, insn_index);
-       }
-    }
-
-  if (attr_equal_p (exp, *pterm))
-    return false_rtx;
-
-  else if (GET_CODE (exp) == NOT && attr_equal_p (XEXP (exp, 0), *pterm))
-    return true_rtx;
-
-  else if (GET_CODE (*pterm) == NOT && attr_equal_p (XEXP (*pterm, 0), exp))
-    return true_rtx;
-
-  else if (GET_CODE (*pterm) == EQ_ATTR && GET_CODE (exp) == NOT
-          && GET_CODE (XEXP (exp, 0)) == EQ_ATTR
-          && XSTR (*pterm, 0) == XSTR (XEXP (exp, 0), 0))
-    *pterm = false_rtx;
-
-  else if (GET_CODE (exp) == EQ_ATTR && GET_CODE (*pterm) == NOT
-          && GET_CODE (XEXP (*pterm, 0)) == EQ_ATTR
-          && XSTR (exp, 0) == XSTR (XEXP (*pterm, 0), 0))
-    return false_rtx;
-
-  return exp;
-}
+  return exp;
+}
 
 /* Compute approximate cost of the expression.  Used to decide whether
    expression is cheap enough for inline.  */
@@ -3037,9 +2317,13 @@ attr_rtx_cost (rtx x)
        return 10;
       else
        return 0;
+
+    case EQ_ATTR_ALT:
+      return 0;
+
     case EQ_ATTR:
       /* Alternatives don't result into function call.  */
-      if (!strcmp (XSTR (x, 0), "alternative"))
+      if (!strcmp_check (XSTR (x, 0), alternative_name))
        return 0;
       else
        return 5;
@@ -3087,891 +2371,590 @@ simplify_test_exp_in_temp (rtx exp, int insn_code, int insn_index)
   return attr_copy_rtx (x);
 }
 
-/* Given an expression, see if it can be simplified for a particular insn
-   code based on the values of other attributes being tested.  This can
-   eliminate nested get_attr_... calls.
-
-   Note that if an endless recursion is specified in the patterns, the
-   optimization will loop.  However, it will do so in precisely the cases where
-   an infinite recursion loop could occur during compilation.  It's better that
-   it occurs here!  */
+/* Returns true if S1 is a subset of S2.  */
 
-static rtx
-simplify_test_exp (rtx exp, int insn_code, int insn_index)
+static bool
+attr_alt_subset_p (rtx s1, rtx s2)
 {
-  rtx left, right;
-  struct attr_desc *attr;
-  struct attr_value *av;
-  struct insn_ent *ie;
-  int i;
-  rtx newexp = exp;
-
-  /* Don't re-simplify something we already simplified.  */
-  if (ATTR_IND_SIMPLIFIED_P (exp) || ATTR_CURR_SIMPLIFIED_P (exp))
-    return exp;
-
-  switch (GET_CODE (exp))
+  switch ((XINT (s1, 1) << 1) | XINT (s2, 1))
     {
-    case AND:
-      left = SIMPLIFY_TEST_EXP (XEXP (exp, 0), insn_code, insn_index);
-      SIMPLIFY_ALTERNATIVE (left);
-      if (left == false_rtx)
-       return false_rtx;
-      right = SIMPLIFY_TEST_EXP (XEXP (exp, 1), insn_code, insn_index);
-      SIMPLIFY_ALTERNATIVE (right);
-      if (left == false_rtx)
-       return false_rtx;
-
-      /* If either side is an IOR and we have (eq_attr "alternative" ..")
-        present on both sides, apply the distributive law since this will
-        yield simplifications.  */
-      if ((GET_CODE (left) == IOR || GET_CODE (right) == IOR)
-         && compute_alternative_mask (left, IOR)
-         && compute_alternative_mask (right, IOR))
-       {
-         if (GET_CODE (left) == IOR)
-           {
-             rtx tem = left;
-             left = right;
-             right = tem;
-           }
-
-         newexp = attr_rtx (IOR,
-                            attr_rtx (AND, left, XEXP (right, 0)),
-                            attr_rtx (AND, left, XEXP (right, 1)));
-
-         return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
-       }
-
-      /* Try with the term on both sides.  */
-      right = simplify_and_tree (right, &left, insn_code, insn_index);
-      if (left == XEXP (exp, 0) && right == XEXP (exp, 1))
-       left = simplify_and_tree (left, &right, insn_code, insn_index);
-
-      if (left == false_rtx || right == false_rtx)
-       return false_rtx;
-      else if (left == true_rtx)
-       {
-         return right;
-       }
-      else if (right == true_rtx)
-       {
-         return left;
-       }
-      /* See if all or all but one of the insn's alternatives are specified
-        in this tree.  Optimize if so.  */
-
-      else if (insn_code >= 0
-              && (GET_CODE (left) == AND
-                  || (GET_CODE (left) == NOT
-                      && GET_CODE (XEXP (left, 0)) == EQ_ATTR
-                      && XSTR (XEXP (left, 0), 0) == alternative_name)
-                  || GET_CODE (right) == AND
-                  || (GET_CODE (right) == NOT
-                      && GET_CODE (XEXP (right, 0)) == EQ_ATTR
-                      && XSTR (XEXP (right, 0), 0) == alternative_name)))
-       {
-         i = compute_alternative_mask (exp, AND);
-         if (i & ~insn_alternatives[insn_code])
-           fatal ("invalid alternative specified for pattern number %d",
-                  insn_index);
-
-         /* If all alternatives are excluded, this is false.  */
-         i ^= insn_alternatives[insn_code];
-         if (i == 0)
-           return false_rtx;
-         else if ((i & (i - 1)) == 0 && insn_alternatives[insn_code] > 1)
-           {
-             /* If just one excluded, AND a comparison with that one to the
-                front of the tree.  The others will be eliminated by
-                optimization.  We do not want to do this if the insn has one
-                alternative and we have tested none of them!  */
-             left = make_alternative_compare (i);
-             right = simplify_and_tree (exp, &left, insn_code, insn_index);
-             newexp = attr_rtx (AND, left, right);
-
-             return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
-           }
-       }
-
-      if (left != XEXP (exp, 0) || right != XEXP (exp, 1))
-       {
-         newexp = attr_rtx (AND, left, right);
-         return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
-       }
-      break;
-
-    case IOR:
-      left = SIMPLIFY_TEST_EXP (XEXP (exp, 0), insn_code, insn_index);
-      SIMPLIFY_ALTERNATIVE (left);
-      if (left == true_rtx)
-       return true_rtx;
-      right = SIMPLIFY_TEST_EXP (XEXP (exp, 1), insn_code, insn_index);
-      SIMPLIFY_ALTERNATIVE (right);
-      if (right == true_rtx)
-       return true_rtx;
-
-      right = simplify_or_tree (right, &left, insn_code, insn_index);
-      if (left == XEXP (exp, 0) && right == XEXP (exp, 1))
-       left = simplify_or_tree (left, &right, insn_code, insn_index);
-
-      if (right == true_rtx || left == true_rtx)
-       return true_rtx;
-      else if (left == false_rtx)
-       {
-         return right;
-       }
-      else if (right == false_rtx)
-       {
-         return left;
-       }
-
-      /* Test for simple cases where the distributive law is useful.  I.e.,
-           convert (ior (and (x) (y))
-                        (and (x) (z)))
-           to      (and (x)
-                        (ior (y) (z)))
-       */
-
-      else if (GET_CODE (left) == AND && GET_CODE (right) == AND
-              && attr_equal_p (XEXP (left, 0), XEXP (right, 0)))
-       {
-         newexp = attr_rtx (IOR, XEXP (left, 1), XEXP (right, 1));
-
-         left = XEXP (left, 0);
-         right = newexp;
-         newexp = attr_rtx (AND, left, right);
-         return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
-       }
-
-      /* See if all or all but one of the insn's alternatives are specified
-        in this tree.  Optimize if so.  */
-
-      else if (insn_code >= 0
-              && (GET_CODE (left) == IOR
-                  || (GET_CODE (left) == EQ_ATTR
-                      && XSTR (left, 0) == alternative_name)
-                  || GET_CODE (right) == IOR
-                  || (GET_CODE (right) == EQ_ATTR
-                      && XSTR (right, 0) == alternative_name)))
-       {
-         i = compute_alternative_mask (exp, IOR);
-         if (i & ~insn_alternatives[insn_code])
-           fatal ("invalid alternative specified for pattern number %d",
-                  insn_index);
-
-         /* If all alternatives are included, this is true.  */
-         i ^= insn_alternatives[insn_code];
-         if (i == 0)
-           return true_rtx;
-         else if ((i & (i - 1)) == 0 && insn_alternatives[insn_code] > 1)
-           {
-             /* If just one excluded, IOR a comparison with that one to the
-                front of the tree.  The others will be eliminated by
-                optimization.  We do not want to do this if the insn has one
-                alternative and we have tested none of them!  */
-             left = make_alternative_compare (i);
-             right = simplify_and_tree (exp, &left, insn_code, insn_index);
-             newexp = attr_rtx (IOR, attr_rtx (NOT, left), right);
-
-             return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
-           }
-       }
-
-      if (left != XEXP (exp, 0) || right != XEXP (exp, 1))
-       {
-         newexp = attr_rtx (IOR, left, right);
-         return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
-       }
-      break;
-
-    case NOT:
-      if (GET_CODE (XEXP (exp, 0)) == NOT)
-       {
-         left = SIMPLIFY_TEST_EXP (XEXP (XEXP (exp, 0), 0),
-                                   insn_code, insn_index);
-         SIMPLIFY_ALTERNATIVE (left);
-         return left;
-       }
-
-      left = SIMPLIFY_TEST_EXP (XEXP (exp, 0), insn_code, insn_index);
-      SIMPLIFY_ALTERNATIVE (left);
-      if (GET_CODE (left) == NOT)
-       return XEXP (left, 0);
-
-      if (left == false_rtx)
-       return true_rtx;
-      else if (left == true_rtx)
-       return false_rtx;
-
-      /* Try to apply De`Morgan's laws.  */
-      else if (GET_CODE (left) == IOR)
-       {
-         newexp = attr_rtx (AND,
-                            attr_rtx (NOT, XEXP (left, 0)),
-                            attr_rtx (NOT, XEXP (left, 1)));
-
-         newexp = SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
-       }
-      else if (GET_CODE (left) == AND)
-       {
-         newexp = attr_rtx (IOR,
-                            attr_rtx (NOT, XEXP (left, 0)),
-                            attr_rtx (NOT, XEXP (left, 1)));
-
-         newexp = SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
-       }
-      else if (left != XEXP (exp, 0))
-       {
-         newexp = attr_rtx (NOT, left);
-       }
-      break;
-
-    case EQ_ATTR:
-      if (current_alternative_string && XSTR (exp, 0) == alternative_name)
-       return (XSTR (exp, 1) == current_alternative_string
-               ? true_rtx : false_rtx);
-
-      /* Look at the value for this insn code in the specified attribute.
-        We normally can replace this comparison with the condition that
-        would give this insn the values being tested for.  */
-      if (XSTR (exp, 0) != alternative_name
-         && (attr = find_attr (XSTR (exp, 0), 0)) != NULL)
-       for (av = attr->first_value; av; av = av->next)
-         for (ie = av->first_insn; ie; ie = ie->next)
-           if (ie->insn_code == insn_code)
-             {
-               rtx x;
-               x = evaluate_eq_attr (exp, av->value, insn_code, insn_index);
-               x = SIMPLIFY_TEST_EXP (x, insn_code, insn_index);
-               if (attr_rtx_cost(x) < 20)
-                 return x;
-             }
-      break;
-
-    default:
-      break;
-    }
-
-  /* We have already simplified this expression.  Simplifying it again
-     won't buy anything unless we weren't given a valid insn code
-     to process (i.e., we are canonicalizing something.).  */
-  if (insn_code != -2 /* Seems wrong: && current_alternative_string.  */
-      && ! ATTR_IND_SIMPLIFIED_P (newexp))
-    return copy_rtx_unchanging (newexp);
-
-  return newexp;
-}
-
-/* Optimize the attribute lists by seeing if we can determine conditional
-   values from the known values of other attributes.  This will save subroutine
-   calls during the compilation.  */
-
-static void
-optimize_attrs (void)
-{
-  struct attr_desc *attr;
-  struct attr_value *av;
-  struct insn_ent *ie;
-  rtx newexp;
-  int i;
-  struct attr_value_list
-  {
-    struct attr_value *av;
-    struct insn_ent *ie;
-    struct attr_desc *attr;
-    struct attr_value_list *next;
-  };
-  struct attr_value_list **insn_code_values;
-  struct attr_value_list *ivbuf;
-  struct attr_value_list *iv;
-
-  /* For each insn code, make a list of all the insn_ent's for it,
-     for all values for all attributes.  */
-
-  if (num_insn_ents == 0)
-    return;
-
-  /* Make 2 extra elements, for "code" values -2 and -1.  */
-  insn_code_values = xcalloc ((insn_code_number + 2),
-                             sizeof (struct attr_value_list *));
-
-  /* Offset the table address so we can index by -2 or -1.  */
-  insn_code_values += 2;
-
-  iv = ivbuf = xmalloc (num_insn_ents * sizeof (struct attr_value_list));
-
-  for (i = 0; i < MAX_ATTRS_INDEX; i++)
-    for (attr = attrs[i]; attr; attr = attr->next)
-      for (av = attr->first_value; av; av = av->next)
-       for (ie = av->first_insn; ie; ie = ie->next)
-         {
-           iv->attr = attr;
-           iv->av = av;
-           iv->ie = ie;
-           iv->next = insn_code_values[ie->insn_code];
-           insn_code_values[ie->insn_code] = iv;
-           iv++;
-         }
+    case (0 << 1) | 0:
+      return !(XINT (s1, 0) &~ XINT (s2, 0));
 
-  /* Sanity check on num_insn_ents.  */
-  if (iv != ivbuf + num_insn_ents)
-    abort ();
+    case (0 << 1) | 1:
+      return !(XINT (s1, 0) & XINT (s2, 0));
 
-  /* Process one insn code at a time.  */
-  for (i = -2; i < insn_code_number; i++)
+    case (1 << 1) | 0:
+      return false;
+
+    case (1 << 1) | 1:
+      return !(XINT (s2, 0) &~ XINT (s1, 0));
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Returns true if S1 is a subset of complement of S2.  */
+
+static bool
+attr_alt_subset_of_compl_p (rtx s1, rtx s2)
+{
+  switch ((XINT (s1, 1) << 1) | XINT (s2, 1))
     {
-      /* Clear the ATTR_CURR_SIMPLIFIED_P flag everywhere relevant.
-        We use it to mean "already simplified for this insn".  */
-      for (iv = insn_code_values[i]; iv; iv = iv->next)
-       clear_struct_flag (iv->av->value);
+    case (0 << 1) | 0:
+      return !(XINT (s1, 0) & XINT (s2, 0));
 
-      for (iv = insn_code_values[i]; iv; iv = iv->next)
-       {
-         struct obstack *old = rtl_obstack;
+    case (0 << 1) | 1:
+      return !(XINT (s1, 0) & ~XINT (s2, 0));
 
-         attr = iv->attr;
-         av = iv->av;
-         ie = iv->ie;
-         if (GET_CODE (av->value) != COND)
-           continue;
+    case (1 << 1) | 0:
+      return !(XINT (s2, 0) &~ XINT (s1, 0));
 
-         rtl_obstack = temp_obstack;
-         newexp = av->value;
-         while (GET_CODE (newexp) == COND)
-           {
-             rtx newexp2 = simplify_cond (newexp, ie->insn_code,
-                                          ie->insn_index);
-             if (newexp2 == newexp)
-               break;
-             newexp = newexp2;
-           }
+    case (1 << 1) | 1:
+      return false;
 
-         rtl_obstack = old;
-         if (newexp != av->value)
-           {
-             newexp = attr_copy_rtx (newexp);
-             remove_insn_ent (av, ie);
-             av = get_attr_value (newexp, attr, ie->insn_code);
-             iv->av = av;
-             insert_insn_ent (av, ie);
-           }
-       }
+    default:
+      gcc_unreachable ();
     }
-
-  free (ivbuf);
-  free (insn_code_values - 2);
 }
 
-/* If EXP is a suitable expression, reorganize it by constructing an
-   equivalent expression that is a COND with the tests being all combinations
-   of attribute values and the values being simple constants.  */
+/* Return EQ_ATTR_ALT expression representing intersection of S1 and S2.  */
 
 static rtx
-simplify_by_exploding (rtx exp)
+attr_alt_intersection (rtx s1, rtx s2)
 {
-  rtx list = 0, link, condexp, defval = NULL_RTX;
-  struct dimension *space;
-  rtx *condtest, *condval;
-  int i, j, total, ndim = 0;
-  int most_tests, num_marks, new_marks;
-  rtx ret;
+  rtx result = rtx_alloc (EQ_ATTR_ALT);
 
-  /* Locate all the EQ_ATTR expressions.  */
-  if (! find_and_mark_used_attributes (exp, &list, &ndim) || ndim == 0)
+  switch ((XINT (s1, 1) << 1) | XINT (s2, 1))
     {
-      unmark_used_attributes (list, 0, 0);
-      return exp;
+    case (0 << 1) | 0:
+      XINT (result, 0) = XINT (s1, 0) & XINT (s2, 0);
+      break;
+    case (0 << 1) | 1:
+      XINT (result, 0) = XINT (s1, 0) & ~XINT (s2, 0);
+      break;
+    case (1 << 1) | 0:
+      XINT (result, 0) = XINT (s2, 0) & ~XINT (s1, 0);
+      break;
+    case (1 << 1) | 1:
+      XINT (result, 0) = XINT (s1, 0) | XINT (s2, 0);
+      break;
+    default:
+      gcc_unreachable ();
     }
+  XINT (result, 1) = XINT (s1, 1) & XINT (s2, 1);
+
+  return result;
+}
 
-  /* Create an attribute space from the list of used attributes.  For each
-     dimension in the attribute space, record the attribute, list of values
-     used, and number of values used.  Add members to the list of values to
-     cover the domain of the attribute.  This makes the expanded COND form
-     order independent.  */
+/* Return EQ_ATTR_ALT expression representing union of S1 and S2.  */
 
-  space = xmalloc (ndim * sizeof (struct dimension));
+static rtx
+attr_alt_union (rtx s1, rtx s2)
+{
+  rtx result = rtx_alloc (EQ_ATTR_ALT);
 
-  total = 1;
-  for (ndim = 0; list; ndim++)
+  switch ((XINT (s1, 1) << 1) | XINT (s2, 1))
     {
-      /* Pull the first attribute value from the list and record that
-        attribute as another dimension in the attribute space.  */
-      const char *name = XSTR (XEXP (list, 0), 0);
-      rtx *prev;
+    case (0 << 1) | 0:
+      XINT (result, 0) = XINT (s1, 0) | XINT (s2, 0);
+      break;
+    case (0 << 1) | 1:
+      XINT (result, 0) = XINT (s2, 0) & ~XINT (s1, 0);
+      break;
+    case (1 << 1) | 0:
+      XINT (result, 0) = XINT (s1, 0) & ~XINT (s2, 0);
+      break;
+    case (1 << 1) | 1:
+      XINT (result, 0) = XINT (s1, 0) & XINT (s2, 0);
+      break;
+    default:
+      gcc_unreachable ();
+    }
 
-      if ((space[ndim].attr = find_attr (name, 0)) == 0
-         || space[ndim].attr->is_numeric)
-       {
-         unmark_used_attributes (list, space, ndim);
-         return exp;
-       }
+  XINT (result, 1) = XINT (s1, 1) | XINT (s2, 1);
+  return result;
+}
 
-      /* Add all remaining attribute values that refer to this attribute.  */
-      space[ndim].num_values = 0;
-      space[ndim].values = 0;
-      prev = &list;
-      for (link = list; link; link = *prev)
-       if (! strcmp (XSTR (XEXP (link, 0), 0), name))
-         {
-           space[ndim].num_values++;
-           *prev = XEXP (link, 1);
-           XEXP (link, 1) = space[ndim].values;
-           space[ndim].values = link;
-         }
-       else
-         prev = &XEXP (link, 1);
+/* Return EQ_ATTR_ALT expression representing complement of S.  */
 
-      /* Add sufficient members to the list of values to make the list
-        mutually exclusive and record the total size of the attribute
-        space.  */
-      total *= add_values_to_cover (&space[ndim]);
-    }
+static rtx
+attr_alt_complement (rtx s)
+{
+  rtx result = rtx_alloc (EQ_ATTR_ALT);
 
-  /* Sort the attribute space so that the attributes go from non-constant
-     to constant and from most values to least values.  */
-  for (i = 0; i < ndim; i++)
-    for (j = ndim - 1; j > i; j--)
-      if ((space[j-1].attr->is_const && !space[j].attr->is_const)
-         || space[j-1].num_values < space[j].num_values)
-       {
-         struct dimension tmp;
-         tmp = space[j];
-         space[j] = space[j - 1];
-         space[j - 1] = tmp;
-       }
+  XINT (result, 0) = XINT (s, 0);
+  XINT (result, 1) = 1 - XINT (s, 1);
 
-  /* Establish the initial current value.  */
-  for (i = 0; i < ndim; i++)
-    space[i].current_value = space[i].values;
+  return result;
+}
 
-  condtest = xmalloc (total * sizeof (rtx));
-  condval = xmalloc (total * sizeof (rtx));
+/* Tests whether a bit B belongs to the set represented by S.  */
 
-  /* Expand the tests and values by iterating over all values in the
-     attribute space.  */
-  for (i = 0;; i++)
-    {
-      condtest[i] = test_for_current_value (space, ndim);
-      condval[i] = simplify_with_current_value (exp, space, ndim);
-      if (! increment_current_value (space, ndim))
-       break;
-    }
-  if (i != total - 1)
-    abort ();
-
-  /* We are now finished with the original expression.  */
-  unmark_used_attributes (0, space, ndim);
-  free (space);
-
-  /* Find the most used constant value and make that the default.  */
-  most_tests = -1;
-  for (i = num_marks = 0; i < total; i++)
-    if (GET_CODE (condval[i]) == CONST_STRING
-       && ! ATTR_EQ_ATTR_P (condval[i]))
-      {
-       /* Mark the unmarked constant value and count how many are marked.  */
-       ATTR_EQ_ATTR_P (condval[i]) = 1;
-       for (j = new_marks = 0; j < total; j++)
-         if (GET_CODE (condval[j]) == CONST_STRING
-             && ATTR_EQ_ATTR_P (condval[j]))
-           new_marks++;
-       if (new_marks - num_marks > most_tests)
-         {
-           most_tests = new_marks - num_marks;
-           defval = condval[i];
-         }
-       num_marks = new_marks;
-      }
-  /* Clear all the marks.  */
-  for (i = 0; i < total; i++)
-    ATTR_EQ_ATTR_P (condval[i]) = 0;
+static bool
+attr_alt_bit_p (rtx s, int b)
+{
+  return XINT (s, 1) ^ ((XINT (s, 0) >> b) & 1);
+}
 
-  /* Give up if nothing is constant.  */
-  if (num_marks == 0)
-    ret = exp;
+/* Return EQ_ATTR_ALT expression representing set containing elements set
+   in E.  */
+
+static rtx
+mk_attr_alt (int e)
+{
+  rtx result = rtx_alloc (EQ_ATTR_ALT);
 
-  /* If all values are the default, use that.  */
-  else if (total == most_tests)
-    ret = defval;
+  XINT (result, 0) = e;
+  XINT (result, 1) = 0;
 
-  /* Make a COND with the most common constant value the default.  (A more
-     complex method where tests with the same value were combined didn't
-     seem to improve things.)  */
-  else
-    {
-      condexp = rtx_alloc (COND);
-      XVEC (condexp, 0) = rtvec_alloc ((total - most_tests) * 2);
-      XEXP (condexp, 1) = defval;
-      for (i = j = 0; i < total; i++)
-       if (condval[i] != defval)
-         {
-           XVECEXP (condexp, 0, 2 * j) = condtest[i];
-           XVECEXP (condexp, 0, 2 * j + 1) = condval[i];
-           j++;
-         }
-      ret = condexp;
-    }
-  free (condtest);
-  free (condval);
-  return ret;
+  return result;
 }
 
-/* Set the ATTR_EQ_ATTR_P flag for all EQ_ATTR expressions in EXP and
-   verify that EXP can be simplified to a constant term if all the EQ_ATTR
-   tests have known value.  */
+/* Given an expression, see if it can be simplified for a particular insn
+   code based on the values of other attributes being tested.  This can
+   eliminate nested get_attr_... calls.
 
-static int
-find_and_mark_used_attributes (rtx exp, rtx *terms, int *nterms)
+   Note that if an endless recursion is specified in the patterns, the
+   optimization will loop.  However, it will do so in precisely the cases where
+   an infinite recursion loop could occur during compilation.  It's better that
+   it occurs here!  */
+
+static rtx
+simplify_test_exp (rtx exp, int insn_code, int insn_index)
 {
+  rtx left, right;
+  struct attr_desc *attr;
+  struct attr_value *av;
+  struct insn_ent *ie;
   int i;
+  rtx newexp = exp;
+  bool left_alt, right_alt;
+
+  /* Don't re-simplify something we already simplified.  */
+  if (ATTR_IND_SIMPLIFIED_P (exp) || ATTR_CURR_SIMPLIFIED_P (exp))
+    return exp;
 
   switch (GET_CODE (exp))
     {
-    case EQ_ATTR:
-      if (! ATTR_EQ_ATTR_P (exp))
+    case AND:
+      left = SIMPLIFY_TEST_EXP (XEXP (exp, 0), insn_code, insn_index);
+      SIMPLIFY_ALTERNATIVE (left);
+      if (left == false_rtx)
+       return false_rtx;
+      right = SIMPLIFY_TEST_EXP (XEXP (exp, 1), insn_code, insn_index);
+      SIMPLIFY_ALTERNATIVE (right);
+      if (left == false_rtx)
+       return false_rtx;
+
+      if (GET_CODE (left) == EQ_ATTR_ALT
+         && GET_CODE (right) == EQ_ATTR_ALT)
        {
-         rtx link = rtx_alloc (EXPR_LIST);
-         XEXP (link, 0) = exp;
-         XEXP (link, 1) = *terms;
-         *terms = link;
-         *nterms += 1;
-         ATTR_EQ_ATTR_P (exp) = 1;
+         exp = attr_alt_intersection (left, right);
+         return simplify_test_exp (exp, insn_code, insn_index);
        }
-      return 1;
 
-    case CONST_STRING:
-    case CONST_INT:
-      return 1;
+      /* If either side is an IOR and we have (eq_attr "alternative" ..")
+        present on both sides, apply the distributive law since this will
+        yield simplifications.  */
+      if ((GET_CODE (left) == IOR || GET_CODE (right) == IOR)
+         && compute_alternative_mask (left, IOR)
+         && compute_alternative_mask (right, IOR))
+       {
+         if (GET_CODE (left) == IOR)
+           {
+             rtx tem = left;
+             left = right;
+             right = tem;
+           }
 
-    case IF_THEN_ELSE:
-      if (! find_and_mark_used_attributes (XEXP (exp, 2), terms, nterms))
-       return 0;
-    case IOR:
-    case AND:
-      if (! find_and_mark_used_attributes (XEXP (exp, 1), terms, nterms))
-       return 0;
-    case NOT:
-      if (! find_and_mark_used_attributes (XEXP (exp, 0), terms, nterms))
-       return 0;
-      return 1;
+         newexp = attr_rtx (IOR,
+                            attr_rtx (AND, left, XEXP (right, 0)),
+                            attr_rtx (AND, left, XEXP (right, 1)));
 
-    case COND:
-      for (i = 0; i < XVECLEN (exp, 0); i++)
-       if (! find_and_mark_used_attributes (XVECEXP (exp, 0, i), terms, nterms))
-         return 0;
-      if (! find_and_mark_used_attributes (XEXP (exp, 1), terms, nterms))
-       return 0;
-      return 1;
+         return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
+       }
 
-    default:
-      return 0;
-    }
-}
+      /* Try with the term on both sides.  */
+      right = simplify_and_tree (right, &left, insn_code, insn_index);
+      if (left == XEXP (exp, 0) && right == XEXP (exp, 1))
+       left = simplify_and_tree (left, &right, insn_code, insn_index);
+
+      if (left == false_rtx || right == false_rtx)
+       return false_rtx;
+      else if (left == true_rtx)
+       {
+         return right;
+       }
+      else if (right == true_rtx)
+       {
+         return left;
+       }
+      /* See if all or all but one of the insn's alternatives are specified
+        in this tree.  Optimize if so.  */
 
-/* Clear the ATTR_EQ_ATTR_P flag in all EQ_ATTR expressions on LIST and
-   in the values of the NDIM-dimensional attribute space SPACE.  */
+      if (GET_CODE (left) == NOT)
+       left_alt = (GET_CODE (XEXP (left, 0)) == EQ_ATTR
+                   && XSTR (XEXP (left, 0), 0) == alternative_name);
+      else
+       left_alt = (GET_CODE (left) == EQ_ATTR_ALT
+                   && XINT (left, 1));
 
-static void
-unmark_used_attributes (rtx list, struct dimension *space, int ndim)
-{
-  rtx link, exp;
-  int i;
+      if (GET_CODE (right) == NOT)
+       right_alt = (GET_CODE (XEXP (right, 0)) == EQ_ATTR
+                    && XSTR (XEXP (right, 0), 0) == alternative_name);
+      else
+       right_alt = (GET_CODE (right) == EQ_ATTR_ALT
+                    && XINT (right, 1));
+
+      if (insn_code >= 0
+         && (GET_CODE (left) == AND
+             || left_alt
+             || GET_CODE (right) == AND
+             || right_alt))
+       {
+         i = compute_alternative_mask (exp, AND);
+         if (i & ~insn_alternatives[insn_code])
+           fatal ("invalid alternative specified for pattern number %d",
+                  insn_index);
 
-  for (i = 0; i < ndim; i++)
-    unmark_used_attributes (space[i].values, 0, 0);
+         /* If all alternatives are excluded, this is false.  */
+         i ^= insn_alternatives[insn_code];
+         if (i == 0)
+           return false_rtx;
+         else if ((i & (i - 1)) == 0 && insn_alternatives[insn_code] > 1)
+           {
+             /* If just one excluded, AND a comparison with that one to the
+                front of the tree.  The others will be eliminated by
+                optimization.  We do not want to do this if the insn has one
+                alternative and we have tested none of them!  */
+             left = make_alternative_compare (i);
+             right = simplify_and_tree (exp, &left, insn_code, insn_index);
+             newexp = attr_rtx (AND, left, right);
 
-  for (link = list; link; link = XEXP (link, 1))
-    {
-      exp = XEXP (link, 0);
-      if (GET_CODE (exp) == EQ_ATTR)
-       ATTR_EQ_ATTR_P (exp) = 0;
-    }
-}
+             return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
+           }
+       }
 
-/* Update the attribute dimension DIM so that all values of the attribute
-   are tested.  Return the updated number of values.  */
+      if (left != XEXP (exp, 0) || right != XEXP (exp, 1))
+       {
+         newexp = attr_rtx (AND, left, right);
+         return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
+       }
+      break;
 
-static int
-add_values_to_cover (struct dimension *dim)
-{
-  struct attr_value *av;
-  rtx exp, link, *prev;
-  int nalt = 0;
-
-  for (av = dim->attr->first_value; av; av = av->next)
-    if (GET_CODE (av->value) == CONST_STRING)
-      nalt++;
-
-  if (nalt < dim->num_values)
-    abort ();
-  else if (nalt == dim->num_values)
-    /* OK.  */
-    ;
-  else if (nalt * 2 < dim->num_values * 3)
-    {
-      /* Most all the values of the attribute are used, so add all the unused
-        values.  */
-      prev = &dim->values;
-      for (link = dim->values; link; link = *prev)
-       prev = &XEXP (link, 1);
-
-      for (av = dim->attr->first_value; av; av = av->next)
-       if (GET_CODE (av->value) == CONST_STRING)
-         {
-           exp = attr_eq (dim->attr->name, XSTR (av->value, 0));
-           if (ATTR_EQ_ATTR_P (exp))
-             continue;
+    case IOR:
+      left = SIMPLIFY_TEST_EXP (XEXP (exp, 0), insn_code, insn_index);
+      SIMPLIFY_ALTERNATIVE (left);
+      if (left == true_rtx)
+       return true_rtx;
+      right = SIMPLIFY_TEST_EXP (XEXP (exp, 1), insn_code, insn_index);
+      SIMPLIFY_ALTERNATIVE (right);
+      if (right == true_rtx)
+       return true_rtx;
 
-           link = rtx_alloc (EXPR_LIST);
-           XEXP (link, 0) = exp;
-           XEXP (link, 1) = 0;
-           *prev = link;
-           prev = &XEXP (link, 1);
-         }
-      dim->num_values = nalt;
-    }
-  else
-    {
-      rtx orexp = false_rtx;
+      if (GET_CODE (left) == EQ_ATTR_ALT
+         && GET_CODE (right) == EQ_ATTR_ALT)
+       {
+         exp = attr_alt_union (left, right);
+         return simplify_test_exp (exp, insn_code, insn_index);
+       }
+
+      right = simplify_or_tree (right, &left, insn_code, insn_index);
+      if (left == XEXP (exp, 0) && right == XEXP (exp, 1))
+       left = simplify_or_tree (left, &right, insn_code, insn_index);
+
+      if (right == true_rtx || left == true_rtx)
+       return true_rtx;
+      else if (left == false_rtx)
+       {
+         return right;
+       }
+      else if (right == false_rtx)
+       {
+         return left;
+       }
+
+      /* Test for simple cases where the distributive law is useful.  I.e.,
+           convert (ior (and (x) (y))
+                        (and (x) (z)))
+           to      (and (x)
+                        (ior (y) (z)))
+       */
 
-      /* Very few values are used, so compute a mutually exclusive
-        expression.  (We could do this for numeric values if that becomes
-        important.)  */
-      prev = &dim->values;
-      for (link = dim->values; link; link = *prev)
+      else if (GET_CODE (left) == AND && GET_CODE (right) == AND
+              && attr_equal_p (XEXP (left, 0), XEXP (right, 0)))
        {
-         orexp = insert_right_side (IOR, orexp, XEXP (link, 0), -2, -2);
-         prev = &XEXP (link, 1);
-       }
-      link = rtx_alloc (EXPR_LIST);
-      XEXP (link, 0) = attr_rtx (NOT, orexp);
-      XEXP (link, 1) = 0;
-      *prev = link;
-      dim->num_values++;
-    }
-  return dim->num_values;
-}
+         newexp = attr_rtx (IOR, XEXP (left, 1), XEXP (right, 1));
 
-/* Increment the current value for the NDIM-dimensional attribute space SPACE
-   and return FALSE if the increment overflowed.  */
+         left = XEXP (left, 0);
+         right = newexp;
+         newexp = attr_rtx (AND, left, right);
+         return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
+       }
 
-static int
-increment_current_value (struct dimension *space, int ndim)
-{
-  int i;
+      /* See if all or all but one of the insn's alternatives are specified
+        in this tree.  Optimize if so.  */
 
-  for (i = ndim - 1; i >= 0; i--)
-    {
-      if ((space[i].current_value = XEXP (space[i].current_value, 1)) == 0)
-       space[i].current_value = space[i].values;
-      else
-       return 1;
-    }
-  return 0;
-}
+      else if (insn_code >= 0
+              && (GET_CODE (left) == IOR
+                  || (GET_CODE (left) == EQ_ATTR_ALT
+                      && !XINT (left, 1))
+                  || (GET_CODE (left) == EQ_ATTR
+                      && XSTR (left, 0) == alternative_name)
+                  || GET_CODE (right) == IOR
+                  || (GET_CODE (right) == EQ_ATTR_ALT
+                      && !XINT (right, 1))
+                  || (GET_CODE (right) == EQ_ATTR
+                      && XSTR (right, 0) == alternative_name)))
+       {
+         i = compute_alternative_mask (exp, IOR);
+         if (i & ~insn_alternatives[insn_code])
+           fatal ("invalid alternative specified for pattern number %d",
+                  insn_index);
 
-/* Construct an expression corresponding to the current value for the
-   NDIM-dimensional attribute space SPACE.  */
+         /* If all alternatives are included, this is true.  */
+         i ^= insn_alternatives[insn_code];
+         if (i == 0)
+           return true_rtx;
+         else if ((i & (i - 1)) == 0 && insn_alternatives[insn_code] > 1)
+           {
+             /* If just one excluded, IOR a comparison with that one to the
+                front of the tree.  The others will be eliminated by
+                optimization.  We do not want to do this if the insn has one
+                alternative and we have tested none of them!  */
+             left = make_alternative_compare (i);
+             right = simplify_and_tree (exp, &left, insn_code, insn_index);
+             newexp = attr_rtx (IOR, attr_rtx (NOT, left), right);
 
-static rtx
-test_for_current_value (struct dimension *space, int ndim)
-{
-  int i;
-  rtx exp = true_rtx;
+             return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
+           }
+       }
 
-  for (i = 0; i < ndim; i++)
-    exp = insert_right_side (AND, exp, XEXP (space[i].current_value, 0),
-                            -2, -2);
+      if (left != XEXP (exp, 0) || right != XEXP (exp, 1))
+       {
+         newexp = attr_rtx (IOR, left, right);
+         return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
+       }
+      break;
 
-  return exp;
-}
+    case NOT:
+      if (GET_CODE (XEXP (exp, 0)) == NOT)
+       {
+         left = SIMPLIFY_TEST_EXP (XEXP (XEXP (exp, 0), 0),
+                                   insn_code, insn_index);
+         SIMPLIFY_ALTERNATIVE (left);
+         return left;
+       }
 
-/* Given the current value of the NDIM-dimensional attribute space SPACE,
-   set the corresponding EQ_ATTR expressions to that value and reduce
-   the expression EXP as much as possible.  On input [and output], all
-   known EQ_ATTR expressions are set to FALSE.  */
+      left = SIMPLIFY_TEST_EXP (XEXP (exp, 0), insn_code, insn_index);
+      SIMPLIFY_ALTERNATIVE (left);
+      if (GET_CODE (left) == NOT)
+       return XEXP (left, 0);
 
-static rtx
-simplify_with_current_value (rtx exp, struct dimension *space, int ndim)
-{
-  int i;
-  rtx x;
+      if (left == false_rtx)
+       return true_rtx;
+      if (left == true_rtx)
+       return false_rtx;
 
-  /* Mark each current value as TRUE.  */
-  for (i = 0; i < ndim; i++)
-    {
-      x = XEXP (space[i].current_value, 0);
-      if (GET_CODE (x) == EQ_ATTR)
-       ATTR_EQ_ATTR_P (x) = 0;
-    }
+      if (GET_CODE (left) == EQ_ATTR_ALT)
+       {
+         exp = attr_alt_complement (left);
+         return simplify_test_exp (exp, insn_code, insn_index);
+       }
 
-  exp = simplify_with_current_value_aux (exp);
+      /* Try to apply De`Morgan's laws.  */
+      if (GET_CODE (left) == IOR)
+       {
+         newexp = attr_rtx (AND,
+                            attr_rtx (NOT, XEXP (left, 0)),
+                            attr_rtx (NOT, XEXP (left, 1)));
 
-  /* Change each current value back to FALSE.  */
-  for (i = 0; i < ndim; i++)
-    {
-      x = XEXP (space[i].current_value, 0);
-      if (GET_CODE (x) == EQ_ATTR)
-       ATTR_EQ_ATTR_P (x) = 1;
-    }
+         newexp = SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
+       }
+      else if (GET_CODE (left) == AND)
+       {
+         newexp = attr_rtx (IOR,
+                            attr_rtx (NOT, XEXP (left, 0)),
+                            attr_rtx (NOT, XEXP (left, 1)));
 
-  return exp;
-}
+         newexp = SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
+       }
+      else if (left != XEXP (exp, 0))
+       {
+         newexp = attr_rtx (NOT, left);
+       }
+      break;
 
-/* Reduce the expression EXP based on the ATTR_EQ_ATTR_P settings of
-   all EQ_ATTR expressions.  */
+    case EQ_ATTR_ALT:
+      if (current_alternative_string)
+       return attr_alt_bit_p (exp, atoi (current_alternative_string)) ? true_rtx : false_rtx;
 
-static rtx
-simplify_with_current_value_aux (rtx exp)
-{
-  int i;
-  rtx cond;
+      if (!XINT (exp, 0))
+       return XINT (exp, 1) ? true_rtx : false_rtx;
+      break;
 
-  switch (GET_CODE (exp))
-    {
     case EQ_ATTR:
-      if (ATTR_EQ_ATTR_P (exp))
-       return false_rtx;
-      else
-       return true_rtx;
-    case CONST_STRING:
-    case CONST_INT:
-      return exp;
-
-    case IF_THEN_ELSE:
-      cond = simplify_with_current_value_aux (XEXP (exp, 0));
-      if (cond == true_rtx)
-       return simplify_with_current_value_aux (XEXP (exp, 1));
-      else if (cond == false_rtx)
-       return simplify_with_current_value_aux (XEXP (exp, 2));
-      else
-       return attr_rtx (IF_THEN_ELSE, cond,
-                        simplify_with_current_value_aux (XEXP (exp, 1)),
-                        simplify_with_current_value_aux (XEXP (exp, 2)));
-
-    case IOR:
-      cond = simplify_with_current_value_aux (XEXP (exp, 1));
-      if (cond == true_rtx)
-       return cond;
-      else if (cond == false_rtx)
-       return simplify_with_current_value_aux (XEXP (exp, 0));
-      else
-       return attr_rtx (IOR, cond,
-                        simplify_with_current_value_aux (XEXP (exp, 0)));
-
-    case AND:
-      cond = simplify_with_current_value_aux (XEXP (exp, 1));
-      if (cond == true_rtx)
-       return simplify_with_current_value_aux (XEXP (exp, 0));
-      else if (cond == false_rtx)
-       return cond;
-      else
-       return attr_rtx (AND, cond,
-                        simplify_with_current_value_aux (XEXP (exp, 0)));
-
-    case NOT:
-      cond = simplify_with_current_value_aux (XEXP (exp, 0));
-      if (cond == true_rtx)
-       return false_rtx;
-      else if (cond == false_rtx)
-       return true_rtx;
-      else
-       return attr_rtx (NOT, cond);
+      if (current_alternative_string && XSTR (exp, 0) == alternative_name)
+       return (XSTR (exp, 1) == current_alternative_string
+               ? true_rtx : false_rtx);
 
-    case COND:
-      for (i = 0; i < XVECLEN (exp, 0); i += 2)
+      if (XSTR (exp, 0) == alternative_name)
        {
-         cond = simplify_with_current_value_aux (XVECEXP (exp, 0, i));
-         if (cond == true_rtx)
-           return simplify_with_current_value_aux (XVECEXP (exp, 0, i + 1));
-         else if (cond == false_rtx)
-           continue;
-         else
-           abort (); /* With all EQ_ATTR's of known value, a case should
-                        have been selected.  */
+         newexp = mk_attr_alt (1 << atoi (XSTR (exp, 1)));
+         break;
        }
-      return simplify_with_current_value_aux (XEXP (exp, 1));
+
+      /* Look at the value for this insn code in the specified attribute.
+        We normally can replace this comparison with the condition that
+        would give this insn the values being tested for.  */
+      if (XSTR (exp, 0) != alternative_name
+         && (attr = find_attr (&XSTR (exp, 0), 0)) != NULL)
+       for (av = attr->first_value; av; av = av->next)
+         for (ie = av->first_insn; ie; ie = ie->next)
+           if (ie->def->insn_code == insn_code)
+             {
+               rtx x;
+               x = evaluate_eq_attr (exp, av->value, insn_code, insn_index);
+               x = SIMPLIFY_TEST_EXP (x, insn_code, insn_index);
+               if (attr_rtx_cost(x) < 20)
+                 return x;
+             }
+      break;
 
     default:
-      abort ();
+      break;
     }
+
+  /* We have already simplified this expression.  Simplifying it again
+     won't buy anything unless we weren't given a valid insn code
+     to process (i.e., we are canonicalizing something.).  */
+  if (insn_code != -2 /* Seems wrong: && current_alternative_string.  */
+      && ! ATTR_IND_SIMPLIFIED_P (newexp))
+    return copy_rtx_unchanging (newexp);
+
+  return newexp;
 }
 
-/* Clear the ATTR_CURR_SIMPLIFIED_P flag in EXP and its subexpressions.  */
+/* Optimize the attribute lists by seeing if we can determine conditional
+   values from the known values of other attributes.  This will save subroutine
+   calls during the compilation.  */
 
 static void
-clear_struct_flag (rtx x)
+optimize_attrs (void)
 {
+  struct attr_desc *attr;
+  struct attr_value *av;
+  struct insn_ent *ie;
+  rtx newexp;
   int i;
-  int j;
-  enum rtx_code code;
-  const char *fmt;
+  struct attr_value_list
+  {
+    struct attr_value *av;
+    struct insn_ent *ie;
+    struct attr_desc *attr;
+    struct attr_value_list *next;
+  };
+  struct attr_value_list **insn_code_values;
+  struct attr_value_list *ivbuf;
+  struct attr_value_list *iv;
 
-  ATTR_CURR_SIMPLIFIED_P (x) = 0;
-  if (ATTR_IND_SIMPLIFIED_P (x))
+  /* For each insn code, make a list of all the insn_ent's for it,
+     for all values for all attributes.  */
+
+  if (num_insn_ents == 0)
     return;
 
-  code = GET_CODE (x);
+  /* Make 2 extra elements, for "code" values -2 and -1.  */
+  insn_code_values = xcalloc ((insn_code_number + 2),
+                             sizeof (struct attr_value_list *));
 
-  switch (code)
-    {
-    case REG:
-    case QUEUED:
-    case CONST_INT:
-    case CONST_DOUBLE:
-    case CONST_VECTOR:
-    case SYMBOL_REF:
-    case CODE_LABEL:
-    case PC:
-    case CC0:
-    case EQ_ATTR:
-    case ATTR_FLAG:
-      return;
+  /* Offset the table address so we can index by -2 or -1.  */
+  insn_code_values += 2;
 
-    default:
-      break;
-    }
+  iv = ivbuf = xmalloc (num_insn_ents * sizeof (struct attr_value_list));
 
-  /* Compare the elements.  If any pair of corresponding elements
-     fail to match, return 0 for the whole things.  */
+  for (i = 0; i < MAX_ATTRS_INDEX; i++)
+    for (attr = attrs[i]; attr; attr = attr->next)
+      for (av = attr->first_value; av; av = av->next)
+       for (ie = av->first_insn; ie; ie = ie->next)
+         {
+           iv->attr = attr;
+           iv->av = av;
+           iv->ie = ie;
+           iv->next = insn_code_values[ie->def->insn_code];
+           insn_code_values[ie->def->insn_code] = iv;
+           iv++;
+         }
 
-  fmt = GET_RTX_FORMAT (code);
-  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+  /* Sanity check on num_insn_ents.  */
+  gcc_assert (iv == ivbuf + num_insn_ents);
+
+  /* Process one insn code at a time.  */
+  for (i = -2; i < insn_code_number; i++)
     {
-      switch (fmt[i])
-       {
-       case 'V':
-       case 'E':
-         for (j = 0; j < XVECLEN (x, i); j++)
-           clear_struct_flag (XVECEXP (x, i, j));
-         break;
+      /* Clear the ATTR_CURR_SIMPLIFIED_P flag everywhere relevant.
+        We use it to mean "already simplified for this insn".  */
+      for (iv = insn_code_values[i]; iv; iv = iv->next)
+       clear_struct_flag (iv->av->value);
+
+      for (iv = insn_code_values[i]; iv; iv = iv->next)
+       {
+         struct obstack *old = rtl_obstack;
 
-       case 'e':
-         clear_struct_flag (XEXP (x, i));
-         break;
+         attr = iv->attr;
+         av = iv->av;
+         ie = iv->ie;
+         if (GET_CODE (av->value) != COND)
+           continue;
+
+         rtl_obstack = temp_obstack;
+         newexp = av->value;
+         while (GET_CODE (newexp) == COND)
+           {
+             rtx newexp2 = simplify_cond (newexp, ie->def->insn_code,
+                                          ie->def->insn_index);
+             if (newexp2 == newexp)
+               break;
+             newexp = newexp2;
+           }
+
+         rtl_obstack = old;
+         if (newexp != av->value)
+           {
+             newexp = attr_copy_rtx (newexp);
+             remove_insn_ent (av, ie);
+             av = get_attr_value (newexp, attr, ie->def->insn_code);
+             iv->av = av;
+             insert_insn_ent (av, ie);
+           }
        }
     }
+
+  free (ivbuf);
+  free (insn_code_values - 2);
 }
 
-/* Return the number of RTX objects making up the expression X.
-   But if we count more than MAX objects, stop counting.  */
+/* Clear the ATTR_CURR_SIMPLIFIED_P flag in EXP and its subexpressions.  */
 
-static int
-count_sub_rtxs (rtx x, int max)
+static void
+clear_struct_flag (rtx x)
 {
   int i;
   int j;
   enum rtx_code code;
   const char *fmt;
-  int total = 0;
+
+  ATTR_CURR_SIMPLIFIED_P (x) = 0;
+  if (ATTR_IND_SIMPLIFIED_P (x))
+    return;
 
   code = GET_CODE (x);
 
   switch (code)
     {
     case REG:
-    case QUEUED:
     case CONST_INT:
     case CONST_DOUBLE:
     case CONST_VECTOR:
@@ -3981,7 +2964,7 @@ count_sub_rtxs (rtx x, int max)
     case CC0:
     case EQ_ATTR:
     case ATTR_FLAG:
-      return 1;
+      return;
 
     default:
       break;
@@ -3993,24 +2976,19 @@ count_sub_rtxs (rtx x, int max)
   fmt = GET_RTX_FORMAT (code);
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
-      if (total >= max)
-       return total;
-
       switch (fmt[i])
        {
        case 'V':
        case 'E':
          for (j = 0; j < XVECLEN (x, i); j++)
-           total += count_sub_rtxs (XVECEXP (x, i, j), max);
+           clear_struct_flag (XVECEXP (x, i, j));
          break;
 
        case 'e':
-         total += count_sub_rtxs (XEXP (x, i), max);
+         clear_struct_flag (XEXP (x, i));
          break;
        }
     }
-  return total;
-
 }
 
 /* Create table entries for DEFINE_ATTR.  */
@@ -4025,7 +3003,7 @@ gen_attr (rtx exp, int lineno)
 
   /* Make a new attribute structure.  Check for duplicate by looking at
      attr->default_val, since it is initialized by this routine.  */
-  attr = find_attr (XSTR (exp, 0), 1);
+  attr = find_attr (&XSTR (exp, 0), 1);
   if (attr->default_val)
     {
       message_with_line (lineno, "duplicate definition for attribute %s",
@@ -4067,7 +3045,7 @@ gen_attr (rtx exp, int lineno)
       XEXP (exp, 2) = XEXP (XEXP (exp, 2), 0);
     }
 
-  if (! strcmp (attr->name, "length") && ! attr->is_numeric)
+  if (! strcmp_check (attr->name, length_str) && ! attr->is_numeric)
     {
       message_with_line (lineno,
                         "`length' attribute must take numeric values");
@@ -4222,7 +3200,7 @@ gen_insn (rtx exp, int lineno)
       break;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }
 
@@ -4259,95 +3237,6 @@ gen_delay (rtx def, int lineno)
   delays = delay;
 }
 
-/* Process a DEFINE_FUNCTION_UNIT.
-
-   This gives information about a function unit contained in the CPU.
-   We fill in a `struct function_unit_op' and a `struct function_unit'
-   with information used later by `expand_unit'.  */
-
-static void
-gen_unit (rtx def, int lineno)
-{
-  struct function_unit *unit;
-  struct function_unit_op *op;
-  const char *name = XSTR (def, 0);
-  int multiplicity = XINT (def, 1);
-  int simultaneity = XINT (def, 2);
-  rtx condexp = XEXP (def, 3);
-  int ready_cost = MAX (XINT (def, 4), 1);
-  int issue_delay = MAX (XINT (def, 5), 1);
-
-  /* See if we have already seen this function unit.  If so, check that
-     the multiplicity and simultaneity values are the same.  If not, make
-     a structure for this function unit.  */
-  for (unit = units; unit; unit = unit->next)
-    if (! strcmp (unit->name, name))
-      {
-       if (unit->multiplicity != multiplicity
-           || unit->simultaneity != simultaneity)
-         {
-           message_with_line (lineno,
-                              "differing specifications given for function unit %s",
-                              unit->name);
-           message_with_line (unit->first_lineno, "previous definition");
-           have_error = 1;
-           return;
-         }
-       break;
-      }
-
-  if (unit == 0)
-    {
-      unit = oballoc (sizeof (struct function_unit));
-      unit->name = name;
-      unit->multiplicity = multiplicity;
-      unit->simultaneity = simultaneity;
-      unit->issue_delay.min = unit->issue_delay.max = issue_delay;
-      unit->num = num_units++;
-      unit->num_opclasses = 0;
-      unit->condexp = false_rtx;
-      unit->ops = 0;
-      unit->next = units;
-      unit->first_lineno = lineno;
-      units = unit;
-    }
-
-  /* Make a new operation class structure entry and initialize it.  */
-  op = oballoc (sizeof (struct function_unit_op));
-  op->condexp = condexp;
-  op->num = unit->num_opclasses++;
-  op->ready = ready_cost;
-  op->issue_delay = issue_delay;
-  op->next = unit->ops;
-  op->lineno = lineno;
-  unit->ops = op;
-  num_unit_opclasses++;
-
-  /* Set our issue expression based on whether or not an optional conflict
-     vector was specified.  */
-  if (XVEC (def, 6))
-    {
-      /* Compute the IOR of all the specified expressions.  */
-      rtx orexp = false_rtx;
-      int i;
-
-      for (i = 0; i < XVECLEN (def, 6); i++)
-       orexp = insert_right_side (IOR, orexp, XVECEXP (def, 6, i), -2, -2);
-
-      op->conflict_exp = orexp;
-      extend_range (&unit->issue_delay, 1, issue_delay);
-    }
-  else
-    {
-      op->conflict_exp = true_rtx;
-      extend_range (&unit->issue_delay, issue_delay, issue_delay);
-    }
-
-  /* Merge our conditional into that of the function unit so we can determine
-     which insns are used by the function unit.  */
-  unit->condexp = insert_right_side (IOR, unit->condexp, op->condexp, -2, -2);
-}
-
 /* Given a piece of RTX, print a C expression to test its truth value.
    We use AND and IOR both for logical and bit-wise operations, so
    interpret them as logical unless they are inside a comparison expression.
@@ -4371,9 +3260,14 @@ write_test_expr (rtx exp, int flags)
   switch (code)
     {
     /* Binary operators.  */
+    case GEU: case GTU:
+    case LEU: case LTU:
+      printf ("(unsigned) ");
+      /* Fall through.  */
+
     case EQ: case NE:
-    case GE: case GT: case GEU: case GTU:
-    case LE: case LT: case LEU: case LTU:
+    case GE: case GT:
+    case LE: case LT:
       comparison_operator = 1;
 
     case PLUS:   case MINUS:  case MULT:     case DIV:      case MOD:
@@ -4450,7 +3344,7 @@ write_test_expr (rtx exp, int flags)
          printf (" >> ");
          break;
        default:
-         abort ();
+         gcc_unreachable ();
        }
 
       write_test_expr (XEXP (exp, 1), flags | comparison_operator);
@@ -4484,12 +3378,58 @@ write_test_expr (rtx exp, int flags)
          printf ("-");
          break;
        default:
-         abort ();
+         gcc_unreachable ();
        }
 
       write_test_expr (XEXP (exp, 0), flags);
       break;
 
+    case EQ_ATTR_ALT:
+       {
+         int set = XINT (exp, 0), bit = 0;
+
+         if (flags & 1)
+           fatal ("EQ_ATTR_ALT not valid inside comparison");
+
+         if (!set)
+           fatal ("Empty EQ_ATTR_ALT should be optimized out");
+
+         if (!(set & (set - 1)))
+           {
+             if (!(set & 0xffff))
+               {
+                 bit += 16;
+                 set >>= 16;
+               }
+             if (!(set & 0xff))
+               {
+                 bit += 8;
+                 set >>= 8;
+               }
+             if (!(set & 0xf))
+               {
+                 bit += 4;
+                 set >>= 4;
+               }
+             if (!(set & 0x3))
+               {
+                 bit += 2;
+                 set >>= 2;
+               }
+             if (!(set & 1))
+               bit++;
+
+             printf ("which_alternative %s= %d",
+                     XINT (exp, 1) ? "!" : "=", bit);
+           }
+         else
+           {
+             printf ("%s((1 << which_alternative) & 0x%x)",
+                     XINT (exp, 1) ? "!" : "", set);
+           }
+       }
+      break;
+
     /* Comparison test of an attribute with a value.  Most of these will
        have been removed by optimization.   Handle "alternative"
        specially and give error if EQ_ATTR present inside a comparison.  */
@@ -4503,9 +3443,8 @@ write_test_expr (rtx exp, int flags)
          break;
        }
 
-      attr = find_attr (XSTR (exp, 0), 0);
-      if (! attr)
-       abort ();
+      attr = find_attr (&XSTR (exp, 0), 0);
+      gcc_assert (attr);
 
       /* Now is the time to expand the value of a constant attribute.  */
       if (attr->is_const)
@@ -4549,10 +3488,6 @@ write_test_expr (rtx exp, int flags)
                XSTR (exp, 1), XINT (exp, 0), GET_MODE_NAME (GET_MODE (exp)));
       break;
 
-    case MATCH_INSN:
-      printf ("%s (insn)", XSTR (exp, 0));
-      break;
-
     /* Constant integer.  */
     case CONST_INT:
       printf (HOST_WIDE_INT_PRINT_DEC, XWINT (exp, 0));
@@ -4560,7 +3495,7 @@ write_test_expr (rtx exp, int flags)
 
     /* A random C expression.  */
     case SYMBOL_REF:
-      printf ("%s", XSTR (exp, 0));
+      print_c_condition (XSTR (exp, 0));
       break;
 
     /* The address of the branch target.  */
@@ -4710,10 +3645,14 @@ walk_attr_value (rtx exp)
       must_extract = 1;
       return;
 
+    case EQ_ATTR_ALT:
+      must_extract = must_constrain = 1;
+      break;
+
     case EQ_ATTR:
       if (XSTR (exp, 0) == alternative_name)
        must_extract = must_constrain = 1;
-      else if (strcmp (XSTR (exp, 0), "length") == 0)
+      else if (strcmp_check (XSTR (exp, 0), length_str) == 0)
        length_used = 1;
       return;
 
@@ -4766,8 +3705,6 @@ write_attr_get (struct attr_desc *attr)
     printf ("static ");
   if (!attr->is_numeric)
     printf ("enum attr_%s\n", attr->name);
-  else if (attr->unsigned_p)
-    printf ("unsigned int\n");
   else
     printf ("int\n");
 
@@ -4785,45 +3722,23 @@ write_attr_get (struct attr_desc *attr)
       for (av = attr->first_value; av; av = av->next)
        if (av->num_insns != 0)
          write_attr_set (attr, 2, av->value, "return", ";",
-                         true_rtx, av->first_insn->insn_code,
-                         av->first_insn->insn_index);
+                         true_rtx, av->first_insn->def->insn_code,
+                         av->first_insn->def->insn_index);
 
       printf ("}\n\n");
       return;
     }
 
   printf ("{\n");
+  printf ("  switch (recog_memoized (insn))\n");
+  printf ("    {\n");
 
-  if (GET_CODE (common_av->value) == FFS)
-    {
-      rtx p = XEXP (common_av->value, 0);
-
-      /* No need to emit code to abort if the insn is unrecognized; the
-         other get_attr_foo functions will do that when we call them.  */
-
-      write_toplevel_expr (p);
-
-      printf ("\n  if (accum && accum == (accum & -accum))\n");
-      printf ("    {\n");
-      printf ("      int i;\n");
-      printf ("      for (i = 0; accum >>= 1; ++i) continue;\n");
-      printf ("      accum = i;\n");
-      printf ("    }\n  else\n");
-      printf ("    accum = ~accum;\n");
-      printf ("  return accum;\n}\n\n");
-    }
-  else
-    {
-      printf ("  switch (recog_memoized (insn))\n");
-      printf ("    {\n");
-
-      for (av = attr->first_value; av; av = av->next)
-       if (av != common_av)
-         write_attr_case (attr, av, 1, "return", ";", 4, true_rtx);
+  for (av = attr->first_value; av; av = av->next)
+    if (av != common_av)
+      write_attr_case (attr, av, 1, "return", ";", 4, true_rtx);
 
-      write_attr_case (attr, common_av, 0, "return", ";", 4, true_rtx);
-      printf ("    }\n}\n\n");
-    }
+  write_attr_case (attr, common_av, 0, "return", ";", 4, true_rtx);
+  printf ("    }\n}\n\n");
 }
 
 /* Given an AND tree of known true terms (because we are inside an `if' with
@@ -4946,6 +3861,25 @@ write_attr_set (struct attr_desc *attr, int indent, rtx value,
     }
 }
 
+/* Write a series of case statements for every instruction in list IE.
+   INDENT is the amount of indentation to write before each case.  */
+
+static void
+write_insn_cases (struct insn_ent *ie, int indent)
+{
+  for (; ie != 0; ie = ie->next)
+    if (ie->def->insn_code != -1)
+      {
+       write_indent (indent);
+       if (GET_CODE (ie->def->def) == DEFINE_PEEPHOLE)
+         printf ("case %d:  /* define_peephole, line %d */\n",
+                 ie->def->insn_code, ie->def->lineno);
+       else
+         printf ("case %d:  /* %s */\n",
+                 ie->def->insn_code, XSTR (ie->def->def, 0));
+      }
+}
+
 /* Write out the computation for one attribute value.  */
 
 static void
@@ -4953,8 +3887,6 @@ write_attr_case (struct attr_desc *attr, struct attr_value *av,
                 int write_case_lines, const char *prefix, const char *suffix,
                 int indent, rtx known_true)
 {
-  struct insn_ent *ie;
-
   if (av->num_insns == 0)
     return;
 
@@ -4971,14 +3903,7 @@ write_attr_case (struct attr_desc *attr, struct attr_value *av,
     }
 
   if (write_case_lines)
-    {
-      for (ie = av->first_insn; ie; ie = ie->next)
-       if (ie->insn_code != -1)
-         {
-           write_indent (indent);
-           printf ("case %d:\n", ie->insn_code);
-         }
-    }
+    write_insn_cases (av->first_insn, indent);
   else
     {
       write_indent (indent);
@@ -5001,8 +3926,8 @@ write_attr_case (struct attr_desc *attr, struct attr_value *av,
     }
 
   write_attr_set (attr, indent + 2, av->value, prefix, suffix,
-                 known_true, av->first_insn->insn_code,
-                 av->first_insn->insn_index);
+                 known_true, av->first_insn->def->insn_code,
+                 av->first_insn->def->insn_index);
 
   if (strncmp (prefix, "return", 6))
     {
@@ -5027,8 +3952,6 @@ write_expr_attr_cache (rtx p, struct attr_desc *attr)
 
       if (!attr->is_numeric)
        printf ("  enum attr_%s ", attr->name);
-      else if (attr->unsigned_p)
-       printf ("  unsigned int ");
       else
        printf ("  int ");
 
@@ -5059,56 +3982,7 @@ write_expr_attr_cache (rtx p, struct attr_desc *attr)
   return 0;
 }
 
-/* Evaluate an expression at top level.  A front end to write_test_expr,
-   in which we cache attribute values and break up excessively large
-   expressions to cater to older compilers.  */
-
-static void
-write_toplevel_expr (rtx p)
-{
-  struct attr_desc *attr;
-  int i;
-
-  for (i = 0; i < MAX_ATTRS_INDEX; ++i)
-    for (attr = attrs[i]; attr; attr = attr->next)
-      if (!attr->is_const)
-       write_expr_attr_cache (p, attr);
-
-  printf ("  unsigned long accum = 0;\n\n");
-
-  while (GET_CODE (p) == IOR)
-    {
-      rtx e;
-      if (GET_CODE (XEXP (p, 0)) == IOR)
-       e = XEXP (p, 1), p = XEXP (p, 0);
-      else
-       e = XEXP (p, 0), p = XEXP (p, 1);
-
-      printf ("  accum |= ");
-      write_test_expr (e, 3);
-      printf (";\n");
-    }
-  printf ("  accum |= ");
-  write_test_expr (p, 3);
-  printf (";\n");
-}
-
-/* Utilities to write names in various forms.  */
-
-static void
-write_unit_name (const char *prefix, int num, const char *suffix)
-{
-  struct function_unit *unit;
-
-  for (unit = units; unit; unit = unit->next)
-    if (unit->num == num)
-      {
-       printf ("%s%s%s", prefix, unit->name, suffix);
-       return;
-      }
-
-  printf ("%s<unknown>%s", prefix, suffix);
-}
+/* Utilities to write in various forms.  */
 
 static void
 write_attr_valueq (struct attr_desc *attr, const char *s)
@@ -5119,32 +3993,7 @@ write_attr_valueq (struct attr_desc *attr, const char *s)
 
       printf ("%d", num);
 
-      /* Make the blockage range values and function units used values easier
-         to read.  */
-      if (attr->func_units_p)
-       {
-         if (num == -1)
-           printf (" /* units: none */");
-         else if (num >= 0)
-           write_unit_name (" /* units: ", num, " */");
-         else
-           {
-             int i;
-             const char *sep = " /* units: ";
-             for (i = 0, num = ~num; num; i++, num >>= 1)
-               if (num & 1)
-                 {
-                   write_unit_name (sep, i, (num == 1) ? " */" : "");
-                   sep = ", ";
-                 }
-           }
-       }
-
-      else if (attr->blockage_p)
-       printf (" /* min %d, max %d */", num >> (HOST_BITS_PER_INT / 2),
-               num & ((1 << (HOST_BITS_PER_INT / 2)) - 1));
-
-      else if (num > 9 || num < 0)
+      if (num > 9 || num < 0)
        printf (" /* 0x%x */", num);
     }
   else
@@ -5171,12 +4020,12 @@ write_attr_value (struct attr_desc *attr, rtx value)
       break;
 
     case SYMBOL_REF:
-      fputs (XSTR (value, 0), stdout);
+      print_c_condition (XSTR (value, 0));
       break;
 
     case ATTR:
       {
-       struct attr_desc *attr2 = find_attr (XSTR (value, 0), 0);
+       struct attr_desc *attr2 = find_attr (&XSTR (value, 0), 0);
        printf ("get_attr_%s (%s)", attr2->name,
                (attr2->is_const ? "" : "insn"));
       }
@@ -5207,7 +4056,7 @@ write_attr_value (struct attr_desc *attr, rtx value)
       break;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }
 
@@ -5250,6 +4099,7 @@ write_eligible_delay (const char *kind)
   struct delay_desc *delay;
   int max_slots;
   char str[50];
+  const char *pstr;
   struct attr_desc *attr;
   struct attr_value *av, *common_av;
   int i;
@@ -5270,17 +4120,20 @@ write_eligible_delay (const char *kind)
   printf ("{\n");
   printf ("  rtx insn;\n");
   printf ("\n");
-  printf ("  if (slot >= %d)\n", max_slots);
-  printf ("    abort ();\n");
+  printf ("  gcc_assert (slot < %d);\n", max_slots);
+  printf ("\n");
+  /* Allow dbr_schedule to pass labels, etc.  This can happen if try_split
+     converts a compound instruction into a loop.  */
+  printf ("  if (!INSN_P (candidate_insn))\n");
+  printf ("    return 0;\n");
   printf ("\n");
 
   /* If more than one delay type, find out which type the delay insn is.  */
 
   if (num_delays > 1)
     {
-      attr = find_attr ("*delay_type", 0);
-      if (! attr)
-       abort ();
+      attr = find_attr (&delay_type_str, 0);
+      gcc_assert (attr);
       common_av = find_most_used (attr);
 
       printf ("  insn = delay_insn;\n");
@@ -5296,8 +4149,7 @@ write_eligible_delay (const char *kind)
       printf ("    }\n\n");
 
       /* Ensure matched.  Otherwise, shouldn't have been called.  */
-      printf ("  if (slot < %d)\n", max_slots);
-      printf ("    abort ();\n\n");
+      printf ("  gcc_assert (slot >= %d);\n\n", max_slots);
     }
 
   /* If just one type of delay slot, write simple switch.  */
@@ -5307,9 +4159,8 @@ write_eligible_delay (const char *kind)
       printf ("  switch (recog_memoized (insn))\n");
       printf ("    {\n");
 
-      attr = find_attr ("*delay_1_0", 0);
-      if (! attr)
-       abort ();
+      attr = find_attr (&delay_1_0_str, 0);
+      gcc_assert (attr);
       common_av = find_most_used (attr);
 
       for (av = attr->first_value; av; av = av->next)
@@ -5337,9 +4188,9 @@ write_eligible_delay (const char *kind)
            printf ("\t{\n");
 
            sprintf (str, "*%s_%d_%d", kind, delay->num, i / 3);
-           attr = find_attr (str, 0);
-           if (! attr)
-             abort ();
+           pstr = str;
+           attr = find_attr (&pstr, 0);
+           gcc_assert (attr);
            common_av = find_most_used (attr);
 
            for (av = attr->first_value; av; av = av->next)
@@ -5351,179 +4202,13 @@ write_eligible_delay (const char *kind)
          }
 
       printf ("    default:\n");
-      printf ("      abort ();\n");
+      printf ("      gcc_unreachable ();\n");
       printf ("    }\n");
     }
 
   printf ("}\n\n");
 }
 
-/* Write routines to compute conflict cost for function units.  Then write a
-   table describing the available function units.  */
-
-static void
-write_function_unit_info (void)
-{
-  struct function_unit *unit;
-  int i;
-
-  /* Write out conflict routines for function units.  Don't bother writing
-     one if there is only one issue delay value.  */
-
-  for (unit = units; unit; unit = unit->next)
-    {
-      if (unit->needs_blockage_function)
-       write_complex_function (unit, "blockage", "block");
-
-      /* If the minimum and maximum conflict costs are the same, there
-        is only one value, so we don't need a function.  */
-      if (! unit->needs_conflict_function)
-       {
-         unit->default_cost = make_numeric_value (unit->issue_delay.max);
-         continue;
-       }
-
-      /* The function first computes the case from the candidate insn.  */
-      unit->default_cost = make_numeric_value (0);
-      write_complex_function (unit, "conflict_cost", "cost");
-    }
-
-  /* Now that all functions have been written, write the table describing
-     the function units.   The name is included for documentation purposes
-     only.  */
-
-  printf ("const struct function_unit_desc function_units[] = {\n");
-
-  /* Write out the descriptions in numeric order, but don't force that order
-     on the list.  Doing so increases the runtime of genattrtab.c.  */
-  for (i = 0; i < num_units; i++)
-    {
-      for (unit = units; unit; unit = unit->next)
-       if (unit->num == i)
-         break;
-
-      printf ("  {\"%s\", %d, %d, %d, %s, %d, %s_unit_ready_cost, ",
-             unit->name, 1 << unit->num, unit->multiplicity,
-             unit->simultaneity, XSTR (unit->default_cost, 0),
-             unit->issue_delay.max, unit->name);
-
-      if (unit->needs_conflict_function)
-       printf ("%s_unit_conflict_cost, ", unit->name);
-      else
-       printf ("0, ");
-
-      printf ("%d, ", unit->max_blockage);
-
-      if (unit->needs_range_function)
-       printf ("%s_unit_blockage_range, ", unit->name);
-      else
-       printf ("0, ");
-
-      if (unit->needs_blockage_function)
-       printf ("%s_unit_blockage", unit->name);
-      else
-       printf ("0");
-
-      printf ("}, \n");
-    }
-
-  if (num_units == 0)
-    printf ("{\"dummy\", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* a dummy element */");
-  printf ("};\n\n");
-}
-
-static void
-write_complex_function (struct function_unit *unit,
-                       const char *name,
-                       const char *connection)
-{
-  struct attr_desc *case_attr, *attr;
-  struct attr_value *av, *common_av;
-  rtx value;
-  char str[256];
-  int using_case;
-  int i;
-
-  printf ("static int\n");
-  printf ("%s_unit_%s (rtx executing_insn, rtx candidate_insn)\n",
-         unit->name, name);
-  printf ("{\n");
-  printf ("  rtx insn;\n");
-  printf ("  int casenum;\n\n");
-  printf ("  insn = executing_insn;\n");
-  printf ("  switch (recog_memoized (insn))\n");
-  printf ("    {\n");
-
-  /* Write the `switch' statement to get the case value.  */
-  if (strlen (unit->name) + sizeof "*_cases" > 256)
-    abort ();
-  sprintf (str, "*%s_cases", unit->name);
-  case_attr = find_attr (str, 0);
-  if (! case_attr)
-    abort ();
-  common_av = find_most_used (case_attr);
-
-  for (av = case_attr->first_value; av; av = av->next)
-    if (av != common_av)
-      write_attr_case (case_attr, av, 1,
-                      "casenum =", ";", 4, unit->condexp);
-
-  write_attr_case (case_attr, common_av, 0,
-                  "casenum =", ";", 4, unit->condexp);
-  printf ("    }\n\n");
-
-  /* Now write an outer switch statement on each case.  Then write
-     the tests on the executing function within each.  */
-  printf ("  insn = candidate_insn;\n");
-  printf ("  switch (casenum)\n");
-  printf ("    {\n");
-
-  for (i = 0; i < unit->num_opclasses; i++)
-    {
-      /* Ensure using this case.  */
-      using_case = 0;
-      for (av = case_attr->first_value; av; av = av->next)
-       if (av->num_insns
-           && contained_in_p (make_numeric_value (i), av->value))
-         using_case = 1;
-
-      if (! using_case)
-       continue;
-
-      printf ("    case %d:\n", i);
-      sprintf (str, "*%s_%s_%d", unit->name, connection, i);
-      attr = find_attr (str, 0);
-      if (! attr)
-       abort ();
-
-      /* If single value, just write it.  */
-      value = find_single_value (attr);
-      if (value)
-       write_attr_set (attr, 6, value, "return", ";\n", true_rtx, -2, -2);
-      else
-       {
-         common_av = find_most_used (attr);
-         printf ("      switch (recog_memoized (insn))\n");
-         printf ("\t{\n");
-
-         for (av = attr->first_value; av; av = av->next)
-           if (av != common_av)
-             write_attr_case (attr, av, 1,
-                              "return", ";", 8, unit->condexp);
-
-         write_attr_case (attr, common_av, 0,
-                          "return", ";", 8, unit->condexp);
-         printf ("      }\n\n");
-       }
-    }
-
-  /* This default case should not be needed, but gcc's analysis is not
-     good enough to realize that the default case is not needed for the
-     second switch statement.  */
-  printf ("    default:\n      abort ();\n");
-  printf ("    }\n}\n\n");
-}
-
 /* This page contains miscellaneous utility routines.  */
 
 /* Given a pointer to a (char *), return a malloc'ed string containing the
@@ -5544,13 +4229,15 @@ next_comma_elt (const char **pstr)
 }
 
 /* Return a `struct attr_desc' pointer for a given named attribute.  If CREATE
-   is nonzero, build a new attribute, if one does not exist.  */
+   is nonzero, build a new attribute, if one does not exist.  *NAME_P is
+   replaced by a pointer to a canonical copy of the string.  */
 
 static struct attr_desc *
-find_attr (const char *name, int create)
+find_attr (const char **name_p, int create)
 {
   struct attr_desc *attr;
   int index;
+  const char *name = *name_p;
 
   /* Before we resort to using `strcmp', see if the string address matches
      anywhere.  In most cases, it should have been canonicalized to do so.  */
@@ -5565,19 +4252,24 @@ find_attr (const char *name, int create)
   /* Otherwise, do it the slow way.  */
   for (attr = attrs[index]; attr; attr = attr->next)
     if (name[0] == attr->name[0] && ! strcmp (name, attr->name))
-      return attr;
+      {
+       *name_p = attr->name;
+       return attr;
+      }
 
   if (! create)
     return NULL;
 
   attr = oballoc (sizeof (struct attr_desc));
-  attr->name = attr_string (name, strlen (name));
+  attr->name = DEF_ATTR_STRING (name);
   attr->first_value = attr->default_val = NULL;
-  attr->is_numeric = attr->negative_ok = attr->is_const = attr->is_special = 0;
-  attr->unsigned_p = attr->func_units_p = attr->blockage_p = attr->static_p = 0;
+  attr->is_numeric = attr->is_const = attr->is_special = 0;
+  attr->static_p = 0;
   attr->next = attrs[index];
   attrs[index] = attr;
 
+  *name_p = attr->name;
+
   return attr;
 }
 
@@ -5588,17 +4280,12 @@ make_internal_attr (const char *name, rtx value, int special)
 {
   struct attr_desc *attr;
 
-  attr = find_attr (name, 1);
-  if (attr->default_val)
-    abort ();
+  attr = find_attr (&name, 1);
+  gcc_assert (!attr->default_val);
 
   attr->is_numeric = 1;
   attr->is_const = 0;
   attr->is_special = (special & ATTR_SPECIAL) != 0;
-  attr->negative_ok = (special & ATTR_NEGATIVE_OK) != 0;
-  attr->unsigned_p = (special & ATTR_UNSIGNED) != 0;
-  attr->func_units_p = (special & ATTR_FUNC_UNITS) != 0;
-  attr->blockage_p = (special & ATTR_BLOCKAGE) != 0;
   attr->static_p = (special & ATTR_STATIC) != 0;
   attr->default_val = get_attr_value (value, attr, -2);
 }
@@ -5622,28 +4309,6 @@ find_most_used (struct attr_desc *attr)
   return most_used;
 }
 
-/* If an attribute only has a single value used, return it.  Otherwise
-   return NULL.  */
-
-static rtx
-find_single_value (struct attr_desc *attr)
-{
-  struct attr_value *av;
-  rtx unique_value;
-
-  unique_value = NULL;
-  for (av = attr->first_value; av; av = av->next)
-    if (av->num_insns)
-      {
-       if (unique_value)
-         return NULL;
-       else
-         unique_value = av->value;
-      }
-
-  return unique_value;
-}
-
 /* Return (attr_value "n") */
 
 rtx
@@ -5653,8 +4318,7 @@ make_numeric_value (int n)
   rtx exp;
   char *p;
 
-  if (n < 0)
-    abort ();
+  gcc_assert (n >= 0);
 
   if (n < 20 && int_values[n])
     return int_values[n];
@@ -5668,15 +4332,6 @@ make_numeric_value (int n)
   return exp;
 }
 
-static void
-extend_range (struct range *range, int min, int max)
-{
-  if (range->min > min)
-    range->min = min;
-  if (range->max < max)
-    range->max = max;
-}
-
 static rtx
 copy_rtx_unchanging (rtx orig)
 {
@@ -5693,9 +4348,8 @@ copy_rtx_unchanging (rtx orig)
 static void
 write_const_num_delay_slots (void)
 {
-  struct attr_desc *attr = find_attr ("*num_delay_slots", 0);
+  struct attr_desc *attr = find_attr (&num_delay_slots_str, 0);
   struct attr_value *av;
-  struct insn_ent *ie;
 
   if (attr)
     {
@@ -5709,12 +4363,7 @@ write_const_num_delay_slots (void)
          length_used = 0;
          walk_attr_value (av->value);
          if (length_used)
-           {
-             for (ie = av->first_insn; ie; ie = ie->next)
-               if (ie->insn_code != -1)
-                 printf ("    case %d:\n", ie->insn_code);
-             printf ("      return 0;\n");
-           }
+           write_insn_cases (av->first_insn, 4);
        }
 
       printf ("    default:\n");
@@ -5734,9 +4383,6 @@ main (int argc, char **argv)
 
   progname = "genattrtab";
 
-  if (argc <= 1)
-    fatal ("no input file name");
-
   if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE)
     return (FATAL_EXIT_CODE);
 
@@ -5751,7 +4397,11 @@ main (int argc, char **argv)
   ATTR_IND_SIMPLIFIED_P (true_rtx) = ATTR_IND_SIMPLIFIED_P (false_rtx) = 1;
   ATTR_PERMANENT_P (true_rtx) = ATTR_PERMANENT_P (false_rtx) = 1;
 
-  alternative_name = attr_string ("alternative", strlen ("alternative"));
+  alternative_name = DEF_ATTR_STRING ("alternative");
+  length_str = DEF_ATTR_STRING ("length");
+  delay_type_str = DEF_ATTR_STRING ("*delay_type");
+  delay_1_0_str = DEF_ATTR_STRING ("*delay_1_0");
+  num_delay_slots_str = DEF_ATTR_STRING ("*num_delay_slots");
 
   printf ("/* Generated automatically by the program `genattrtab'\n\
 from the machine description file `md'.  */\n\n");
@@ -5783,10 +4433,6 @@ from the machine description file `md'.  */\n\n");
          gen_delay (desc, lineno);
          break;
 
-       case DEFINE_FUNCTION_UNIT:
-         gen_unit (desc, lineno);
-         break;
-
        case DEFINE_CPU_UNIT:
          gen_cpu_unit (desc);
          break;
@@ -5859,14 +4505,10 @@ from the machine description file `md'.  */\n\n");
   if (num_delays)
     expand_delays ();
 
-  if (num_units || num_dfa_decls)
-    {
-      /* Expand DEFINE_FUNCTION_UNIT information into new attributes.  */
-      expand_units ();
-      /* Build DFA, output some functions and expand DFA information
-        into new attributes.  */
-      expand_automata ();
-    }
+  /* Build DFA, output some functions and expand DFA information
+     to new attributes.  */
+  if (num_dfa_decls)
+    expand_automata ();
 
   printf ("#include \"config.h\"\n");
   printf ("#include \"system.h\"\n");
@@ -5922,8 +4564,7 @@ from the machine description file `md'.  */\n\n");
   optimize_attrs ();
 
   /* Now write out all the `gen_attr_...' routines.  Do these before the
-     special routines (specifically before write_function_unit_info), so
-     that they get defined before they are used.  */
+     special routines so that they get defined before they are used.  */
 
   for (i = 0; i < MAX_ATTRS_INDEX; i++)
     for (attr = attrs[i]; attr; attr = attr->next)
@@ -5934,7 +4575,7 @@ from the machine description file `md'.  */\n\n");
 
            insn_alts_p
              = (attr->name [0] == '*'
-                && strcmp (&attr->name [1], INSN_ALTS_FUNC_NAME) == 0);
+                && strcmp (&attr->name[1], INSN_ALTS_FUNC_NAME) == 0);
            if (insn_alts_p)
              printf ("\n#if AUTOMATON_ALTS\n");
            write_attr_get (attr);
@@ -5955,14 +4596,10 @@ from the machine description file `md'.  */\n\n");
        write_eligible_delay ("annul_false");
     }
 
-  if (num_units || num_dfa_decls)
-    {
-      /* Write out information about function units.  */
-      write_function_unit_info ();
-      /* Output code for pipeline hazards recognition based on DFA
-        (deterministic finite state automata.  */
-      write_automata ();
-    }
+  /* Output code for pipeline hazards recognition based on DFA
+     (deterministic finite-state automata).  */
+  if (num_dfa_decls)
+    write_automata ();
 
   /* Write out constant delay slot info.  */
   write_const_num_delay_slots ();