varasm.c (struct rtx_const, [...]): Remove.
authorRichard Henderson <rth@redhat.com>
Fri, 30 Jan 2004 19:16:39 +0000 (11:16 -0800)
committerRichard Henderson <rth@gcc.gnu.org>
Fri, 30 Jan 2004 19:16:39 +0000 (11:16 -0800)
        * varasm.c (struct rtx_const, struct pool_constant): Remove.
        (MAX_RTX_HASH_TABLE): Remove.
        (const_rtx_hash_table, const_rtx_sym_hash_table): Remove.
        (first_pool, last_pool, pool_offset): Remove.
        (struct rtx_constant_pool): Split out from ...
        (struct varasm_status): ... here.  Reference one via pointer.
        (struct constant_descriptor_rtx): Merge struct pool_constant.
        (SYMHASH): Remove.
        (decode_rtx_const): Remove.
        (const_hash_rtx, compare_constant_rtx): Remove.
        (record_constant_rtx): Remove.
        (const_desc_rtx_hash, const_desc_rtx_eq): New.
        (const_desc_rtx_sym_hash, const_desc_rtx_sym_eq): New.
        (const_rtx_hash_1, const_rtx_hash): New.
        (init_varasm_status): Allocate a rtx_constant_pool, and its hashes.
        (simplify_subtraction): Use simplify_rtx.
        (force_const_mem): Rewrite to use new data structures.
        (find_pool_constant): Likewise.
        (get_pool_constant, get_pool_constant_mark,
        get_pool_constant_for_function, get_pool_mode,
        get_pool_mode_for_function, get_pool_offset, get_pool_size): Likewise.
        (output_constant_pool_2): Split out from output_constant_pool.
        (output_constant_pool_1): Likewise.  Use new pool datastructures.
        (output_constant_pool): Zap entire pool datastructure.
        (mark_constant): Use new pool datastructures.
        (mark_constants): Use for_each_rtx.
        (mark_constant_pool): Use new pool datastructures.

From-SVN: r76985

gcc/ChangeLog
gcc/varasm.c

index 11c3060..b566b71 100644 (file)
@@ -1,3 +1,33 @@
+2004-01-30  Richard Henderson  <rth@redhat.com>
+
+       * varasm.c (struct rtx_const, struct pool_constant): Remove.
+       (MAX_RTX_HASH_TABLE): Remove.
+       (const_rtx_hash_table, const_rtx_sym_hash_table): Remove.
+       (first_pool, last_pool, pool_offset): Remove.
+       (struct rtx_constant_pool): Split out from ...
+       (struct varasm_status): ... here.  Reference one via pointer.
+       (struct constant_descriptor_rtx): Merge struct pool_constant.
+       (SYMHASH): Remove.
+       (decode_rtx_const): Remove.
+       (const_hash_rtx, compare_constant_rtx): Remove.
+       (record_constant_rtx): Remove.
+       (const_desc_rtx_hash, const_desc_rtx_eq): New.
+       (const_desc_rtx_sym_hash, const_desc_rtx_sym_eq): New.
+       (const_rtx_hash_1, const_rtx_hash): New.
+       (init_varasm_status): Allocate a rtx_constant_pool, and its hashes.
+       (simplify_subtraction): Use simplify_rtx.
+       (force_const_mem): Rewrite to use new data structures.
+       (find_pool_constant): Likewise.
+       (get_pool_constant, get_pool_constant_mark,
+       get_pool_constant_for_function, get_pool_mode,
+       get_pool_mode_for_function, get_pool_offset, get_pool_size): Likewise.
+       (output_constant_pool_2): Split out from output_constant_pool.
+       (output_constant_pool_1): Likewise.  Use new pool datastructures.
+       (output_constant_pool): Zap entire pool datastructure.
+       (mark_constant): Use new pool datastructures.
+       (mark_constants): Use for_each_rtx.
+       (mark_constant_pool): Use new pool datastructures.
+
 2004-01-30  Fariborz Jahanian <fjahanian@apple.com>
         
         * config/rs6000/rs6000.c (rs6000_emit_move): Remove #if 0. 
index 7af71bf..f9acb38 100644 (file)
@@ -69,44 +69,18 @@ const char *weak_global_object_name;
 
 struct addr_const;
 struct constant_descriptor_rtx;
-struct rtx_const;
-struct pool_constant;
-
-#define MAX_RTX_HASH_TABLE 61
+struct rtx_constant_pool;
 
 struct varasm_status GTY(())
 {
-  /* Hash facility for making memory-constants
-     from constant rtl-expressions.  It is used on RISC machines
-     where immediate integer arguments and constant addresses are restricted
-     so that such constants must be stored in memory.
-
-     This pool of constants is reinitialized for each function
-     so each function gets its own constants-pool that comes right before
-     it.  */
-  struct constant_descriptor_rtx ** GTY ((length ("MAX_RTX_HASH_TABLE")))
-    x_const_rtx_hash_table;
-  struct pool_constant ** GTY ((length ("MAX_RTX_HASH_TABLE")))
-    x_const_rtx_sym_hash_table;
-
-  /* Pointers to first and last constant in pool.  */
-  struct pool_constant *x_first_pool;
-  struct pool_constant *x_last_pool;
-
-  /* Current offset in constant pool (does not include any machine-specific
-     header).  */
-  HOST_WIDE_INT x_pool_offset;
+  /* If we're using a per-function constant pool, this is it.  */
+  struct rtx_constant_pool *pool;
 
   /* Number of tree-constants deferred during the expansion of this
      function.  */
   unsigned int deferred_constants;
 };
 
