OSDN Git Service

* haifa-sched.c (BUF_LEN): Increase a lot.
[pf3gnuchains/gcc-fork.git] / gcc / genattrtab.c
index 68a6f86..0b15599 100644 (file)
@@ -1,6 +1,6 @@
 /* Generate code from machine description to compute values of attributes.
-   Copyright (C) 1991 Free Software Foundation, Inc.
-   Contributed by Richard Kenner (kenner@nyu.edu)
+   Copyright (C) 1991, 93-99, 2000 Free Software Foundation, Inc.
+   Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
 
 This file is part of GNU CC.
 
@@ -16,7 +16,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 /* This program handles insn attributes and the DEFINE_DELAY and
    DEFINE_FUNCTION_UNIT definitions.
@@ -33,7 +34,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
    If the attribute `alternative', or a random C expression is present,
    `constrain_operands' is called.  If either of these cases of a reference to
-   an operand is found, `insn_extract' is called.
+   an operand is found, `extract_insn' is called.
 
    The special attribute `length' is also recognized.  For this operand, 
    expressions involving the address of an operand or the current insn,
@@ -94,12 +95,19 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
       EQ_ATTR rtx is true if !volatil and false if volatil.  */
 
 
-#include "gvarargs.h"
-#include "config.h"
+#include "hconfig.h"
+#include "system.h"
 #include "rtl.h"
+#include "ggc.h"
+
+#ifdef HAVE_SYS_RESOURCE_H
+# include <sys/resource.h>
+#endif
+
+/* We must include obstack.h after <sys/time.h>, to avoid lossage with
+   /usr/include/sys/stdtypes.h on Sun OS 4.x.  */
 #include "obstack.h"
-#include "insn-config.h"       /* For REGISTER_CONSTRAINTS */
-#include <stdio.h>
+#include "errors.h"
 
 static struct obstack obstack, obstack1, obstack2;
 struct obstack *rtl_obstack = &obstack;
@@ -109,15 +117,6 @@ struct obstack *temp_obstack = &obstack2;
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
 
-/* Define this so we can link with print-rtl.o to get debug_rtx function.  */
-char **insn_name_ptr = 0;
-
-extern void free ();
-extern rtx read_rtx ();
-
-static void fatal ();
-void fancy_abort ();
-
 /* enough space to reserve for printing out ints */
 #define MAX_DIGITS (HOST_BITS_PER_INT * 3 / 10 + 3)
 
@@ -130,12 +129,12 @@ void fancy_abort ();
 
 struct insn_def
 {
-  int insn_code;               /* Instruction number. */
-  int insn_index;              /* Expression numer in file, for errors. */
-  struct insn_def *next;       /* Next insn in chain. */
-  rtx def;                     /* The DEFINE_... */
+  int insn_code;               /* Instruction number.  */
+  int insn_index;              /* Expression numer in file, for errors.  */
+  struct insn_def *next;       /* Next insn in chain.  */
+  rtx def;                     /* The DEFINE_...  */
   int num_alternatives;                /* Number of alternatives.  */
-  int vec_idx;                 /* Index of attribute vector in `def'. */
+  int vec_idx;                 /* Index of attribute vector in `def'.  */
 };
 
 /* Once everything has been read in, we store in each attribute value a list
@@ -166,15 +165,17 @@ struct attr_value
 
 struct attr_desc
 {
-  char *name;                  /* Name of attribute. */
-  struct attr_desc *next;      /* Next attribute. */
-  int is_numeric;              /* Values of this attribute are numeric. */
-  int negative_ok;             /* Allow negative numeric values.  */
-  int unsigned_p;              /* Make the output function unsigned int.  */
-  int is_const;                        /* Attribute value constant for each run.  */
-  int is_special;              /* Don't call `write_attr_set'. */
-  struct attr_value *first_value; /* First value of this attribute. */
-  struct attr_value *default_val; /* Default value for this attribute. */
+  char *name;                  /* Name of attribute.  */
+  struct attr_desc *next;      /* Next attribute.  */
+  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 */
+  struct attr_value *first_value; /* First value of this attribute.  */
+  struct attr_value *default_val; /* Default value for this attribute.  */
 };
 
 #define NULL_ATTR (struct attr_desc *) NULL
@@ -192,7 +193,7 @@ struct range
 struct delay_desc
 {
   rtx def;                     /* DEFINE_DELAY expression.  */
-  struct delay_desc *next;     /* Next DEFINE_DELAY. */
+  struct delay_desc *next;     /* Next DEFINE_DELAY.  */
   int num;                     /* Number of DEFINE_DELAY, starting at 1.  */
 };
 
@@ -220,12 +221,12 @@ struct function_unit
   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. */
+  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 a blockage range 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.  */
@@ -240,7 +241,50 @@ static struct insn_def *defs;
 static struct delay_desc *delays;
 static struct function_unit *units;
 
-/* Other variables. */
+/* 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 MEM_VOLATILE_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.  */
 
 static int insn_code_number;
 static int insn_index_number;
@@ -248,13 +292,15 @@ static int got_define_asm_attributes;
 static int must_extract;
 static int must_constrain;
 static int address_used;
+static int length_used;
 static int num_delays;
 static int have_annul_true, have_annul_false;
-static int num_units;
+static int num_units, num_unit_opclasses;
+static int num_insn_ents;
 
 /* Used as operand to `operate_exp':  */
 
-enum operator {PLUS_OP, MINUS_OP, POS_MINUS_OP, EQ_OP, OR_OP, MAX_OP, MIN_OP, RANGE_OP};
+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.  */
 
@@ -279,6 +325,16 @@ static rtx true_rtx, false_rtx;
 
 static char *alternative_name;
 
+/* Indicate that REG_DEAD notes are valid if dead_or_set_p is ever
+   called.  */
+
+int reload_completed = 0;
+
+/* Some machines test `optimize' in macros called from rtlanal.c, so we need
+   to define it here.  */
+
+int optimize = 0;
+
 /* Simplify an expression.  Only call the routine if there is something to
    simplify.  */
 #define SIMPLIFY_TEST_EXP(EXP,INSN_CODE,INSN_INDEX)    \
@@ -297,85 +353,107 @@ static char *alternative_name;
 /* These are referenced by rtlanal.c and hence need to be defined somewhere.
    They won't actually be used.  */
 
-rtx frame_pointer_rtx, stack_pointer_rtx, arg_pointer_rtx;
-
-static rtx attr_rtx ();
-static char *attr_printf ();
-static char *attr_string ();
-static rtx check_attr_test ();
-static rtx check_attr_value ();
-static rtx convert_set_attr_alternative ();
-static rtx convert_set_attr ();
-static void check_defs ();
-static rtx convert_const_symbol_ref ();
-static rtx make_canonical ();
-static struct attr_value *get_attr_value ();
-static rtx copy_rtx_unchanging ();
-static rtx copy_boolean ();
-static void expand_delays ();
-static rtx operate_exp ();
-static void expand_units ();
-static rtx simplify_knowing ();
-static rtx encode_units_mask ();
-static void fill_attr ();
-static rtx substitute_address ();
-static void make_length_attrs ();
-static rtx identity_fn ();
-static rtx zero_fn ();
-static rtx one_fn ();
-static rtx max_fn ();
-static rtx simplify_cond ();
-static rtx simplify_by_alternatives ();
-static rtx simplify_by_exploding ();
-static int find_and_mark_used_attributes ();
-static void unmark_used_attributes ();
-static int add_values_to_cover ();
-static int increment_current_value ();
-static rtx test_for_current_value ();
-static rtx simplify_with_current_value ();
-static rtx simplify_with_current_value_aux ();
-static void remove_insn_ent ();
-static void insert_insn_ent ();
-static rtx insert_right_side ();
-static rtx make_alternative_compare ();
-static int compute_alternative_mask ();
-static rtx evaluate_eq_attr ();
-static rtx simplify_and_tree ();
-static rtx simplify_or_tree ();
-static rtx simplify_test_exp ();
-static void optimize_attrs ();
-static void gen_attr ();
-static int count_alternatives ();
-static int compares_alternatives_p ();
-static int contained_in_p ();
-static void gen_insn ();
-static void gen_delay ();
-static void gen_unit ();
-static void write_test_expr ();
-static int max_attr_value ();
-static void walk_attr_value ();
-static void write_attr_get ();
-static rtx eliminate_known_true ();
-static void write_attr_set ();
-static void write_attr_case ();
-static void write_attr_value ();
-static void write_attr_valueq ();
-static void write_upcase ();
-static void write_indent ();
-static void write_eligible_delay ();
-static void write_function_unit_info ();
-static void write_complex_function ();
-static int n_comma_elts ();
-static char *next_comma_elt ();
-static struct attr_desc *find_attr ();
-static void make_internal_attr ();
-static struct attr_value *find_most_used ();
-static rtx find_single_value ();
-static rtx make_numeric_value ();
-static void extend_range ();
-char *xrealloc ();
-char *xmalloc ();
-static void fatal ();
+rtx global_rtl[GR_MAX];
+rtx pic_offset_table_rtx;
+
+static void attr_hash_add_rtx  PARAMS ((int, rtx));
+static void attr_hash_add_string PARAMS ((int, char *));
+static rtx attr_rtx            PARAMS ((enum rtx_code, ...));
+static char *attr_printf       PARAMS ((int, const char *, ...))
+  ATTRIBUTE_PRINTF_2;
+static char *attr_string        PARAMS ((const char *, int));
+static rtx check_attr_test     PARAMS ((rtx, int));
+static rtx check_attr_value    PARAMS ((rtx, struct attr_desc *));
+static rtx convert_set_attr_alternative PARAMS ((rtx, int, int));
+static rtx convert_set_attr    PARAMS ((rtx, int, int));
+static void check_defs         PARAMS ((void));
+#if 0
+static rtx convert_const_symbol_ref PARAMS ((rtx, struct attr_desc *));
+#endif
+static rtx make_canonical      PARAMS ((struct attr_desc *, rtx));
+static struct attr_value *get_attr_value PARAMS ((rtx, struct attr_desc *, int));
+static rtx copy_rtx_unchanging PARAMS ((rtx));
+static rtx copy_boolean                PARAMS ((rtx));
+static void expand_delays      PARAMS ((void));
+static rtx operate_exp         PARAMS ((enum operator, rtx, rtx));
+static void expand_units       PARAMS ((void));
+static rtx simplify_knowing    PARAMS ((rtx, rtx));
+static rtx encode_units_mask   PARAMS ((rtx));
+static void fill_attr          PARAMS ((struct attr_desc *));
+/* dpx2 compiler chokes if we specify the arg types of the args.  */
+static rtx substitute_address  PARAMS ((rtx, rtx (*) (rtx), rtx (*) (rtx)));
+static void make_length_attrs  PARAMS ((void));
+static rtx identity_fn         PARAMS ((rtx));
+static rtx zero_fn             PARAMS ((rtx));
+static rtx one_fn              PARAMS ((rtx));
+static rtx max_fn              PARAMS ((rtx));
+static void write_length_unit_log PARAMS ((void));
+static rtx simplify_cond       PARAMS ((rtx, int, int));
+#if 0
+static rtx simplify_by_alternatives PARAMS ((rtx, int, int));
+#endif
+static rtx simplify_by_exploding PARAMS ((rtx));
+static int find_and_mark_used_attributes PARAMS ((rtx, rtx *, int *));
+static void unmark_used_attributes PARAMS ((rtx, struct dimension *, int));
+static int add_values_to_cover PARAMS ((struct dimension *));
+static int increment_current_value PARAMS ((struct dimension *, int));
+static rtx test_for_current_value PARAMS ((struct dimension *, int));
+static rtx simplify_with_current_value PARAMS ((rtx, struct dimension *, int));
+static rtx simplify_with_current_value_aux PARAMS ((rtx));
+static void clear_struct_flag PARAMS ((rtx));
+static int count_sub_rtxs    PARAMS ((rtx, int));
+static void remove_insn_ent  PARAMS ((struct attr_value *, struct insn_ent *));
+static void insert_insn_ent  PARAMS ((struct attr_value *, struct insn_ent *));
+static rtx insert_right_side   PARAMS ((enum rtx_code, rtx, rtx, int, int));
+static rtx make_alternative_compare PARAMS ((int));
+static int compute_alternative_mask PARAMS ((rtx, enum rtx_code));
+static rtx evaluate_eq_attr    PARAMS ((rtx, rtx, int, int));
+static rtx simplify_and_tree   PARAMS ((rtx, rtx *, int, int));
+static rtx simplify_or_tree    PARAMS ((rtx, rtx *, int, int));
+static rtx simplify_test_exp   PARAMS ((rtx, int, int));
+static void optimize_attrs     PARAMS ((void));
+static void gen_attr           PARAMS ((rtx));
+static int count_alternatives  PARAMS ((rtx));
+static int compares_alternatives_p PARAMS ((rtx));
+static int contained_in_p      PARAMS ((rtx, rtx));
+static void gen_insn           PARAMS ((rtx));
+static void gen_delay          PARAMS ((rtx));
+static void gen_unit           PARAMS ((rtx));
+static void write_test_expr    PARAMS ((rtx, int));
+static int max_attr_value      PARAMS ((rtx, int*));
+static int or_attr_value       PARAMS ((rtx, int*));
+static void walk_attr_value    PARAMS ((rtx));
+static void write_attr_get     PARAMS ((struct attr_desc *));
+static rtx eliminate_known_true PARAMS ((rtx, rtx, int, int));
+static void write_attr_set     PARAMS ((struct attr_desc *, int, rtx,
+                                      const char *, const char *, rtx,
+                                      int, int));
+static void write_attr_case    PARAMS ((struct attr_desc *, struct attr_value *,
+                                      int, const char *, const char *, int, rtx));
+static void write_unit_name    PARAMS ((const char *, int, const char *));
+static void write_attr_valueq  PARAMS ((struct attr_desc *, char *));
+static void write_attr_value   PARAMS ((struct attr_desc *, rtx));
+static void write_upcase       PARAMS ((const char *));
+static void write_indent       PARAMS ((int));
+static void write_eligible_delay PARAMS ((const char *));
+static void write_function_unit_info PARAMS ((void));
+static void write_complex_function PARAMS ((struct function_unit *, const char *,
+                                         const char *));
+static int write_expr_attr_cache PARAMS ((rtx, struct attr_desc *));
+static void write_toplevel_expr        PARAMS ((rtx));
+static void write_const_num_delay_slots PARAMS ((void));
+static int n_comma_elts                PARAMS ((char *));
+static char *next_comma_elt    PARAMS ((char **));
+static struct attr_desc *find_attr PARAMS ((const char *, int));
+static void make_internal_attr PARAMS ((const char *, rtx, int));
+static struct attr_value *find_most_used  PARAMS ((struct attr_desc *));
+static rtx find_single_value   PARAMS ((struct attr_desc *));
+static rtx make_numeric_value  PARAMS ((int));
+static void extend_range       PARAMS ((struct range *, int, int));
+static rtx attr_eq             PARAMS ((char *, char *));
+static char *attr_numeral      PARAMS ((int));
+static int attr_equal_p                PARAMS ((rtx, rtx));
+static rtx attr_copy_rtx       PARAMS ((rtx));
 
 #define oballoc(size) obstack_alloc (hash_obstack, size)
 
