OSDN Git Service

* c-lex.c (read_escape, read_ucs): Delete.
[pf3gnuchains/gcc-fork.git] / gcc / varasm.c
index e71ba3a..3e7b295 100644 (file)
@@ -1,6 +1,6 @@
 /* Output variables, constants and external declarations, for GNU compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000 Free Software Foundation, Inc.
+   1998, 1999, 2000, 2001 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -35,15 +35,15 @@ Boston, MA 02111-1307, USA.  */
 #include "flags.h"
 #include "function.h"
 #include "expr.h"
-#include "output.h"
 #include "hard-reg-set.h"
 #include "regs.h"
-#include "defaults.h"
+#include "output.h"
 #include "real.h"
 #include "toplev.h"
 #include "dbxout.h"
 #include "sdbout.h"
 #include "obstack.h"
+#include "hashtab.h"
 #include "c-pragma.h"
 #include "ggc.h"
 #include "tm_p.h"
@@ -57,19 +57,11 @@ Boston, MA 02111-1307, USA.  */
 #endif
 
 #ifndef ASM_STABS_OP
-#define ASM_STABS_OP ".stabs"
+#define ASM_STABS_OP "\t.stabs\t"
 #endif
 
 /* Define the prefix to use when check_memory_usage_flag is enable.  */
-#ifdef NO_DOLLAR_IN_LABEL
-#ifdef NO_DOT_IN_LABEL
-#define CHKR_PREFIX "chkr_prefix_"
-#else /* !NO_DOT_IN_LABEL */
-#define CHKR_PREFIX "chkr."
-#endif 
-#else /* !NO_DOLLAR_IN_LABEL */
-#define CHKR_PREFIX "chkr$"
-#endif
+#define CHKR_PREFIX "_CHKR_"
 #define CHKR_PREFIX_SIZE (sizeof (CHKR_PREFIX) - 1)
 
 /* File in which assembler code is being written.  */
@@ -77,12 +69,9 @@ Boston, MA 02111-1307, USA.  */
 extern FILE *asm_out_file;
 
 /* The (assembler) name of the first globally-visible object output.  */
-char *first_global_object_name;
-char *weak_global_object_name;
+const char *first_global_object_name;
+const char *weak_global_object_name;
 
-extern struct obstack *current_obstack;
-extern struct obstack *saveable_obstack;
-extern struct obstack *rtl_obstack;
 extern struct obstack permanent_obstack;
 #define obstack_chunk_alloc xmalloc
 
@@ -104,13 +93,13 @@ struct varasm_status
      so each function gets its own constants-pool that comes right before
      it.  */
   struct constant_descriptor **x_const_rtx_hash_table;
-  struct pool_sym **x_const_rtx_sym_hash_table;
+  struct pool_constant **x_const_rtx_sym_hash_table;
 
   /* Pointers to first and last constant in pool.  */
   struct pool_constant *x_first_pool, *x_last_pool;
 
   /* Current offset in constant pool (does not include any machine-specific
-     header.  */
+     header).  */
   int x_pool_offset;
 
   /* Chain of all CONST_DOUBLE rtx's constructed for the current function.
@@ -156,7 +145,7 @@ static void decode_addr_const               PARAMS ((tree, struct addr_const *));
 static int const_hash                  PARAMS ((tree));
 static int compare_constant            PARAMS ((tree,
                                               struct constant_descriptor *));
-static char *compare_constant_1                PARAMS ((tree, char *));
+static const unsigned char *compare_constant_1  PARAMS ((tree, const unsigned char *));
 static struct constant_descriptor *record_constant PARAMS ((tree));
 static void record_constant_1          PARAMS ((tree));
 static tree copy_constant              PARAMS ((tree));
@@ -171,24 +160,31 @@ static struct constant_descriptor *record_constant_rtx PARAMS ((enum machine_mod
 static struct pool_constant *find_pool_constant PARAMS ((struct function *, rtx));
 static void mark_constant_pool         PARAMS ((void));
 static void mark_constants             PARAMS ((rtx));
+static int mark_constant               PARAMS ((rtx *current_rtx, void *data));
 static int output_addressed_constants  PARAMS ((tree));
 static void output_after_function_constants PARAMS ((void));
+static unsigned HOST_WIDE_INT array_size_for_constructor PARAMS ((tree));
 static void output_constructor         PARAMS ((tree, int));
 #ifdef ASM_WEAKEN_LABEL
-static void remove_from_pending_weak_list      PARAMS ((char *));
+static void remove_from_pending_weak_list      PARAMS ((const char *));
 #endif
 #ifdef ASM_OUTPUT_BSS
-static void asm_output_bss             PARAMS ((FILE *, tree, char *, int, int));
+static void asm_output_bss             PARAMS ((FILE *, tree, const char *, int, int));
 #endif
 #ifdef BSS_SECTION_ASM_OP
 #ifdef ASM_OUTPUT_ALIGNED_BSS
-static void asm_output_aligned_bss     PARAMS ((FILE *, tree, char *, int, int));
+static void asm_output_aligned_bss     PARAMS ((FILE *, tree, const char *,
+                                                int, int));
 #endif
 #endif /* BSS_SECTION_ASM_OP */
 static void mark_pool_constant          PARAMS ((struct pool_constant *));
-static void mark_pool_sym_hash_table   PARAMS ((struct pool_sym **));
 static void mark_const_hash_entry      PARAMS ((void *));
-static void asm_emit_uninitialised     PARAMS ((tree, char *, int, int));
+static int mark_const_str_htab_1       PARAMS ((void **, void *));
+static void mark_const_str_htab                PARAMS ((void *));
+static hashval_t const_str_htab_hash   PARAMS ((const void *x));
+static int const_str_htab_eq           PARAMS ((const void *x, const void *y));
+static void const_str_htab_del         PARAMS ((void *));
+static void asm_emit_uninitialised     PARAMS ((tree, const char*, int, int));
 \f
 static enum in_section { no_section, in_text, in_data, in_named
 #ifdef BSS_SECTION_ASM_OP
@@ -210,7 +206,7 @@ static enum in_section { no_section, in_text, in_data, in_named
 #endif
      
 /* Text of section name when in_section == in_named.  */
-static char *in_named_name;
+static const char *in_named_name;
 
 /* Define functions like text_section for any extra sections.  */
 #ifdef EXTRA_SECTION_FUNCTIONS
@@ -300,8 +296,7 @@ named_section (decl, name, reloc)
      const char *name;
      int reloc ATTRIBUTE_UNUSED;
 {
-  if (decl != NULL_TREE
-      && TREE_CODE_CLASS (TREE_CODE (decl)) != 'd')
+  if (decl != NULL_TREE && !DECL_P (decl))
     abort ();
   if (name == NULL)
     name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
@@ -317,35 +312,11 @@ named_section (decl, name, reloc)
       abort ();
 #endif
 
-      in_named_name = ggc_alloc_string (name, -1);
+      in_named_name = ggc_strdup (name);
       in_section = in_named;
     }
 }
 
-#ifdef ASM_OUTPUT_SECTION_NAME
-#ifndef UNIQUE_SECTION
-#define UNIQUE_SECTION(DECL,RELOC)                             \
-do {                                                           \
-  int len;                                                     \
-  const char *name;                                            \
-  char *string;                                                        \
-                                                               \
-  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (DECL));      \
-  /* Strip off any encoding in name.  */                       \
-  STRIP_NAME_ENCODING (name, name);                            \
-                                                               \
-  len = strlen (name) + 1;                                     \
-  string = alloca (len + 1);                                   \
-  sprintf (string, ".%s", name);                               \
-                                                               \
-  DECL_SECTION_NAME (DECL) = build_string (len, string);       \
-} while (0)
-#endif
-#ifndef UNIQUE_SECTION_P
-#define UNIQUE_SECTION_P(DECL) 0
-#endif
-#endif
-
 #ifdef BSS_SECTION_ASM_OP
 
 /* Tell the assembler to switch to the bss section.  */
@@ -377,7 +348,7 @@ static void
 asm_output_bss (file, decl, name, size, rounded)
      FILE *file;
      tree decl ATTRIBUTE_UNUSED;
-     char *name;
+     const char *name;
      int size ATTRIBUTE_UNUSED, rounded;
 {
   ASM_GLOBALIZE_LABEL (file, name);
@@ -405,7 +376,7 @@ static void
 asm_output_aligned_bss (file, decl, name, size, align)
      FILE *file;
      tree decl;
-     char *name;
+     const char *name;
      int size, align;
 {
   ASM_GLOBALIZE_LABEL (file, name);
@@ -511,75 +482,6 @@ exception_section ()
 #endif
 }
 \f
-/* Create the rtl to represent a function, for a function definition.
-   DECL is a FUNCTION_DECL node which describes which function.
-   The rtl is stored into DECL.  */
-
-void
-make_function_rtl (decl)
-     tree decl;
-{
-  char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
-  char *new_name = name;
-
-  /* Rename a nested function to avoid conflicts.  */
-  if (decl_function_context (decl) != 0
-      && DECL_INITIAL (decl) != 0
-      && DECL_RTL (decl) == 0)
-    {
-      char *label;
-
-      name = IDENTIFIER_POINTER (DECL_NAME (decl));
-      ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno);
-      name = ggc_alloc_string (label, -1);
-      var_labelno++;
-    }
-  else
-    {
-      /* When -fprefix-function-name is used, every function name is
-         prefixed.  Even static functions are prefixed because they
-         could be declared latter.  Note that a nested function name
-         is not prefixed.  */
-      if (flag_prefix_function_name)
-        {
-         size_t name_len = strlen (name);
-
-          new_name = ggc_alloc_string (NULL, name_len + CHKR_PREFIX_SIZE);
-         memcpy (new_name, CHKR_PREFIX, CHKR_PREFIX_SIZE);
-         memcpy (new_name + CHKR_PREFIX_SIZE, name, name_len + 1);
-          name = new_name;
-        }
-    }
-
-  if (DECL_RTL (decl) == 0)
-    {
-      DECL_RTL (decl)
-       = gen_rtx_MEM (DECL_MODE (decl),
-                      gen_rtx_SYMBOL_REF (Pmode, name));
-
-      /* Optionally set flags or add text to the name to record information
-        such as that it is a function name.  If the name is changed, the macro
-        ASM_OUTPUT_LABELREF will have to know how to strip this information.  */
-#ifdef ENCODE_SECTION_INFO
-      ENCODE_SECTION_INFO (decl);
-#endif
-    }
-  else
-    {
-      /* ??? Another way to do this would be to do what halfpic.c does
-        and maintain a hashed table of such critters.  */
-      /* ??? Another way to do this would be to pass a flag bit to
-        ENCODE_SECTION_INFO saying whether this is a new decl or not.  */
-      /* Let the target reassign the RTL if it wants.
-        This is necessary, for example, when one machine specific
-        decl attribute overrides another.  */
-#ifdef REDO_SECTION_INFO_P
-      if (REDO_SECTION_INFO_P (decl))
-       ENCODE_SECTION_INFO (decl);
-#endif
-    }
-}
-
 /* Given NAME, a putative register name, discard any customary prefixes.  */
 
 static const char *
@@ -637,7 +539,7 @@ decode_reg_name (asmspec)
        static struct { const char *name; int number; } table[]
          = ADDITIONAL_REGISTER_NAMES;
 
-       for (i = 0; i < (int)(sizeof (table) / sizeof (table[0])); i++)
+       for (i = 0; i < (int) ARRAY_SIZE (table); i++)
          if (! strcmp (asmspec, table[i].name))
            return table[i].number;
       }
@@ -655,72 +557,100 @@ decode_reg_name (asmspec)
   return -1;
 }
 \f
-/* Create the DECL_RTL for a declaration for a static or external variable
-   or static or external function.
-   ASMSPEC, if not 0, is the string which the user specified
-   as the assembler symbol name.
-   TOP_LEVEL is nonzero if this is a file-scope variable.
+/* Create the DECL_RTL for a VAR_DECL or FUNCTION_DECL.  DECL should
+   have static storage duration.  In other words, it should not be an
+   automatic variable, including PARM_DECLs.
+
+   There is, however, one exception: this function handles variables
+   explicitly placed in a particular register by the user.
+
+   ASMSPEC, if not 0, is the string which the user specified as the
+   assembler symbol name.
 
    This is never called for PARM_DECL nodes.  */
 
 void
-make_decl_rtl (decl, asmspec, top_level)
+make_decl_rtl (decl, asmspec)
      tree decl;
      const char *asmspec;