-#define const_rtx_hash_table (cfun->varasm->x_const_rtx_hash_table)
-#define const_rtx_sym_hash_table (cfun->varasm->x_const_rtx_sym_hash_table)
-#define first_pool (cfun->varasm->x_first_pool)
-#define last_pool (cfun->varasm->x_last_pool)
-#define pool_offset (cfun->varasm->x_pool_offset)
 #define n_deferred_constants (cfun->varasm->deferred_constants)
 
 /* Number for making the label on the next
@@ -147,16 +121,6 @@ static hashval_t const_hash_1 (const tree);
 static int compare_constant (const tree, const tree);
 static tree copy_constant (tree);
 static void output_constant_def_contents (rtx);
-static void decode_rtx_const (enum machine_mode, rtx, struct rtx_const *);
-static unsigned int const_hash_rtx (enum machine_mode, rtx);
-static int compare_constant_rtx (enum machine_mode, rtx,
-                                struct constant_descriptor_rtx *);
-static struct constant_descriptor_rtx * record_constant_rtx
-  (enum machine_mode, rtx);
-static struct pool_constant *find_pool_constant (struct function *, rtx);
-static void mark_constant_pool (void);
-static void mark_constants (rtx);
-static int mark_constant (rtx *current_rtx, void *data);
 static void output_addressed_constants (tree);
 static unsigned HOST_WIDE_INT array_size_for_constructor (tree);
 static unsigned min_align (unsigned, unsigned);
@@ -2025,36 +1989,6 @@ decode_addr_const (tree exp, struct addr_const *value)
   value->offset = offset;
 }
 \f
-/* We do RTX_UNSPEC + XINT (blah), so nothing can go after RTX_UNSPEC.  */
-enum kind { RTX_UNKNOWN, RTX_DOUBLE, RTX_VECTOR, RTX_INT, RTX_UNSPEC };
-struct rtx_const GTY(())
-{
-  ENUM_BITFIELD(kind) kind : 16;
-  ENUM_BITFIELD(machine_mode) mode : 16;
-  union rtx_const_un {
-    REAL_VALUE_TYPE GTY ((tag ("4"))) du;
-    struct rtx_const_u_addr {
-      rtx base;
-      const char *symbol;
-      HOST_WIDE_INT offset;
-    } GTY ((tag ("1"))) addr;
-    struct rtx_const_u_di {
-      HOST_WIDE_INT high;
-      HOST_WIDE_INT low;
-    } GTY ((tag ("0"))) di;
-
-    /* The max vector size we have is 16 wide; two variants for
-       integral and floating point vectors.  */
-    struct rtx_const_int_vec {
-      HOST_WIDE_INT high;
-      HOST_WIDE_INT low;
-    } GTY ((tag ("2"))) int_vec[16];
-
-    REAL_VALUE_TYPE GTY ((tag ("3"))) fp_vec[8];
-
-  } GTY ((desc ("%1.kind >= RTX_INT"), descbits ("1"))) un;
-};
-
 /* Uniquize all constants that appear in memory.
    Each constant in memory thus far output is recorded
    in `const_desc_table'.  */