@@ -409,7 +487,7 @@ struct attr_hash *attr_hash_table[RTL_HASH_SIZE];
 
 /* Here is how primitive or already-shared RTL's hash
    codes are made.  */
-#define RTL_HASH(RTL) ((HOST_WIDE_INT) (RTL) & 0777777)
+#define RTL_HASH(RTL) ((long) (RTL) & 0777777)
 
 /* Add an entry to the hash table for RTL with hash code HASHCODE.  */
 
@@ -457,20 +535,24 @@ attr_hash_add_string (hashcode, str)
 
 /*VARARGS1*/
 static rtx
-attr_rtx (va_alist)
-     va_dcl
+attr_rtx VPARAMS ((enum rtx_code code, ...))
 {
-  va_list p;
+#ifndef ANSI_PROTOTYPES
   enum rtx_code code;
+#endif
+  va_list p;
   register int i;              /* Array indices...                     */
-  register char *fmt;          /* Current rtx's format...              */
-  register rtx rt_val;         /* RTX to return to caller...           */
+  register const char *fmt;    /* Current rtx's format...              */
+  register rtx rt_val = NULL_RTX;/* RTX to return to caller...         */
   int hashcode;
   register struct attr_hash *h;
   struct obstack *old_obstack = rtl_obstack;
 
-  va_start (p);
+  VA_START (p, code);
+
+#ifndef ANSI_PROTOTYPES
   code = va_arg (p, enum rtx_code);
+#endif
 
   /* For each of several cases, search the hash table for an existing entry.
      Use that entry if one is found; otherwise create a new RTL and add it
@@ -585,9 +667,15 @@ attr_rtx (va_alist)
     {
       HOST_WIDE_INT arg0 = va_arg (p, HOST_WIDE_INT);
       if (arg0 == 0)
-       return false_rtx;
+       {
+         va_end (p);
+         return false_rtx;
+       }
       if (arg0 == 1)
-       return true_rtx;
+       {
+         va_end (p);
+         return true_rtx;
+       }
       goto nohash;
     }
   else
@@ -648,48 +736,33 @@ attr_rtx (va_alist)
 
    rtx attr_printf (len, format, [arg1, ..., argn])  */
 
-#ifdef HAVE_VPRINTF
-
 /*VARARGS2*/
 static char *
-attr_printf (va_alist)
-     va_dcl
+attr_printf VPARAMS ((register int len, const char *fmt, ...))
 {
-  va_list p;
+#ifndef ANSI_PROTOTYPES
   register int len;
-  register char *fmt;
+  const char *fmt;
+#endif
+  va_list p;
   register char *str;
 
-  /* Print the string into a temporary location.  */
-  va_start (p);
-  len = va_arg (p, int);
-  str = (char *) alloca (len);
-  fmt = va_arg (p, char *);
-  vsprintf (str, fmt, p);
-  va_end (p);
-
-  return attr_string (str, strlen (str));
-}
+  VA_START (p, fmt);
 
-#else /* not HAVE_VPRINTF */
-
-static char *
-attr_printf (len, fmt, arg1, arg2, arg3)
-     int len;
-     char *fmt;
-     char *arg1, *arg2, *arg3; /* also int */
-{
-  register char *str;
+#ifndef ANSI_PROTOTYPES
+  len = va_arg (p, int);
+  fmt = va_arg (p, const char *);
+#endif
 
   /* Print the string into a temporary location.  */
   str = (char *) alloca (len);
-  sprintf (str, fmt, arg1, arg2, arg3);
+  vsprintf (str, fmt, p);
+  va_end (p);
 
   return attr_string (str, strlen (str));
 }
-#endif /* not HAVE_VPRINTF */
 
-rtx
+static rtx
 attr_eq (name, value)
      char *name, *value;
 {
@@ -697,7 +770,7 @@ attr_eq (name, value)
                   attr_string (value, strlen (value)));
 }
 
-char *
+static char *
 attr_numeral (n)
      int n;
 {
@@ -709,7 +782,7 @@ attr_numeral (n)
 
 static char *
 attr_string (str, len)
-     char *str;
+     const char *str;
      int len;
 {
   register struct attr_hash *h;
@@ -743,7 +816,7 @@ attr_string (str, len)
    taking advantage of the fact that if both are hashed
    then they can't be equal unless they are the same object.  */
 
-int
+static int
 attr_equal_p (x, y)
      rtx x, y;
 {
@@ -755,14 +828,14 @@ attr_equal_p (x, y)
    descending to all depths, but not copying any
    permanent hashed subexpressions.  */
 
-rtx
+static rtx
 attr_copy_rtx (orig)
      register rtx orig;
 {
   register rtx copy;
   register int i, j;
   register RTX_CODE code;
-  register char *format_ptr;
+  register const char *format_ptr;
 
   /* No need to copy a permanent object.  */
   if (RTX_INTEGRATED_P (orig))
@@ -781,6 +854,9 @@ attr_copy_rtx (orig)
     case PC:
     case CC0:
       return orig;
+
+    default:
+      break;
     }
 
   copy = rtx_alloc (code);
@@ -881,12 +957,12 @@ check_attr_test (exp, is_const)
                  return exp;
                }
              else
-               fatal ("Unknown attribute `%s' in EQ_ATTR", XEXP (exp, 0));
+               fatal ("Unknown attribute `%s' in EQ_ATTR", XSTR (exp, 0));
            }
 
          if (is_const && ! attr->is_const)
            fatal ("Constant expression uses insn attribute `%s' in EQ_ATTR",
-                  XEXP (exp, 0));
+                  XSTR (exp, 0));
 
          /* Copy this just to make it permanent,
             so expressions using it can be permanent too.  */
@@ -903,7 +979,7 @@ check_attr_test (exp, is_const)
              for (p = XSTR (exp, 1); *p; p++)
                if (*p < '0' || *p > '9')
                   fatal ("Attribute `%s' takes only numeric values", 
-                         XEXP (exp, 0));
+                         XSTR (exp, 0));
            }
          else
            {
@@ -914,7 +990,7 @@ check_attr_test (exp, is_const)
 
              if (av == NULL)
                fatal ("Unknown value `%s' for `%s' attribute",
-                      XEXP (exp, 1), XEXP (exp, 0));
+                      XSTR (exp, 1), XSTR (exp, 0));
            }
        }
       else