-     int top_level;
 {
-  register char *name = 0;
+  int top_level = (DECL_CONTEXT (decl) == NULL_TREE);
+  const char *name = 0;
+  const char *new_name = 0;
   int reg_number;
 
-  reg_number = decode_reg_name (asmspec);
+  /* Check that we are not being given an automatic variable.  */
+  /* A weak alias has TREE_PUBLIC set but not the other bits.  */
+  if (TREE_CODE (decl) == PARM_DECL
+      || TREE_CODE (decl) == RESULT_DECL
+      || (TREE_CODE (decl) == VAR_DECL
+         && !TREE_STATIC (decl)
+         && !TREE_PUBLIC (decl)
+         && !DECL_EXTERNAL (decl)
+         && !DECL_REGISTER (decl)))
+    abort ();
+  /* And that we were not given a type or a label.  */
+  else if (TREE_CODE (decl) == TYPE_DECL 
+          || TREE_CODE (decl) == LABEL_DECL)
+    abort ();
 
-  if (DECL_ASSEMBLER_NAME (decl) != NULL_TREE)
-    name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+  /* For a duplicate declaration, we can be called twice on the
+     same DECL node.  Don't discard the RTL already made.  */
+  if (DECL_RTL_SET_P (decl))
+    {
+      /* If the old RTL had the wrong mode, fix the mode.  */
+      if (GET_MODE (DECL_RTL (decl)) != DECL_MODE (decl))
+       {
+         rtx rtl = DECL_RTL (decl);
+         PUT_MODE (rtl, DECL_MODE (decl));
+       }
 
+      /* ??? Another way to do this would be to do what halfpic.c does
+        and maintain a hashed table of such critters.  */
+      /* ??? Another way to do this would be to pass a flag bit to
+        ENCODE_SECTION_INFO saying whether this is a new decl or not.  */
+      /* Let the target reassign the RTL if it wants.
+        This is necessary, for example, when one machine specific
+        decl attribute overrides another.  */
+#ifdef REDO_SECTION_INFO_P
+      if (REDO_SECTION_INFO_P (decl))
+       ENCODE_SECTION_INFO (decl);
+#endif
+      return;
+    }
+
+  new_name = name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+
+  reg_number = decode_reg_name (asmspec);
   if (reg_number == -2)
     {
-      /* ASMSPEC is given, and not the name of a register.  */
-      size_t len = strlen (asmspec);
-
-      name = ggc_alloc_string (NULL, len + 1);
-      name[0] = '*';
-      memcpy (&name[1], asmspec, len + 1);
+      /* ASMSPEC is given, and not the name of a register.  Mark the
+        name with a star so assemble_name won't munge it.  */
+      char *starred = alloca (strlen (asmspec) + 2);
+      starred[0] = '*';
+      strcpy (starred + 1, asmspec);
+      new_name = starred;
     }
 
-  /* For a duplicate declaration, we can be called twice on the
-     same DECL node.  Don't discard the RTL already made.  */
-  if (DECL_RTL (decl) == 0)
+  if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
     {
       /* First detect errors in declaring global registers.  */
-      if (TREE_CODE (decl) != FUNCTION_DECL
-         && DECL_REGISTER (decl) && reg_number == -1)
-       error_with_decl (decl,
-                        "register name not specified for `%s'");
-      else if (TREE_CODE (decl) != FUNCTION_DECL
-              && DECL_REGISTER (decl) && reg_number < 0)
-       error_with_decl (decl,
-                        "invalid register name for `%s'");
-      else if ((reg_number >= 0 || reg_number == -3)
-              && (TREE_CODE (decl) == FUNCTION_DECL
-                  && ! DECL_REGISTER (decl)))
-       error_with_decl (decl,
-                        "register name given for non-register variable `%s'");
-      else if (TREE_CODE (decl) != FUNCTION_DECL
-              && DECL_REGISTER (decl)
-              && TYPE_MODE (TREE_TYPE (decl)) == BLKmode)
+      if (reg_number == -1)
+       error_with_decl (decl, "register name not specified for `%s'");
+      else if (reg_number < 0)
+       error_with_decl (decl, "invalid register name for `%s'");
+      else if (TYPE_MODE (TREE_TYPE (decl)) == BLKmode)
        error_with_decl (decl,
                         "data type of `%s' isn't suitable for a register");
-      else if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl)
-              && ! HARD_REGNO_MODE_OK (reg_number,
-                                       TYPE_MODE (TREE_TYPE (decl))))
+      else if (! HARD_REGNO_MODE_OK (reg_number, TYPE_MODE (TREE_TYPE (decl))))
        error_with_decl (decl,
-                        "register number for `%s' isn't suitable for data type");
+                        "register specified for `%s' isn't suitable for data type");
       /* Now handle properly declared static register variables.  */
-      else if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
+      else
        {
          int nregs;
 
-         if (DECL_INITIAL (decl) != 0 && top_level)
+         if (DECL_INITIAL (decl) != 0 && TREE_STATIC (decl))
            {
              DECL_INITIAL (decl) = 0;
              error ("global register variable has initial value");
@@ -734,12 +664,13 @@ make_decl_rtl (decl, asmspec, top_level)
             usage is somewhat suspect, we nevertheless use the following
             kludge to avoid setting DECL_RTL to frame_pointer_rtx.  */
 
-         DECL_RTL (decl)
-           = gen_rtx_REG (DECL_MODE (decl), FIRST_PSEUDO_REGISTER);
+         SET_DECL_RTL (decl,
+                       gen_rtx_REG (DECL_MODE (decl), 
+                                    FIRST_PSEUDO_REGISTER));
          REGNO (DECL_RTL (decl)) = reg_number;
          REG_USERVAR_P (DECL_RTL (decl)) = 1;
 
-         if (top_level)
+         if (TREE_STATIC (decl))
            {
              /* Make this register global, so not usable for anything
                 else.  */
@@ -750,101 +681,83 @@ make_decl_rtl (decl, asmspec, top_level)
              while (nregs > 0)
                globalize_reg (reg_number + --nregs);
            }
+
+         /* As a register variable, it has no section.  */
+         return;
        }
-      /* Specifying a section attribute on a variable forces it into a
-         non-.bss section, and thus it cannot be common. */
-      else if (TREE_CODE (decl) == VAR_DECL
-              && DECL_SECTION_NAME (decl) != NULL_TREE
-              && DECL_INITIAL (decl) == NULL_TREE
-              && DECL_COMMON (decl))
-          DECL_COMMON (decl) = 0;
-
-      /* Now handle ordinary static variables and functions (in memory).
-        Also handle vars declared register invalidly.  */
-      if (DECL_RTL (decl) == 0)
-       {
-         /* Can't use just the variable's own name for a variable
-            whose scope is less than the whole file.
-            Concatenate a distinguishing number.  */
-         if (!top_level && !TREE_PUBLIC (decl) && asmspec == 0)
-           {
-             char *label;
+    }
 
-             ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno);
-             name = ggc_alloc_string (label, -1);
-             var_labelno++;
-           }
+  /* Now handle ordinary static variables and functions (in memory).
+     Also handle vars declared register invalidly.  */
 
-         if (name == 0)
-           abort ();
+  if (reg_number >= 0 || reg_number == -3)
+    error_with_decl (decl,
+                    "register name given for non-register variable `%s'");
 
-         /* When -fprefix-function-name is used, the functions
-            names are prefixed.  Only nested function names are not
-            prefixed.  */
-         if (flag_prefix_function_name && TREE_CODE (decl) == FUNCTION_DECL)
-           {
-             size_t name_len = strlen (name);
-             char *new_name;
+  /* Specifying a section attribute on a variable forces it into a
+     non-.bss section, and thus it cannot be common. */
+  if (TREE_CODE (decl) == VAR_DECL
+      && DECL_SECTION_NAME (decl) != NULL_TREE
+      && DECL_INITIAL (decl) == NULL_TREE
+      && DECL_COMMON (decl))
+    DECL_COMMON (decl) = 0;
+
+  /* Can't use just the variable's own name for a variable
+     whose scope is less than the whole file, unless it's a member
+     of a local class (which will already be unambiguous).
+     Concatenate a distinguishing number.  */
+  if (!top_level && !TREE_PUBLIC (decl)
+      && ! (DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl)))
+      && asmspec == 0
+      && name == IDENTIFIER_POINTER (DECL_NAME (decl)))
+    {
+      char *label;
+      ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno);
+      var_labelno++;
+      new_name = label;
+    }
 
-             new_name = ggc_alloc_string (NULL, name_len + CHKR_PREFIX_SIZE);
-             memcpy (new_name, CHKR_PREFIX, CHKR_PREFIX_SIZE);
-             memcpy (new_name + CHKR_PREFIX_SIZE, name, name_len + 1);
-             name = new_name;
-           }
+  /* When -fprefix-function-name is used, the functions
+     names are prefixed.  Only nested function names are not
+     prefixed.  */
+  else if (flag_prefix_function_name && TREE_CODE (decl) == FUNCTION_DECL)
+    {
+      size_t name_len = IDENTIFIER_LENGTH (DECL_ASSEMBLER_NAME (decl));
+      char *pname;
 
-         DECL_RTL (decl) = gen_rtx_MEM (DECL_MODE (decl),
-                                        gen_rtx_SYMBOL_REF (Pmode, name));
-         MEM_ALIAS_SET (DECL_RTL (decl)) = get_alias_set (decl);
-
-         /* If this variable is to be treated as volatile, show its
-            tree node has side effects.  If it has side effects, either
-            because of this test or from TREE_THIS_VOLATILE also
-            being set, show the MEM is volatile.  */
-         if (flag_volatile_global && TREE_CODE (decl) == VAR_DECL
-             && TREE_PUBLIC (decl))
-           TREE_SIDE_EFFECTS (decl) = 1;
-         else if (flag_volatile_static && TREE_CODE (decl) == VAR_DECL
-              && (TREE_PUBLIC (decl) || TREE_STATIC (decl)))
-           TREE_SIDE_EFFECTS (decl) = 1;
-
-         if (TREE_SIDE_EFFECTS (decl))
-           MEM_VOLATILE_P (DECL_RTL (decl)) = 1;
-
-         if (TREE_READONLY (decl))
-           RTX_UNCHANGING_P (DECL_RTL (decl)) = 1;
-         MEM_SET_IN_STRUCT_P (DECL_RTL (decl),
-                              AGGREGATE_TYPE_P (TREE_TYPE (decl)));
-
-         /* Optionally set flags or add text to the name to record information
-            such as that it is a function name.
-            If the name is changed, the macro ASM_OUTPUT_LABELREF
-            will have to know how to strip this information.  */
-#ifdef ENCODE_SECTION_INFO
-         ENCODE_SECTION_INFO (decl);
-#endif
-       }
+      pname = alloca (name_len + CHKR_PREFIX_SIZE + 1);
+      memcpy (pname, CHKR_PREFIX, CHKR_PREFIX_SIZE);
+      memcpy (pname + CHKR_PREFIX_SIZE, name, name_len + 1);
+      new_name = pname;
     }
-  else
+
+  if (name != new_name)
     {
-      /* If the old RTL had the wrong mode, fix the mode.  */
-      if (GET_MODE (DECL_RTL (decl)) != DECL_MODE (decl))
-       {
-         rtx rtl = DECL_RTL (decl);
-         PUT_MODE (rtl, DECL_MODE (decl));
-       }
+      SET_DECL_ASSEMBLER_NAME (decl, get_identifier (new_name));
+      name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+    }
 
-      /* ??? Another way to do this would be to do what halfpic.c does
-        and maintain a hashed table of such critters.  */
-      /* ??? Another way to do this would be to pass a flag bit to
-        ENCODE_SECTION_INFO saying whether this is a new decl or not.  */
-      /* Let the target reassign the RTL if it wants.
-        This is necessary, for example, when one machine specific
-        decl attribute overrides another.  */
-#ifdef REDO_SECTION_INFO_P
-      if (REDO_SECTION_INFO_P (decl))
-       ENCODE_SECTION_INFO (decl);
+  /* If this variable is to be treated as volatile, show its
+     tree node has side effects.   */
+  if ((flag_volatile_global && TREE_CODE (decl) == VAR_DECL
+       && TREE_PUBLIC (decl))
+      || ((flag_volatile_static && TREE_CODE (decl) == VAR_DECL
+          && (TREE_PUBLIC (decl) || TREE_STATIC (decl)))))
+    TREE_SIDE_EFFECTS (decl) = 1;
+
+  SET_DECL_RTL (decl, gen_rtx_MEM (DECL_MODE (decl),
+                                  gen_rtx_SYMBOL_REF (Pmode, name)));
+  SYMBOL_REF_WEAK (XEXP (DECL_RTL (decl), 0)) = DECL_WEAK (decl);
+  if (TREE_CODE (decl) != FUNCTION_DECL)
+    set_mem_attributes (DECL_RTL (decl), decl, 1);
+
+  /* Optionally set flags or add text to the name to record information
+     such as that it is a function name.
+     If the name is changed, the macro ASM_OUTPUT_LABELREF
+     will have to know how to strip this information.  */
+#ifdef ENCODE_SECTION_INFO
+  ENCODE_SECTION_INFO (decl);
 #endif