@@ -2612,314 +2546,189 @@ lookup_constant_def (tree exp)
 \f
 /* Used in the hash tables to avoid outputting the same constant
    twice.  Unlike 'struct constant_descriptor_tree', RTX constants
-   are output once per function, not once per file; there seems
-   to be no reason for the difference.  */
-
-struct constant_descriptor_rtx GTY(())
-{
-  /* More constant_descriptors with the same hash code.  */
-  struct constant_descriptor_rtx *next;
-
-  /* A MEM for the constant.  */
-  rtx rtl;
-
-  /* The value of the constant.  */
-  struct rtx_const value;
+   are output once per function, not once per file.  */
+/* ??? Only a few targets need per-function constant pools.  Most
+   can use one per-file pool.  Should add a targetm bit to tell the
+   difference.  */
+
+struct rtx_constant_pool GTY(())
+{
+  /* Pointers to first and last constant in pool, as ordered by offset.  */
+  struct constant_descriptor_rtx *first;
+  struct constant_descriptor_rtx *last;
+
+  /* Hash facility for making memory-constants from constant rtl-expressions.
+     It is used on RISC machines where immediate integer arguments and
+     constant addresses are restricted so that such constants must be stored
+     in memory.  */
+  htab_t GTY((param_is (struct constant_descriptor_rtx))) const_rtx_htab;
+  htab_t GTY((param_is (struct constant_descriptor_rtx))) const_rtx_sym_htab;
+
+  /* Current offset in constant pool (does not include any
+     machine-specific header).  */
+  HOST_WIDE_INT offset;
 };
 
-/* Structure to represent sufficient information about a constant so that
-   it can be output when the constant pool is output, so that function
-   integration can be done, and to simplify handling on machines that reference
-   constant pool as base+displacement.  */
-
-struct pool_constant GTY(())
+struct constant_descriptor_rtx GTY((chain_next ("%h.next")))
 {
-  struct constant_descriptor_rtx *desc;
-  struct pool_constant *next;
-  struct pool_constant *next_sym;
+  struct constant_descriptor_rtx *next;
+  rtx mem;
+  rtx sym;
   rtx constant;
+  HOST_WIDE_INT offset;
+  hashval_t hash;
   enum machine_mode mode;
-  int labelno;
   unsigned int align;
-  HOST_WIDE_INT offset;
+  int labelno;
   int mark;
 };
 
-/* Hash code for a SYMBOL_REF with CONSTANT_POOL_ADDRESS_P true.
-   The argument is XSTR (... , 0)  */
+/* Hash and compare functions for const_rtx_htab.  */
 
-#define SYMHASH(LABEL) (((unsigned long) (LABEL)) % MAX_RTX_HASH_TABLE)
-\f
-/* Initialize constant pool hashing for a new function.  */
+static hashval_t
+const_desc_rtx_hash (const void *ptr)
+{
+  const struct constant_descriptor_rtx *desc = ptr;
+  return desc->hash;
+}
 
-void
-init_varasm_status (struct function *f)
+static int
+const_desc_rtx_eq (const void *a, const void *b)
 {
-  struct varasm_status *p;
-  p = ggc_alloc (sizeof (struct varasm_status));
-  f->varasm = p;
-  p->x_const_rtx_hash_table
-    = ggc_alloc_cleared (MAX_RTX_HASH_TABLE
-                        * sizeof (struct constant_descriptor_rtx *));
-  p->x_const_rtx_sym_hash_table
-    = ggc_alloc_cleared (MAX_RTX_HASH_TABLE
-                        * sizeof (struct pool_constant *));
-
-  p->x_first_pool = p->x_last_pool = 0;
-  p->x_pool_offset = 0;
-  p->deferred_constants = 0;
+  const struct constant_descriptor_rtx *x = a;
+  const struct constant_descriptor_rtx *y = b;
+
+  if (x->mode != y->mode)
+    return 0;
+  return rtx_equal_p (x->constant, y->constant);
 }
-\f
 
-/* Express an rtx for a constant integer (perhaps symbolic)
-   as the sum of a symbol or label plus an explicit integer.
-   They are stored into VALUE.  */
+/* Hash and compare functions for const_rtx_sym_htab.  */
 
-static void
-decode_rtx_const (enum machine_mode mode, rtx x, struct rtx_const *value)
+static hashval_t
+const_desc_rtx_sym_hash (const void *ptr)
 {
-  /* Clear the whole structure, including any gaps.  */
-  memset (value, 0, sizeof (struct rtx_const));
+  const struct constant_descriptor_rtx *desc = ptr;
+  return htab_hash_string (XSTR (desc->sym, 0));
+}
 
-  value->kind = RTX_INT;       /* Most usual kind.  */
-  value->mode = mode;
+static int
+const_desc_rtx_sym_eq (const void *a, const void *b)
+{
+  const struct constant_descriptor_rtx *x = a;
+  const struct constant_descriptor_rtx *y = b;
+  return x->sym == y->sym;
+}
 
-  switch (GET_CODE (x))
-    {
-    case CONST_DOUBLE:
-      value->kind = RTX_DOUBLE;
-      if (GET_MODE (x) != VOIDmode)
-       {
-         const REAL_VALUE_TYPE *r = CONST_DOUBLE_REAL_VALUE (x);
+/* This is the worker function for const_rtx_hash, called via for_each_rtx.  */
 
-         value->mode = GET_MODE (x);
+static int
+const_rtx_hash_1 (rtx *xp, void *data)
+{
+  unsigned HOST_WIDE_INT hwi;
+  enum machine_mode mode;
+  enum rtx_code code;
+  hashval_t h, *hp;
+  rtx x;
 
-         /* Copy the REAL_VALUE_TYPE by members so that we don't
-            copy garbage from the original structure into our
-            carefully cleaned hashing structure.  */
-         value->un.du.class = r->class;
-         value->un.du.sign = r->sign;
-         switch (r->class)
-           {
-           case rvc_zero:
-           case rvc_inf:
-             break;
-           case rvc_normal:
-             value->un.du.exp = r->exp;
-             /* Fall through.  */
-           case rvc_nan:
-             memcpy (value->un.du.sig, r->sig, sizeof (r->sig));
-             break;
-           default:
-             abort ();
-           }
-       }
-      else
-       {
-         value->un.di.low = CONST_DOUBLE_LOW (x);
-         value->un.di.high = CONST_DOUBLE_HIGH (x);
-       }
-      break;
+  x = *xp;
+  code = GET_CODE (x);
+  mode = GET_MODE (x);
+  h = (hashval_t) code * 1048573 + mode;
 
-    case CONST_VECTOR:
+  switch (code)
+    {
+    case CONST_INT:
+      hwi = INTVAL (x);
+    fold_hwi:
       {
-       int units, i;
+       const int shift = sizeof (hashval_t) * CHAR_BIT;
+       const int n = sizeof (HOST_WIDE_INT) / sizeof (hashval_t);
+       int i;
 
-       units = CONST_VECTOR_NUNITS (x);
-       value->kind = RTX_VECTOR;
-       value->mode = mode;
-
-       if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT)
-         {
-           for (i = 0; i < units; ++i)
-             {
-               rtx elt = CONST_VECTOR_ELT (x, i);
-               if (GET_CODE (elt) == CONST_INT)
-                 {
-                   value->un.int_vec[i].low = INTVAL (elt);
-                   value->un.int_vec[i].high = 0;
-                 }
-               else
-                 {
-                   value->un.int_vec[i].low = CONST_DOUBLE_LOW (elt);
-                   value->un.int_vec[i].high = CONST_DOUBLE_HIGH (elt);
-                 }
-             }
-         }
-       else if (GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
+       h ^= (hashval_t) hwi;
+       for (i = 1; i < n; ++i)
          {
-           for (i = 0; i < units; ++i)
-             {
-               const REAL_VALUE_TYPE *r
-                 = CONST_DOUBLE_REAL_VALUE (CONST_VECTOR_ELT (x, i));
-               REAL_VALUE_TYPE *d = &value->un.fp_vec[i];
-
-               /* Copy the REAL_VALUE_TYPE by members so that we don't
-                  copy garbage from the original structure into our
-                  carefully cleaned hashing structure.  */
-               d->class = r->class;
-               d->sign = r->sign;
-               switch (r->class)
-                 {
-                 case rvc_zero:
-                 case rvc_inf:
-                   break;
-                 case rvc_normal:
-                   d->exp = r->exp;
-                   /* Fall through.  */
-                 case rvc_nan:
-                   memcpy (d->sig, r->sig, sizeof (r->sig));
-                   break;
-                 default:
-                   abort ();
-                 }
-             }
+           hwi >>= shift;
+           h ^= (hashval_t) hwi;
          }
-       else
-         abort ();
       }
       break;
 
-    case CONST_INT:
-      value->un.addr.offset = INTVAL (x);
+    case CONST_DOUBLE:
+      if (mode == VOIDmode)
+       {
+         hwi = CONST_DOUBLE_LOW (x) ^ CONST_DOUBLE_HIGH (x);
+         goto fold_hwi;
+       }
+      else
+       h ^= real_hash (CONST_DOUBLE_REAL_VALUE (x));
       break;
 
     case SYMBOL_REF:
+      h ^= htab_hash_string (XSTR (x, 0));
+      break;
+
     case LABEL_REF:
-    case PC:
-      value->un.addr.base = x;
+      h = h * 251 + CODE_LABEL_NUMBER (XEXP (x, 0));
       break;
 
-    case CONST:
-      x = XEXP (x, 0);
-      if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
-       {
-         value->un.addr.base = XEXP (x, 0);
-         value->un.addr.offset = INTVAL (XEXP (x, 1));
-       }
-      else if (GET_CODE (x) == MINUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
-       {
-         value->un.addr.base = XEXP (x, 0);
-         value->un.addr.offset = - INTVAL (XEXP (x, 1));
-       }
-      else
-       {
-         value->un.addr.base = x;
-         value->un.addr.offset = 0;
-       }
+    case UNSPEC:
+    case UNSPEC_VOLATILE:
+      h = h * 251 + XINT (x, 1);
       break;
 
     default:
-      value->kind = RTX_UNKNOWN;
       break;
     }
 
-  if (value->kind == RTX_INT && value->un.addr.base != 0
-      && GET_CODE (value->un.addr.base) == UNSPEC)
-    {
-      /* For a simple UNSPEC, the base is set to the
-        operand, the kind field is set to the index of
-        the unspec expression.
-        Together with the code below, in case that
-        the operand is a SYMBOL_REF or LABEL_REF,
-        the address of the string or the code_label
-        is taken as base.  */
-      if (XVECLEN (value->un.addr.base, 0) == 1)
-       {
-         value->kind = RTX_UNSPEC + XINT (value->un.addr.base, 1);
-         value->un.addr.base = XVECEXP (value->un.addr.base, 0, 0);
-       }
-    }
-
-  if (value->kind >= RTX_INT && value->un.addr.base != 0)
-    switch (GET_CODE (value->un.addr.base))
-      {
-      case SYMBOL_REF:
-       /* Use the string's address, not the SYMBOL_REF's address,
-          for the sake of addresses of library routines.  */
-       value->un.addr.symbol = XSTR (value->un.addr.base, 0);
-       value->un.addr.base = NULL_RTX;
-       break;
-
-      case LABEL_REF:
-       /* For a LABEL_REF, compare labels.  */
-       value->un.addr.base = XEXP (value->un.addr.base, 0);
-
-      default:
-       break;
-      }
+  hp = data;
+  *hp = *hp * 509 + h;
+  return 0;
 }
 
-/* Given a MINUS expression, simplify it if both sides
-   include the same symbol.  */
+/* Compute a hash value for X, which should be a constant.  */
 
-rtx
-simplify_subtraction (rtx x)
+static hashval_t
+const_rtx_hash (rtx x)
 {
-  struct rtx_const val0, val1;
-
-  decode_rtx_const (GET_MODE (x), XEXP (x, 0), &val0);
-  decode_rtx_const (GET_MODE (x), XEXP (x, 1), &val1);
-
-  if (val0.kind >= RTX_INT
-      && val0.kind == val1.kind
-      && val0.un.addr.base == val1.un.addr.base
-      && val0.un.addr.symbol == val1.un.addr.symbol)
-    return GEN_INT (val0.un.addr.offset - val1.un.addr.offset);
-
-  return x;
+  hashval_t h = 0;
+  for_each_rtx (&x, const_rtx_hash_1, &h);
+  return h;
 }
 
-/* Compute a hash code for a constant RTL expression.  */
+\f
+/* Initialize constant pool hashing for a new function.  */
 
-static unsigned int
-const_hash_rtx (enum machine_mode mode, rtx x)
+void
+init_varasm_status (struct function *f)
 {
-  union {
-    struct rtx_const value;
-    unsigned int data[sizeof(struct rtx_const) / sizeof (unsigned int)];
-  } u;
-
-  unsigned int hi;
-  size_t i;
-
-  decode_rtx_const (mode, x, &u.value);
-
-  /* Compute hashing function.  */
-  hi = 0;
-  for (i = 0; i < ARRAY_SIZE (u.data); i++)
-    hi = hi * 613 + u.data[i];
-
-  return hi % MAX_RTX_HASH_TABLE;
-}
-
-/* Compare a constant rtl object X with a constant-descriptor DESC.
-   Return 1 if DESC describes a constant with the same value as X.  */
+  struct varasm_status *p;
+  struct rtx_constant_pool *pool;
 
-static int
-compare_constant_rtx (enum machine_mode mode, rtx x,
-                     struct constant_descriptor_rtx *desc)
-{
-  struct rtx_const value;
+  p = ggc_alloc (sizeof (struct varasm_status));
+  f->varasm = p;
 
-  decode_rtx_const (mode, x, &value);
+  pool = ggc_alloc (sizeof (struct rtx_constant_pool));
+  p->pool = pool;
+  p->deferred_constants = 0;
 
-  /* Compare constant contents.  */
-  return memcmp (&value, &desc->value, sizeof (struct rtx_const)) == 0;
+  pool->const_rtx_htab = htab_create_ggc (31, const_desc_rtx_hash,
+                                         const_desc_rtx_eq, NULL);
+  pool->const_rtx_sym_htab = htab_create_ggc (31, const_desc_rtx_sym_hash,
+                                             const_desc_rtx_sym_eq, NULL);
+  pool->first = pool->last = NULL;
+  pool->offset = 0;
 }
+\f
+/* Given a MINUS expression, simplify it if both sides
+   include the same symbol.  */
 
-/* Construct a constant descriptor for the rtl-expression X.
-   It is up to the caller to enter the descriptor in the hash table.  */
-
-static struct constant_descriptor_rtx *
-record_constant_rtx (enum machine_mode mode, rtx x)
+rtx
+simplify_subtraction (rtx x)
 {
-  struct constant_descriptor_rtx *ptr;
-
-  ptr = ggc_alloc (sizeof (*ptr));
-  decode_rtx_const (mode, x, &ptr->value);
-
-  return ptr;
+  rtx r = simplify_rtx (x);
+  return r ? r : x;
 }
 \f
 /* Given a constant rtx X, make (or find) a memory constant for its value
@@ -2928,30 +2737,32 @@ record_constant_rtx (enum machine_mode mode, rtx x)
 rtx
 force_const_mem (enum machine_mode mode, rtx x)
 {
-  int hash;
-  struct constant_descriptor_rtx *desc;
+  struct constant_descriptor_rtx *desc, tmp;
+  struct rtx_constant_pool *pool = cfun->varasm->pool;
   char label[256];
   rtx def, symbol;
-  struct pool_constant *pool;
+  hashval_t hash;
   unsigned int align;
+  void **slot;
 
   /* If we're not allowed to drop X into the constant pool, don't.  */
   if ((*targetm.cannot_force_const_mem) (x))
     return NULL_RTX;
 
-  /* Compute hash code of X.  Search the descriptors for that hash code
-     to see if any of them describes X.  If yes, we have an rtx to use.  */
-  hash = const_hash_rtx (mode, x);
-  for (desc = const_rtx_hash_table[hash]; desc; desc = desc->next)
-    if (compare_constant_rtx (mode, x, desc))
-      return copy_rtx (desc->rtl);
-
-  /* No constant equal to X is known to have been output.
-     Make a constant descriptor to enter X in the hash table
-     and make a MEM for it.  */
-  desc = record_constant_rtx (mode, x);
-  desc->next = const_rtx_hash_table[hash];
-  const_rtx_hash_table[hash] = desc;
+  /* Lookup the value in the hashtable.  */
+  tmp.constant = x;
+  tmp.mode = mode;
+  hash = const_rtx_hash (x);
+  slot = htab_find_slot_with_hash (pool->const_rtx_htab, &tmp, hash, INSERT);
+  desc = *slot;
+  
+  /* If the constant was already present, return its memory.  */
+  if (desc)
+    return copy_rtx (desc->mem);
+
+  /* Otherwise, create a new descriptor.  */
+  desc = ggc_alloc (sizeof (*desc));
+  *slot = desc;
 
   /* Align the location counter as required by EXP's data type.  */
   align = GET_MODE_ALIGNMENT (mode == VOIDmode ? word_mode : mode);
@@ -2963,73 +2774,64 @@ force_const_mem (enum machine_mode mode, rtx x)
   }
 #endif
 
-  pool_offset += (align / BITS_PER_UNIT) - 1;
-  pool_offset &= ~ ((align / BITS_PER_UNIT) - 1);
-
-  if (GET_CODE (x) == LABEL_REF)
-    LABEL_PRESERVE_P (XEXP (x, 0)) = 1;
-
-  /* Allocate a pool constant descriptor, fill it in, and chain it in.  */
-  pool = ggc_alloc (sizeof (struct pool_constant));
-  pool->desc = desc;
-  pool->constant = x;
-  pool->mode = mode;
-  pool->labelno = const_labelno;
-  pool->align = align;
-  pool->offset = pool_offset;
-  pool->mark = 1;
-  pool->next = 0;
-
-  if (last_pool == 0)
-    first_pool = pool;
+  pool->offset += (align / BITS_PER_UNIT) - 1;
+  pool->offset &= ~ ((align / BITS_PER_UNIT) - 1);
+
+  desc->next = NULL;
+  desc->constant = tmp.constant;
+  desc->offset = pool->offset;
+  desc->hash = hash;
+  desc->mode = mode;
+  desc->align = align;
+  desc->labelno = const_labelno;
+  desc->mark = 0;
+
+  pool->offset += GET_MODE_SIZE (mode);
+  if (pool->last)
+    pool->last->next = desc;
   else
-    last_pool->next = pool;
-
-  last_pool = pool;
-  pool_offset += GET_MODE_SIZE (mode);
+    pool->first = pool->last = desc;
+  pool->last = desc;
 
   /* Create a string containing the label name, in LABEL.  */
   ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
-
   ++const_labelno;
 
-  /* Construct the SYMBOL_REF and the MEM.  */
-
-  symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label));
+  /* Construct the SYMBOL_REF.  Make sure to mark it as belonging to
+     the constants pool.  */
+  desc->sym = symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label));
   SYMBOL_REF_FLAGS (symbol) = SYMBOL_FLAG_LOCAL;
