OSDN Git Service

* c-lex.c (read_escape, read_ucs): Delete.
[pf3gnuchains/gcc-fork.git] / gcc / varasm.c
index af76b15..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.
 
@@ -37,13 +37,13 @@ Boston, MA 02111-1307, USA.  */
 #include "expr.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.  */
@@ -80,9 +72,6 @@ extern FILE *asm_out_file;
 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.
@@ -171,8 +160,10 @@ 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 ((const char *));
@@ -187,8 +178,12 @@ static void asm_output_aligned_bss PARAMS ((FILE *, tree, const char *,
 #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 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
@@ -211,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
@@ -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.  */
@@ -511,83 +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;
-{
-  const char *name;
-  const char *new_name;
-
-  if (DECL_RTL (decl) != 0)
-    {
-      /* ??? 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;
-    }
-
-  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
-  new_name = name;
-
-  /* Rename a nested function to avoid conflicts, unless it's a member of
-     a local class, in which case the class name is already unique.  */
-  if (decl_function_context (decl) != 0
-      && ! TYPE_P (DECL_CONTEXT (decl))
-      && DECL_INITIAL (decl) != 0
-      && DECL_RTL (decl) == 0)
-    {
-      char *label;
-      ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno);
-      var_labelno++;
-      new_name = label;
-    }
-  /* 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.  */
-  else if (flag_prefix_function_name)
-    {
-      size_t name_len = IDENTIFIER_LENGTH (DECL_ASSEMBLER_NAME (decl));
-      char *pname;
-
-      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;
-    }
-
-  if (name != new_name)
-    {
-      DECL_ASSEMBLER_NAME (decl) = get_identifier (new_name);
-      name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
-    }
-
-  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
-}
-
-
 /* Given NAME, a putative register name, discard any customary prefixes.  */
 
 static const char *
@@ -663,27 +557,46 @@ 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;
 {
+  int top_level = (DECL_CONTEXT (decl) == NULL_TREE);
   const char *name = 0;
   const char *new_name = 0;
   int reg_number;
 
+  /* 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 ();
+
   /* 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 (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))
@@ -737,7 +650,7 @@ make_decl_rtl (decl, asmspec, top_level)
        {
          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");
@@ -751,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.  */
@@ -794,7 +708,8 @@ make_decl_rtl (decl, asmspec, top_level)
      Concatenate a distinguishing number.  */
   if (!top_level && !TREE_PUBLIC (decl)
       && ! (DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl)))
-      && asmspec == 0)
+      && asmspec == 0
+      && name == IDENTIFIER_POINTER (DECL_NAME (decl)))
     {
       char *label;
       ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno);
@@ -818,7 +733,7 @@ make_decl_rtl (decl, asmspec, top_level)
 
   if (name != new_name)
     {
-      DECL_ASSEMBLER_NAME (decl) = get_identifier (new_name);
+      SET_DECL_ASSEMBLER_NAME (decl, get_identifier (new_name));
       name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
     }
 
@@ -830,8 +745,9 @@ make_decl_rtl (decl, asmspec, top_level)
           && (TREE_PUBLIC (decl) || TREE_STATIC (decl)))))
     TREE_SIDE_EFFECTS (decl) = 1;
 
-  DECL_RTL (decl) = gen_rtx_MEM (DECL_MODE (decl),
-                                gen_rtx_SYMBOL_REF (Pmode, name));
+  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);
 
@@ -922,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);
     }
@@ -942,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);
     }
@@ -962,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);
     }
@@ -1127,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");
@@ -1136,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
@@ -1325,7 +1241,7 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
 
   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.  */
@@ -1709,6 +1625,13 @@ 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 (DECL_P (decl) && DECL_EXTERNAL (decl) && TREE_PUBLIC (decl))
     {
@@ -1775,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);
@@ -1796,7 +1719,7 @@ assemble_static_space (size)
      int size;
 {
   char name[12];
-  char *namestring;
+  const char *namestring;
   rtx x;
 
 #if 0
@@ -1806,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);
 
@@ -1841,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.  */
@@ -1862,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
@@ -1975,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;
@@ -2024,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
@@ -2069,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);
 
@@ -2110,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 ();
+  /* No; make a new one and add it to the chain.  */
   r = gen_rtx_CONST_DOUBLE (mode, const0_rtx, i0, i1);
-  pop_obstacks ();
 
   /* Don't touch const_double_chain if not inside any function.  */
   if (current_function_decl != 0)
@@ -2177,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;
 
@@ -2186,14 +2099,10 @@ 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);
 
   /* If we aren't inside a function, don't put r on the
      const_double_chain.  */