-    }
 }
 
 /* Make the rtl for variable VAR be volatile.
@@ -925,7 +838,7 @@ assemble_destructor (name)
     {
       /* Now tell GNU LD that this is part of the static destructor set.  */
       /* This code works for any machine provided you use GNU as/ld.  */
-      fprintf (asm_out_file, "%s \"___DTOR_LIST__\",22,0,0,", ASM_STABS_OP);
+      fprintf (asm_out_file, "%s\"___DTOR_LIST__\",22,0,0,", ASM_STABS_OP);
       assemble_name (asm_out_file, name);
       fputc ('\n', asm_out_file);
     }
@@ -945,7 +858,7 @@ assemble_constructor (name)
     {
       /* Now tell GNU LD that this is part of the static constructor set.  */
       /* This code works for any machine provided you use GNU as/ld.  */
-      fprintf (asm_out_file, "%s \"___CTOR_LIST__\",22,0,0,", ASM_STABS_OP);
+      fprintf (asm_out_file, "%s\"___CTOR_LIST__\",22,0,0,", ASM_STABS_OP);
       assemble_name (asm_out_file, name);
       fputc ('\n', asm_out_file);
     }
@@ -965,7 +878,7 @@ assemble_gc_entry (name)
   if (flag_gnu_linker)
     {
       /* Now tell GNU LD that this is part of the static constructor set.  */
-      fprintf (asm_out_file, "%s \"___PTR_LIST__\",22,0,0,", ASM_STABS_OP);
+      fprintf (asm_out_file, "%s\"___PTR_LIST__\",22,0,0,", ASM_STABS_OP);
       assemble_name (asm_out_file, name);
       fputc ('\n', asm_out_file);
     }
@@ -990,7 +903,7 @@ assemble_gc_entry (name)
 void
 assemble_start_function (decl, fnname)
      tree decl;