+  CONSTANT_POOL_ADDRESS_P (symbol) = 1;
+  current_function_uses_const_pool = 1;
+
+  /* Insert the descriptor into the symbol cross-reference table too.  */
+  slot = htab_find_slot (pool->const_rtx_sym_htab, desc, INSERT);
+  if (*slot)
+    abort ();
+  *slot = desc;
 
-  pool->desc->rtl = def = gen_rtx_MEM (mode, symbol);
+  /* Construct the MEM.  */
+  desc->mem = def = gen_rtx_MEM (mode, symbol);
   set_mem_attributes (def, (*lang_hooks.types.type_for_mode) (mode, 0), 1);
   RTX_UNCHANGING_P (def) = 1;
 
-  /* Add label to symbol hash table.  */
-  hash = SYMHASH (XSTR (symbol, 0));
-  pool->next_sym = const_rtx_sym_hash_table[hash];
-  const_rtx_sym_hash_table[hash] = pool;
-
-  /* Mark the symbol_ref as belonging to this constants pool.  */
-  CONSTANT_POOL_ADDRESS_P (symbol) = 1;
-  SYMBOL_REF_FLAGS (symbol) = SYMBOL_FLAG_LOCAL;
-  current_function_uses_const_pool = 1;
+  /* If we're dropping a label to the constant pool, make sure we
+     don't delete it.  */
+  if (GET_CODE (x) == LABEL_REF)
+    LABEL_PRESERVE_P (XEXP (x, 0)) = 1;
 
   return copy_rtx (def);
 }
 \f
 /* Given a SYMBOL_REF with CONSTANT_POOL_ADDRESS_P true, return a pointer to
-   the corresponding pool_constant structure.  */
+   the corresponding constant_descriptor_rtx structure.  */
 
