OSDN Git Service

* java-tree.h (end_params_node): Declare global.
[pf3gnuchains/gcc-fork.git] / gcc / genattrtab.c
index ac5cf0a..8bb3dc6 100644 (file)
@@ -1,5 +1,5 @@
 /* Generate code from machine description to compute values of attributes.
-   Copyright (C) 1991, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1991, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
    Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
 
 This file is part of GNU CC.
@@ -34,7 +34,7 @@ Boston, MA 02111-1307, 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,
@@ -96,27 +96,10 @@ Boston, MA 02111-1307, USA.  */
 
 
 #include "hconfig.h"
-/* varargs must always be included after *config.h.  */
-#ifdef __STDC__
-#include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
-#include <stdio.h>
+#include "system.h"
 #include "rtl.h"
 #include "insn-config.h"       /* For REGISTER_CONSTRAINTS */
 
-#ifdef TIME_WITH_SYS_TIME
-# include <sys/time.h>
-# include <time.h>
-#else
-# if HAVE_SYS_TIME_H
-# include <sys/time.h>
-# else
-#  include <time.h>
-#endif
-#endif
-
 #ifdef HAVE_SYS_RESOURCE_H
 # include <sys/resource.h>
 #endif
@@ -136,11 +119,9 @@ struct obstack *temp_obstack = &obstack2;
 /* 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 ();
+static void fatal PVPROTO ((char *, ...))
+  ATTRIBUTE_PRINTF_1 ATTRIBUTE_NORETURN;
+void fancy_abort PROTO((void)) ATTRIBUTE_NORETURN;
 
 /* enough space to reserve for printing out ints */
 #define MAX_DIGITS (HOST_BITS_PER_INT * 3 / 10 + 3)
@@ -192,11 +173,13 @@ 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'.  */
+  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.  */
 };
@@ -318,12 +301,12 @@ 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.  */
 
@@ -348,6 +331,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)    \
@@ -367,21 +360,21 @@ static char *alternative_name;
    They won't actually be used.  */
 
 struct _global_rtl global_rtl;
+rtx pic_offset_table_rtx;
 
+static void attr_hash_add_rtx  PROTO((int, rtx));
+static void attr_hash_add_string PROTO((int, char *));
 static rtx attr_rtx            PVPROTO((enum rtx_code, ...));
-#ifdef HAVE_VPRINTF
 static char *attr_printf       PVPROTO((int, char *, ...));
-#else
-static char *attr_printf ();
-#endif
-
 static char *attr_string        PROTO((char *, int));
 static rtx check_attr_test     PROTO((rtx, int));
 static rtx check_attr_value    PROTO((rtx, struct attr_desc *));
-static rtx convert_set_attr_alternative PROTO((rtx, int, int, int));
-static rtx convert_set_attr    PROTO((rtx, int, int, int));
+static rtx convert_set_attr_alternative PROTO((rtx, int, int));
+static rtx convert_set_attr    PROTO((rtx, int, int));
 static void check_defs         PROTO((void));
+#if 0
 static rtx convert_const_symbol_ref PROTO((rtx, struct attr_desc *));
+#endif
 static rtx make_canonical      PROTO((struct attr_desc *, rtx));
 static struct attr_value *get_attr_value PROTO((rtx, struct attr_desc *, int));
 static rtx copy_rtx_unchanging PROTO((rtx));
@@ -399,6 +392,7 @@ static rtx identity_fn              PROTO((rtx));
 static rtx zero_fn             PROTO((rtx));
 static rtx one_fn              PROTO((rtx));
 static rtx max_fn              PROTO((rtx));
+static void write_length_unit_log PROTO ((void));
 static rtx simplify_cond       PROTO((rtx, int, int));
 #if 0
 static rtx simplify_by_alternatives PROTO((rtx, int, int));
@@ -432,6 +426,7 @@ static void gen_delay               PROTO((rtx));
 static void gen_unit           PROTO((rtx));
 static void write_test_expr    PROTO((rtx, int));
 static int max_attr_value      PROTO((rtx));
+static int or_attr_value       PROTO((rtx));
 static void walk_attr_value    PROTO((rtx));
 static void write_attr_get     PROTO((struct attr_desc *));
 static rtx eliminate_known_true PROTO((rtx, rtx, int, int));