-     char *fnname;
+     const char *fnname;
 {
   int align;
 
@@ -1053,16 +966,16 @@ assemble_start_function (decl, fnname)
       if (! first_global_object_name)
        {
          const char *p;
-         char **name;
+         char *name;
+
+         STRIP_NAME_ENCODING (p, fnname);
+         name = permalloc (strlen (p) + 1);
+         strcpy (name, p);
 
          if (! DECL_WEAK (decl) && ! DECL_ONE_ONLY (decl))
-           name = &first_global_object_name;
+           first_global_object_name = name;
          else
-           name = &weak_global_object_name;
-
-         STRIP_NAME_ENCODING (p, fnname);
-         *name = permalloc (strlen (p) + 1);
-         strcpy (*name, p);
+           weak_global_object_name = name;
        }
 
 #ifdef ASM_WEAKEN_LABEL
@@ -1130,7 +1043,7 @@ assemble_zeros (size)
        {
 #ifdef ASM_BYTE_OP
          fprintf (asm_out_file,
-                  "%s 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n", ASM_BYTE_OP);
+                  "%s0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n", ASM_BYTE_OP);
 #else
          fprintf (asm_out_file,
                   "\tbyte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n");
@@ -1139,7 +1052,7 @@ assemble_zeros (size)
       if (i < size)
         {
 #ifdef ASM_BYTE_OP
-         fprintf (asm_out_file, "%s 0", ASM_BYTE_OP);
+         fprintf (asm_out_file, "%s0", ASM_BYTE_OP);
 #else
          fprintf (asm_out_file, "\tbyte 0");
 #endif
@@ -1232,7 +1145,7 @@ assemble_string (p, size)
 static void
 asm_emit_uninitialised (decl, name, size, rounded)
      tree decl;
-     char * name;
+     const char * name;
      int size ATTRIBUTE_UNUSED;
      int rounded ATTRIBUTE_UNUSED;
 {
@@ -1281,7 +1194,7 @@ asm_emit_uninitialised (decl, name, size, rounded)
 #ifdef ASM_OUTPUT_SECTION_NAME
   /* We already know that DECL_SECTION_NAME() == NULL.  */
   if (flag_data_sections != 0 || UNIQUE_SECTION_P (decl))
-    UNIQUE_SECTION (decl, NULL);
+    UNIQUE_SECTION (decl, 0);
 #endif
   
   switch (destination)
@@ -1321,15 +1234,14 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
      int at_end ATTRIBUTE_UNUSED;
      int dont_output_data;
 {
-  register char *name;
+  register const char *name;
   unsigned int align;
-  tree size_tree = NULL_TREE;
   int reloc = 0;
   enum in_section saved_in_section;
 
   last_assemble_variable_decl = 0;
 
-  if (GET_CODE (DECL_RTL (decl)) == REG)
+  if (DECL_RTL_SET_P (decl) && GET_CODE (DECL_RTL (decl)) == REG)
     {
       /* Do output symbol info for global register variables, but do nothing
         else for them.  */
@@ -1415,22 +1327,11 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
 
   app_disable ();
 
-  if (! dont_output_data)
+  if (! dont_output_data
+      && ! host_integerp (DECL_SIZE_UNIT (decl), 1))
     {
-      int size;
-
-      if (TREE_CODE (DECL_SIZE_UNIT (decl)) != INTEGER_CST)
-       goto finish;
-
-      size_tree = DECL_SIZE_UNIT (decl);
-      size = TREE_INT_CST_LOW (size_tree);
-
-      if (TREE_INT_CST_HIGH (size_tree) != 0
-         || size != TREE_INT_CST_LOW (size_tree))
-       {
-         error_with_decl (decl, "size of variable `%s' is too large");
-         goto finish;
-       }
+      error_with_decl (decl, "size of variable `%s' is too large");
+      goto finish;
     }
 
   name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
@@ -1442,10 +1343,12 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
       && ! DECL_ONE_ONLY (decl))
     {
       const char *p;
+      char *xname;
 
       STRIP_NAME_ENCODING (p, name);
-      first_global_object_name = permalloc (strlen (p) + 1);
-      strcpy (first_global_object_name, p);
+      xname = permalloc (strlen (p) + 1);
+      strcpy (xname, p);
+      first_global_object_name = xname;
     }
 
   /* Compute the alignment of this data.  */
@@ -1496,20 +1399,23 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
       && DECL_SECTION_NAME (decl) == NULL_TREE
       && ! dont_output_data)
     {
-      int size = TREE_INT_CST_LOW (size_tree);
-      int rounded = size;
+      unsigned HOST_WIDE_INT size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
+      unsigned HOST_WIDE_INT rounded = size;
 
       /* Don't allocate zero bytes of common,
         since that means "undefined external" in the linker.  */
-      if (size == 0) rounded = 1;
+      if (size == 0)
+       rounded = 1;
+
       /* Round size up to multiple of BIGGEST_ALIGNMENT bits
         so that each uninitialized object starts on such a boundary.  */
       rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;
       rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
                 * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
       
-#if !defined(ASM_OUTPUT_ALIGNED_COMMON) && !defined(ASM_OUTPUT_ALIGNED_BSS)
-      if ((DECL_ALIGN (decl) / BITS_PER_UNIT) > (unsigned int) rounded)
+/* Don't continue this line--convex cc version 4.1 would lose.  */
+#if !defined(ASM_OUTPUT_ALIGNED_COMMON) && !defined(ASM_OUTPUT_ALIGNED_DECL_COMMON) && !defined(ASM_OUTPUT_ALIGNED_BSS)
+      if ((unsigned HOST_WIDE_INT) DECL_ALIGN (decl) / BITS_PER_UNIT > rounded)
          warning_with_decl 
            (decl, "requested alignment for %s is greater than implemented alignment of %d.",rounded);
 #endif
@@ -1643,10 +1549,11 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
     {
       if (DECL_INITIAL (decl))
        /* Output the actual data.  */
-       output_constant (DECL_INITIAL (decl), TREE_INT_CST_LOW (size_tree));
+       output_constant (DECL_INITIAL (decl),
+                        tree_low_cst (DECL_SIZE_UNIT (decl), 1));
       else
        /* Leave space for it.  */
-       assemble_zeros (TREE_INT_CST_LOW (size_tree));
+       assemble_zeros (tree_low_cst (DECL_SIZE_UNIT (decl), 1));
     }
 
  finish:
@@ -1718,9 +1625,15 @@ void
 assemble_external (decl)
      tree decl ATTRIBUTE_UNUSED;
 {
+  /* Because most platforms do not define ASM_OUTPUT_EXTERNAL, the
+     main body of this code is only rarely exercised.  To provide some
+     testing, on all platforms, we make sure that the ASM_OUT_FILE is
+     open.  If it's not, we should not be calling this function.  */
+  if (!asm_out_file)
+    abort ();
+
 #ifdef ASM_OUTPUT_EXTERNAL
-  if (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd'
-      && DECL_EXTERNAL (decl) && TREE_PUBLIC (decl))
+  if (DECL_P (decl) && DECL_EXTERNAL (decl) && TREE_PUBLIC (decl))
     {
       rtx rtl = DECL_RTL (decl);
 
@@ -1785,7 +1698,7 @@ assemble_name (file, name)
 
   STRIP_NAME_ENCODING (real_name, name);
   if (flag_prefix_function_name 
-      && ! bcmp (real_name, CHKR_PREFIX, CHKR_PREFIX_SIZE))
+      && ! memcmp (real_name, CHKR_PREFIX, CHKR_PREFIX_SIZE))
     real_name = real_name + CHKR_PREFIX_SIZE;
 
   id = maybe_get_identifier (real_name);
@@ -1806,7 +1719,7 @@ assemble_static_space (size)
      int size;
 {
   char name[12];
-  char *namestring;
+  const char *namestring;
   rtx x;
 
 #if 0
@@ -1816,7 +1729,7 @@ assemble_static_space (size)
 
   ASM_GENERATE_INTERNAL_LABEL (name, "LF", const_labelno);
   ++const_labelno;
-  namestring = ggc_alloc_string (name, -1);
+  namestring = ggc_strdup (name);
 
   x = gen_rtx_SYMBOL_REF (Pmode, namestring);
 
@@ -1851,7 +1764,7 @@ rtx
 assemble_trampoline_template ()
 {
   char label[256];
-  char *name;
+  const char *name;
   int align;
 
   /* By default, put trampoline templates in read-only data section.  */
@@ -1872,7 +1785,7 @@ assemble_trampoline_template ()
 
   /* Record the rtl to refer to it.  */
   ASM_GENERATE_INTERNAL_LABEL (label, "LTRAMP", 0);
-  name = ggc_alloc_string (label, -1);
+  name = ggc_strdup (label);
   return gen_rtx_SYMBOL_REF (Pmode, name);
 }
 #endif
@@ -1985,7 +1898,7 @@ assemble_real (d, mode)
     {
       error ("floating point trap outputting a constant");
 #ifdef REAL_IS_NOT_DOUBLE
-      bzero ((char *) &d, sizeof d);
+      memset ((char *) &d, 0, sizeof d);
       d = dconst0;
 #else
       d = 0;
@@ -2034,7 +1947,7 @@ assemble_real (d, mode)
       abort ();
     }
 
-  set_float_handler (NULL_PTR);
+  set_float_handler (NULL);
 }
 \f
 /* Here we combine duplicate floating constants to make
@@ -2079,7 +1992,7 @@ immed_double_const (i0, i1, mode)
         represented as a 64 bit value -1, and not as 0x00000000ffffffff.
         The later confuses the sparc backend.  */
 
-      if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width
+      if (width < HOST_BITS_PER_WIDE_INT
          && (i0 & ((HOST_WIDE_INT) 1 << (width - 1))))
        i0 |= ((HOST_WIDE_INT) (-1) << width);
 
@@ -2120,18 +2033,8 @@ immed_double_const (i0, i1, mode)
          && GET_MODE (r) == mode)
        return r;
 
-  /* No; make a new one and add it to the chain.
-
-     We may be called by an optimizer which may be discarding any memory
-     allocated during its processing (such as combine and loop).  However,
-     we will be leaving this constant on the chain, so we cannot tolerate
-     freed memory.  So switch to saveable_obstack for this allocation
-     and then switch back if we were in current_obstack.  */
-
-  push_obstacks_nochange ();
-  rtl_in_saveable_obstack ();
-  r = gen_rtx_CONST_DOUBLE (mode, NULL_RTX, i0, i1);
-  pop_obstacks ();
+  /* No; make a new one and add it to the chain.  */
+  r = gen_rtx_CONST_DOUBLE (mode, const0_rtx, i0, i1);
 
   /* Don't touch const_double_chain if not inside any function.  */
   if (current_function_decl != 0)
@@ -2140,11 +2043,6 @@ immed_double_const (i0, i1, mode)
       const_double_chain = r;
     }
 
-  /* Store const0_rtx in mem-slot since this CONST_DOUBLE is on the chain.
-     Actual use of mem-slot is only through force_const_mem.  */
-
-  CONST_DOUBLE_MEM (r) = const0_rtx;
-
   return r;
 }
 
@@ -2164,15 +2062,19 @@ immed_real_const_1 (d, mode)
 
   u.d = d;
 
-  /* Detect special cases.  */
-
-  if (REAL_VALUES_IDENTICAL (dconst0, d))
+  /* Detect special cases.  But be careful we don't use a CONST_DOUBLE
+     that's from a parent function since it may be in its constant pool.  */
+  if (REAL_VALUES_IDENTICAL (dconst0, d)
+      && (cfun == 0 || decl_function_context (current_function_decl) == 0))
     return CONST0_RTX (mode);
+
   /* Check for NaN first, because some ports (specifically the i386) do not
      emit correct ieee-fp code by default, and thus will generate a core
      dump here if we pass a NaN to REAL_VALUES_EQUAL and if REAL_VALUES_EQUAL
      does a floating point comparison.  */
-  else if (! REAL_VALUE_ISNAN (d) && REAL_VALUES_EQUAL (dconst1, d))
+  else if ((! REAL_VALUE_ISNAN (d) && REAL_VALUES_EQUAL (dconst1, d))
+          && (cfun == 0
+              || decl_function_context (current_function_decl) == 0))
     return CONST1_RTX (mode);
 
   if (sizeof u == sizeof (HOST_WIDE_INT))
@@ -2188,7 +2090,7 @@ immed_real_const_1 (d, mode)
      If one is found, return it.  */
   if (cfun != 0)
     for (r = const_double_chain; r; r = CONST_DOUBLE_CHAIN (r))
-      if (! bcmp ((char *) &CONST_DOUBLE_LOW (r), (char *) &u, sizeof u)
+      if (! memcmp ((char *) &CONST_DOUBLE_LOW (r), (char *) &u, sizeof u)
          && GET_MODE (r) == mode)
        return r;
 
@@ -2197,21 +2099,20 @@ immed_real_const_1 (d, mode)
      We may be called by an optimizer which may be discarding any memory
      allocated during its processing (such as combine and loop).  However,
      we will be leaving this constant on the chain, so we cannot tolerate
-     freed memory.  So switch to saveable_obstack for this allocation
-     and then switch back if we were in current_obstack.  */
-  push_obstacks_nochange ();
-  rtl_in_saveable_obstack ();
+     freed memory.  */
   r = rtx_alloc (CONST_DOUBLE);
-  pop_obstacks ();
   PUT_MODE (r, mode);
-  bcopy ((char *) &u, (char *) &CONST_DOUBLE_LOW (r), sizeof u);
+  memcpy ((char *) &CONST_DOUBLE_LOW (r), (char *) &u, sizeof u);
 
-  /* Don't touch const_double_chain if not inside any function.  */
+  /* If we aren't inside a function, don't put r on the
+     const_double_chain.  */
   if (current_function_decl != 0)
     {
       CONST_DOUBLE_CHAIN (r) = const_double_chain;
       const_double_chain = r;
     }
+  else
+    CONST_DOUBLE_CHAIN (r) = NULL_RTX;
 
   /* Store const0_rtx in CONST_DOUBLE_MEM since this CONST_DOUBLE is on the
      chain, but has not been allocated memory.  Actual use of CONST_DOUBLE_MEM
@@ -2273,20 +2174,16 @@ decode_addr_const (exp, value)
   while (1)
     {
       if (TREE_CODE (target) == COMPONENT_REF
-         && (TREE_CODE (DECL_FIELD_BITPOS (TREE_OPERAND (target, 1)))
-             == INTEGER_CST))
+         && host_integerp (byte_position (TREE_OPERAND (target, 1)), 0))
+
        {
-         offset += TREE_INT_CST_LOW (DECL_FIELD_BITPOS (TREE_OPERAND (target, 1))) / BITS_PER_UNIT;
+         offset += int_byte_position (TREE_OPERAND (target, 1));
          target = TREE_OPERAND (target, 0);
        }
       else if (TREE_CODE (target) == ARRAY_REF)
        {
-         if (TREE_CODE (TREE_OPERAND (target, 1)) != INTEGER_CST
-             || TREE_CODE (TYPE_SIZE (TREE_TYPE (target))) != INTEGER_CST)
-           abort ();
-         offset += ((TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (target)))
-                     * TREE_INT_CST_LOW (TREE_OPERAND (target, 1)))
-                    / BITS_PER_UNIT);
+         offset += (tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (target)), 1)
+                    * tree_low_cst (TREE_OPERAND (target, 1), 0));
          target = TREE_OPERAND (target, 0);
        }
       else
@@ -2326,6 +2223,18 @@ decode_addr_const (exp, value)
   value->offset = offset;
 }
 \f
+enum kind { RTX_DOUBLE, RTX_INT };
+struct rtx_const
+{
+  ENUM_BITFIELD(kind) kind : 16;
+  ENUM_BITFIELD(machine_mode) mode : 16;
+  union {
+    union real_extract du;
+    struct addr_const addr;
+    struct {HOST_WIDE_INT high, low;} di;
+  } un;
+};
+
 /* Uniquize all constants that appear in memory.
    Each constant in memory thus far output is recorded
    in `const_hash_table' with a `struct constant_descriptor'
@@ -2338,15 +2247,35 @@ decode_addr_const (exp, value)
 struct constant_descriptor
 {
   struct constant_descriptor *next;
-  char *label;
+  const char *label;
   rtx rtl;
-  char contents[1];
+  /* Make sure the data is reasonably aligned.  */
+  union 
+  {
+    unsigned char contents[1];
+#ifdef HAVE_LONG_DOUBLE
+    long double d;
+#else
+    double d;
+#endif
+  } u;
 };
 
 #define HASHBITS 30
 #define MAX_HASH_TABLE 1009
 static struct constant_descriptor *const_hash_table[MAX_HASH_TABLE];
 
+#define STRHASH(x) ((hashval_t)((long)(x) >> 3))
+
+struct deferred_string
+{
+  const char *label;
+  tree exp;
+  int labelno;
+};
+
+static htab_t const_str_htab;
+
 /* Mark a const_hash_table descriptor for GC.  */
 
 static void 
@@ -2357,19 +2286,70 @@ mark_const_hash_entry (ptr)
 
   while (desc)
     {
-      ggc_mark_string (desc->label);
       ggc_mark_rtx (desc->rtl);
       desc = desc->next;
     }
 }
 
+/* Mark the hash-table element X (which is really a pointer to an
+   struct deferred_string *).  */
+   
+static int
+mark_const_str_htab_1 (x, data)
+     void **x;
+     void *data ATTRIBUTE_UNUSED;
+{
+  ggc_mark_tree (((struct deferred_string *) *x)->exp);
+  return 1;
+}
+
+/* Mark a const_str_htab for GC.  */
+
+static void 
+mark_const_str_htab (htab)
+     void *htab;
+{
+  htab_traverse (*((htab_t *) htab), mark_const_str_htab_1, NULL);
+}
+
+/* Returns a hash code for X (which is a really a
+   struct deferred_string *).  */
+
+static hashval_t
+const_str_htab_hash (x)
+     const void *x;
+{
+  return STRHASH (((const struct deferred_string *) x)->label);
+}
+
+/* Returns non-zero if the value represented by X (which is really a
+   struct deferred_string *) is the same as that given by Y
+   (which is really a char *).  */
+
+static int
+const_str_htab_eq (x, y)
+     const void *x;
+     const void *y;
+{
+  return (((const struct deferred_string *) x)->label == (const char *) y);
+}
+
+/* Delete the hash table entry dfsp.  */
+
+static void
+const_str_htab_del (dfsp)
+    void *dfsp;
+{
+  free (dfsp);
+}
+
 /* Compute a hash code for a constant expression.  */
 
 static int
 const_hash (exp)
      tree exp;
 {
-  register char *p;
+  register const char *p;
   register int len, hi, i;
   register enum tree_code code = TREE_CODE (exp);
 
@@ -2379,8 +2359,8 @@ const_hash (exp)
   switch (code)
     {
     case INTEGER_CST:
-      p = (char *) &TREE_INT_CST_LOW (exp);
-      len = 2 * sizeof TREE_INT_CST_LOW (exp);
+      p = (char *) &TREE_INT_CST (exp);
+      len = sizeof TREE_INT_CST (exp);
       break;
 
     case REAL_CST:
@@ -2400,9 +2380,12 @@ const_hash (exp)
     case CONSTRUCTOR:
       if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
        {
+         char *tmp;
+
          len = int_size_in_bytes (TREE_TYPE (exp));
-         p = (char *) alloca (len);
-         get_set_constructor_bytes (exp, (unsigned char *) p, len);
+         tmp = (char *) alloca (len);
+         get_set_constructor_bytes (exp, (unsigned char *) tmp, len);
+         p = tmp;
          break;
        }
       else
@@ -2465,7 +2448,8 @@ const_hash (exp)
       return const_hash (TREE_OPERAND (exp, 0)) * 7 + 2;
       
     default:
-      abort ();
+      /* A language specific constant. Just hash the code. */
+      return (int) code % MAX_HASH_TABLE;
     }
 
   /* Compute hashing function */
@@ -2486,7 +2470,7 @@ compare_constant (exp, desc)
      tree exp;
      struct constant_descriptor *desc;
 {
-  return 0 != compare_constant_1 (exp, desc->contents);
+  return 0 != compare_constant_1 (exp, desc->u.contents);
 }
 
 /* Compare constant expression EXP with a substring P of a constant descriptor.
@@ -2498,12 +2482,12 @@ compare_constant (exp, desc)
    against a subdescriptor, and if it succeeds it returns the
    address of the subdescriptor for the next operand.  */
 
-static char *
+static const unsigned char *
 compare_constant_1 (exp, p)
      tree exp;
-     char *p;
+     const unsigned char *p;
 {
-  register char *strp;
+  register const unsigned char *strp;
   register int len;
   register enum tree_code code = TREE_CODE (exp);
 
@@ -2520,8 +2504,8 @@ compare_constant_1 (exp, p)
       if (*p++ != TYPE_PRECISION (TREE_TYPE (exp)))
        return 0;
 
-      strp = (char *) &TREE_INT_CST_LOW (exp);
-      len = 2 * sizeof TREE_INT_CST_LOW (exp);
+      strp = (unsigned char *) &TREE_INT_CST (exp);
+      len = sizeof TREE_INT_CST (exp);
       break;
 
     case REAL_CST:
@@ -2529,7 +2513,7 @@ compare_constant_1 (exp, p)
       if (*p++ != TYPE_PRECISION (TREE_TYPE (exp)))
        return 0;
 
-      strp = (char *) &TREE_REAL_CST (exp);
+      strp = (unsigned char *) &TREE_REAL_CST (exp);
       len = sizeof TREE_REAL_CST (exp);
       break;
 
@@ -2540,9 +2524,9 @@ compare_constant_1 (exp, p)
       if ((enum machine_mode) *p++ != TYPE_MODE (TREE_TYPE (exp)))
        return 0;
 
-      strp = TREE_STRING_POINTER (exp);
+      strp = (const unsigned char *)TREE_STRING_POINTER (exp);
       len = TREE_STRING_LENGTH (exp);
-      if (bcmp ((char *) &TREE_STRING_LENGTH (exp), p,
+      if (memcmp ((char *) &TREE_STRING_LENGTH (exp), p,
                sizeof TREE_STRING_LENGTH (exp)))
        return 0;
 
@@ -2560,10 +2544,11 @@ compare_constant_1 (exp, p)
       if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
        {
          int xlen = len = int_size_in_bytes (TREE_TYPE (exp));
+         unsigned char *tmp = (unsigned char *) alloca (len);
 
-         strp = (char *) alloca (len);
-         get_set_constructor_bytes (exp, (unsigned char *) strp, len);
-         if (bcmp ((char *) &xlen, p, sizeof xlen))
+         get_set_constructor_bytes (exp, tmp, len);
+         strp = (unsigned char *) tmp;
+         if (memcmp ((char *) &xlen, p, sizeof xlen))
            return 0;
 
          p += sizeof xlen;
@@ -2581,7 +2566,7 @@ compare_constant_1 (exp, p)
            if (TREE_PURPOSE (link))
              have_purpose = 1;
 
-         if (bcmp ((char *) &length, p, sizeof length))
+         if (memcmp ((char *) &length, p, sizeof length))
            return 0;
 
          p += sizeof length;
@@ -2595,12 +2580,12 @@ compare_constant_1 (exp, p)
          else
            type = 0;
 
-         if (bcmp ((char *) &type, p, sizeof type))
+         if (memcmp ((char *) &type, p, sizeof type))
            return 0;
 
          if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
            {
-             if (bcmp ((char *) &mode, p, sizeof mode))
+             if (memcmp ((char *) &mode, p, sizeof mode))
                return 0;
 
              p += sizeof mode;
@@ -2608,7 +2593,7 @@ compare_constant_1 (exp, p)
 
          p += sizeof type;
 
-         if (bcmp ((char *) &have_purpose, p, sizeof have_purpose))
+         if (memcmp ((char *) &have_purpose, p, sizeof have_purpose))
            return 0;
 
          p += sizeof have_purpose;
@@ -2618,7 +2603,7 @@ compare_constant_1 (exp, p)
            {
              HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp));
 
-             if (bcmp ((char *) &size, p, sizeof size))
+             if (memcmp ((char *) &size, p, sizeof size))
                return 0;
 
              p += sizeof size;
@@ -2635,7 +2620,7 @@ compare_constant_1 (exp, p)
                {
                  tree zero = 0;
 
-                 if (bcmp ((char *) &zero, p, sizeof zero))
+                 if (memcmp ((char *) &zero, p, sizeof zero))
                    return 0;
 
                  p += sizeof zero;
@@ -2644,7 +2629,7 @@ compare_constant_1 (exp, p)
              if (TREE_PURPOSE (link)
                  && TREE_CODE (TREE_PURPOSE (link)) == FIELD_DECL)
                {
-                 if (bcmp ((char *) &TREE_PURPOSE (link), p,
+                 if (memcmp ((char *) &TREE_PURPOSE (link), p,
                            sizeof TREE_PURPOSE (link)))
                    return 0;
 
@@ -2659,7 +2644,7 @@ compare_constant_1 (exp, p)
                {
                  int zero = 0;
 
-                 if (bcmp ((char *) &zero, p, sizeof zero))
+                 if (memcmp ((char *) &zero, p, sizeof zero))
                    return 0;
 
                  p += sizeof zero;
@@ -2674,7 +2659,7 @@ compare_constant_1 (exp, p)
        struct addr_const value;
 
        decode_addr_const (exp, &value);
-       strp = (char *) &value.offset;
+       strp = (unsigned char *) &value.offset;
        len = sizeof value.offset;
        /* Compare the offset.  */
        while (--len >= 0)
@@ -2682,8 +2667,8 @@ compare_constant_1 (exp, p)
            return 0;
 
        /* Compare symbol name.  */
-       strp = XSTR (value.base, 0);
-       len = strlen (strp) + 1;
+       strp = (const unsigned char *) XSTR (value.base, 0);
+       len = strlen ((const char *) strp) + 1;
       }
       break;
 
@@ -2702,7 +2687,12 @@ compare_constant_1 (exp, p)
       return compare_constant_1 (TREE_OPERAND (exp, 0), p);
 
     default:
-      abort ();
+      if (lang_expand_constant)
+        {
+          exp = (*lang_expand_constant) (exp);
+          return compare_constant_1 (exp, p);
+        }
+      return 0;
     }
 
   /* Compare constant contents.  */
@@ -2723,6 +2713,7 @@ record_constant (exp)
   struct constant_descriptor *next = 0;
   char *label = 0;
   rtx rtl = 0;
+  int pad;
 
   /* Make a struct constant_descriptor.  The first three pointers will
      be filled in later.  Here we just leave space for them.  */
@@ -2730,6 +2721,14 @@ record_constant (exp)
   obstack_grow (&permanent_obstack, (char *) &next, sizeof next);
   obstack_grow (&permanent_obstack, (char *) &label, sizeof label);
   obstack_grow (&permanent_obstack, (char *) &rtl, sizeof rtl);
+
+  /* Align the descriptor for the data payload.  */
+  pad = (offsetof (struct constant_descriptor, u)
+        - offsetof(struct constant_descriptor, rtl)
+        - sizeof(next->rtl));
+  if (pad > 0)
+    obstack_blank (&permanent_obstack, pad);
+
   record_constant_1 (exp);
   return (struct constant_descriptor *) obstack_finish (&permanent_obstack);
 }
@@ -2743,7 +2742,7 @@ static void
 record_constant_1 (exp)
      tree exp;
 {
-  register char *strp;
+  register const unsigned char *strp;
   register int len;
   register enum tree_code code = TREE_CODE (exp);
 
@@ -2753,13 +2752,13 @@ record_constant_1 (exp)
     {
     case INTEGER_CST:
       obstack_1grow (&permanent_obstack, TYPE_PRECISION (TREE_TYPE (exp)));
-      strp = (char *) &TREE_INT_CST_LOW (exp);
-      len = 2 * sizeof TREE_INT_CST_LOW (exp);
+      strp = (unsigned char *) &TREE_INT_CST (exp);
+      len = sizeof TREE_INT_CST (exp);
       break;
 
     case REAL_CST:
       obstack_1grow (&permanent_obstack, TYPE_PRECISION (TREE_TYPE (exp)));
-      strp = (char *) &TREE_REAL_CST (exp);
+      strp = (unsigned char *) &TREE_REAL_CST (exp);
       len = sizeof TREE_REAL_CST (exp);
       break;
 
@@ -2768,7 +2767,7 @@ record_constant_1 (exp)
        return;
 
       obstack_1grow (&permanent_obstack, TYPE_MODE (TREE_TYPE (exp)));
-      strp = TREE_STRING_POINTER (exp);
+      strp = (const unsigned char *) TREE_STRING_POINTER (exp);
       len = TREE_STRING_LENGTH (exp);
       obstack_grow (&permanent_obstack, (char *) &TREE_STRING_LENGTH (exp),
                    sizeof TREE_STRING_LENGTH (exp));
@@ -2865,9 +2864,24 @@ record_constant_1 (exp)
        /* Record the offset.  */
        obstack_grow (&permanent_obstack,
                      (char *) &value.offset, sizeof value.offset);
-       /* Record the symbol name.  */
-       obstack_grow (&permanent_obstack, XSTR (value.base, 0),
-                     strlen (XSTR (value.base, 0)) + 1);
+
+       switch (GET_CODE (value.base))
+         {
+         case SYMBOL_REF:
+           /* Record the symbol name.  */
+           obstack_grow (&permanent_obstack, XSTR (value.base, 0),
+                         strlen (XSTR (value.base, 0)) + 1);
+           break;
+         case LABEL_REF:
+           /* Record the address of the CODE_LABEL.  It may not have
+              been emitted yet, so it's UID may be zero.  But pointer
+              identity is good enough.  */
+           obstack_grow (&permanent_obstack, &XEXP (value.base, 0),
+                         sizeof (rtx));
+           break;
+         default:
+           abort ();
+         }
       }
       return;
 
@@ -2885,7 +2899,12 @@ record_constant_1 (exp)
       return;
 
     default:
-      abort ();
+      if (lang_expand_constant)
+        {
+          exp = (*lang_expand_constant) (exp);
+          record_constant_1 (exp);
+        }
+      return;
     }
 
   /* Record constant contents.  */
@@ -3031,18 +3050,25 @@ copy_constant (exp)
    Otherwise, output such a constant in memory (or defer it for later)
    and generate an rtx for it.
 
+   If DEFER is non-zero, the output of string constants can be deferred
+   and output only if referenced in the function after all optimizations.
+
    The TREE_CST_RTL of EXP is set up to point to that rtx.
    The const_hash_table records which constants already have label strings.  */
 
 rtx
-output_constant_def (exp)
+output_constant_def (exp, defer)
      tree exp;
+     int defer;
 {
   register int hash;
   register struct constant_descriptor *desc;
+  struct deferred_string **defstr;
   char label[256];
   int reloc;
   int found = 1;
+  int after_function = 0;
+  int labelno = -1;
 
   if (TREE_CST_RTL (exp))
     return TREE_CST_RTL (exp);
@@ -3070,31 +3096,20 @@ output_constant_def (exp)
         future calls to this function to find.  */
          
       /* Create a string containing the label name, in LABEL.  */
-      ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
+      labelno = const_labelno++;
+      ASM_GENERATE_INTERNAL_LABEL (label, "LC", labelno);
 
       desc = record_constant (exp);
       desc->next = const_hash_table[hash];
-      desc->label = ggc_alloc_string (label, -1);
+      desc->label = ggc_strdup (label);
       const_hash_table[hash] = desc;
   
-      /* We have a symbol name; construct the SYMBOL_REF and the MEM
-        in the permanent obstack.  We could also construct this in the
-        obstack of EXP and put it into TREE_CST_RTL, but we have no way
-        of knowing what obstack it is (e.g., it might be in a function
-        obstack of a function we are nested inside).  */
-
-      push_obstacks_nochange ();
-      end_temporary_allocation ();
-
+      /* We have a symbol name; construct the SYMBOL_REF and the MEM.  */
       desc->rtl
        = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)),
                       gen_rtx_SYMBOL_REF (Pmode, desc->label));
 
-      RTX_UNCHANGING_P (desc->rtl) = 1;
-      if (AGGREGATE_TYPE_P (TREE_TYPE (exp)))
-       MEM_SET_IN_STRUCT_P (desc->rtl, 1);
-
-      pop_obstacks ();
+      set_mem_attributes (desc->rtl, exp, 1);
 
       found = 0;
     }
@@ -3105,32 +3120,52 @@ output_constant_def (exp)
      such as that it is a function name.  If the name is changed, the macro
      ASM_OUTPUT_LABELREF will have to know how to strip this information.  */
 #ifdef ENCODE_SECTION_INFO
-  ENCODE_SECTION_INFO (exp);
-#endif
-
-  /* If this is the first time we've seen this particular constant,
-     output it (or defer its output for later).  */
+  /* A previously-processed constant would already have section info
+     encoded in it.  */
   if (! found)
     {
-      int after_function = 0;
+      ENCODE_SECTION_INFO (exp);
+      desc->rtl = TREE_CST_RTL (exp);
+      desc->label = XSTR (XEXP (desc->rtl, 0), 0);
+    }
+#endif
 
 #ifdef CONSTANT_AFTER_FUNCTION_P
-      if (current_function_decl != 0
-         && CONSTANT_AFTER_FUNCTION_P (exp))
-       after_function = 1;
+  if (current_function_decl != 0
+      && CONSTANT_AFTER_FUNCTION_P (exp))
+    after_function = 1;
 #endif
 
+  if (found
+      && STRING_POOL_ADDRESS_P (XEXP (desc->rtl, 0))
+      && (!defer || defer_addressed_constants_flag || after_function))
+    {
+      defstr = (struct deferred_string **)
+       htab_find_slot_with_hash (const_str_htab, desc->label,
+                                 STRHASH (desc->label), NO_INSERT);
+      if (defstr)
+       {
+         /* If the string is currently deferred but we need to output it now,
+            remove it from deferred string hash table.  */
+         found = 0;
+         labelno = (*defstr)->labelno;
+         STRING_POOL_ADDRESS_P (XEXP (desc->rtl, 0)) = 0;
+         htab_clear_slot (const_str_htab, (void **) defstr);
+       }
+    }
+
+  /* If this is the first time we've seen this particular constant,
+     output it (or defer its output for later).  */
+  if (! found)
+    {
       if (defer_addressed_constants_flag || after_function)
        {
          struct deferred_constant *p;
          p = (struct deferred_constant *) xmalloc (sizeof (struct deferred_constant));
 
-         push_obstacks_nochange ();
-         suspend_momentary ();
          p->exp = copy_constant (exp);
-         pop_obstacks ();
          p->reloc = reloc;
-         p->labelno = const_labelno++;
+         p->labelno = labelno;
          if (after_function)
            {
              p->next = after_function_constants;
@@ -3146,8 +3181,30 @@ output_constant_def (exp)
        {
          /* Do no output if -fsyntax-only.  */
          if (! flag_syntax_only)
-           output_constant_def_contents (exp, reloc, const_labelno);
-         ++const_labelno;
+           {
+             if (TREE_CODE (exp) != STRING_CST
+                 || !defer
+                 || flag_writable_strings
+                 || (defstr = (struct deferred_string **)
+                              htab_find_slot_with_hash (const_str_htab,
+                                                        desc->label,
+                                                        STRHASH (desc->label),
+                                                        INSERT)) == NULL)
+               output_constant_def_contents (exp, reloc, labelno);
+             else
+               {
+                 struct deferred_string *p;
+
+                 p = (struct deferred_string *)
+                     xmalloc (sizeof (struct deferred_string));
+
+                 p->exp = copy_constant (exp);
+                 p->label = desc->label;
+                 p->labelno = labelno;
+                 *defstr = p;
+                 STRING_POOL_ADDRESS_P (XEXP (desc->rtl, 0)) = 1;
+               }
+           }
        }
     }
 
@@ -3209,25 +3266,16 @@ output_constant_def_contents (exp, reloc, labelno)
 struct pool_constant
 {
   struct constant_descriptor *desc;
-  struct pool_constant *next;
-  enum machine_mode mode;
+  struct pool_constant *next, *next_sym;
+  const char *label;
   rtx constant;
+  enum machine_mode mode;
   int labelno;
   int align;
   int offset;
   int mark;
 };
 
-/* Structure used to maintain hash table mapping symbols used to their
-   corresponding constants.  */
-
-struct pool_sym
-{
-  char *label;
-  struct pool_constant *pool;
-  struct pool_sym *next;
-};
-
 /* Hash code for a SYMBOL_REF with CONSTANT_POOL_ADDRESS_P true.
    The argument is XSTR (... , 0)  */
 
@@ -3245,14 +3293,10 @@ init_varasm_status (f)
   f->varasm = p;
   p->x_const_rtx_hash_table
     = ((struct constant_descriptor **)
-       xmalloc (MAX_RTX_HASH_TABLE * sizeof (struct constant_descriptor *)));
+       xcalloc (MAX_RTX_HASH_TABLE, sizeof (struct constant_descriptor *)));
   p->x_const_rtx_sym_hash_table
-    = ((struct pool_sym **)
-       xmalloc (MAX_RTX_HASH_TABLE * sizeof (struct pool_sym *)));
-  bzero ((char *) p->x_const_rtx_hash_table,
-        MAX_RTX_HASH_TABLE * sizeof (struct constant_descriptor *));
-  bzero ((char *) p->x_const_rtx_sym_hash_table,
-        MAX_RTX_HASH_TABLE * sizeof (struct pool_sym *));
+    = ((struct pool_constant **)
+       xcalloc (MAX_RTX_HASH_TABLE, sizeof (struct pool_constant *)));
 
   p->x_first_pool = p->x_last_pool = 0;
   p->x_pool_offset = 0;
@@ -3267,25 +3311,12 @@ mark_pool_constant (pc)
 {
   while (pc)
     {
+      ggc_mark (pc);
       ggc_mark_rtx (pc->constant);
       pc = pc->next;
     }
 }
 
-/* Mark PPS for GC.  */
-
-static void
-mark_pool_sym_hash_table (pps)
-     struct pool_sym **pps;
-{
-  struct pool_sym *ps;
-  int i;
-
-  for (i = 0; i < MAX_RTX_HASH_TABLE; ++i)
-    for (ps = pps[i]; ps ; ps = ps->next)
-      ggc_mark_string (ps->label);
-}
-
 /* Mark P for GC.  */
 
 void
@@ -3296,7 +3327,6 @@ mark_varasm_status (p)
     return;
 
   mark_pool_constant (p->x_first_pool);
-  mark_pool_sym_hash_table (p->x_const_rtx_sym_hash_table);
   ggc_mark_rtx (p->x_const_double_chain);
 }
 
@@ -3309,31 +3339,29 @@ free_varasm_status (f)
      struct function *f;
 {
   struct varasm_status *p;
+  int i;
 
   p = f->varasm;
+
+  /* Clear out the hash tables.  */
+  for (i = 0; i < MAX_RTX_HASH_TABLE; ++i)
+    {
+      struct constant_descriptor* cd;
+
+      cd = p->x_const_rtx_hash_table[i];
+      while (cd) {
+       struct constant_descriptor* next = cd->next;
+       free (cd);
+       cd = next;
+      }
+    }
+
   free (p->x_const_rtx_hash_table);
   free (p->x_const_rtx_sym_hash_table);
   free (p);
   f->varasm = NULL;
 }
 \f
-enum kind { RTX_DOUBLE, RTX_INT };
-
-struct rtx_const
-{
-#ifdef ONLY_INT_FIELDS
-  unsigned int kind : 16;
-  unsigned int mode : 16;
-#else
-  enum kind kind : 16;
-  enum machine_mode mode : 16;
-#endif
-  union {
-    union real_extract du;
-    struct addr_const addr;
-    struct {HOST_WIDE_INT high, low;} di;
-  } un;
-};
 
 /* Express an rtx for a constant integer (perhaps symbolic)
    as the sum of a symbol or label plus an explicit integer.
@@ -3346,13 +3374,7 @@ decode_rtx_const (mode, x, value)
      struct rtx_const *value;
 {
   /* Clear the whole structure, including any gaps.  */
-
-  {
-    int *p = (int *) value;
-    int *end = (int *) (value + 1);
-    while (p < end)
-      *p++ = 0;
-  }
+  memset (value, 0, sizeof (struct rtx_const));
 
   value->kind = RTX_INT;       /* Most usual kind.  */
   value->mode = mode;
@@ -3364,8 +3386,8 @@ decode_rtx_const (mode, x, value)
       if (GET_MODE (x) != VOIDmode)
        {
          value->mode = GET_MODE (x);
-         bcopy ((char *) &CONST_DOUBLE_LOW (x),
-                (char *) &value->un.du, sizeof value->un.du);
+         memcpy ((char *) &value->un.du,
+                 (char *) &CONST_DOUBLE_LOW (x), sizeof value->un.du);
        }
       else
        {
@@ -3386,22 +3408,21 @@ decode_rtx_const (mode, x, value)
 
     case CONST:
       x = XEXP (x, 0);
-      if (GET_CODE (x) == PLUS)
+      if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
        {
          value->un.addr.base = XEXP (x, 0);
-         if (GET_CODE (XEXP (x, 1)) != CONST_INT)
-           abort ();
          value->un.addr.offset = INTVAL (XEXP (x, 1));
        }
-      else if (GET_CODE (x) == MINUS)
+      else if (GET_CODE (x) == MINUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
        {
          value->un.addr.base = XEXP (x, 0);
-         if (GET_CODE (XEXP (x, 1)) != CONST_INT)
-           abort ();
          value->un.addr.offset = - INTVAL (XEXP (x, 1));
        }
       else
-       abort ();
+       {
+         value->un.addr.base = x;
+         value->un.addr.offset = 0;
+       }
       break;
 
     default:
@@ -3475,7 +3496,7 @@ compare_constant_rtx (mode, x, desc)
      rtx x;
      struct constant_descriptor *desc;
 {
-  register int *p = (int *) desc->contents;
+  register int *p = (int *) desc->u.contents;
   register int *strp;
   register int len;
   struct rtx_const value;
@@ -3501,23 +3522,13 @@ record_constant_rtx (mode, x)
      rtx x;
 {
   struct constant_descriptor *ptr;
-  char *label;
-  rtx rtl;
-  struct rtx_const value;
-
-  decode_rtx_const (mode, x, &value);
 
-  /* Put these things in the saveable obstack so we can ensure it won't
-     be freed if we are called from combine or some other phase that discards
-     memory allocated from function_obstack (current_obstack).  */
-  obstack_grow (saveable_obstack, &ptr, sizeof ptr);
-  obstack_grow (saveable_obstack, &label, sizeof label);
-  obstack_grow (saveable_obstack, &rtl, sizeof rtl);
+  ptr = ((struct constant_descriptor *) 
+        xcalloc (1, (offsetof (struct constant_descriptor, u)
+                     + sizeof (struct rtx_const))));
+  decode_rtx_const (mode, x, (struct rtx_const *) ptr->u.contents);
 
-  /* Record constant contents.  */
-  obstack_grow (saveable_obstack, &value, sizeof value);
-
-  return (struct constant_descriptor *) obstack_finish (saveable_obstack);
+  return ptr;
 }
 \f
 /* Given a constant rtx X, make (or find) a memory constant for its value
@@ -3531,7 +3542,7 @@ force_const_mem (mode, x)
   register int hash;
   register struct constant_descriptor *desc;
   char label[256];
-  char *found = 0;
+  const char *found = 0;
   rtx def;
 
   /* If we want this CONST_DOUBLE in the same mode as it is in memory
@@ -3563,7 +3574,6 @@ force_const_mem (mode, x)
   if (found == 0)
     {
       register struct pool_constant *pool;
-      register struct pool_sym *sym;
       int align;
 
       /* No constant equal to X is known to have been output.
@@ -3587,32 +3597,12 @@ force_const_mem (mode, x)
       pool_offset += align - 1;
       pool_offset &= ~ (align - 1);
 
-      /* If RTL is not being placed into the saveable obstack, make a
-        copy of X that is in the saveable obstack in case we are
-        being called from combine or some other phase that discards
-        memory it allocates.  We used to only do this if it is a
-        CONST; however, reload can allocate a CONST_INT when
-        eliminating registers.  */
-      if (rtl_obstack != saveable_obstack
-         && (GET_CODE (x) == CONST || GET_CODE (x) == CONST_INT))
-       {
-         push_obstacks_nochange ();
-         rtl_in_saveable_obstack ();
-
-         if (GET_CODE (x) == CONST)
-           x = gen_rtx_CONST (GET_MODE (x), 
-                              gen_rtx_PLUS (GET_MODE (x), 
-                                            XEXP (XEXP (x, 0), 0),
-                                            XEXP (XEXP (x, 0), 1)));
-         else
-           x = GEN_INT (INTVAL (x));
-
-         pop_obstacks ();
-       }
+      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 = (struct pool_constant *) savealloc (sizeof (struct pool_constant));
+      pool = (struct pool_constant *) ggc_alloc (sizeof (struct pool_constant));
       pool->desc = desc;
       pool->constant = x;
       pool->mode = mode;
@@ -3635,22 +3625,21 @@ force_const_mem (mode, x)
 
       ++const_labelno;
 
-      desc->label = found = ggc_alloc_string (label, -1);
+      desc->label = found = ggc_strdup (label);
 
       /* Add label to symbol hash table.  */
       hash = SYMHASH (found);
-      sym = (struct pool_sym *) savealloc (sizeof (struct pool_sym));
-      sym->label = found;
-      sym->pool = pool;
-      sym->next = const_rtx_sym_hash_table[hash];
-      const_rtx_sym_hash_table[hash] = sym;
+      pool->label = found;
+      pool->next_sym = const_rtx_sym_hash_table[hash];
+      const_rtx_sym_hash_table[hash] = pool;
     }
 
   /* We have a symbol name; construct the SYMBOL_REF and the MEM.  */
 
   def = gen_rtx_MEM (mode, gen_rtx_SYMBOL_REF (Pmode, found));
-
+  set_mem_attributes (def, type_for_mode (mode, 0), 1);
   RTX_UNCHANGING_P (def) = 1;
+
   /* Mark the symbol_ref as belonging to this constants pool.  */
   CONSTANT_POOL_ADDRESS_P (XEXP (def, 0)) = 1;
   current_function_uses_const_pool = 1;
@@ -3676,12 +3665,13 @@ find_pool_constant (f, addr)
      struct function *f;
      rtx addr;
 {
-  struct pool_sym *sym;
-  char *label = XSTR (addr, 0);
+  struct pool_constant *pool;
+  const char *label = XSTR (addr, 0);
 
-  for (sym = f->varasm->x_const_rtx_sym_hash_table[SYMHASH (label)]; sym; sym = sym->next)
-    if (sym->label == label)
-      return sym->pool;
+  for (pool = f->varasm->x_const_rtx_sym_hash_table[SYMHASH (label)]; pool;
+       pool = pool->next_sym)
+    if (pool->label == label)
+      return pool;
 
   abort ();
 }
@@ -3761,6 +3751,8 @@ output_constant_pool (fnname, fndecl)
 
   for (pool = first_pool; pool; pool = pool->next)
     {
+      rtx tmp;
+
       x = pool->constant;
 
       if (! pool->mark)
@@ -3771,14 +3763,34 @@ output_constant_pool (fnname, fndecl)
         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.  */
-      if (((GET_CODE (x) == LABEL_REF
-           && (INSN_DELETED_P (XEXP (x, 0))
-               || GET_CODE (XEXP (x, 0)) == NOTE)))
-         || (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS
-             && GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF
-             && (INSN_DELETED_P (XEXP (XEXP (XEXP (x, 0), 0), 0))
-                 || GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == NOTE)))
-       x = const0_rtx;
+      /* ??? 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 */
+
+       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;
+       }
 
       /* First switch to correct section.  */
 #ifdef SELECT_RTX_SECTION
@@ -3805,7 +3817,7 @@ output_constant_pool (fnname, fndecl)
          if (GET_CODE (x) != CONST_DOUBLE)
            abort ();
 
-         bcopy ((char *) &CONST_DOUBLE_LOW (x), (char *) &u, sizeof u);
+         memcpy ((char *) &u, (char *) &CONST_DOUBLE_LOW (x), sizeof u);
          assemble_real (u.d, pool->mode);
          break;
 
@@ -3833,7 +3845,8 @@ output_constant_pool (fnname, fndecl)
 }
 
 /* Look through the instructions for this function, and mark all the
-   entries in the constant pool which are actually being used.  */
+   entries in the constant pool which are actually being used.
+   Emit used deferred strings.  */
 
 static void
 mark_constant_pool ()
@@ -3841,56 +3854,31 @@ mark_constant_pool ()
   register rtx insn;
   struct pool_constant *pool;
 
-  if (first_pool == 0)
+  if (first_pool == 0 && htab_elements (const_str_htab) == 0)
     return;
 
   for (pool = first_pool; pool; pool = pool->next)
     pool->mark = 0;
 
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
-    if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+    if (INSN_P (insn))
       mark_constants (PATTERN (insn));
 
   for (insn = current_function_epilogue_delay_list;
        insn;
        insn = XEXP (insn, 1))
-    if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+    if (INSN_P (insn))
       mark_constants (PATTERN (insn));
-
-  /* It's possible that the only reference to a symbol is in a symbol
-     that's in the constant pool.  This happens in Fortran under some
-     situations.  (When the constant contains the address of another
-     constant, and only the first is used directly in an insn.) 
-     This is potentially suboptimal if there's ever a possibility of
-     backwards (in pool order) 2'd level references.  However, it's
-     not clear that 2'd level references can happen. */
-  for (pool = first_pool; pool; pool = pool->next)
-    {
-      struct pool_sym *sym;
-      char *label;
-
-      /* skip unmarked entries; no insn refers to them. */
-      if (!pool->mark)
-         continue;
-
-      /* Skip everything except SYMBOL_REFs.  */
-      if (GET_CODE (pool->constant) != SYMBOL_REF)
-       continue;
-      label = XSTR (pool->constant, 0);
-
-      /* Be sure the symbol's value is marked. */
-      for (sym = const_rtx_sym_hash_table[SYMHASH (label)]; sym; 
-           sym = sym->next)
-         if (sym->label == label)
-           sym->pool->mark = 1;
-      /* If we didn't find it, there's something truly wrong here, but it
-        will be announced by the assembler. */
-    }
 }
 
+/* Look through appropriate parts of X, 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 (x)
-     register rtx x;
+     rtx x;
 {
   register int i;
   register const char *format_ptr;
@@ -3900,8 +3888,7 @@ mark_constants (x)
 
   if (GET_CODE (x) == SYMBOL_REF)
     {
-      if (CONSTANT_POOL_ADDRESS_P (x))
-       find_pool_constant (cfun, x)->mark = 1;
+      mark_constant (&x, NULL);
       return;
     }
   /* Never search inside a CONST_DOUBLE, because CONST_DOUBLE_MEM may be
@@ -3912,7 +3899,7 @@ mark_constants (x)
   /* 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 (GET_RTX_CLASS (GET_CODE (x)) == 'i')
+  if (INSN_P (x))
     {
       mark_constants (PATTERN (x));
       return;
@@ -3952,6 +3939,55 @@ mark_constants (x)
        }
     }
 }
+
+/* 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.  */
+
+static int
+mark_constant (current_rtx, data)
+     rtx *current_rtx;
+     void *data ATTRIBUTE_UNUSED;
+{
+  rtx x = *current_rtx;
+
+  if (x == NULL_RTX)
+    return 0;
+  else if (GET_CODE(x) == CONST_DOUBLE)
+    /* Never search inside a CONST_DOUBLE because CONST_DOUBLE_MEM may
+       be a MEM but does not constitute a use of that MEM.  */
+    return -1;
+  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 (STRING_POOL_ADDRESS_P (x))
+       {
+         struct deferred_string **defstr;
+
+         defstr = (struct deferred_string **)
+           htab_find_slot_with_hash (const_str_htab, XSTR (x, 0),
+                                     STRHASH (XSTR (x, 0)), NO_INSERT);
+         if (defstr)
+           {
+             struct deferred_string *p = *defstr;
+
+             STRING_POOL_ADDRESS_P (x) = 0;
+             output_constant_def_contents (p->exp, 0, p->labelno);
+             htab_clear_slot (const_str_htab, (void **) defstr);
+           }
+       }
+    }
+  return 0;
+}
 \f
 /* Find all the constants whose addresses are referenced inside of EXP,
    and make sure assembler code with a label has been output for each one.
@@ -3963,6 +3999,11 @@ output_addressed_constants (exp)
 {
   int reloc = 0;
 
+  /* Give the front-end a chance to convert VALUE to something that
+     looks more like a constant to the back-end.  */
+  if (lang_expand_constant)
+    exp = (*lang_expand_constant) (exp);
+
   switch (TREE_CODE (exp))
     {
     case ADDR_EXPR:
@@ -3978,7 +4019,7 @@ output_addressed_constants (exp)
            || TREE_CODE (constant) == CONSTRUCTOR)
          /* No need to do anything here
             for addresses of variables or functions.  */
-         output_constant_def (constant);
+         output_constant_def (constant, 0);
       }
       reloc = 1;
       break;
@@ -4025,6 +4066,11 @@ initializer_constant_valid_p (value, endtype)
      tree value;
      tree endtype;
 {
+  /* Give the front-end a chance to convert VALUE to something that
+     looks more like a constant to the back-end.  */
+  if (lang_expand_constant)
+    value = (*lang_expand_constant) (value);
+
   switch (TREE_CODE (value))
     {
     case CONSTRUCTOR:
@@ -4045,7 +4091,7 @@ initializer_constant_valid_p (value, endtype)
       return null_pointer_node;
 
     case ADDR_EXPR:
-      return TREE_OPERAND (value, 0);
+      return staticp (TREE_OPERAND (value, 0)) ? TREE_OPERAND (value, 0) : 0;
 
     case NON_LVALUE_EXPR:
       return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
@@ -4139,6 +4185,14 @@ initializer_constant_valid_p (value, endtype)
             Then the value is absolute.  */
          if (valid0 == valid1 && valid0 != 0)
            return null_pointer_node;
+
+         /* Since GCC guarantees that string constants are unique in the
+            generated code, a subtraction between two copies of the same
+            constant string is absolute.  */
+         if (valid0 && TREE_CODE (valid0) == STRING_CST &&
+             valid1 && TREE_CODE (valid1) == STRING_CST &&
+             TREE_STRING_POINTER (valid0) == TREE_STRING_POINTER (valid1))
+           return null_pointer_node;
        }
 
       /* Support differences between labels.  */
@@ -4195,19 +4249,28 @@ output_constant (exp, size)
      directly.  Give the front-end a chance to convert EXP to a
      language-independent representation.  */
   if (lang_expand_constant)
-    exp = (*lang_expand_constant) (exp);
+    {
+      exp = (*lang_expand_constant) (exp);
+      code = TREE_CODE (TREE_TYPE (exp));
+    }
 
   if (size == 0 || flag_syntax_only)
     return;
 
   /* Eliminate the NON_LVALUE_EXPR_EXPR that makes a cast not be an lvalue.
      That way we get the constant (we hope) inside it.  Also, strip off any
-     NOP_EXPR that converts between two record, union, array, or set types.  */
+     NOP_EXPR that converts between two record, union, array, or set types
+     or a CONVERT_EXPR that converts to a union TYPE.  */
   while ((TREE_CODE (exp) == NOP_EXPR 
          && (TREE_TYPE (exp) == TREE_TYPE (TREE_OPERAND (exp, 0))
              || AGGREGATE_TYPE_P (TREE_TYPE (exp))))
+        || (TREE_CODE (exp) == CONVERT_EXPR
+            && code == UNION_TYPE)
         || TREE_CODE (exp) == NON_LVALUE_EXPR)
-    exp = TREE_OPERAND (exp, 0);
+    {
+      exp = TREE_OPERAND (exp, 0);
+      code = TREE_CODE (TREE_TYPE (exp));
+    }
 
   /* Allow a constructor with no elements for any data type.
      This means to fill the space with zeros.  */
@@ -4308,8 +4371,43 @@ output_constant (exp, size)
 }
 
 \f
-/* Subroutine of output_constant, used for CONSTRUCTORs
-   (aggregate constants).
+/* Subroutine of output_constructor, used for computing the size of
+   arrays of unspecified length.  VAL must be a CONSTRUCTOR of an array
+   type with an unspecified upper bound.  */
+
+static unsigned HOST_WIDE_INT
+array_size_for_constructor (val)
+     tree val;
+{
+  tree max_index, i;
+
+  max_index = NULL_TREE;
+  for (i = CONSTRUCTOR_ELTS (val); i ; i = TREE_CHAIN (i))
+    {
+      tree index = TREE_PURPOSE (i);
+
+      if (TREE_CODE (index) == RANGE_EXPR)
+       index = TREE_OPERAND (index, 1);
+      if (max_index == NULL_TREE || tree_int_cst_lt (max_index, index))
+       max_index = index;
+    }
+
+  if (max_index == NULL_TREE)
+    return 0;
+
+  /* Compute the total number of array elements.  */
+  i = size_binop (MINUS_EXPR, convert (sizetype, max_index), 
+                 convert (sizetype,
+                          TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (val)))));
+  i = size_binop (PLUS_EXPR, i, convert (sizetype, integer_one_node));
+
+  /* Multiply by the array element unit size to find number of bytes.  */
+  i = size_binop (MULT_EXPR, i, TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (val))));
+
+  return tree_low_cst (i, 1);
+}
+
+/* Subroutine of output_constant, used for CONSTRUCTORs (aggregate constants).
    Generate at least SIZE bytes, padding if necessary.  */
 
 static void