-static struct pool_constant *
-find_pool_constant (struct function *f, rtx addr)
+static struct constant_descriptor_rtx *
+find_pool_constant (struct rtx_constant_pool *pool, rtx sym)
 {
-  struct pool_constant *pool;
-  const char *label = XSTR (addr, 0);
-
-  for (pool = f->varasm->x_const_rtx_sym_hash_table[SYMHASH (label)]; pool;
-       pool = pool->next_sym)
-    if (XSTR (XEXP (pool->desc->rtl, 0), 0) == label)
-      return pool;
-
-  abort ();
+  struct constant_descriptor_rtx tmp;
+  tmp.sym = sym;
+  return htab_find (pool->const_rtx_sym_htab, &tmp);
 }
 
 /* Given a constant pool SYMBOL_REF, return the corresponding constant.  */
@@ -3037,7 +2839,7 @@ find_pool_constant (struct function *f, rtx addr)
 rtx
 get_pool_constant (rtx addr)
 {
-  return (find_pool_constant (cfun, addr))->constant;
+  return find_pool_constant (cfun->varasm->pool, addr)->constant;
 }
 
 /* Given a constant pool SYMBOL_REF, return the corresponding constant
@@ -3046,9 +2848,11 @@ get_pool_constant (rtx addr)
 rtx
 get_pool_constant_mark (rtx addr, bool *pmarked)
 {
-  struct pool_constant *pool = find_pool_constant (cfun, addr);
-  *pmarked = (pool->mark != 0);
-  return pool->constant;
+  struct constant_descriptor_rtx *desc;
+
+  desc = find_pool_constant (cfun->varasm->pool, addr);
+  *pmarked = (desc->mark != 0);
+  return desc->constant;
 }
 
 /* Likewise, but for the constant pool of a specific function.  */