@@ -439,6 +434,7 @@ static void write_attr_set  PROTO((struct attr_desc *, int, rtx, char *,
                                       char *, rtx, int, int));
 static void write_attr_case    PROTO((struct attr_desc *, struct attr_value *,
                                       int, char *, char *, int, rtx));
+static void write_unit_name    PROTO((char *, int, char *));
 static void write_attr_valueq  PROTO((struct attr_desc *, char *));
 static void write_attr_value   PROTO((struct attr_desc *, rtx));
 static void write_upcase       PROTO((char *));
@@ -447,6 +443,8 @@ static void write_eligible_delay PROTO((char *));
 static void write_function_unit_info PROTO((void));
 static void write_complex_function PROTO((struct function_unit *, char *,
                                          char *));
+static int write_expr_attr_cache PROTO((rtx, struct attr_desc *));
+static void write_toplevel_expr        PROTO((rtx));
 static int n_comma_elts                PROTO((char *));
 static char *next_comma_elt    PROTO((char **));
 static struct attr_desc *find_attr PROTO((char *, int));
@@ -490,7 +488,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.  */
 
@@ -540,7 +538,7 @@ attr_hash_add_string (hashcode, str)
 static rtx
 attr_rtx VPROTO((enum rtx_code code, ...))
 {
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
   enum rtx_code code;
 #endif
   va_list p;
@@ -553,7 +551,7 @@ attr_rtx VPROTO((enum rtx_code code, ...))
 
   VA_START (p, code);
 
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
   code = va_arg (p, enum rtx_code);
 #endif
 
@@ -733,13 +731,11 @@ attr_rtx VPROTO((enum rtx_code code, ...))
 
    rtx attr_printf (len, format, [arg1, ..., argn])  */
 
-#ifdef HAVE_VPRINTF
-
 /*VARARGS2*/
 static char *
 attr_printf VPROTO((register int len, char *fmt, ...))
 {
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
   register int len;
   char *fmt;
 #endif
@@ -748,7 +744,7 @@ attr_printf VPROTO((register int len, char *fmt, ...))
 
   VA_START (p, fmt);
 
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
   len = va_arg (p, int);
   fmt = va_arg (p, char *);
 #endif
@@ -761,24 +757,6 @@ attr_printf VPROTO((register int len, char *fmt, ...))
   return attr_string (str, strlen (str));
 }
 
-#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;
-
-  /* Print the string into a temporary location.  */
-  str = (char *) alloca (len);
-  sprintf (str, fmt, arg1, arg2, arg3);
-
-  return attr_string (str, strlen (str));
-}
-#endif /* not HAVE_VPRINTF */
-
 rtx
 attr_eq (name, value)
      char *name, *value;
@@ -974,12 +952,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.  */
@@ -996,7 +974,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
            {
@@ -1007,7 +985,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
@@ -1045,14 +1023,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:
@@ -1144,6 +1123,16 @@ check_attr_value (exp, attr)
       XEXP (exp, 2) = check_attr_value (XEXP (exp, 2), attr);
       break;
 
+    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");
@@ -1178,10 +1167,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;
@@ -1219,10 +1208,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;
@@ -1246,7 +1235,7 @@ 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
@@ -1279,13 +1268,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:
@@ -1303,6 +1291,7 @@ check_defs ()
     }
 }
 \f
+#if 0
 /* Given a constant SYMBOL_REF expression, convert to a COND that
    explicitly tests each enumerated value.  */
 
@@ -1353,6 +1342,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
@@ -1390,6 +1380,10 @@ 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);
@@ -1397,6 +1391,10 @@ make_canonical (attr, exp)
          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);
@@ -1410,7 +1408,6 @@ make_canonical (attr, exp)
       /* Fall through to COND case since this is now a COND.  */
 
     case COND:
-    cond:
       {
        int allsame = 1;
        rtx defval;
@@ -1634,6 +1631,7 @@ operate_exp (op, left, right)
              break;
 
            case OR_OP:
+           case ORX_OP:
              i = left_value | right_value;
              break;
 
@@ -1663,6 +1661,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)
@@ -1715,6 +1717,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)
     {
@@ -1857,19 +1866,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)
     {
-      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 (OR_OP, unitsmask, newexp);
+        }
+    }
+  else
+    {
+      /* Merge each function unit into the unit mask attributes.  */
+      for (unit = units; unit; unit = unit->next)
+        {
+          XEXP (newexp, 0) = unit->condexp;
+          XEXP (newexp, 1) = make_numeric_value (1 << unit->num);
+          unitsmask = operate_exp (ORX_OP, unitsmask, attr_copy_rtx (newexp));
+        }
     }
 
   /* 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.  */