@@ -4317,11 +4415,12 @@ output_constructor (exp, size)
      tree exp;
      int size;
 {
+  tree type = TREE_TYPE (exp);
   register tree link, field = 0;
-  HOST_WIDE_INT min_index = 0;
+  tree min_index = 0;
   /* Number of bytes output or skipped so far.
      In other words, current position within the constructor.  */
-  int total_bytes = 0;
+  HOST_WIDE_INT total_bytes = 0;
   /* Non-zero means BYTE contains part of a byte, to be output.  */
   int byte_buffer_in_use = 0;
   register int byte = 0;
@@ -4329,13 +4428,12 @@ output_constructor (exp, size)
   if (HOST_BITS_PER_WIDE_INT < BITS_PER_UNIT)
     abort ();
 
-  if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
-    field = TYPE_FIELDS (TREE_TYPE (exp));
+  if (TREE_CODE (type) == RECORD_TYPE)
+    field = TYPE_FIELDS (type);
 
-  if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE
-      && TYPE_DOMAIN (TREE_TYPE (exp)) != 0)
-    min_index
-      = TREE_INT_CST_LOW (TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (exp))));
+  if (TREE_CODE (type) == ARRAY_TYPE
+      && TYPE_DOMAIN (type) != 0)
+    min_index = TYPE_MIN_VALUE (TYPE_DOMAIN (type));
 
   /* As LINK goes through the elements of the constant,
      FIELD goes through the structure fields, if the constant is a structure.
@@ -4354,17 +4452,14 @@ output_constructor (exp, size)
       tree val = TREE_VALUE (link);
       tree index = 0;
 
-      /* the element in a union constructor specifies the proper field.  */
+      /* The element in a union constructor specifies the proper field
+        or index.  */
+      if ((TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE
+          || TREE_CODE (type) == QUAL_UNION_TYPE)
+         && TREE_PURPOSE (link) != 0)
+       field = TREE_PURPOSE (link);
 