@@ -2314,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'
@@ -2326,15 +2247,35 @@ decode_addr_const (exp, value)
 struct constant_descriptor
 {
   struct constant_descriptor *next;
-  char *label;
+  const char *label;
   rtx rtl;
-  unsigned 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 
@@ -2345,12 +2286,63 @@ mark_const_hash_entry (ptr)
 
   while (desc)
     {
-      ggc_mark_string ((const char *)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
@@ -2457,7 +2449,7 @@ const_hash (exp)
       
     default:
       /* A language specific constant. Just hash the code. */
-      return code % MAX_HASH_TABLE;
+      return (int) code % MAX_HASH_TABLE;
     }
 
   /* Compute hashing function */
@@ -2478,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.
@@ -2532,9 +2524,9 @@ compare_constant_1 (exp, p)
       if ((enum machine_mode) *p++ != TYPE_MODE (TREE_TYPE (exp)))
        return 0;
 
-      strp = (unsigned char *)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;
 
@@ -2556,7 +2548,7 @@ compare_constant_1 (exp, p)
 
          get_set_constructor_bytes (exp, tmp, len);
          strp = (unsigned char *) tmp;
-         if (bcmp ((char *) &xlen, p, sizeof xlen))
+         if (memcmp ((char *) &xlen, p, sizeof xlen))
            return 0;
 
          p += sizeof xlen;
@@ -2574,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;
@@ -2588,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;
@@ -2601,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;
@@ -2611,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;
@@ -2628,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;
@@ -2637,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;
 
@@ -2652,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;
@@ -2675,8 +2667,8 @@ compare_constant_1 (exp, p)
            return 0;
 
        /* Compare symbol name.  */
-       strp = (unsigned char *) XSTR (value.base, 0);
-       len = strlen ((char *) strp) + 1;
+       strp = (const unsigned char *) XSTR (value.base, 0);
+       len = strlen ((const char *) strp) + 1;
       }
       break;
 
@@ -2721,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.  */
@@ -2728,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);
 }
@@ -2741,7 +2742,7 @@ static void
 record_constant_1 (exp)
      tree exp;
 {
-  register unsigned char *strp;
+  register const unsigned char *strp;
   register int len;
   register enum tree_code code = TREE_CODE (exp);
 
@@ -2766,7 +2767,7 @@ record_constant_1 (exp)
        return;
 
       obstack_1grow (&permanent_obstack, TYPE_MODE (TREE_TYPE (exp)));
-      strp = (unsigned char *) 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));
@@ -3049,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);
@@ -3088,28 +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));
 
       set_mem_attributes (desc->rtl, exp, 1);
-      pop_obstacks ();
 
       found = 0;
     }
@@ -3120,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;
@@ -3161,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;
+               }
+           }
        }
     }
 
@@ -3224,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)  */
 
@@ -3260,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;
@@ -3282,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
@@ -3311,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);
 }
 
@@ -3324,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.
@@ -3361,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;
@@ -3379,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
        {
@@ -3401,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:
@@ -3490,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;
@@ -3516,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);
-
-  /* Record constant contents.  */
-  obstack_grow (saveable_obstack, &value, sizeof value);
+  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);
 
-  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
@@ -3546,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
@@ -3578,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.
@@ -3602,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;
@@ -3650,15 +3625,13 @@ 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.  */
@@ -3692,13 +3665,13 @@ find_pool_constant (f, addr)
      struct function *f;
      rtx addr;
 {
-  struct pool_sym *sym;
+  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 ();
 }
@@ -3844,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;
 
@@ -3872,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 ()
@@ -3880,7 +3854,7 @@ 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)
@@ -3895,41 +3869,16 @@ mark_constant_pool ()
        insn = XEXP (insn, 1))
     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;
-      const 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;
@@ -3939,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
@@ -3991,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.
@@ -4002,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:
@@ -4017,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;
@@ -4183,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.  */
@@ -4239,7 +4249,10 @@ 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;
@@ -4358,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
@@ -4420,7 +4468,7 @@ output_constructor (exp, size)
 
       if (index && TREE_CODE (index) == RANGE_EXPR)
        {
-         register int fieldsize
+         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);
@@ -4442,7 +4490,7 @@ 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.  */
          HOST_WIDE_INT pos = field ? int_byte_position (field) : 0;
@@ -4477,7 +4525,32 @@ output_constructor (exp, size)
 
          /* Determine size this element should occupy.  */
          if (field)
-           fieldsize = tree_low_cst (DECL_SIZE_UNIT (field), 1);
+           {
+             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 (type));
 
@@ -4737,8 +4810,11 @@ assemble_alias (decl, target)
 {
   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.  */
@@ -4778,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
@@ -4831,9 +4898,12 @@ 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.  */