@@ -2082,13 +2121,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"),
@@ -2352,7 +2391,7 @@ make_length_attrs ()
                              "*insn_current_length"};
   static rtx (*no_address_fn[]) PROTO((rtx)) = {identity_fn, zero_fn, zero_fn};
   static rtx (*address_fn[]) PROTO((rtx)) = {max_fn, one_fn, identity_fn};
-  int i;
+  size_t i;
   struct attr_desc *length_attr, *new_attr;
   struct attr_value *av, *new_av;
   struct insn_ent *ie, *new_ie;
@@ -2403,14 +2442,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);
 }
@@ -2421,6 +2460,26 @@ max_fn (exp)
 {
   return make_numeric_value (max_attr_value (exp));
 }
+
+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;
+
+  if (length_attr == 0)
+    return;
+  length_or = or_attr_value (length_attr->default_val->value);
+    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);
+  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
    simplified.  If any are known true or known false for the particular insn
@@ -2737,6 +2796,26 @@ 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++)
+       if (*p >= 'a' && *p <= 'z')
+         *p -= 'a' - 'A';
+      
+      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
@@ -3461,7 +3540,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;
@@ -3625,6 +3704,7 @@ find_and_mark_used_attributes (exp, terms, nterms)
          MEM_VOLATILE_P (exp) = 1;
        }
     case CONST_STRING:
+    case CONST_INT:
       return 1;
 
     case IF_THEN_ELSE:
@@ -3830,6 +3910,7 @@ simplify_with_current_value_aux (exp)
       else
        return true_rtx;
     case CONST_STRING:
+    case CONST_INT:
       return exp;
 
     case IF_THEN_ELSE:
@@ -3948,7 +4029,7 @@ 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)
@@ -4292,6 +4373,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.  */
@@ -4318,15 +4400,18 @@ gen_unit (def)
   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;
@@ -4348,7 +4433,7 @@ write_test_expr (exp, in_comparison)
     case PLUS:   case MINUS:  case MULT:     case DIV:      case MOD:
     case AND:    case IOR:    case XOR:
     case ASHIFT: case LSHIFTRT: case ASHIFTRT:
-      write_test_expr (XEXP (exp, 0), in_comparison || comparison_operator);
+      write_test_expr (XEXP (exp, 0), flags | comparison_operator);
       switch (code)
         {
        case EQ:
@@ -4397,13 +4482,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 (" || ");
@@ -4422,12 +4507,12 @@ write_test_expr (exp, in_comparison)
          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));
@@ -4441,7 +4526,7 @@ write_test_expr (exp, in_comparison)
       switch (code)
        {
        case NOT:
-         if (in_comparison)
+         if (flags & 1)
            printf ("~ ");
          else
            printf ("! ");
@@ -4456,14 +4541,14 @@ write_test_expr (exp, in_comparison)
          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)
@@ -4480,18 +4565,22 @@ write_test_expr (exp, in_comparison)
        {
          write_test_expr (evaluate_eq_attr (exp, attr->default_val->value,
                                             -2, -2),
-                          in_comparison);
+                          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 (in_comparison)
+      if (flags & 1)
        fatal ("ATTR_FLAG not valid inside comparison");
       printf ("(flags & ATTR_FLAG_%s) != 0", XSTR (exp, 0));
       break;
@@ -4513,13 +4602,13 @@ write_test_expr (exp, in_comparison)
                XSTR (exp, 1), XINT (exp, 0), GET_MODE_NAME (GET_MODE (exp)));
       break;
 
+    case MATCH_INSN:
+      printf ("%s (insn)", XSTR (exp, 0));
+      break;
+
     /* Constant integer.  */
     case CONST_INT:
-#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.  */
@@ -4533,12 +4622,25 @@ write_test_expr (exp, in_comparison)
              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:
@@ -4590,6 +4692,42 @@ max_attr_value (exp)
 
   return current_max;
 }