@@ -925,13 +1001,16 @@ check_attr_test (exp, is_const)
          while ((p = next_comma_elt (&name_ptr)) != NULL)
            {
              newexp = attr_eq (XSTR (exp, 0), p);
-             orexp = insert_right_side (IOR, orexp, newexp, -2);
+             orexp = insert_right_side (IOR, orexp, newexp, -2, -2);
            }
 
          return check_attr_test (orexp, is_const);
        }
       break;
 
+    case ATTR_FLAG:
+      break;
+
     case CONST_INT:
       /* Either TRUE or FALSE.  */
       if (XWINT (exp, 0))
@@ -949,14 +1028,15 @@ check_attr_test (exp, is_const)
       XEXP (exp, 0) = check_attr_test (XEXP (exp, 0), is_const);
       break;
 
+    case MATCH_INSN:
     case MATCH_OPERAND:
       if (is_const)
        fatal ("RTL operator \"%s\" not valid in constant attribute test",
-              GET_RTX_NAME (MATCH_OPERAND));
+              GET_RTX_NAME (GET_CODE (exp)));
       /* These cases can't be simplified.  */
       RTX_UNCHANGING_P (exp) = 1;
       break;
-
     case LE:  case LT:  case GT:  case GE:
     case LEU: case LTU: case GTU: case GEU:
     case NE:  case EQ:
@@ -1008,7 +1088,7 @@ check_attr_value (exp, attr)
        fatal ("CONST_INT not valid for non-numeric `%s' attribute",
               attr->name);
 
-      if (INTVAL (exp) < 0)
+      if (INTVAL (exp) < 0 && ! attr->negative_ok)
        fatal ("Negative numeric value specified for `%s' attribute",
               attr->name);
 
@@ -1048,6 +1128,26 @@ check_attr_value (exp, attr)
       XEXP (exp, 2) = check_attr_value (XEXP (exp, 2), attr);
       break;
 
+    case PLUS:
+    case MINUS:
+    case MULT:
+    case DIV:
+    case MOD:
+      if (attr && !attr->is_numeric)
+       fatal ("Invalid operation `%s' for non-numeric attribute value",
+              GET_RTX_NAME (GET_CODE (exp)));
+      /* FALLTHRU */
+
+    case IOR:
+    case AND:
+      XEXP (exp, 0) = check_attr_value (XEXP (exp, 0), attr);
+      XEXP (exp, 1) = check_attr_value (XEXP (exp, 1), attr);
+      break;
+
+    case FFS:
+      XEXP (exp, 0) = check_attr_value (XEXP (exp, 0), attr);
+      break;
+
     case COND:
       if (XVECLEN (exp, 0) % 2 != 0)
        fatal ("First operand of COND must have even length");
@@ -1063,15 +1163,30 @@ check_attr_value (exp, attr)
       XEXP (exp, 1) = check_attr_value (XEXP (exp, 1), attr);
       break;
 
+    case ATTR:
+      {
+       struct attr_desc *attr2 = find_attr (XSTR (exp, 0), 0);
+       if (attr2 == NULL)
+         fatal ("Unknown attribute `%s' in ATTR", XSTR (exp, 0));
+       else if ((attr && attr->is_const) && ! attr2->is_const)
+         fatal ("Non-constant attribute `%s' referenced from `%s'",
+                XSTR (exp, 0), attr->name);
+       else if (attr 
+                && (attr->is_numeric != attr2->is_numeric
+                    || (! attr->negative_ok && attr2->negative_ok)))
+         fatal ("Numeric attribute mismatch calling `%s' from `%s'",
+                XSTR (exp, 0), attr->name);
+      }
+      break;
+
     case SYMBOL_REF:
-      if (attr && attr->is_const)
-       /* A constant SYMBOL_REF is valid as a constant attribute test and
-          is expanded later by make_canonical into a COND.  */
-       return attr_rtx (SYMBOL_REF, XSTR (exp, 0));
-      /* Otherwise, fall through... */
+      /* A constant SYMBOL_REF is valid as a constant attribute test and
+         is expanded later by make_canonical into a COND.  In a non-constant
+         attribute test, it is left be.  */
+      return attr_rtx (SYMBOL_REF, XSTR (exp, 0));
 
     default:
-      fatal ("Illegal operation `%s' for attribute value",
+      fatal ("Invalid operation `%s' for attribute value",
             GET_RTX_NAME (GET_CODE (exp)));
     }
 
@@ -1082,10 +1197,10 @@ check_attr_value (exp, attr)
    It becomes a COND with each test being (eq_attr "alternative "n") */
 
 static rtx
-convert_set_attr_alternative (exp, num_alt, insn_code, insn_index)
+convert_set_attr_alternative (exp, num_alt, insn_index)
      rtx exp;
      int num_alt;
-     int insn_code, insn_index;
+     int insn_index;
 {
   rtx condexp;
   int i;
@@ -1123,10 +1238,10 @@ convert_set_attr_alternative (exp, num_alt, insn_code, insn_index)
    list of values is given, convert to SET_ATTR_ALTERNATIVE first.  */
 
 static rtx
-convert_set_attr (exp, num_alt, insn_code, insn_index)
+convert_set_attr (exp, num_alt, insn_index)
      rtx exp;
      int num_alt;
-     int insn_code, insn_index;
+     int insn_index;
 {
   rtx newexp;
   char *name_ptr;
@@ -1150,12 +1265,12 @@ convert_set_attr (exp, num_alt, insn_code, insn_index)
   while ((p = next_comma_elt (&name_ptr)) != NULL)
     XVECEXP (newexp, 1, n++) = attr_rtx (CONST_STRING, p);
 
-  return convert_set_attr_alternative (newexp, num_alt, insn_code, insn_index);
+  return convert_set_attr_alternative (newexp, num_alt, insn_index);
 }
 \f
 /* Scan all definitions, checking for validity.  Also, convert any SET_ATTR
    and SET_ATTR_ALTERNATIVE expressions to the corresponding SET
-   expressions. */
+   expressions.  */
 
 static void
 check_defs ()
@@ -1183,13 +1298,12 @@ check_defs ()
            case SET_ATTR_ALTERNATIVE:
              value = convert_set_attr_alternative (value,
                                                    id->num_alternatives,
-                                                   id->insn_code,
                                                    id->insn_index);
              break;
 
            case SET_ATTR:
              value = convert_set_attr (value, id->num_alternatives,
-                                       id->insn_code, id->insn_index);
+                                       id->insn_index);
              break;
 
            default:
@@ -1207,6 +1321,7 @@ check_defs ()
     }
 }
 \f
+#if 0
 /* Given a constant SYMBOL_REF expression, convert to a COND that
    explicitly tests each enumerated value.  */
 
@@ -1244,8 +1359,7 @@ convert_const_symbol_ref (exp, attr)
       strcat (p, "_");
       strcat (p, XSTR (av->value, 0));
       for (; *p != '\0'; p++)
-       if (*p >= 'a' && *p <= 'z')
-         *p -= 'a' - 'A';
+       *p = TOUPPER (*p);
 
       value = attr_rtx (SYMBOL_REF, string);
       RTX_UNCHANGING_P (value) = 1;
@@ -1257,6 +1371,7 @@ convert_const_symbol_ref (exp, attr)
 
   return condexp;
 }
+#endif
 \f
 /* Given a valid expression for an attribute value, remove any IF_THEN_ELSE
    expressions by converting them into a COND.  This removes cases from this
@@ -1294,13 +1409,21 @@ make_canonical (attr, exp)
         This makes the COND something that won't be considered an arbitrary
         expression by walk_attr_value.  */
       RTX_UNCHANGING_P (exp) = 1;
+#if 0
+      /* ??? Why do we do this?  With attribute values { A B C D E }, this
+         tends to generate (!(x==A) && !(x==B) && !(x==C) && !(x==D)) rather
+        than (x==E). */
       exp = convert_const_symbol_ref (exp, attr);
       RTX_UNCHANGING_P (exp) = 1;
       exp = check_attr_value (exp, attr);
       /* Goto COND case since this is now a COND.  Note that while the
-         new expression is rescanned, all symbol_ref notes are mared as
+         new expression is rescanned, all symbol_ref notes are marked as
         unchanging.  */
       goto cond;
+#else
+      exp = check_attr_value (exp, attr);
+      break;
+#endif
 
     case IF_THEN_ELSE:
       newexp = rtx_alloc (COND);
@@ -1314,12 +1437,11 @@ make_canonical (attr, exp)
       /* Fall through to COND case since this is now a COND.  */
 
     case COND:
-    cond:
       {
        int allsame = 1;
        rtx defval;
 
-       /* First, check for degenerate COND. */
+       /* First, check for degenerate COND.  */
        if (XVECLEN (exp, 0) == 0)
          return make_canonical (attr, XEXP (exp, 1));
        defval = XEXP (exp, 1) = make_canonical (attr, XEXP (exp, 1));
@@ -1334,8 +1456,11 @@ make_canonical (attr, exp)
          }
        if (allsame)
          return defval;
-       break;
       }
+      break;
+
+    default:
+      break;
     }
 
   return exp;
@@ -1535,6 +1660,7 @@ operate_exp (op, left, right)
              break;
 
            case OR_OP:
+           case ORX_OP:
              i = left_value | right_value;
              break;
 
@@ -1564,6 +1690,10 @@ operate_exp (op, left, right)
              abort ();
            }
 
+         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)
@@ -1598,7 +1728,8 @@ operate_exp (op, left, right)
             give the same value), optimize it away.  */
          if (allsame)
            {
-             obstack_free (rtl_obstack, newexp);
+             if (!ggc_p)
+               obstack_free (rtl_obstack, newexp);
              return operate_exp (op, left, XEXP (right, 1));
            }
 
@@ -1606,7 +1737,8 @@ operate_exp (op, left, right)
             just use that.  */
          if (rtx_equal_p (newexp, right))
            {
-             obstack_free (rtl_obstack, newexp);
+             if (!ggc_p)
+               obstack_free (rtl_obstack, newexp);
              return right;
            }
 
@@ -1616,6 +1748,13 @@ operate_exp (op, left, right)
        fatal ("Badly formed attribute value");
     }
 