@@ -3056,7 +2860,7 @@ get_pool_constant_mark (rtx addr, bool *pmarked)
 rtx
 get_pool_constant_for_function (struct function *f, rtx addr)
 {
-  return (find_pool_constant (f, addr))->constant;
+  return find_pool_constant (f->varasm->pool, addr)->constant;
 }
 
 /* Similar, return the mode.  */
@@ -3064,13 +2868,13 @@ get_pool_constant_for_function (struct function *f, rtx addr)
 enum machine_mode
 get_pool_mode (rtx addr)
 {
-  return (find_pool_constant (cfun, addr))->mode;
+  return find_pool_constant (cfun->varasm->pool, addr)->mode;
 }
 
 enum machine_mode
 get_pool_mode_for_function (struct function *f, rtx addr)
 {
-  return (find_pool_constant (f, addr))->mode;
+  return find_pool_constant (f->varasm->pool, addr)->mode;
 }
 
 /* Similar, return the offset in the constant pool.  */
@@ -3078,7 +2882,7 @@ get_pool_mode_for_function (struct function *f, rtx addr)
 int
 get_pool_offset (rtx addr)
 {
-  return (find_pool_constant (cfun, addr))->offset;
+  return find_pool_constant (cfun->varasm->pool, addr)->offset;
 }
 
 /* Return the size of the constant pool.  */
@@ -3086,295 +2890,243 @@ get_pool_offset (rtx addr)
 int
 get_pool_size (void)
 {
-  return pool_offset;
+  return cfun->varasm->pool->offset;
 }
 \f
-/* Write all the constants in the constant pool.  */
+/* Worker function for output_constant_pool_1.  Emit assembly for X
+   in MODE with known alignment ALIGN.  */
 