+
+/* Given an attribute value, return the result of ORing together all
+   CONST_STRING arguments encountered.  It is assumed that they are
+   all numeric.  */
+
+static int
+or_attr_value (exp)
+     rtx exp;
+{
+  int current_or = 0;
+  int i;
+
+  if (GET_CODE (exp) == CONST_STRING)
+    return atoi (XSTR (exp, 0));
+
+  else if (GET_CODE (exp) == COND)
+    {
+      for (i = 0; i < XVECLEN (exp, 0); i += 2)
+       {
+         current_or |= or_attr_value (XVECEXP (exp, 0, i + 1));
+       }
+
+      current_or |= or_attr_value (XEXP (exp, 1));
+    }
+
+  else if (GET_CODE (exp) == IF_THEN_ELSE)
+    {
+      current_or = or_attr_value (XEXP (exp, 1));
+      current_or |= or_attr_value (XEXP (exp, 2));
+    }
+
+  else
+    abort ();
+
+  return current_or;
+}
 \f
 /* Scan an attribute value, possibly a conditional, and record what actions
    will be required to do any conditional tests in it.
@@ -4707,17 +4845,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
@@ -4902,14 +5063,14 @@ write_attr_case (attr, av, write_case_lines, prefix, suffix, indent,
   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
@@ -4927,19 +5088,148 @@ write_attr_case (attr, av, write_case_lines, prefix, suffix, indent,
   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;
+{
+  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)
+     char *prefix;
+     int num;
+     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;
+             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
     {
@@ -5266,6 +5556,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
@@ -5375,6 +5669,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);
 }
 
@@ -5518,12 +5814,22 @@ copy_rtx_unchanging (orig)
 }
 
 static void
-fatal (s, a1, a2)
-     char *s;
-     char *a1, *a2;
+fatal VPROTO ((char *format, ...))
 {
+#ifndef ANSI_PROTOTYPES
+  char *format;
+#endif
+  va_list ap;
+
+  VA_START (ap, format);
+
+#ifndef ANSI_PROTOTYPES
+  format = va_arg (ap, char *);
+#endif
+
   fprintf (stderr, "genattrtab: ");
-  fprintf (stderr, s, a1, a2);
+  vfprintf (stderr, format, ap);
+  va_end (ap);
   fprintf (stderr, "\n");
   exit (FATAL_EXIT_CODE);
 }
@@ -5546,7 +5852,6 @@ write_const_num_delay_slots ()
   struct attr_desc *attr = find_attr ("*num_delay_slots", 0);
   struct attr_value *av;
   struct insn_ent *ie;
-  int i;
 
   if (attr)
     {
@@ -5571,7 +5876,7 @@ write_const_num_delay_slots ()
 
       printf ("    default:\n");
       printf ("      return 1;\n");
-      printf ("    }\n}\n");
+      printf ("    }\n}\n\n");
     }
 }
 
@@ -5589,7 +5894,7 @@ main (argc, argv)
   rtx tem;
   int i;
 
-#ifdef RLIMIT_STACK
+#if defined (RLIMIT_STACK) && defined (HAVE_GETRLIMIT) && defined (HAVE_SETRLIMIT)
   /* Get rid of any avoidable limit on stack size.  */
   {
     struct rlimit rlim;
@@ -5599,7 +5904,7 @@ main (argc, argv)
     rlim.rlim_cur = rlim.rlim_max;
     setrlimit (RLIMIT_STACK, &rlim);
   }
-#endif /* RLIMIT_STACK defined */
+#endif
 
   obstack_init (rtl_obstack);
   obstack_init (hash_obstack);
@@ -5687,7 +5992,7 @@ from the machine description file `md'.  */\n\n");
     expand_units ();
 
   printf ("#include \"config.h\"\n");
-  printf ("#include <stdio.h>\n");
+  printf ("#include \"system.h\"\n");
   printf ("#include \"rtl.h\"\n");
   printf ("#include \"insn-config.h\"\n");
   printf ("#include \"recog.h\"\n");
@@ -5695,6 +6000,7 @@ from the machine description file `md'.  */\n\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");
 
@@ -5735,7 +6041,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);
       }
 
@@ -5758,6 +6064,8 @@ from the machine description file `md'.  */\n\n");
   /* 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 */