+  /* 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)
+    {
+      return attr_rtx (IOR, left, right);
+    }
+
   /* Otherwise, do recursion the other way.  */
   else if (GET_CODE (left) == IF_THEN_ELSE)
     {
@@ -1648,7 +1787,8 @@ operate_exp (op, left, right)
         optimize it away.  */
       if (allsame)
        {
-         obstack_free (rtl_obstack, newexp);
+         if (!ggc_p)
+           obstack_free (rtl_obstack, newexp);
          return operate_exp (op, XEXP (left, 1), right);
        }
 
@@ -1656,7 +1796,8 @@ operate_exp (op, left, right)
         just use that.  */
       if (rtx_equal_p (newexp, left))
        {
-         obstack_free (rtl_obstack, newexp);
+         if (!ggc_p)
+           obstack_free (rtl_obstack, newexp);
          return left;
        }
 
@@ -1709,7 +1850,7 @@ expand_units ()
   rtx unitsmask;
   rtx readycost;
   rtx newexp;
-  char *str;
+  const char *str;
   int i, j, u, num, nvalues;
 
   /* Rebuild the condition for the unit to share the RTL expressions.
@@ -1720,8 +1861,6 @@ expand_units ()
 
   for (unit = units; unit; unit = unit->next)
     {
-      rtx min_issue = make_numeric_value (unit->issue_delay.min);
-
       unit->condexp = check_attr_test (unit->condexp, 0);
 
       for (op = unit->ops; op; op = op->next)
@@ -1760,19 +1899,49 @@ expand_units ()
   newexp = rtx_alloc (IF_THEN_ELSE);
   XEXP (newexp, 2) = make_numeric_value (0);
 
-  /* Merge each function unit into the unit mask attributes.  */
-  for (unit = units; unit; unit = unit->next)
+  /* 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
+
+  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
     {
-      XEXP (newexp, 0) = unit->condexp;
-      XEXP (newexp, 1) = make_numeric_value (1 << unit->num);
-      unitsmask = operate_exp (OR_OP, unitsmask, newexp);
+      /* 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));
+        }
     }
 
   /* Simplify the unit mask expression, encode it, and make an attribute
      for the function_units_used function.  */
   unitsmask = simplify_by_exploding (unitsmask);
-  unitsmask = encode_units_mask (unitsmask);
-  make_internal_attr ("*function_units_used", unitsmask, 2);
+
+  if (num_unit_opclasses < NUM_UNITOP_CUTOFF)
+    unitsmask = encode_units_mask (unitsmask);
+  else
+    {
+      /* 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);
+    }
+
+  make_internal_attr ("*function_units_used", unitsmask, 10);
 
   /* 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.  */
@@ -1803,7 +1972,7 @@ expand_units ()
            * sizeof (struct function_unit_op *));
 
   for (unit = units, i = 0; unit; i += unit->num_opclasses, unit = unit->next)
-    bcopy (unit_ops[unit->num], &op_array[i],
+    bcopy ((char *) unit_ops[unit->num], (char *) &op_array[i],
           unit->num_opclasses * sizeof (struct function_unit_op *));
 
   /* Compute the ready cost function for each unit by computing the
@@ -1854,7 +2023,7 @@ expand_units ()
              if (op->ready <= 1)
                break;
              else if (op->ready == value)
-               orexp = insert_right_side (IOR, orexp, op->condexp, -2);
+               orexp = insert_right_side (IOR, orexp, op->condexp, -2, -2);
              else
                {
                  XVECEXP (readycost, 0, nvalues * 2) = orexp;
@@ -1884,6 +2053,10 @@ expand_units ()
             candidate insn, so in the expressions below, C is a known
             term and E is an unknown term.
 
+            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.
+
             The issue delay function for C is op->issue_exp and is used to
             write the `<name>_unit_conflict_cost' function.  Symbolicly
             this is "ISSUE-DELAY (E,C)".
@@ -1917,18 +2090,7 @@ expand_units ()
 
          for (op = unit->ops; op; op = op->next)
            {
-             rtx blockage = readycost;
-             int delay = op->ready - 1;
-
-             if (unit->simultaneity != 0)
-               delay = MIN (delay, ((unit->simultaneity - 1)
-                                    * unit->issue_delay.min));
-
-             if (delay > 0)
-               blockage = operate_exp (POS_MINUS_OP, blockage,
-                                       make_numeric_value (delay));
-
-             blockage = operate_exp (MAX_OP, blockage, op->issue_exp);
+             rtx blockage = op->issue_exp;
              blockage = simplify_knowing (blockage, unit->condexp);
 
              /* Add this op's contribution to MAX (BLOCKAGE (E,*)) and
@@ -1954,7 +2116,10 @@ expand_units ()
            }
 
          /* Record MAX (BLOCKAGE (*,*)).  */
-         unit->max_blockage = max_attr_value (max_blockage);
+         {
+           int unknown;
+           unit->max_blockage = max_attr_value (max_blockage, &unknown);
+         }
 
          /* See if the upper and lower bounds of BLOCKAGE (E,*) are the
             same.  If so, the blockage function carries no additional
@@ -1974,13 +2139,13 @@ expand_units ()
          if (unit->needs_range_function)
            {
              /* Compute the blockage range function and make an attribute
-                for writing it's value.  */
+                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, 4);
+             make_internal_attr (str, newexp, 20);
            }
 
          str = attr_printf (strlen (unit->name) + sizeof ("*_unit_ready_cost"),
@@ -2039,9 +2204,14 @@ simplify_knowing (exp, known_true)
 {
   if (GET_CODE (exp) != CONST_STRING)
     {
-      exp = attr_rtx (IF_THEN_ELSE, known_true, exp,
-                     make_numeric_value (max_attr_value (exp)));
-      exp = simplify_by_exploding (exp);
+      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);
+       }
     }
   return exp;
 }
@@ -2058,7 +2228,7 @@ encode_units_mask (x)
   register int i;
   register int j;
   register enum rtx_code code;
-  register char *fmt;
+  register const char *fmt;
 
   code = GET_CODE (x);
 
@@ -2086,6 +2256,9 @@ encode_units_mask (x)
     case CC0:
     case EQ_ATTR:
       return x;
+      
+    default:
+      break;
     }
 
   /* Compare the elements.  If any pair of corresponding elements
@@ -2162,8 +2335,8 @@ fill_attr (attr)
 static rtx
 substitute_address (exp, no_address_fn, address_fn)
      rtx exp;
-     rtx (*no_address_fn) ();
-     rtx (*address_fn) ();
+     rtx (*no_address_fn) PARAMS ((rtx));
+     rtx (*address_fn) PARAMS ((rtx));
 {
   int i;
   rtx newexp;
@@ -2236,12 +2409,12 @@ substitute_address (exp, no_address_fn, address_fn)
 static void
 make_length_attrs ()
 {
-  static char *new_names[] = {"*insn_default_length",
-                             "*insn_variable_length_p",
-                             "*insn_current_length"};
-  static rtx (*no_address_fn[]) () = {identity_fn, zero_fn, zero_fn};
-  static rtx (*address_fn[]) () = {max_fn, one_fn, identity_fn};
-  int i;
+  static const char *new_names[] = {"*insn_default_length",
+                                     "*insn_variable_length_p",
+                                     "*insn_current_length"};
+  static rtx (*no_address_fn[]) PARAMS ((rtx)) = {identity_fn, zero_fn, zero_fn};
+  static rtx (*address_fn[]) PARAMS ((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;
@@ -2292,14 +2465,14 @@ identity_fn (exp)
 
 static rtx
 zero_fn (exp)
-     rtx exp;
+     rtx exp ATTRIBUTE_UNUSED;
 {
   return make_numeric_value (0);
 }
 
 static rtx
 one_fn (exp)
-     rtx exp;
+     rtx exp ATTRIBUTE_UNUSED;
 {
   return make_numeric_value (1);
 }
@@ -2308,7 +2481,35 @@ static rtx
 max_fn (exp)
      rtx exp;
 {
-  return make_numeric_value (max_attr_value (exp));
+  int unknown;
+  return make_numeric_value (max_attr_value (exp, &unknown));
+}
+
+static void
+write_length_unit_log ()
+{
+  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);
+
+  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);
 }
 \f
 /* Take a COND expression and see if any of the conditions in it can be
@@ -2329,7 +2530,6 @@ simplify_cond (exp, insn_code, insn_index)
      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 = (rtx *) alloca (len * sizeof (rtx));
   int allsame = 1;
@@ -2338,7 +2538,7 @@ simplify_cond (exp, insn_code, insn_index)
   /* This lets us free all storage allocated below, if appropriate.  */
   first_spacer = (char *) obstack_finish (rtl_obstack);
 
-  bcopy (&XVECEXP (exp, 0, 0), tests, len * sizeof (rtx));
+  bcopy ((char *) XVEC (exp, 0)->elem, (char *) tests, len * sizeof (rtx));
 
   /* See if default value needs simplification.  */
   if (GET_CODE (defval) == COND)
@@ -2415,14 +2615,16 @@ simplify_cond (exp, insn_code, insn_index)
 
   if (len == 0)
     {
-      obstack_free (rtl_obstack, first_spacer);
+      if (!ggc_p)
+       obstack_free (rtl_obstack, first_spacer);
       if (GET_CODE (defval) == COND)
        return simplify_cond (defval, insn_code, insn_index);
       return defval;
     }
   else if (allsame)
     {
-      obstack_free (rtl_obstack, first_spacer);
+      if (!ggc_p)
+       obstack_free (rtl_obstack, first_spacer);
       return exp;
     }
   else
@@ -2430,7 +2632,8 @@ simplify_cond (exp, insn_code, insn_index)
       rtx newexp = rtx_alloc (COND);
 
       XVEC (newexp, 0) = rtvec_alloc (len);
-      bcopy (tests, &XVECEXP (newexp, 0, 0), len * sizeof (rtx));
+      bcopy ((char *) tests, (char *) XVEC (newexp, 0)->elem,
+            len * sizeof (rtx));
       XEXP (newexp, 1) = new_defval;
       return newexp;
     }
@@ -2457,6 +2660,8 @@ remove_insn_ent (av, ie)
   av->num_insns--;
   if (ie->insn_code == -1)
     av->has_asm_insn = 0;
+
+  num_insn_ents--;
 }
 
 /* Insert an insn entry in an attribute value list.  */
@@ -2471,6 +2676,8 @@ insert_insn_ent (av, ie)
   av->num_insns++;
   if (ie->insn_code == -1)
     av->has_asm_insn = 1;
+
+  num_insn_ents++;
 }
 \f
 /* This is a utility routine to take an expression that is a tree of either
@@ -2484,7 +2691,7 @@ insert_insn_ent (av, ie)
 
 static rtx
 insert_right_side (code, exp, term, insn_code, insn_index)
-     RTX_CODE code;
+     enum rtx_code code;
      rtx exp;
      rtx term;
      int insn_code, insn_index;
@@ -2546,13 +2753,12 @@ insert_right_side (code, exp, term, insn_code, insn_index)
    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 present.
-   ??? What does "present" mean?  */
+   bitmask indicating which alternatives are mentioned within EXP.  */
 
 static int
 compute_alternative_mask (exp, code)
      rtx exp;