-void
-output_constant_pool (const char *fnname ATTRIBUTE_UNUSED,
-                     tree fndecl ATTRIBUTE_UNUSED)
+static void
+output_constant_pool_2 (enum machine_mode mode, rtx x, unsigned int align)
 {
-  struct pool_constant *pool;
-  rtx x;
-  REAL_VALUE_TYPE r;
-
-  /* It is possible for gcc to call force_const_mem and then to later
-     discard the instructions which refer to the constant.  In such a
-     case we do not need to output the constant.  */
-  mark_constant_pool ();
-
-#ifdef ASM_OUTPUT_POOL_PROLOGUE
-  ASM_OUTPUT_POOL_PROLOGUE (asm_out_file, fnname, fndecl, pool_offset);
-#endif
-
-  for (pool = first_pool; pool; pool = pool->next)
+  switch (GET_MODE_CLASS (mode))
     {
-      rtx tmp;
-
-      x = pool->constant;
-
-      if (! pool->mark)
-       continue;
-
-      /* See if X is a LABEL_REF (or a CONST referring to a LABEL_REF)
-        whose CODE_LABEL has been deleted.  This can occur if a jump table
-        is eliminated by optimization.  If so, write a constant of zero
-        instead.  Note that this can also happen by turning the
-        CODE_LABEL into a NOTE.  */
-      /* ??? This seems completely and utterly wrong.  Certainly it's
-        not true for NOTE_INSN_DELETED_LABEL, but I disbelieve proper
-        functioning even with INSN_DELETED_P and friends.  */
-
-      tmp = x;
-      switch (GET_CODE (x))
+    case MODE_FLOAT:
+      if (GET_CODE (x) != CONST_DOUBLE)
+       abort ();
+      else
        {
-       case CONST:
-         if (GET_CODE (XEXP (x, 0)) != PLUS
-             || GET_CODE (XEXP (XEXP (x, 0), 0)) != LABEL_REF)
-           break;
-         tmp = XEXP (XEXP (x, 0), 0);
-         /* Fall through.  */
-
-       case LABEL_REF:
-         tmp = XEXP (x, 0);
-         if (INSN_DELETED_P (tmp)
-             || (GET_CODE (tmp) == NOTE
-                 && NOTE_LINE_NUMBER (tmp) == NOTE_INSN_DELETED))
-           {
-             abort ();
-             x = const0_rtx;
-           }
-         break;
-
-       default:
-         break;
+         REAL_VALUE_TYPE r;
+         REAL_VALUE_FROM_CONST_DOUBLE (r, x);
+         assemble_real (r, mode, align);
        }
+      break;
 
-      /* First switch to correct section.  */
-      (*targetm.asm_out.select_rtx_section) (pool->mode, x, pool->align);
-
-#ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
-      ASM_OUTPUT_SPECIAL_POOL_ENTRY (asm_out_file, x, pool->mode,
-                                    pool->align, pool->labelno, done);
-#endif
-
-      assemble_align (pool->align);
-
-      /* Output the label.  */
-      (*targetm.asm_out.internal_label) (asm_out_file, "LC", pool->labelno);
-
-      /* Output the value of the constant itself.  */
-      switch (GET_MODE_CLASS (pool->mode))
-       {
-       case MODE_FLOAT:
-         if (GET_CODE (x) != CONST_DOUBLE)
-           abort ();
+    case MODE_INT:
+    case MODE_PARTIAL_INT:
+      assemble_integer (x, GET_MODE_SIZE (mode), align, 1);
+      break;
 
-         REAL_VALUE_FROM_CONST_DOUBLE (r, x);
-         assemble_real (r, pool->mode, pool->align);
-         break;
+    case MODE_VECTOR_FLOAT:
+    case MODE_VECTOR_INT:
+      {
+       int i, units;
+        enum machine_mode submode = GET_MODE_INNER (mode);
+       unsigned int subalign = MIN (align, GET_MODE_BITSIZE (submode));
 
-       case MODE_INT:
-       case MODE_PARTIAL_INT:
-         assemble_integer (x, GET_MODE_SIZE (pool->mode), pool->align, 1);
-         break;
+       if (GET_CODE (x) != CONST_VECTOR)
+         abort ();
+       units = CONST_VECTOR_NUNITS (x);
 
-       case MODE_VECTOR_FLOAT:
+       for (i = 0; i < units; i++)
          {
-           int i, units;
-           rtx elt;
-
-           if (GET_CODE (x) != CONST_VECTOR)
-             abort ();
-
-           units = CONST_VECTOR_NUNITS (x);
-
-           for (i = 0; i < units; i++)
-             {
-               elt = CONST_VECTOR_ELT (x, i);
-               REAL_VALUE_FROM_CONST_DOUBLE (r, elt);
-               assemble_real (r, GET_MODE_INNER (pool->mode), pool->align);
-             }
+           rtx elt = CONST_VECTOR_ELT (x, i);
+           output_constant_pool_2 (submode, elt, i ? subalign : align);
          }
-         break;
+      }
+      break;
 
-       case MODE_VECTOR_INT:
-         {
-           int i, units;
-           rtx elt;
+    default:
+      abort ();
+    }
+}
 
-           if (GET_CODE (x) != CONST_VECTOR)
-             abort ();
+/* Worker function for output_constant_pool.  Emit POOL.  */
 
-           units = CONST_VECTOR_NUNITS (x);
+static void
+output_constant_pool_1 (struct constant_descriptor_rtx *desc)
+{
+  rtx x, tmp;
 
-           for (i = 0; i < units; i++)
-             {
-               elt = CONST_VECTOR_ELT (x, i);
-               assemble_integer (elt, GET_MODE_UNIT_SIZE (pool->mode),
-                                 pool->align, 1);
-             }
-         }
-         break;
+  if (!desc->mark)
+    return;
+  x = desc->constant;
+
+  /* See if X is a LABEL_REF (or a CONST referring to a LABEL_REF)
+     whose CODE_LABEL has been deleted.  This can occur if a jump table
+     is eliminated by optimization.  If so, write a constant of zero
+     instead.  Note that this can also happen by turning the
+     CODE_LABEL into a NOTE.  */
+  /* ??? This seems completely and utterly wrong.  Certainly it's
+     not true for NOTE_INSN_DELETED_LABEL, but I disbelieve proper
+     functioning even with INSN_DELETED_P and friends.  */
+
+  tmp = x;
+  switch (GET_CODE (x))
+    {
+    case CONST:
+      if (GET_CODE (XEXP (x, 0)) != PLUS
+         || GET_CODE (XEXP (XEXP (x, 0), 0)) != LABEL_REF)
+       break;
+      tmp = XEXP (XEXP (x, 0), 0);
+      /* FALLTHRU  */
 
-       default:
+    case LABEL_REF:
+      tmp = XEXP (x, 0);
+      if (INSN_DELETED_P (tmp)
+         || (GET_CODE (tmp) == NOTE
+             && NOTE_LINE_NUMBER (tmp) == NOTE_INSN_DELETED))
+       {
          abort ();
+         x = const0_rtx;
        }
+      break;
+
+    default:
+      break;
+    }
 
-      /* Make sure all constants in SECTION_MERGE and not SECTION_STRINGS
-        sections have proper size.  */
-      if (pool->align > GET_MODE_BITSIZE (pool->mode)
-         && in_section == in_named
-         && get_named_section_flags (in_named_name) & SECTION_MERGE)
-       assemble_align (pool->align);
+  /* First switch to correct section.  */
+  (*targetm.asm_out.select_rtx_section) (desc->mode, x, desc->align);
 
 #ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
-    done: ;
+  ASM_OUTPUT_SPECIAL_POOL_ENTRY (asm_out_file, x, desc->mode,
+                                desc->align, desc->labelno, done);
 #endif
-    }
 
-#ifdef ASM_OUTPUT_POOL_EPILOGUE
-  ASM_OUTPUT_POOL_EPILOGUE (asm_out_file, fnname, fndecl, pool_offset);
-#endif
+  assemble_align (desc->align);
 
-  /* Done with this pool.  */
-  first_pool = last_pool = 0;
-}
+  /* Output the label.  */
+  (*targetm.asm_out.internal_label) (asm_out_file, "LC", desc->labelno);
 
-/* Look through the instructions for this function, and mark all the
-   entries in the constant pool which are actually being used.  Emit
-   deferred constants which have indeed been used.  */
+  /* Output the data.  */
+  output_constant_pool_2 (desc->mode, x, desc->align);
 
-static void
-mark_constant_pool (void)
-{
-  rtx insn;
-  rtx link;
-  struct pool_constant *pool;
+  /* Make sure all constants in SECTION_MERGE and not SECTION_STRINGS
+     sections have proper size.  */
+  if (desc->align > GET_MODE_BITSIZE (desc->mode)
+      && in_section == in_named
+      && get_named_section_flags (in_named_name) & SECTION_MERGE)
+    assemble_align (desc->align);
 
-  if (first_pool == 0 && n_deferred_constants == 0)
-    return;
+#ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
+ done:
+#endif
+  return;
+}
 
-  for (pool = first_pool; pool; pool = pool->next)
-    pool->mark = 0;
+/* Given a SYMBOL_REF CURRENT_RTX, mark it and all constants it refers
+   to as used.  Emit referenced deferred strings.  This function can
+   be used with for_each_rtx to mark all SYMBOL_REFs in an rtx.  */
 