-      if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE
-         || TREE_CODE (TREE_TYPE (exp)) == UNION_TYPE)
-       {
-         /* if available, use the type given by link */
-         if (TREE_PURPOSE (link) != 0)
-           field = TREE_PURPOSE (link);
-       }
-
-      if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
+      else if (TREE_CODE (type) == ARRAY_TYPE)
        index = TREE_PURPOSE (link);
 
       /* Eliminate the marker that makes a cast not be an lvalue.  */
@@ -4373,11 +4468,12 @@ output_constructor (exp, size)
 
       if (index && TREE_CODE (index) == RANGE_EXPR)
        {
-         register int fieldsize
-           = int_size_in_bytes (TREE_TYPE (TREE_TYPE (exp)));
-         HOST_WIDE_INT lo_index = TREE_INT_CST_LOW (TREE_OPERAND (index, 0));
-         HOST_WIDE_INT hi_index = TREE_INT_CST_LOW (TREE_OPERAND (index, 1));
+         unsigned HOST_WIDE_INT fieldsize
+           = int_size_in_bytes (TREE_TYPE (type));
+         HOST_WIDE_INT lo_index = tree_low_cst (TREE_OPERAND (index, 0), 0);
+         HOST_WIDE_INT hi_index = tree_low_cst (TREE_OPERAND (index, 1), 0);
          HOST_WIDE_INT index;
+
          for (index = lo_index; index <= hi_index; index++)
            {
              /* Output the element's initial value.  */
@@ -4394,16 +4490,14 @@ output_constructor (exp, size)
        {
          /* An element that is not a bit-field.  */
 
-         register int fieldsize;
+         unsigned HOST_WIDE_INT fieldsize;
          /* Since this structure is static,
             we know the positions are constant.  */
-         int bitpos = (field ? (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field))
-                                / BITS_PER_UNIT)
-                       : 0);
+         HOST_WIDE_INT pos = field ? int_byte_position (field) : 0;
+
          if (index != 0)
-           bitpos = (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (val)))
-                     / BITS_PER_UNIT
-                     * (TREE_INT_CST_LOW (index) - min_index));
+           pos = (tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (val)), 1)
+                  * (tree_low_cst (index, 0) - tree_low_cst (min_index, 0)));
 
          /* Output any buffered-up bit-fields preceding this element.  */
          if (byte_buffer_in_use)