-     RTX_CODE code;
+     enum rtx_code code;
 {
   char *string;
   if (GET_CODE (exp) == code)
@@ -2600,9 +2806,10 @@ make_alternative_compare (mask)
    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.  */
+   intact because addresses are only valid for the `length' attribute. 
 
-/* ??? Kenner, document the meanings of the arguments!!!  */
+   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 (exp, value, insn_code, insn_index)
@@ -2622,6 +2829,25 @@ evaluate_eq_attr (exp, value, insn_code, insn_index)
       else
        newexp = false_rtx;
     }
+  else if (GET_CODE (value) == SYMBOL_REF)
+    {
+      char *p, *string;
+
+      if (GET_CODE (exp) != EQ_ATTR)
+       abort();
+
+      string = (char *) alloca (2 + strlen (XSTR (exp, 0))
+                               + strlen (XSTR (exp, 1)));
+      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
@@ -2634,7 +2860,7 @@ evaluate_eq_attr (exp, value, insn_code, insn_index)
         For each possible COND value, call ourselves recursively.
 
         The extra TRUE and FALSE expressions will be eliminated by another
-        call to the simplification routine. */
+        call to the simplification routine.  */
 
       orexp = false_rtx;
       andexp = true_rtx;
@@ -2652,8 +2878,10 @@ evaluate_eq_attr (exp, value, insn_code, insn_index)
          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),
+                                    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);
@@ -2667,7 +2895,7 @@ evaluate_eq_attr (exp, value, 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),
                                 insn_code, insn_index);
       newexp = insert_right_side (IOR, orexp, right, insn_code, insn_index);
     }
@@ -2914,16 +3142,6 @@ simplify_test_exp (exp, insn_code, insn_index)
   rtx newexp = exp;
   char *spacer = (char *) obstack_finish (rtl_obstack);
 
-  static rtx loser = 0;
-  static int count = 0;
-  static stopcount = 0;
-
-  if (exp == loser)
-    do_nothing ();
-  count++;
-  if (count == stopcount)
-    do_nothing ();
-
   /* Don't re-simplify something we already simplified.  */
   if (RTX_UNCHANGING_P (exp) || MEM_IN_STRUCT_P (exp))
     return exp;
@@ -2935,14 +3153,16 @@ simplify_test_exp (exp, insn_code, insn_index)
       SIMPLIFY_ALTERNATIVE (left);
       if (left == false_rtx)
        {
-         obstack_free (rtl_obstack, spacer);
+         if (!ggc_p)
+           obstack_free (rtl_obstack, spacer);
          return false_rtx;
        }
       right = SIMPLIFY_TEST_EXP (XEXP (exp, 1), insn_code, insn_index);
       SIMPLIFY_ALTERNATIVE (right);
       if (left == false_rtx)
        {
-         obstack_free (rtl_obstack, spacer);
+         if (!ggc_p)
+           obstack_free (rtl_obstack, spacer);
          return false_rtx;
        }
 
@@ -2974,7 +3194,8 @@ simplify_test_exp (exp, insn_code, insn_index)
 
       if (left == false_rtx || right == false_rtx)
        {
-         obstack_free (rtl_obstack, spacer);
+         if (!ggc_p)
+           obstack_free (rtl_obstack, spacer);
          return false_rtx;
        }
       else if (left == true_rtx)
@@ -3000,10 +3221,10 @@ simplify_test_exp (exp, insn_code, insn_index)
        {
          i = compute_alternative_mask (exp, AND);
          if (i & ~insn_alternatives[insn_code])
-           fatal ("Illegal alternative specified for pattern number %d",
+           fatal ("Invalid alternative specified for pattern number %d",
                   insn_index);
 
-         /* If all alternatives are excluded, this is false. */
+         /* If all alternatives are excluded, this is false.  */
          i ^= insn_alternatives[insn_code];
          if (i == 0)
            return false_rtx;
@@ -3033,14 +3254,16 @@ simplify_test_exp (exp, insn_code, insn_index)
       SIMPLIFY_ALTERNATIVE (left);
       if (left == true_rtx)
        {
-         obstack_free (rtl_obstack, spacer);
+         if (!ggc_p)
+           obstack_free (rtl_obstack, spacer);
          return true_rtx;
        }
       right = SIMPLIFY_TEST_EXP (XEXP (exp, 1), insn_code, insn_index);
       SIMPLIFY_ALTERNATIVE (right);
       if (right == true_rtx)
        {
-         obstack_free (rtl_obstack, spacer);
+         if (!ggc_p)
+           obstack_free (rtl_obstack, spacer);
          return true_rtx;
        }
 
@@ -3050,7 +3273,8 @@ simplify_test_exp (exp, insn_code, insn_index)
 
       if (right == true_rtx || left == true_rtx)
        {
-         obstack_free (rtl_obstack, spacer);
+         if (!ggc_p)
+           obstack_free (rtl_obstack, spacer);
          return true_rtx;
        }
       else if (left == false_rtx)
@@ -3093,10 +3317,10 @@ simplify_test_exp (exp, insn_code, insn_index)
        {
          i = compute_alternative_mask (exp, IOR);
          if (i & ~insn_alternatives[insn_code])
-           fatal ("Illegal alternative specified for pattern number %d",
+           fatal ("Invalid alternative specified for pattern number %d",
                   insn_index);
 
-         /* If all alternatives are included, this is true. */
+         /* If all alternatives are included, this is true.  */
          i ^= insn_alternatives[insn_code];
          if (i == 0)
            return true_rtx;
@@ -3137,12 +3361,14 @@ simplify_test_exp (exp, insn_code, insn_index)
 
       if (left == false_rtx)
        {
-         obstack_free (rtl_obstack, spacer);
+         if (!ggc_p)
+           obstack_free (rtl_obstack, spacer);
          return true_rtx;
        }
       else if (left == true_rtx)
        {
-         obstack_free (rtl_obstack, spacer);
+         if (!ggc_p)
+           obstack_free (rtl_obstack, spacer);
          return false_rtx;
        }
 
@@ -3183,6 +3409,10 @@ simplify_test_exp (exp, insn_code, insn_index)
          for (ie = av->first_insn; ie; ie = ie->next)
            if (ie->insn_code == insn_code)
              return evaluate_eq_attr (exp, av->value, insn_code, insn_index);
+      break;
+      
+    default:
+      break;
     }
 
   /* We have already simplified this expression.  Simplifying it again
@@ -3194,9 +3424,6 @@ simplify_test_exp (exp, insn_code, insn_index)
 
   return newexp;
 }
-
-do_nothing ()
-{}
 \f
 /* Optimize the attribute lists by seeing if we can determine conditional
    values from the known values of other attributes.  This will save subroutine
@@ -3216,34 +3443,48 @@ optimize_attrs ()
                           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
     = (struct attr_value_list **) alloca ((insn_code_number + 2)
                                          * sizeof (struct attr_value_list *));
-  bzero (insn_code_values,
+  bzero ((char *) insn_code_values,
         (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;
 
+  /* Allocate the attr_value_list structures using xmalloc rather than
+     alloca, because using alloca can overflow the maximum permitted
+     stack limit on SPARC Lynx.  */
+  iv = ivbuf = ((struct attr_value_list *)
+               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 = ((struct attr_value_list *)
-                 alloca (sizeof (struct attr_value_list)));
            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++;
          }
 
+  /* Sanity check on num_insn_ents.  */
+  if (iv != ivbuf + num_insn_ents)
+    abort ();
+
   /* Process one insn code at a time.  */
   for (i = -2; i < insn_code_number; i++)
     {
@@ -3289,10 +3530,13 @@ optimize_attrs ()
                  insert_insn_ent (av, ie);
                  something_changed = 1;
                }
-             obstack_free (temp_obstack, spacer);
+             if (!ggc_p)
+               obstack_free (temp_obstack, spacer);
            }
        }
     }
+
+  free (ivbuf);
 }
 
 #if 0
@@ -3329,49 +3573,6 @@ simplify_by_alternatives (exp, insn_code, insn_index)
 }
 #endif
 \f
-/* 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 MEM_VOLATILE_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.  */
-};
-
 /* 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.  */
@@ -3380,7 +3581,7 @@ static rtx
 simplify_by_exploding (exp)
      rtx exp;
 {
-  rtx list = 0, link, condexp, defval;
+  rtx list = 0, link, condexp, defval = NULL_RTX;
   struct dimension *space;
   rtx *condtest, *condval;
   int i, j, total, ndim = 0;
@@ -3543,7 +3744,10 @@ find_and_mark_used_attributes (exp, terms, nterms)
          *nterms += 1;
          MEM_VOLATILE_P (exp) = 1;
        }
+      return 1;
+
     case CONST_STRING:
+    case CONST_INT:
       return 1;
 
     case IF_THEN_ELSE:
@@ -3565,9 +3769,10 @@ find_and_mark_used_attributes (exp, terms, nterms)
       if (! find_and_mark_used_attributes (XEXP (exp, 1), terms, nterms))
        return 0;
       return 1;
-    }
 
-  return 0;
+    default:
+      return 0;
+    }
 }
 
 /* Clear the MEM_VOLATILE_P flag in all EQ_ATTR expressions on LIST and
@@ -3645,7 +3850,7 @@ add_values_to_cover (dim)
       prev = &dim->values;
       for (link = dim->values; link; link = *prev)
        {
-         orexp = insert_right_side (IOR, orexp, XEXP (link, 0), -2);
+         orexp = insert_right_side (IOR, orexp, XEXP (link, 0), -2, -2);
          prev = &XEXP (link, 1);
        }
       link = rtx_alloc (EXPR_LIST);
@@ -3689,7 +3894,8 @@ test_for_current_value (space, ndim)
   rtx exp = true_rtx;
 
   for (i = 0; i < ndim; i++)
-    exp = insert_right_side (AND, exp, XEXP (space[i].current_value, 0), -2);
+    exp = insert_right_side (AND, exp, XEXP (space[i].current_value, 0),
+                            -2, -2);
 
   return exp;
 }
@@ -3747,6 +3953,7 @@ simplify_with_current_value_aux (exp)
       else
        return true_rtx;
     case CONST_STRING:
+    case CONST_INT:
       return exp;
 
     case IF_THEN_ELSE:
@@ -3802,19 +4009,22 @@ simplify_with_current_value_aux (exp)
                         have been selected.  */
        }
       return simplify_with_current_value_aux (XEXP (exp, 1));
+
+    default:
+      abort ();
     }
-  abort ();
 }
 \f
 /* Clear the MEM_IN_STRUCT_P flag in EXP and its subexpressions.  */
 
+static void
 clear_struct_flag (x)
      rtx x;
 {
   register int i;
   register int j;
   register enum rtx_code code;
-  register char *fmt;
+  register const char *fmt;
 
   MEM_IN_STRUCT_P (x) = 0;
   if (RTX_UNCHANGING_P (x))
@@ -3833,7 +4043,11 @@ clear_struct_flag (x)
     case PC:
     case CC0:
     case EQ_ATTR:
+    case ATTR_FLAG:
       return;
+      
+    default:
+      break;
     }
 
   /* Compare the elements.  If any pair of corresponding elements
@@ -3858,8 +4072,9 @@ clear_struct_flag (x)
 }
 
 /* Return the number of RTX objects making up the expression X.
-   But if we count more more than MAX objects, stop counting.  */
+   But if we count more than MAX objects, stop counting.  */
 
+static int
 count_sub_rtxs (x, max)
      rtx x;
      int max;
@@ -3867,7 +4082,7 @@ count_sub_rtxs (x, max)
   register int i;
   register int j;
   register enum rtx_code code;
-  register char *fmt;
+  register const char *fmt;
   int total = 0;
 
   code = GET_CODE (x);
@@ -3883,7 +4098,11 @@ count_sub_rtxs (x, max)
     case PC:
     case CC0:
     case EQ_ATTR:
+    case ATTR_FLAG:
       return 1;
+      
+    default:
+      break;
     }
 
   /* Compare the elements.  If any pair of corresponding elements
@@ -3930,7 +4149,7 @@ gen_attr (exp)
     fatal ("Duplicate definition for `%s' attribute", attr->name);
 
   if (*XSTR (exp, 1) == '\0')
-      attr->is_numeric = 1;
+    attr->is_numeric = 1;
   else
     {
       name_ptr = XSTR (exp, 1);
@@ -3958,7 +4177,7 @@ gen_attr (exp)
   if (! strcmp (attr->name, "length") && ! attr->is_numeric)
     fatal ("`length' attribute must take numeric values");
 
-  /* Set up the default value. */
+  /* Set up the default value.  */
   XEXP (exp, 2) = check_attr_value (XEXP (exp, 2), attr);
   attr->default_val = get_attr_value (XEXP (exp, 2), attr, -2);
 }
@@ -3972,7 +4191,7 @@ count_alternatives (exp)
      rtx exp;
 {
   int i, j, n;
-  char *fmt;
+  const char *fmt;
   
   if (GET_CODE (exp) == MATCH_OPERAND)
     return n_comma_elts (XSTR (exp, 2));
@@ -4010,7 +4229,7 @@ compares_alternatives_p (exp)
      rtx exp;
 {
   int i, j;
-  char *fmt;
+  const char *fmt;
 
   if (GET_CODE (exp) == EQ_ATTR && XSTR (exp, 0) == alternative_name)
     return 1;
@@ -4043,7 +4262,7 @@ contained_in_p (inner, exp)
      rtx exp;
 {
   int i, j;
-  char *fmt;
+  const char *fmt;
 
   if (rtx_equal_p (inner, exp))
     return 1;
@@ -4108,6 +4327,9 @@ gen_insn (exp)
       id->vec_idx = 0;
       got_define_asm_attributes = 1;
       break;
+      
+    default:
+      abort ();
     }
 }
 \f
@@ -4194,6 +4416,7 @@ gen_unit (def)
   op->issue_delay = issue_delay;
   op->next = unit->ops;
   unit->ops = op;
+  num_unit_opclasses++;
 
   /* Set our issue expression based on whether or not an optional conflict
      vector was specified.  */
@@ -4204,7 +4427,7 @@ gen_unit (def)
       int i;
 
       for (i = 0; i < XVECLEN (def, 6); i++)
-       orexp = insert_right_side (IOR, orexp, XVECEXP (def, 6, i), -2);
+       orexp = insert_right_side (IOR, orexp, XVECEXP (def, 6, i), -2, -2);
 
       op->conflict_exp = orexp;
       extend_range (&unit->issue_delay, 1, issue_delay);
@@ -4217,18 +4440,21 @@ gen_unit (def)
 
   /* 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);
+  unit->condexp = insert_right_side (IOR, unit->condexp, op->condexp, -2, -2);
 }
 \f
-/* Given a piece of RTX, print a C expression to test it's truth value.
+/* 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.
-   The second operand of this function will be non-zero in that case.  */
+   The first bit of FLAGS will be non-zero in that case.
+
+   Set the second bit of FLAGS to make references to attribute values use
+   a cached local variable instead of calling a function.  */
 
 static void
-write_test_expr (exp, in_comparison)
+write_test_expr (exp, flags)
      rtx exp;
-     int in_comparison;
+     int flags;
 {
   int comparison_operator = 0;
   RTX_CODE code;
@@ -4249,8 +4475,8 @@ write_test_expr (exp, in_comparison)
 
     case PLUS:   case MINUS:  case MULT:     case DIV:      case MOD:
     case AND:    case IOR:    case XOR:
-    case LSHIFT: case ASHIFT: case LSHIFTRT: case ASHIFTRT:
-      write_test_expr (XEXP (exp, 0), in_comparison || comparison_operator);
+    case ASHIFT: case LSHIFTRT: case ASHIFTRT:
+      write_test_expr (XEXP (exp, 0), flags | comparison_operator);
       switch (code)
         {
        case EQ:
@@ -4299,13 +4525,13 @@ write_test_expr (exp, in_comparison)
          printf (" %% ");
          break;
        case AND:
-         if (in_comparison)
+         if (flags & 1)
            printf (" & ");
          else
            printf (" && ");
          break;
        case IOR:
-         if (in_comparison)
+         if (flags & 1)
            printf (" | ");
          else
            printf (" || ");
@@ -4313,7 +4539,6 @@ write_test_expr (exp, in_comparison)
        case XOR:
          printf (" ^ ");
          break;
-       case LSHIFT:
        case ASHIFT:
          printf (" << ");
          break;
@@ -4321,14 +4546,16 @@ write_test_expr (exp, in_comparison)
        case ASHIFTRT:
          printf (" >> ");
          break;
+       default:
+         abort ();
         }
 
-      write_test_expr (XEXP (exp, 1), in_comparison || comparison_operator);
+      write_test_expr (XEXP (exp, 1), flags | comparison_operator);
       break;
 
     case NOT:
       /* Special-case (not (eq_attrq "alternative" "x")) */
-      if (! in_comparison && GET_CODE (XEXP (exp, 0)) == EQ_ATTR
+      if (! (flags & 1) && GET_CODE (XEXP (exp, 0)) == EQ_ATTR
          && XSTR (XEXP (exp, 0), 0) == alternative_name)
        {
          printf ("which_alternative != %s", XSTR (XEXP (exp, 0), 1));
@@ -4342,7 +4569,7 @@ write_test_expr (exp, in_comparison)
       switch (code)
        {
        case NOT:
-         if (in_comparison)
+         if (flags & 1)
            printf ("~ ");
          else
            printf ("! ");
@@ -4353,16 +4580,18 @@ write_test_expr (exp, in_comparison)
        case NEG:
          printf ("-");
          break;
+       default:
+         abort ();
        }
 
-      write_test_expr (XEXP (exp, 0), in_comparison);
+      write_test_expr (XEXP (exp, 0), flags);
       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.  */
     case EQ_ATTR:
-      if (in_comparison)
+      if (flags & 1)
        fatal ("EQ_ATTR not valid inside comparison");
 
       if (XSTR (exp, 0) == alternative_name)
@@ -4378,16 +4607,27 @@ write_test_expr (exp, in_comparison)
       if (attr->is_const)
        {
          write_test_expr (evaluate_eq_attr (exp, attr->default_val->value,
-                                            0, 0),
-                          in_comparison);
+                                            -2, -2),
+                          flags);
        }
       else
        {
-         printf ("get_attr_%s (insn) == ", attr->name);
-         write_attr_valueq (attr, XSTR (exp, 1)); 
+         if (flags & 2)
+           printf ("attr_%s", attr->name);
+         else
+           printf ("get_attr_%s (insn)", attr->name);
+         printf (" == ");
+         write_attr_valueq (attr, XSTR (exp, 1));
        }
       break;
 
+    /* Comparison test of flags for define_delays.  */
+    case ATTR_FLAG:
+      if (flags & 1)
+       fatal ("ATTR_FLAG not valid inside comparison");
+      printf ("(flags & ATTR_FLAG_%s) != 0", XSTR (exp, 0));
+      break;
+
     /* See if an operand matches a predicate.  */
     case MATCH_OPERAND:
       /* If only a mode is given, just ensure the mode matches the operand.
@@ -4405,31 +4645,45 @@ write_test_expr (exp, in_comparison)
                XSTR (exp, 1), XINT (exp, 0), GET_MODE_NAME (GET_MODE (exp)));
       break;
 
-    /* Constant integer. */
+    case MATCH_INSN:
+      printf ("%s (insn)", XSTR (exp, 0));
+      break;
+
+    /* Constant integer.  */
     case CONST_INT:
-#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
-      printf ("%d", XWINT (exp, 0));
-#else
-      printf ("%ld", XWINT (exp, 0));
-#endif
+      printf (HOST_WIDE_INT_PRINT_DEC, XWINT (exp, 0));
       break;
 
-    /* A random C expression. */
+    /* A random C expression.  */
     case SYMBOL_REF:
       printf ("%s", XSTR (exp, 0));
       break;
 
     /* The address of the branch target.  */
     case MATCH_DUP:
-      printf ("insn_addresses[INSN_UID (JUMP_LABEL (insn))]");
+      printf ("insn_addresses[INSN_UID (GET_CODE (operands[%d]) == LABEL_REF ? XEXP (operands[%d], 0) : operands[%d])]",
+             XINT (exp, 0), XINT (exp, 0), XINT (exp, 0));
       break;
 
-    /* The address of the current insn.  It would be more consistent with
-       other usage to make this the address of the NEXT insn, but this gets
-       too confusing because of the ambiguity regarding the length of the
-       current insn.  */
     case PC:
-      printf ("insn_current_address");
+      /* The address of the current insn.  We implement this actually as the
+        address of the current insn for backward branches, but the last
+        address of the next insn for forward branches, and both with
+        adjustments that account for the worst-case possible stretching of
+        intervening alignments between this insn and its destination.  */
+      printf("insn_current_reference_address (insn)");
+      break;
+
+    case CONST_STRING:
+      printf ("%s", XSTR (exp, 0));
+      break;
+
+    case IF_THEN_ELSE:
+      write_test_expr (XEXP (exp, 0), flags & 2);
+      printf (" ? ");
+      write_test_expr (XEXP (exp, 1), flags | 1);
+      printf (" : ");
+      write_test_expr (XEXP (exp, 2), flags | 1);
       break;
 
     default:
@@ -4441,45 +4695,84 @@ write_test_expr (exp, in_comparison)
 }
 \f
 /* Given an attribute value, return the maximum CONST_STRING argument
-   encountered.  It is assumed that they are all numeric.  */
+   encountered.  Set *UNKNOWNP and return INT_MAX if the value is unknown.  */
 
 static int
-max_attr_value (exp)
+max_attr_value (exp, unknownp)
      rtx exp;
+     int *unknownp;
 {
-  int current_max = 0;
-  int n;
-  int i;
+  int current_max;
+  int i, n;
 
-  if (GET_CODE (exp) == CONST_STRING)
-    return atoi (XSTR (exp, 0));
-
-  else if (GET_CODE (exp) == COND)
+  switch (GET_CODE (exp))
     {
+    case CONST_STRING:
+      current_max = atoi (XSTR (exp, 0));
+      break;
+
+    case COND:
+      current_max = max_attr_value (XEXP (exp, 1), unknownp);
       for (i = 0; i < XVECLEN (exp, 0); i += 2)
        {
-         n = max_attr_value (XVECEXP (exp, 0, i + 1));
+         n = max_attr_value (XVECEXP (exp, 0, i + 1), unknownp);
          if (n > current_max)
            current_max = n;
        }
+      break;
 
-      n = max_attr_value (XEXP (exp, 1));
+    case IF_THEN_ELSE:
+      current_max = max_attr_value (XEXP (exp, 1), unknownp);
+      n = max_attr_value (XEXP (exp, 2), unknownp);
       if (n > current_max)
        current_max = n;
+      break;
+
+    default:
+      *unknownp = 1;
+      current_max = INT_MAX;
+      break;
     }
 
-  else if (GET_CODE (exp) == IF_THEN_ELSE)
+  return current_max;
+}
+
+/* Given an attribute value, return the result of ORing together all
+   CONST_STRING arguments encountered.  Set *UNKNOWNP and return -1
+   if the numeric value is not known.  */
+
+static int
+or_attr_value (exp, unknownp)
+     rtx exp;
+     int *unknownp;
+{
+  int current_or;
+  int i;
+
+  switch (GET_CODE (exp))
     {
-      current_max = max_attr_value (XEXP (exp, 1));
-      n = max_attr_value (XEXP (exp, 2));
-      if (n > current_max)
-       current_max = n;
-    }
+    case CONST_STRING:
+      current_or = atoi (XSTR (exp, 0));
+      break;
 
-  else
-    abort ();
+    case COND:
+      current_or = or_attr_value (XEXP (exp, 1), unknownp);
+      for (i = 0; i < XVECLEN (exp, 0); i += 2)
+       current_or |= or_attr_value (XVECEXP (exp, 0, i + 1), unknownp);
+      break;
 
-  return current_max;
+    case IF_THEN_ELSE:
+      current_or = or_attr_value (XEXP (exp, 1), unknownp);
+      current_or |= or_attr_value (XEXP (exp, 2), unknownp);
+      break;
+
+    default:
+      *unknownp = 1;
+      current_or = -1;
+      break;
+    }
+
+  return current_or;
 }
 \f
 /* Scan an attribute value, possibly a conditional, and record what actions
@@ -4489,6 +4782,7 @@ max_attr_value (exp)
        `must_extract'    if we need to extract the insn operands
        `must_constrain'  if we must compute `which_alternative'
        `address_used'    if an address expression was used
+       `length_used'     if an (eq_attr "length" ...) was used
  */
 
 static void
@@ -4496,7 +4790,7 @@ walk_attr_value (exp)
      rtx exp;
 {
   register int i, j;
-  register char *fmt;
+  register const char *fmt;
   RTX_CODE code;
 
   if (exp == NULL)
@@ -4520,12 +4814,24 @@ walk_attr_value (exp)
     case EQ_ATTR:
       if (XSTR (exp, 0) == alternative_name)
        must_extract = must_constrain = 1;
+      else if (strcmp (XSTR (exp, 0), "length") == 0)
+       length_used = 1;
       return;
 
     case MATCH_DUP:
+      must_extract = 1;
+      address_used = 1;
+      return;
+
     case PC:
       address_used = 1;
       return;
+
+    case ATTR_FLAG:
+      return;
+
+    default:
+      break;
     }
 
   for (i = 0, fmt = GET_RTX_FORMAT (code); i < GET_RTX_LENGTH (code); i++)
@@ -4553,9 +4859,24 @@ write_attr_get (attr)
   struct attr_value *av, *common_av;
 
   /* Find the most used attribute value.  Handle that as the `default' of the
-     switch we will generate. */
+     switch we will generate.  */
   common_av = find_most_used (attr);
 
+  /* Write out prototype of function. */
+  if (!attr->is_numeric)
+    printf ("extern enum attr_%s ", attr->name);
+  else if (attr->unsigned_p)
+    printf ("extern unsigned int ");
+  else
+    printf ("extern int ");
+  /* If the attribute name starts with a star, the remainder is the name of
+     the subroutine to use, instead of `get_attr_...'.  */
+  if (attr->name[0] == '*')
+    printf ("%s PARAMS ((rtx));\n", &attr->name[1]);
+  else
+    printf ("get_attr_%s PARAMS ((%s));\n", attr->name,
+           (attr->is_const ? "void" : "rtx"));
+
   /* Write out start of function, then all values with explicit `case' lines,
      then a `default', then the value with the most uses.  */
   if (!attr->is_numeric)
@@ -4585,17 +4906,40 @@ write_attr_get (attr)
       printf ("}\n\n");
       return;
     }