-  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
-    if (INSN_P (insn))
-      mark_constants (PATTERN (insn));
+static int
+mark_constant (rtx *current_rtx, void *data)
+{
+  struct rtx_constant_pool *pool = data;
+  rtx x = *current_rtx;
 
-  for (link = current_function_epilogue_delay_list;
-       link;
-       link = XEXP (link, 1))
-    {
-      insn = XEXP (link, 0);
+  if (x == NULL_RTX || GET_CODE (x) != SYMBOL_REF)
+    return 0;
 
-      if (INSN_P (insn))
-       mark_constants (PATTERN (insn));
+  if (CONSTANT_POOL_ADDRESS_P (x))
+    {
+      struct constant_descriptor_rtx *desc = find_pool_constant (pool, x);
+      if (desc->mark == 0)
+       {
+         desc->mark = 1;
+         for_each_rtx (&desc->constant, mark_constant, pool);
+       }
     }
-}
+  else if (TREE_CONSTANT_POOL_ADDRESS_P (x))
+    {
+      tree exp = SYMBOL_REF_DECL (x);
+      if (!TREE_ASM_WRITTEN (exp))
+       {
+         n_deferred_constants--;
+         output_constant_def_contents (x);
+       }
+    }
+
+  return -1;
+} 
 
-/* Look through appropriate parts of X, marking all entries in the
+/* Look through appropriate parts of INSN, marking all entries in the
    constant pool which are actually being used.  Entries that are only
    referenced by other constants are also marked as used.  Emit
    deferred strings that are used.  */
 
 static void
-mark_constants (rtx x)
+mark_constants (struct rtx_constant_pool *pool, rtx insn)
 {
-  int i;
-  const char *format_ptr;
-
-  if (x == 0)
+  if (!INSN_P (insn))
     return;
 
-  if (GET_CODE (x) == SYMBOL_REF)
-    {
-      mark_constant (&x, NULL);
-      return;
-    }
-
   /* Insns may appear inside a SEQUENCE.  Only check the patterns of
      insns, not any notes that may be attached.  We don't want to mark
      a constant just because it happens to appear in a REG_EQUIV note.  */
-  if (INSN_P (x))
+  if (GET_CODE (PATTERN (insn)) == SEQUENCE)
     {
-      mark_constants (PATTERN (x));
-      return;
+      rtx seq = PATTERN (insn);
+      int i, n = XVECLEN (seq, 0);
+      for (i = 0; i < n; ++i)
+       {
+         rtx subinsn = XVECEXP (seq, 0, i);
+         if (INSN_P (subinsn))
+           for_each_rtx (&PATTERN (subinsn), mark_constant, pool);
+       }
     }
+  else
+    for_each_rtx (&PATTERN (insn), mark_constant, pool);
+}
 
-  format_ptr = GET_RTX_FORMAT (GET_CODE (x));
-
-  for (i = 0; i < GET_RTX_LENGTH (GET_CODE (x)); i++)
-    {
-      switch (*format_ptr++)
-       {
-       case 'e':
-         mark_constants (XEXP (x, i));
-         break;
+/* Look through the instructions for this function, and mark all the
+   entries in POOL which are actually being used.  Emit deferred constants
+   which have indeed been used.  */
 
-       case 'E':
-         if (XVEC (x, i) != 0)
-           {
-             int j;
+static void
+mark_constant_pool (struct rtx_constant_pool *pool)
+{
+  rtx insn, link;
 
-             for (j = 0; j < XVECLEN (x, i); j++)
-               mark_constants (XVECEXP (x, i, j));
-           }
-         break;
+  if (pool->first == 0 && n_deferred_constants == 0)
+    return;
 
-       case 'S':
-       case 's':
-       case '0':
-       case 'i':
-       case 'w':
-       case 'n':
-       case 'u':
-       case 'B':
-         break;
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    mark_constants (pool, insn);
 
-       default:
-         abort ();
-       }
-    }
+  for (link = current_function_epilogue_delay_list;
+       link;
+       link = XEXP (link, 1))
+    mark_constants (pool, XEXP (link, 0));
 }
 
-/* Given a SYMBOL_REF CURRENT_RTX, mark it and all constants it refers
-   to as used.  Emit referenced deferred strings.  This function can
-   be used with for_each_rtx to mark all SYMBOL_REFs in an rtx.  */
+/* Write all the constants in the constant pool.  */
 
-static int
-mark_constant (rtx *current_rtx, void *data ATTRIBUTE_UNUSED)
+void
+output_constant_pool (const char *fnname ATTRIBUTE_UNUSED,
+                     tree fndecl ATTRIBUTE_UNUSED)
 {
-  rtx x = *current_rtx;
+  struct rtx_constant_pool *pool = cfun->varasm->pool;
+  struct constant_descriptor_rtx *desc;
 
-  if (x == NULL_RTX)
-    return 0;
+  /* It is possible for gcc to call force_const_mem and then to later
+     discard the instructions which refer to the constant.  In such a
+     case we do not need to output the constant.  */
+  mark_constant_pool (pool);
 
-  else if (GET_CODE (x) == SYMBOL_REF)
-    {
-      if (CONSTANT_POOL_ADDRESS_P (x))
-       {
-         struct pool_constant *pool = find_pool_constant (cfun, x);
-         if (pool->mark == 0)
-           {
-             pool->mark = 1;
-             for_each_rtx (&(pool->constant), &mark_constant, NULL);
-           }
-         else
-           return -1;
-       }
-      else if (TREE_CONSTANT_POOL_ADDRESS_P (x))
-       {
-         tree exp = SYMBOL_REF_DECL (x);
-         if (!TREE_ASM_WRITTEN (exp))
-           {
-             n_deferred_constants--;
-             output_constant_def_contents (x);
-           }
-       }
-    }
-  return 0;
+#ifdef ASM_OUTPUT_POOL_PROLOGUE
+  ASM_OUTPUT_POOL_PROLOGUE (asm_out_file, fnname, fndecl, pool->offset);
+#endif
+
+  for (desc = pool->first; desc ; desc = desc->next)
+    output_constant_pool_1 (desc);
+
+#ifdef ASM_OUTPUT_POOL_EPILOGUE
+  ASM_OUTPUT_POOL_EPILOGUE (asm_out_file, fnname, fndecl, pool->offset);
+#endif
+
+  /* Done with this pool.  */
+  cfun->varasm->pool = NULL;
 }
 \f
 /* Determine what kind of relocations EXP may need.  */