@@ -4416,22 +4510,49 @@ output_constructor (exp, size)
          /* Advance to offset of this element.
             Note no alignment needed in an array, since that is guaranteed
             if each element has the proper size.  */
-         if ((field != 0 || index != 0) && bitpos != total_bytes)
+         if ((field != 0 || index != 0) && pos != total_bytes)
            {
-             assemble_zeros (bitpos - total_bytes);
-             total_bytes = bitpos;
+             assemble_zeros (pos - total_bytes);
+             total_bytes = pos;
            }
 
+          else if (field != 0 && DECL_PACKED (field))
+           /* Some assemblers automaticallly align a datum according to its
+              size if no align directive is specified.  The datum, however,
+              may be declared with 'packed' attribute, so we have to disable
+              such a feature.  */
+           ASM_OUTPUT_ALIGN (asm_out_file, 0);
+
          /* Determine size this element should occupy.  */
          if (field)
            {
-             if (TREE_CODE (DECL_SIZE_UNIT (field)) != INTEGER_CST)
-               abort ();
-
-             fieldsize = TREE_INT_CST_LOW (DECL_SIZE_UNIT (field));
+             fieldsize = 0;
+
+             /* If this is an array with an unspecified upper bound,
+                the initializer determines the size.  */
+             /* ??? This ought to only checked if DECL_SIZE_UNIT is NULL,
+                but we cannot do this until the deprecated support for
+                initializing zero-length array members is removed.  */
+             if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
+                 && TYPE_DOMAIN (TREE_TYPE (field))
+                 && ! TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (field))))
+               {
+                 fieldsize = array_size_for_constructor (val);
+                 /* Given a non-empty initialization, this field had
+                    better be last.  */
+                 if (fieldsize != 0 && TREE_CHAIN (field) != NULL_TREE)
+                   abort ();
+               }
+             else if (DECL_SIZE_UNIT (field))
+               {
+                 /* ??? This can't be right.  If the decl size overflows
+                    a host integer we will silently emit no data.  */
+                 if (host_integerp (DECL_SIZE_UNIT (field), 1))
+                   fieldsize = tree_low_cst (DECL_SIZE_UNIT (field), 1);
+               }
            }
          else