+
   printf ("     rtx insn;\n");
   printf ("{\n");
-  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);
+  if (GET_CODE (common_av->value) == FFS)
+    {
+      rtx p = XEXP (common_av->value, 0);
 
-  write_attr_case (attr, common_av, 0, "return", ";", 4, true_rtx);
-  printf ("    }\n}\n\n");
+      /* 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);
+
+      write_attr_case (attr, common_av, 0, "return", ";", 4, true_rtx);
+      printf ("    }\n}\n\n");
+    }
 }
 \f
 /* Given an AND tree of known true terms (because we are inside an `if' with
@@ -4640,19 +4984,12 @@ write_attr_set (attr, indent, value, prefix, suffix, known_true,
      struct attr_desc *attr;
      int indent;
      rtx value;
-     char *prefix;
-     char *suffix;
+     const char *prefix;
+     const char *suffix;
      rtx known_true;
      int insn_code, insn_index;
 {
-  if (GET_CODE (value) == CONST_STRING)
-    {
-      write_indent (indent);
-      printf ("%s ", prefix);
-      write_attr_value (attr, value);
-      printf ("%s\n", suffix);
-    }
-  else if (GET_CODE (value) == COND)
+  if (GET_CODE (value) == COND)
     {
       /* Assume the default value will be the default of the COND unless we
         find an always true expression.  */
@@ -4726,17 +5063,23 @@ write_attr_set (attr, indent, value, prefix, suffix, known_true,
        }
     }
   else
-    abort ();
+    {
+      write_indent (indent);
+      printf ("%s ", prefix);
+      write_attr_value (attr, value);
+      printf ("%s\n", suffix);
+    }
 }
 \f
 /* Write out the computation for one attribute value.  */
 
 static void
-write_attr_case (attr, av, write_case_lines, prefix, suffix, indent, known_true)
+write_attr_case (attr, av, write_case_lines, prefix, suffix, indent,
+                known_true)
      struct attr_desc *attr;
      struct attr_value *av;
      int write_case_lines;
-     char *prefix, *suffix;
+     const char *prefix, *suffix;
      int indent;
      rtx known_true;
 {
@@ -4772,24 +5115,22 @@ write_attr_case (attr, av, write_case_lines, prefix, suffix, indent, known_true)
       printf ("default:\n");
     }
 
-  /* See what we have to do to handle output this value.  */
+  /* See what we have to do to output this value.  */
   must_extract = must_constrain = address_used = 0;
   walk_attr_value (av->value);
 
   if (must_extract)
     {
       write_indent (indent + 2);
-      printf ("insn_extract (insn);\n");
+      printf ("extract_insn (insn);\n");
     }
 
   if (must_constrain)
     {
-#ifdef REGISTER_CONSTRAINTS
       write_indent (indent + 2);
-      printf ("if (! constrain_operands (INSN_CODE (insn), reload_completed))\n");
+      printf ("if (! constrain_operands (reload_completed))\n");
       write_indent (indent + 2);
       printf ("  fatal_insn_not_found (insn);\n");
-#endif
     }
 
   write_attr_set (attr, indent + 2, av->value, prefix, suffix,
@@ -4804,19 +5145,148 @@ write_attr_case (attr, av, write_case_lines, prefix, suffix, indent, known_true)
   printf ("\n");
 }
 \f
+/* Search for uses of non-const attributes and write code to cache them.  */
+
+static int
+write_expr_attr_cache (p, attr)
+     rtx p;
+     struct attr_desc *attr;
+{
+  const char *fmt;
+  int i, ie, j, je;
+
+  if (GET_CODE (p) == EQ_ATTR)
+    {
+      if (XSTR (p, 0) != attr->name)
+       return 0;
+
+      if (!attr->is_numeric)
+       printf ("  register enum attr_%s ", attr->name);
+      else if (attr->unsigned_p)
+       printf ("  register unsigned int ");
+      else
+       printf ("  register int ");
+
+      printf ("attr_%s = get_attr_%s (insn);\n", attr->name, attr->name);
+      return 1;
+    }
+
+  fmt = GET_RTX_FORMAT (GET_CODE (p));
+  ie = GET_RTX_LENGTH (GET_CODE (p));
+  for (i = 0; i < ie; i++)
+    {
+      switch (*fmt++)
+       {
+       case 'e':
+         if (write_expr_attr_cache (XEXP (p, i), attr))
+           return 1;
+         break;
+
+       case 'E':
+         je = XVECLEN (p, i);
+         for (j = 0; j < je; ++j)
+           if (write_expr_attr_cache (XVECEXP (p, i, j), attr))
+             return 1;
+         break;
+       }
+    }
+
+  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 (p)
+     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("  register 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");
+}
+\f
 /* Utilities to write names in various forms.  */
 
 static void