-           fieldsize = int_size_in_bytes (TREE_TYPE (TREE_TYPE (exp)));
+           fieldsize = int_size_in_bytes (TREE_TYPE (type));
 
          /* Output the element's initial value.  */
          if (val == 0)
@@ -4449,9 +4570,9 @@ output_constructor (exp, size)
        {
          /* Element that is a bit-field.  */
 
-         int next_offset = TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field));
-         int end_offset
-           = (next_offset + TREE_INT_CST_LOW (DECL_SIZE (field)));
+         HOST_WIDE_INT next_offset = int_bit_position (field);
+         HOST_WIDE_INT end_offset
+           = (next_offset + tree_low_cst (DECL_SIZE (field), 1));
 
          if (val == 0)
            val = integer_zero_node;
@@ -4492,8 +4613,8 @@ output_constructor (exp, size)
              int this_time;
              int shift;
              HOST_WIDE_INT value;
-             int next_byte = next_offset / BITS_PER_UNIT;
-             int next_bit = next_offset % BITS_PER_UNIT;
+             HOST_WIDE_INT next_byte = next_offset / BITS_PER_UNIT;
+             HOST_WIDE_INT next_bit = next_offset % BITS_PER_UNIT;
 
              /* Advance from byte to byte
                 within this element when necessary.  */
@@ -4514,6 +4635,7 @@ output_constructor (exp, size)
                     first (of the bits that are significant)
                     and put them into bytes from the most significant end.  */
                  shift = end_offset - next_offset - this_time;
+
                  /* Don't try to take a bunch of bits that cross
                     the word boundary in the INTEGER_CST. We can
                     only select bits from the LOW or HIGH part
@@ -4527,9 +4649,7 @@ output_constructor (exp, size)
 
                  /* Now get the bits from the appropriate constant word.  */
                  if (shift < HOST_BITS_PER_WIDE_INT)
-                   {
-                     value = TREE_INT_CST_LOW (val);
-                   }
+                   value = TREE_INT_CST_LOW (val);
                  else if (shift < 2 * HOST_BITS_PER_WIDE_INT)
                    {
                      value = TREE_INT_CST_HIGH (val);
@@ -4537,6 +4657,7 @@ output_constructor (exp, size)
                    }
                  else
                    abort ();
+
                  /* Get the result. This works only when:
                     1 <= this_time <= HOST_BITS_PER_WIDE_INT.  */
                  byte |= (((value >> shift)
@@ -4549,17 +4670,15 @@ output_constructor (exp, size)
                     take first the least significant bits of the value
                     and pack them starting at the least significant
                     bits of the bytes.  */
-                 shift = (next_offset
-                          - TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field)));
+                 shift = next_offset - int_bit_position (field);
+
                  /* Don't try to take a bunch of bits that cross
                     the word boundary in the INTEGER_CST. We can
                     only select bits from the LOW or HIGH part
                     not from both.  */
                  if (shift < HOST_BITS_PER_WIDE_INT
                      && shift + this_time > HOST_BITS_PER_WIDE_INT)
-                   {
-                     this_time = (HOST_BITS_PER_WIDE_INT - shift);
-                   }
+                   this_time = (HOST_BITS_PER_WIDE_INT - shift);
 
                  /* Now get the bits from the appropriate constant word.  */
                  if (shift < HOST_BITS_PER_WIDE_INT)
@@ -4571,22 +4690,26 @@ output_constructor (exp, size)
                    }
                  else
                    abort ();
+
                  /* Get the result. This works only when:
                     1 <= this_time <= HOST_BITS_PER_WIDE_INT.  */
                  byte |= (((value >> shift)
                            & (((HOST_WIDE_INT) 2 << (this_time - 1)) - 1))
                           << next_bit);
                }
+
              next_offset += this_time;
              byte_buffer_in_use = 1;
            }
        }
     }
+
   if (byte_buffer_in_use)
     {
       ASM_OUTPUT_BYTE (asm_out_file, byte);
       total_bytes++;
     }
+
   if (total_bytes < size)
     assemble_zeros (size - total_bytes);
 }
@@ -4597,8 +4720,8 @@ output_constructor (exp, size)
    
 int
 add_weak (name, value)
-     char *name;
-     char *value;
+     const char *name;
+     const char *value;
 {
   struct weak_syms *weak;
 
@@ -4665,7 +4788,7 @@ weak_finish ()
 #ifdef ASM_WEAKEN_LABEL
 static void
 remove_from_pending_weak_list (name)
-     char *name ATTRIBUTE_UNUSED;
+     const char *name ATTRIBUTE_UNUSED;
 {
 #ifdef HANDLE_PRAGMA_WEAK
   if (HANDLE_PRAGMA_WEAK)
@@ -4685,10 +4808,13 @@ void
 assemble_alias (decl, target)
      tree decl, target ATTRIBUTE_UNUSED;
 {
-  char *name;
+  const char *name;
 
-  make_decl_rtl (decl, (char *) 0, 1);
-  name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
+  /* We must force creation of DECL_RTL for debug info generation, even though
+     we don't use it here.  */
+  make_decl_rtl (decl, NULL);
+
+  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
 
 #ifdef ASM_OUTPUT_DEF
   /* Make name accessible from other files, if appropriate.  */
@@ -4728,15 +4854,6 @@ assemble_alias (decl, target)
 #endif
 }
 
-/* This determines whether or not we support link-once semantics.  */
-#ifndef SUPPORTS_ONE_ONLY
-#ifdef MAKE_DECL_ONE_ONLY
-#define SUPPORTS_ONE_ONLY 1
-#else
-#define SUPPORTS_ONE_ONLY 0
-#endif
-#endif
-
 /* Returns 1 if the target configuration supports defining public symbols
    so that one of them will be chosen at link time instead of generating a
    multiply-defined symbol error, whether through the use of weak symbols or
@@ -4781,7 +4898,81 @@ make_decl_one_only (decl)
 void
 init_varasm_once ()
 {
+  const_str_htab = htab_create (128, const_str_htab_hash, const_str_htab_eq,
+                               const_str_htab_del);
   ggc_add_root (const_hash_table, MAX_HASH_TABLE, sizeof const_hash_table[0],
                mark_const_hash_entry);
-  ggc_add_string_root (&in_named_name, 1);
+  ggc_add_root (&const_str_htab, 1, sizeof const_str_htab,
+               mark_const_str_htab);
 }
+
+/* Extra support for EH values.  */
+void
+assemble_eh_label (name)
+     const char *name;
+{
+#ifdef ASM_OUTPUT_EH_LABEL
+  ASM_OUTPUT_EH_LABEL (asm_out_file, name);
+#else
+  assemble_label (name);
+#endif
+}
+
+/* Assemble an alignment pseudo op for an ALIGN-bit boundary.  */
+
+void
+assemble_eh_align (align)
+     int align;
+{
+#ifdef ASM_OUTPUT_EH_ALIGN
+  if (align > BITS_PER_UNIT)
+    ASM_OUTPUT_EH_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
+#else
+  assemble_align (align);
+#endif
+}
+
+
+/* On some platforms, we may want to specify a special mechansim to
+   output EH data when generating with a function..  */
+int
+assemble_eh_integer (x, size, force)
+     rtx x;
+     int size;
+     int force;
+{
+
+  switch (size)
+    {
+#ifdef ASM_OUTPUT_EH_CHAR
+    case 1:
+      ASM_OUTPUT_EH_CHAR (asm_out_file, x);
+      return 1;
+#endif
+
+#ifdef ASM_OUTPUT_EH_SHORT
+    case 2:
+      ASM_OUTPUT_EH_SHORT (asm_out_file, x);
+      return 1;
+#endif
+
+#ifdef ASM_OUTPUT_EH_INT
+    case 4:
+      ASM_OUTPUT_EH_INT (asm_out_file, x);
+      return 1;
+#endif
+
+#ifdef ASM_OUTPUT_EH_DOUBLE_INT
+    case 8:
+      ASM_OUTPUT_EH_DOUBLE_INT (asm_out_file, x);
+      return 1;
+#endif
+
+    default:
+      break;
+    }
+  return (assemble_integer (x, size, force));
+}
+
+
+