+write_unit_name (prefix, num, suffix)
+     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);
+}
+
+static void
 write_attr_valueq (attr, s)
      struct attr_desc *attr;
      char *s;
 {
   if (attr->is_numeric)
     {
-      printf ("%s", s);
-      /* Make the blockage range values easier to read.  */
-      if (strlen (s) > 1)
-       printf (" /* 0x%x */", atoi (s));
+      int num = atoi (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)
+       printf (" /* 0x%x */", num);
     }
   else
     {
@@ -4831,21 +5301,65 @@ write_attr_value (attr, value)
      struct attr_desc *attr;
      rtx value;
 {
-  if (GET_CODE (value) != CONST_STRING)
-    abort ();
+  int op;
+
+  switch (GET_CODE (value))
+    {
+    case CONST_STRING:
+      write_attr_valueq (attr, XSTR (value, 0));
+      break;
+
+    case SYMBOL_REF:
+      fputs (XSTR (value, 0), stdout);
+      break;
+
+    case ATTR:
+      {
+       struct attr_desc *attr2 = find_attr (XSTR (value, 0), 0);
+       printf ("get_attr_%s (%s)", attr2->name, 
+               (attr2->is_const ? "" : "insn"));
+      }
+      break;
+
+    case PLUS:
+      op = '+';
+      goto do_operator;
+    case MINUS:
+      op = '-';
+      goto do_operator;
+    case MULT:
+      op = '*';
+      goto do_operator;
+    case DIV:
+      op = '/';
+      goto do_operator;
+    case MOD:
+      op = '%';
+      goto do_operator;
+
+    do_operator:
+      write_attr_value (attr, XEXP (value, 0));
+      putchar (' ');
+      putchar (op);
+      putchar (' ');
+      write_attr_value (attr, XEXP (value, 1));
+      break;
 
-  write_attr_valueq (attr, XSTR (value, 0));
+    default:
+      abort ();
+    }
 }
 
 static void
 write_upcase (str)
-     char *str;
+     const char *str;
 {
   while (*str)
-    if (*str < 'a' || *str > 'z')
-      printf ("%c", *str++);
-    else
-      printf ("%c", *str++ - 'a' + 'A');
+  {
+    /* The argument of TOUPPER should not have side effects.  */
+    putchar (TOUPPER(*str));
+    str++;
+  }
 }
 
 static void
@@ -4873,7 +5387,7 @@ write_indent (indent)
 
 static void
 write_eligible_delay (kind)
-     char *kind;
+  const char *kind;
 {
   struct delay_desc *delay;
   int max_slots;
@@ -4893,10 +5407,12 @@ write_eligible_delay (kind)
   /* Write function prelude.  */
 
   printf ("int\n");
-  printf ("eligible_for_%s (delay_insn, slot, candidate_insn)\n", kind);
+  printf ("eligible_for_%s (delay_insn, slot, candidate_insn, flags)\n", 
+          kind);
   printf ("     rtx delay_insn;\n");
   printf ("     int slot;\n");
   printf ("     rtx candidate_insn;\n");
+  printf ("     int flags ATTRIBUTE_UNUSED;\n");
   printf ("{\n");
   printf ("  rtx insn;\n");
   printf ("\n");
@@ -5060,7 +5576,7 @@ write_function_unit_info ()
 static void
 write_complex_function (unit, name, connection)
      struct function_unit *unit;
-     char *name, *connection;
+     const char *name, *connection;
 {
   struct attr_desc *case_attr, *attr;
   struct attr_value *av, *common_av;
@@ -5069,6 +5585,7 @@ write_complex_function (unit, name, connection)
   int using_case;
   int i;
 
+  printf ("static int %s_unit_%s PARAMS ((rtx, rtx));\n", unit->name, name);
   printf ("static int\n");
   printf ("%s_unit_%s (executing_insn, candidate_insn)\n",
          unit->name, name);
@@ -5077,7 +5594,7 @@ write_complex_function (unit, name, connection)
   printf ("{\n");
   printf ("  rtx insn;\n");
   printf ("  int casenum;\n\n");
-  printf ("  insn = candidate_insn;\n");
+  printf ("  insn = executing_insn;\n");
   printf ("  switch (recog_memoized (insn))\n");
   printf ("    {\n");
 
@@ -5099,7 +5616,7 @@ write_complex_function (unit, name, connection)
 
   /* Now write an outer switch statement on each case.  Then write
      the tests on the executing function within each.  */
-  printf ("  insn = executing_insn;\n");
+  printf ("  insn = candidate_insn;\n");
   printf ("  switch (casenum)\n");
   printf ("    {\n");
 
@@ -5123,7 +5640,7 @@ write_complex_function (unit, name, connection)
       /* If single value, just write it.  */
       value = find_single_value (attr);
       if (value)
-       write_attr_set (attr, 6, value, "return", ";\n", true_rtx, -2);
+       write_attr_set (attr, 6, value, "return", ";\n", true_rtx, -2, -2);
       else
        {
          common_av = find_most_used (attr);
@@ -5141,6 +5658,10 @@ write_complex_function (unit, name, connection)
        }
     }
 
+  /* 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");
 }
 \f
@@ -5197,7 +5718,7 @@ next_comma_elt (pstr)
 
 static struct attr_desc *
 find_attr (name, create)
-     char *name;
+     const char *name;
      int create;
 {
   struct attr_desc *attr;
@@ -5235,7 +5756,7 @@ find_attr (name, create)
 
 static void
 make_internal_attr (name, value, special)
-     char *name;
+     const char *name;
      rtx value;
      int special;
 {
@@ -5250,6 +5771,8 @@ make_internal_attr (name, value, special)
   attr->is_special = (special & 1) != 0;
   attr->negative_ok = (special & 2) != 0;
   attr->unsigned_p = (special & 4) != 0;
+  attr->func_units_p = (special & 8) != 0;
+  attr->blockage_p = (special & 16) != 0;
   attr->default_val = get_attr_value (value, attr, -2);
 }
 
@@ -5331,22 +5854,26 @@ extend_range (range, min, max)
   if (range->max < max) range->max = max;
 }
 
-char *
-xrealloc (ptr, size)
-     char *ptr;
-     unsigned size;
+PTR
+xrealloc (old, size)
+  PTR old;
+  size_t size;
 {
-  char *result = (char *) realloc (ptr, size);
-  if (!result)
+  register PTR ptr;
+  if (old)
+    ptr = (PTR) realloc (old, size);
+  else
+    ptr = (PTR) malloc (size);
+  if (!ptr)
     fatal ("virtual memory exhausted");
-  return result;
+  return ptr;
 }
 
-char *
+PTR
 xmalloc (size)
-     unsigned size;
+  size_t size;
 {
-  register char *val = (char *) malloc (size);
+  register PTR val = (PTR) malloc (size);
 
   if (val == 0)
     fatal ("virtual memory exhausted");
@@ -5377,37 +5904,61 @@ copy_rtx_unchanging (orig)
     case SYMBOL_REF:
     case CODE_LABEL:
       return orig;
+      
+    default:
+      break;
     }
 
   copy = rtx_alloc (code);
   PUT_MODE (copy, GET_MODE (orig));
   RTX_UNCHANGING_P (copy) = 1;
   
-  bcopy (&XEXP (orig, 0), &XEXP (copy, 0),
+  bcopy ((char *) &XEXP (orig, 0), (char *) &XEXP (copy, 0),
         GET_RTX_LENGTH (GET_CODE (copy)) * sizeof (rtx));
   return copy;
 #endif
 }
 
+/* Determine if an insn has a constant number of delay slots, i.e., the
+   number of delay slots is not a function of the length of the insn.  */
+
 static void
-fatal (s, a1, a2)
-     char *s;
+write_const_num_delay_slots ()
 {
-  fprintf (stderr, "genattrtab: ");
-  fprintf (stderr, s, a1, a2);
-  fprintf (stderr, "\n");
-  exit (FATAL_EXIT_CODE);
-}
+  struct attr_desc *attr = find_attr ("*num_delay_slots", 0);
+  struct attr_value *av;
+  struct insn_ent *ie;
 
-/* More 'friendly' abort that prints the line and file.
-   config.h can #define abort fancy_abort if you like that sort of thing.  */
+  if (attr)
+    {
+      printf ("int\nconst_num_delay_slots (insn)\n");
+      printf ("     rtx insn;\n");
+      printf ("{\n");
+      printf ("  switch (recog_memoized (insn))\n");
+      printf ("    {\n");
 
-void
-fancy_abort ()
-{
-  fatal ("Internal gcc abort.");
+      for (av = attr->first_value; av; av = av->next)
+       {
+         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");
+           }
+       }
+
+      printf ("    default:\n");
+      printf ("      return 1;\n");
+      printf ("    }\n}\n\n");
+    }
 }
+
 \f
+extern int main PARAMS ((int, char **));
+
 int
 main (argc, argv)
      int argc;
@@ -5421,6 +5972,21 @@ main (argc, argv)
   rtx tem;
   int i;
 
+  progname = "genattrtab";
+
+#if defined (RLIMIT_STACK) && defined (HAVE_GETRLIMIT) && defined (HAVE_SETRLIMIT)
+  /* Get rid of any avoidable limit on stack size.  */
+  {
+    struct rlimit rlim;
+
+    /* Set the stack limit huge so that alloca does not fail.  */
+    getrlimit (RLIMIT_STACK, &rlim);
+    rlim.rlim_cur = rlim.rlim_max;
+    setrlimit (RLIMIT_STACK, &rlim);
+  }
+#endif
+
+  progname = "genattrtab";
   obstack_init (rtl_obstack);
   obstack_init (hash_obstack);
   obstack_init (temp_obstack);
@@ -5432,10 +5998,9 @@ main (argc, argv)
   if (infile == 0)
     {
       perror (argv[1]);
-      exit (FATAL_EXIT_CODE);
+      return (FATAL_EXIT_CODE);
     }
-
-  init_rtl ();
+  read_rtx_filename = argv[1];
 
   /* Set up true and false rtx's */
   true_rtx = rtx_alloc (CONST_INT);
@@ -5471,6 +6036,9 @@ from the machine description file `md'.  */\n\n");
       else if (GET_CODE (desc) == DEFINE_SPLIT)
        insn_code_number++, insn_index_number++;
 
+      else if (GET_CODE (desc) == DEFINE_PEEPHOLE2)
+       insn_code_number++, insn_index_number++;
+
       else if (GET_CODE (desc) == DEFINE_ATTR)
        {
          gen_attr (desc);
@@ -5507,15 +6075,18 @@ from the machine description file `md'.  */\n\n");
     expand_units ();
 
   printf ("#include \"config.h\"\n");
+  printf ("#include \"system.h\"\n");
   printf ("#include \"rtl.h\"\n");
+  printf ("#include \"tm_p.h\"\n");
   printf ("#include \"insn-config.h\"\n");
   printf ("#include \"recog.h\"\n");
   printf ("#include \"regs.h\"\n");
   printf ("#include \"real.h\"\n");
   printf ("#include \"output.h\"\n");
   printf ("#include \"insn-attr.h\"\n");
+  printf ("#include \"toplev.h\"\n");
   printf ("\n");  
-  printf ("#define operands recog_operand\n\n");
+  printf ("#define operands recog_data.operand\n\n");
 
   /* Make `insn_alternatives'.  */
   insn_alternatives = (int *) oballoc (insn_code_number * sizeof (int));
@@ -5544,7 +6115,7 @@ from the machine description file `md'.  */\n\n");
   /* Construct extra attributes for `length'.  */
   make_length_attrs ();
 
-  /* Perform any possible optimizations to speed up compilation. */
+  /* Perform any possible optimizations to speed up compilation.  */
   optimize_attrs ();
 
   /* Now write out all the `gen_attr_...' routines.  Do these before the
@@ -5554,7 +6125,7 @@ from the machine description file `md'.  */\n\n");
   for (i = 0; i < MAX_ATTRS_INDEX; i++)
     for (attr = attrs[i]; attr; attr = attr->next)
       {
-       if (! attr->is_special)
+       if (! attr->is_special && ! attr->is_const)
          write_attr_get (attr);
       }
 
@@ -5574,8 +6145,19 @@ from the machine description file `md'.  */\n\n");
   if (num_units)
     write_function_unit_info ();
 
+  /* Write out constant delay slot info */
+  write_const_num_delay_slots ();
+
+  write_length_unit_log ();
+
   fflush (stdout);
-  exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
-  /* NOTREACHED */
-  return 0;
+  return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
+}
+
+/* Define this so we can link with print-rtl.o to get debug_rtx function.  */
+const char *
+get_insn_name (code)
+     int code ATTRIBUTE_UNUSED;
+{
+  return NULL;
 }