sbitmap.c: Fix comment formatting.
[gcc.git] / gcc / varasm.c
index 497931f128fbfa974738bdf2b904af1bb918dcd9..8b340624b8efc4c20f26696b42e08553e8df1888 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.
 
@@ -29,7 +29,6 @@ Boston, MA 02111-1307, USA.  */
 
 #include "config.h"
 #include "system.h"
-#include <setjmp.h>
 #include "rtl.h"
 #include "tree.h"
 #include "flags.h"
@@ -37,19 +36,20 @@ 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"
+#include "debug.h"
+#include "target.h"
 
 #ifdef XCOFF_DEBUGGING_INFO
-#include "xcoffout.h"
+#include "xcoffout.h"          /* Needed for external data
+                                  declarations for e.g. AIX 4.x.  */
 #endif
 
 #ifndef TRAMPOLINE_ALIGNMENT
@@ -61,21 +61,9 @@ Boston, MA 02111-1307, USA.  */
 #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.  */
-
-extern FILE *asm_out_file;
-
 /* The (assembler) name of the first globally-visible object output.  */
 const char *first_global_object_name;
 const char *weak_global_object_name;
@@ -101,13 +89,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.
@@ -149,6 +137,7 @@ tree last_assemble_variable_decl;
 
 static const char *strip_reg_name      PARAMS ((const char *));
 static int contains_pointers_p         PARAMS ((tree));
+static void assemble_real_1            PARAMS ((PTR));
 static void decode_addr_const          PARAMS ((tree, struct addr_const *));
 static int const_hash                  PARAMS ((tree));
 static int compare_constant            PARAMS ((tree,
@@ -168,12 +157,16 @@ 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 *));
 #endif
+static int in_named_entry_eq           PARAMS ((const PTR, const PTR));
+static hashval_t in_named_entry_hash   PARAMS ((const PTR));
 #ifdef ASM_OUTPUT_BSS
 static void asm_output_bss             PARAMS ((FILE *, tree, const char *, int, int));
 #endif
@@ -184,16 +177,24 @@ 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));
+static void resolve_unique_section     PARAMS ((tree, int));
 \f
 static enum in_section { no_section, in_text, in_data, in_named
 #ifdef BSS_SECTION_ASM_OP
   , in_bss
 #endif
-#ifdef EH_FRAME_SECTION_ASM_OP
-  , in_eh_frame
+#ifdef CTORS_SECTION_ASM_OP
+  , in_ctors
+#endif
+#ifdef DTORS_SECTION_ASM_OP
+  , in_dtors
 #endif
 #ifdef EXTRA_SECTIONS
   , EXTRA_SECTIONS
@@ -208,7 +209,17 @@ 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;
+
+/* Hash table of flags that have been used for a particular named section.  */
+
+struct in_named_entry
+{
+  const char *name;
+  unsigned int flags;
+};
+
+static htab_t in_named_htab;
 
 /* Define functions like text_section for any extra sections.  */
 #ifdef EXTRA_SECTION_FUNCTIONS
@@ -222,7 +233,11 @@ text_section ()
 {
   if (in_section != in_text)
     {
+#ifdef TEXT_SECTION
+      TEXT_SECTION ();
+#else
       fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
+#endif
       in_section = in_text;
     }
 }
@@ -249,7 +264,7 @@ data_section ()
     }
 }
 /* Tell assembler to ALWAYS switch to data section, in case
-   it's not sure where it it.  */
+   it's not sure where it is.  */
 
 void
 force_data_section ()
@@ -287,6 +302,97 @@ in_data_section ()
   return in_section == in_data;
 }
 
+/* Helper routines for maintaining in_named_htab.  */
+
+static int
+in_named_entry_eq (p1, p2)
+     const PTR p1;
+     const PTR p2;
+{
+  const struct in_named_entry *old = p1;
+  const char *new = p2;
+
+  return strcmp (old->name, new) == 0;
+}
+
+static hashval_t
+in_named_entry_hash (p)
+     const PTR p;
+{
+  const struct in_named_entry *old = p;
+  return htab_hash_string (old->name);
+}
+
+/* If SECTION has been seen before as a named section, return the flags
+   that were used.  Otherwise, return 0.  Note, that 0 is a perfectly valid
+   set of flags for a section to have, so 0 does not mean that the section
+   has not been seen.  */
+
+unsigned int
+get_named_section_flags (section)
+     const char *section;
+{
+  struct in_named_entry **slot;
+
+  slot = (struct in_named_entry**)
+    htab_find_slot_with_hash (in_named_htab, section,
+                             htab_hash_string (section), NO_INSERT);
+
+  return slot ? (*slot)->flags : 0;
+}
+
+/* Record FLAGS for SECTION.  If SECTION was previously recorded with a
+   different set of flags, return false.  */
+
+bool
+set_named_section_flags (section, flags)
+     const char *section;
+     unsigned int flags;
+{
+  struct in_named_entry **slot, *entry;
+
+  slot = (struct in_named_entry**)
+    htab_find_slot_with_hash (in_named_htab, section,
+                             htab_hash_string (section), INSERT);
+  entry = *slot;
+
+  if (!entry)
+    {
+      entry = (struct in_named_entry *) xmalloc (sizeof (*entry));
+      *slot = entry;
+      entry->name = ggc_strdup (section);
+      entry->flags = flags;
+    }
+  else if (entry->flags != flags)
+    return false;
+
+  return true;
+}
+
+/* Tell assembler to change to section NAME with attributes FLAGS.  */
+
+void
+named_section_flags (name, flags)
+     const char *name;
+     unsigned int flags;
+{
+  if (in_section != in_named || strcmp (name, in_named_name) != 0)
+    {
+      if (! set_named_section_flags (name, flags))
+       abort ();
+
+      (* targetm.asm_out.named_section) (name, flags);
+
+      if (flags & SECTION_FORGET)
+       in_section = no_section;
+      else
+       {
+         in_named_name = ggc_strdup (name);
+         in_section = in_named;
+       }
+    }
+}
+
 /* Tell assembler to change to section NAME for DECL.
    If DECL is NULL, just switch to section NAME.
    If NAME is NULL, get the name from DECL.
@@ -296,52 +402,41 @@ void
 named_section (decl, name, reloc)
      tree decl;
      const char *name;
-     int reloc ATTRIBUTE_UNUSED;
+     int reloc;
 {
+  unsigned int flags;
+
   if (decl != NULL_TREE && !DECL_P (decl))
     abort ();
   if (name == NULL)
     name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
 
-  if (in_section != in_named || strcmp (name, in_named_name))
-    {
-#ifdef ASM_OUTPUT_SECTION_NAME
-      ASM_OUTPUT_SECTION_NAME (asm_out_file, decl, name, reloc);
-#else
-      /* Section attributes are not supported if this macro isn't provided -
-        some host formats don't support them at all.  The front-end should
-        already have flagged this as an error.  */
-      abort ();
-#endif
+  flags = (* targetm.section_type_flags) (decl, name, reloc);
 
-      in_named_name = ggc_alloc_string (name, -1);
-      in_section = in_named;
+  /* Sanity check user variables for flag changes.  Non-user
+     section flag changes will abort in named_section_flags.  */
+  if (decl && ! set_named_section_flags (name, flags))
+    {
+      error_with_decl (decl, "%s causes a section type conflict");
+      flags = get_named_section_flags (name);
     }
+
+  named_section_flags (name, flags);
 }
 
-#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
+/* If required, set DECL_SECTION_NAME to a unique name.  */
+
+static void
+resolve_unique_section (decl, reloc)
+     tree decl;
+     int reloc ATTRIBUTE_UNUSED;
+{
+  if (DECL_SECTION_NAME (decl) == NULL_TREE
+      && (flag_function_sections
+         || (targetm.have_named_sections
+             && DECL_ONE_ONLY (decl))))
+    UNIQUE_SECTION (decl, reloc);
+}
 
 #ifdef BSS_SECTION_ASM_OP
 
@@ -422,18 +517,6 @@ asm_output_aligned_bss (file, decl, name, size, align)
 
 #endif /* BSS_SECTION_ASM_OP */
 
-#ifdef EH_FRAME_SECTION_ASM_OP
-void
-eh_frame_section ()
-{
-  if (in_section != in_eh_frame)
-    {
-      fprintf (asm_out_file, "%s\n", EH_FRAME_SECTION_ASM_OP);
-      in_section = in_eh_frame;
-    }
-} 
-#endif
-
 /* Switch to the section for function DECL.
 
    If DECL is NULL_TREE, switch to the text section.
@@ -497,94 +580,15 @@ exception_section ()
 #if defined (EXCEPTION_SECTION)
   EXCEPTION_SECTION ();
 #else
-#ifdef ASM_OUTPUT_SECTION_NAME
-  named_section (NULL_TREE, ".gcc_except_table", 0);
-#else
-  if (flag_pic)
+  if (targetm.have_named_sections)
+    named_section (NULL_TREE, ".gcc_except_table", 0);
+  else if (flag_pic)
     data_section ();
   else
     readonly_data_section ();
 #endif
-#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 *
@@ -660,27 +664,47 @@ 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;
+  rtx x;
+
+  /* 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))
@@ -734,7 +758,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");
@@ -748,12 +772,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.  */
@@ -778,7 +803,7 @@ make_decl_rtl (decl, asmspec, top_level)
                     "register name given for non-register variable `%s'");
 
   /* Specifying a section attribute on a variable forces it into a
-     non-.bss section, and thus it cannot be common. */
+     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
@@ -791,7 +816,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);
@@ -815,7 +841,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));
     }
 
@@ -827,10 +853,11 @@ 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));
+  x = gen_rtx_MEM (DECL_MODE (decl), gen_rtx_SYMBOL_REF (Pmode, name));
+  SYMBOL_REF_WEAK (XEXP (x, 0)) = DECL_WEAK (decl);
   if (TREE_CODE (decl) != FUNCTION_DECL)
-    set_mem_attributes (DECL_RTL (decl), decl, 1);
+    set_mem_attributes (x, decl, 1);
+  SET_DECL_RTL (decl, x);
 
   /* Optionally set flags or add text to the name to record information
      such as that it is a function name.
@@ -887,84 +914,128 @@ assemble_asm (string)
   fprintf (asm_out_file, "\t%s\n", TREE_STRING_POINTER (string));
 }
 
-#if 0 /* This should no longer be needed, because
-        flag_gnu_linker should be 0 on these systems,
-        which should prevent any output
-        if ASM_OUTPUT_CONSTRUCTOR and ASM_OUTPUT_DESTRUCTOR are absent.  */
-#if !(defined(DBX_DEBUGGING_INFO) && !defined(FASCIST_ASSEMBLER))
-#ifndef ASM_OUTPUT_CONSTRUCTOR
-#define ASM_OUTPUT_CONSTRUCTOR(file, name)
-#endif
-#ifndef ASM_OUTPUT_DESTRUCTOR
-#define ASM_OUTPUT_DESTRUCTOR(file, name)
-#endif
-#endif
-#endif /* 0 */
+/* Record an element in the table of global destructors.  SYMBOL is
+   a SYMBOL_REF of the function to be called; PRIORITY is a number
+   between 0 and MAX_INIT_PRIORITY.  */
 
-/* Record an element in the table of global destructors.
-   How this is done depends on what sort of assembler and linker
-   are in use.
+void
+default_stabs_asm_out_destructor (symbol, priority)
+     rtx symbol;
+     int priority ATTRIBUTE_UNUSED;
+{
+  /* Tell GNU LD that this is part of the static destructor set.
+     This will work for any system that uses stabs, most usefully
+     aout systems.  */
+  fprintf (asm_out_file, "%s\"___DTOR_LIST__\",22,0,0,", ASM_STABS_OP);
+  assemble_name (asm_out_file, XSTR (symbol, 0));
+  fputc ('\n', asm_out_file);
+}
+
+void
+default_named_section_asm_out_destructor (symbol, priority)
+     rtx symbol;
+     int priority;
+{
+  const char *section = ".dtors";
+  char buf[16];
 
-   NAME should be the name of a global function to be called
-   at exit time.  This name is output using assemble_name.  */
+  /* ??? This only works reliably with the GNU linker.   */
+  if (priority != DEFAULT_INIT_PRIORITY)
+    {
+      sprintf (buf, ".dtors.%.5u",
+              /* Invert the numbering so the linker puts us in the proper
+                 order; constructors are run from right to left, and the
+                 linker sorts in increasing order.  */
+              MAX_INIT_PRIORITY - priority);
+      section = buf;
+    }
 
+  named_section_flags (section, SECTION_WRITE);
+  assemble_align (POINTER_SIZE);
+  assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, 1);
+}
+
+#ifdef DTORS_SECTION_ASM_OP
 void
-assemble_destructor (name)
-     const char *name;
+dtors_section ()
 {
-#ifdef ASM_OUTPUT_DESTRUCTOR
-  ASM_OUTPUT_DESTRUCTOR (asm_out_file, name);
-#else
-  if (flag_gnu_linker)
+  if (in_section != in_dtors)
     {
-      /* 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);
-      assemble_name (asm_out_file, name);
+      in_section = in_dtors;
+      fputs (DTORS_SECTION_ASM_OP, asm_out_file);
       fputc ('\n', asm_out_file);
     }
-#endif
 }
 
+void
+default_dtor_section_asm_out_destructor (symbol, priority)
+     rtx symbol;
+     int priority ATTRIBUTE_UNUSED;
+{
+  dtors_section ();
+  assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, 1);
+}
+#endif
+
 /* Likewise for global constructors.  */
 
 void
-assemble_constructor (name)
-     const char *name;
+default_stabs_asm_out_constructor (symbol, priority)
+     rtx symbol;
+     int priority ATTRIBUTE_UNUSED;
 {
-#ifdef ASM_OUTPUT_CONSTRUCTOR
-  ASM_OUTPUT_CONSTRUCTOR (asm_out_file, name);
-#else
-  if (flag_gnu_linker)
+  /* Tell GNU LD that this is part of the static destructor set.
+     This will work for any system that uses stabs, most usefully
+     aout systems.  */
+  fprintf (asm_out_file, "%s\"___CTOR_LIST__\",22,0,0,", ASM_STABS_OP);
+  assemble_name (asm_out_file, XSTR (symbol, 0));
+  fputc ('\n', asm_out_file);
+}
+
+void
+default_named_section_asm_out_constructor (symbol, priority)
+     rtx symbol;
+     int priority;
+{
+  const char *section = ".ctors";
+  char buf[16];
+
+  /* ??? This only works reliably with the GNU linker.   */
+  if (priority != DEFAULT_INIT_PRIORITY)
     {
-      /* 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);
-      assemble_name (asm_out_file, name);
-      fputc ('\n', asm_out_file);
+      sprintf (buf, ".ctors.%.5u",
+              /* Invert the numbering so the linker puts us in the proper
+                 order; constructors are run from right to left, and the
+                 linker sorts in increasing order.  */
+              MAX_INIT_PRIORITY - priority);
+      section = buf;
     }
-#endif
-}
 
-/* Likewise for entries we want to record for garbage collection.
-   Garbage collection is still under development.  */
+  named_section_flags (section, SECTION_WRITE);
+  assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, 1);
+}
 
+#ifdef CTORS_SECTION_ASM_OP
 void
-assemble_gc_entry (name)
-     const char *name;
+ctors_section ()
 {
-#ifdef ASM_OUTPUT_GC_ENTRY
-  ASM_OUTPUT_GC_ENTRY (asm_out_file, name);
-#else
-  if (flag_gnu_linker)
+  if (in_section != in_ctors)
     {
-      /* 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);
-      assemble_name (asm_out_file, name);
+      in_section = in_ctors;
+      fputs (CTORS_SECTION_ASM_OP, asm_out_file);
       fputc ('\n', asm_out_file);
     }
-#endif
 }
+
+void
+default_ctor_section_asm_out_constructor (symbol, priority)
+     rtx symbol;
+     int priority ATTRIBUTE_UNUSED;
+{
+  ctors_section ();
+  assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, 1);
+}
+#endif
 \f
 /* CONSTANT_POOL_BEFORE_FUNCTION may be defined as an expression with
    a non-zero value if the constant pool should be output before the
@@ -995,15 +1066,7 @@ assemble_start_function (decl, fnname)
   if (CONSTANT_POOL_BEFORE_FUNCTION)
     output_constant_pool (fnname, decl);
 
-#ifdef ASM_OUTPUT_SECTION_NAME
-  /* If the function is to be put in its own section and it's not in a section
-     already, indicate so.  */
-  if ((flag_function_sections
-       && DECL_SECTION_NAME (decl) == NULL_TREE)
-      || UNIQUE_SECTION_P (decl))
-    UNIQUE_SECTION (decl, 0);
-#endif
-
+  resolve_unique_section (decl, 0);
   function_section (decl);
 
   /* Tell assembler to move to target machine's alignment for functions.  */
@@ -1028,17 +1091,7 @@ assemble_start_function (decl, fnname)
   ASM_OUTPUT_FUNCTION_PREFIX (asm_out_file, fnname);
 #endif
 
-#ifdef SDB_DEBUGGING_INFO
-  /* Output SDB definition of the function.  */
-  if (write_symbols == SDB_DEBUG)
-    sdbout_mark_begin_function ();
-#endif
-
-#ifdef DBX_DEBUGGING_INFO
-  /* Output DBX definition of the function.  */
-  if (write_symbols == DBX_DEBUG)
-    dbxout_begin_function (decl);
-#endif
+  (*debug_hooks->begin_function) (decl);
 
   /* Make function name accessible from other files, if appropriate.  */
 
@@ -1272,12 +1325,8 @@ 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, 0);
-#endif
-  
+  resolve_unique_section (decl, 0);
+
   switch (destination)
     {
 #ifdef ASM_EMIT_BSS
@@ -1318,48 +1367,10 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
   register const char *name;
   unsigned int align;
   int reloc = 0;
-  enum in_section saved_in_section;
+  rtx decl_rtl;
 
   last_assemble_variable_decl = 0;
 
-  if (GET_CODE (DECL_RTL (decl)) == REG)
-    {
-      /* Do output symbol info for global register variables, but do nothing
-        else for them.  */
-
-      if (TREE_ASM_WRITTEN (decl))
-       return;
-      TREE_ASM_WRITTEN (decl) = 1;
-
-      /* Do no output if -fsyntax-only.  */
-      if (flag_syntax_only)
-       return;
-
-#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
-      /* File-scope global variables are output here.  */
-      if ((write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG)
-          && top_level)
-       dbxout_symbol (decl, 0);
-#endif
-#ifdef SDB_DEBUGGING_INFO
-      if (write_symbols == SDB_DEBUG && top_level
-         /* Leave initialized global vars for end of compilation;
-            see comment in compile_file.  */
-         && (TREE_PUBLIC (decl) == 0 || DECL_INITIAL (decl) == 0))
-       sdbout_symbol (decl, 0);
-#endif
-
-      /* Don't output any DWARF debugging information for variables here.
-        In the case of local variables, the information for them is output
-        when we do our recursive traversal of the tree representation for
-        the entire containing function.  In the case of file-scope variables,
-        we output information for all of them at the very end of compilation
-        while we are doing our final traversal of the chain of file-scope
-        declarations.  */
-
-      return;
-    }
-
   /* Normally no need to say anything here for external references,
      since assemble_external is called by the language-specific code
      when a declaration is first seen.  */
@@ -1373,6 +1384,13 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
   if (TREE_CODE (decl) == FUNCTION_DECL)
     return;
 
+  /* Do nothing for global register variables.  */
+  if (DECL_RTL_SET_P (decl) && GET_CODE (DECL_RTL (decl)) == REG)
+    {
+      TREE_ASM_WRITTEN (decl) = 1;
+      return;
+    }
+
   /* If type was incomplete when the variable was declared,
      see if it is complete now.  */
 
@@ -1400,6 +1418,9 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
   if (TREE_ASM_WRITTEN (decl))
     return;
 
+  /* Make sure ENCODE_SECTION_INFO is invoked before we set ASM_WRITTEN.  */
+  decl_rtl = DECL_RTL (decl);
   TREE_ASM_WRITTEN (decl) = 1;
 
   /* Do no output if -fsyntax-only.  */
@@ -1412,10 +1433,10 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
       && ! host_integerp (DECL_SIZE_UNIT (decl), 1))
     {
       error_with_decl (decl, "size of variable `%s' is too large");
-      goto finish;
+      return;
     }
 
-  name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
+  name = XSTR (XEXP (decl_rtl, 0), 0);
   if (TREE_PUBLIC (decl) && DECL_NAME (decl)
       && ! first_global_object_name
       && ! (DECL_COMMON (decl) && (DECL_INITIAL (decl) == 0
@@ -1457,13 +1478,16 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
     }
 
   /* On some machines, it is good to increase alignment sometimes.  */
+  if (! DECL_USER_ALIGN (decl))
+    {
 #ifdef DATA_ALIGNMENT
-  align = DATA_ALIGNMENT (TREE_TYPE (decl), align);
+      align = DATA_ALIGNMENT (TREE_TYPE (decl), align);
 #endif
 #ifdef CONSTANT_ALIGNMENT
-  if (DECL_INITIAL (decl) != 0 && DECL_INITIAL (decl) != error_mark_node)
-    align = CONSTANT_ALIGNMENT (DECL_INITIAL (decl), align);
+      if (DECL_INITIAL (decl) != 0 && DECL_INITIAL (decl) != error_mark_node)
+        align = CONSTANT_ALIGNMENT (DECL_INITIAL (decl), align);
 #endif
+    }
 
   /* Reset the alignment in case we have made it tighter, so we can benefit
      from it in get_pointer_alignment.  */
@@ -1501,35 +1525,9 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
            (decl, "requested alignment for %s is greater than implemented alignment of %d.",rounded);
 #endif
        
-#ifdef DBX_DEBUGGING_INFO
-      /* File-scope global variables are output here.  */
-      if (write_symbols == DBX_DEBUG && top_level)
-       dbxout_symbol (decl, 0);
-#endif
-#ifdef SDB_DEBUGGING_INFO
-      if (write_symbols == SDB_DEBUG && top_level
-         /* Leave initialized global vars for end of compilation;
-            see comment in compile_file.  */
-         && (TREE_PUBLIC (decl) == 0 || DECL_INITIAL (decl) == 0))
-       sdbout_symbol (decl, 0);
-#endif
-
-      /* Don't output any DWARF debugging information for variables here.
-        In the case of local variables, the information for them is output
-        when we do our recursive traversal of the tree representation for
-        the entire containing function.  In the case of file-scope variables,
-        we output information for all of them at the very end of compilation
-        while we are doing our final traversal of the chain of file-scope
-        declarations.  */
-
-#if 0 /* ??? We should either delete this or add a comment describing what
-        it was intended to do and why we shouldn't delete it.  */
-      if (flag_shared_data)
-       data_section ();
-#endif
       asm_emit_uninitialised (decl, name, size, rounded);
 
-      goto finish;
+      return;
     }
 
   /* Handle initialized definitions.
@@ -1552,15 +1550,6 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
 #endif
       ASM_GLOBALIZE_LABEL (asm_out_file, name);
     }
-#if 0
-  for (d = equivalents; d; d = TREE_CHAIN (d))
-    {
-      tree e = TREE_VALUE (d);
-      if (TREE_PUBLIC (e) && DECL_NAME (e))
-       ASM_GLOBALIZE_LABEL (asm_out_file,
-                            XSTR (XEXP (DECL_RTL (e), 0), 0));
-    }
-#endif
 
   /* Output any data that we will need to use the address of.  */
   if (DECL_INITIAL (decl) == error_mark_node)
@@ -1568,50 +1557,14 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
   else if (DECL_INITIAL (decl))
     reloc = output_addressed_constants (DECL_INITIAL (decl));
 
-#ifdef ASM_OUTPUT_SECTION_NAME
-  if ((flag_data_sections != 0 && DECL_SECTION_NAME (decl) == NULL_TREE)
-      || UNIQUE_SECTION_P (decl))
-    UNIQUE_SECTION (decl, reloc);
-#endif
-
   /* Switch to the appropriate section.  */
+  resolve_unique_section (decl, reloc);
   variable_section (decl, reloc);
 
   /* dbxout.c needs to know this.  */
   if (in_text_section ())
     DECL_IN_TEXT_SECTION (decl) = 1;
 
-  /* Record current section so we can restore it if dbxout.c clobbers it.  */
-  saved_in_section = in_section;
-
-  /* Output the dbx info now that we have chosen the section.  */
-
-#ifdef DBX_DEBUGGING_INFO
-  /* File-scope global variables are output here.  */
-  if (write_symbols == DBX_DEBUG && top_level)
-    dbxout_symbol (decl, 0);
-#endif
-#ifdef SDB_DEBUGGING_INFO
-  if (write_symbols == SDB_DEBUG && top_level
-      /* Leave initialized global vars for end of compilation;
-        see comment in compile_file.  */
-      && (TREE_PUBLIC (decl) == 0 || DECL_INITIAL (decl) == 0))
-    sdbout_symbol (decl, 0);
-#endif
-
-  /* Don't output any DWARF debugging information for variables here.
-     In the case of local variables, the information for them is output
-     when we do our recursive traversal of the tree representation for
-     the entire containing function.  In the case of file-scope variables,
-     we output information for all of them at the very end of compilation
-     while we are doing our final traversal of the chain of file-scope
-     declarations.  */
-
-  /* If the debugging output changed sections, reselect the section
-     that's supposed to be selected.  */
-  if (in_section != saved_in_section)
-    variable_section (decl, reloc);
-
   /* Output the alignment of this data.  */
   if (align > BITS_PER_UNIT)
     ASM_OUTPUT_ALIGN (asm_out_file,
@@ -1636,29 +1589,6 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
        /* Leave space for it.  */
        assemble_zeros (tree_low_cst (DECL_SIZE_UNIT (decl), 1));
     }
-
- finish:
-#ifdef XCOFF_DEBUGGING_INFO
-  /* Unfortunately, the IBM assembler cannot handle stabx before the actual
-     declaration.  When something like ".stabx  "aa:S-2",aa,133,0" is emitted 
-     and `aa' hasn't been output yet, the assembler generates a stab entry with
-     a value of zero, in addition to creating an unnecessary external entry
-     for `aa'.  Hence, we must postpone dbxout_symbol to here at the end.  */
-
-  /* File-scope global variables are output here.  */
-  if (write_symbols == XCOFF_DEBUG && top_level)
-    {
-      saved_in_section = in_section;
-
-      dbxout_symbol (decl, 0);
-
-      if (in_section != saved_in_section)
-       variable_section (decl, reloc);
-    }
-#else
-  /* There must be a statement after a label.  */
-  ;
-#endif
 }
 
 /* Return 1 if type TYPE contains any pointers.  */
@@ -1706,6 +1636,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))
     {
@@ -1772,7 +1709,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);
@@ -1793,7 +1730,7 @@ assemble_static_space (size)
      int size;
 {
   char name[12];
-  char *namestring;
+  const char *namestring;
   rtx x;
 
 #if 0
@@ -1803,7 +1740,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);
 
@@ -1817,7 +1754,7 @@ assemble_static_space (size)
   {
     /* Round size up to multiple of BIGGEST_ALIGNMENT bits
        so that each uninitialized object starts on such a boundary.  */
-    /* Variable `rounded' might or might not be used in ASM_OUTPUT_LOCAL. */
+    /* Variable `rounded' might or might not be used in ASM_OUTPUT_LOCAL.  */
     int rounded ATTRIBUTE_UNUSED
       = ((size + (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1)
         / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
@@ -1838,7 +1775,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.  */
@@ -1859,7 +1796,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
@@ -1960,68 +1897,74 @@ assemble_integer (x, size, force)
 }
 \f
 /* Assemble the floating-point constant D into an object of size MODE.  */
-
-void
-assemble_real (d, mode)
-     REAL_VALUE_TYPE d;
-     enum machine_mode mode;
+struct assemble_real_args
 {
-  jmp_buf output_constant_handler;
-
-  if (setjmp (output_constant_handler))
-    {
-      error ("floating point trap outputting a constant");
-#ifdef REAL_IS_NOT_DOUBLE
-      bzero ((char *) &d, sizeof d);
-      d = dconst0;
-#else
-      d = 0;
-#endif
-    }
+  REAL_VALUE_TYPE *d;
+  enum machine_mode mode;
+};
 
-  set_float_handler (output_constant_handler);
+static void
+assemble_real_1 (p)
+     PTR p;
+{
+  struct assemble_real_args *args = (struct assemble_real_args *) p;
+  REAL_VALUE_TYPE *d = args->d;
+  enum machine_mode mode = args->mode;
 
   switch (mode)
     {
 #ifdef ASM_OUTPUT_BYTE_FLOAT
     case QFmode:
-      ASM_OUTPUT_BYTE_FLOAT (asm_out_file, d);
+      ASM_OUTPUT_BYTE_FLOAT (asm_out_file, *d);
       break;
 #endif
 #ifdef ASM_OUTPUT_SHORT_FLOAT
     case HFmode:
-      ASM_OUTPUT_SHORT_FLOAT (asm_out_file, d);
+      ASM_OUTPUT_SHORT_FLOAT (asm_out_file, *d);
       break;
 #endif
 #ifdef ASM_OUTPUT_THREE_QUARTER_FLOAT
     case TQFmode:
-      ASM_OUTPUT_THREE_QUARTER_FLOAT (asm_out_file, d);
+      ASM_OUTPUT_THREE_QUARTER_FLOAT (asm_out_file, *d);
       break;
 #endif
 #ifdef ASM_OUTPUT_FLOAT
     case SFmode:
-      ASM_OUTPUT_FLOAT (asm_out_file, d);
+      ASM_OUTPUT_FLOAT (asm_out_file, *d);
       break;
 #endif
 
 #ifdef ASM_OUTPUT_DOUBLE
     case DFmode:
-      ASM_OUTPUT_DOUBLE (asm_out_file, d);
+      ASM_OUTPUT_DOUBLE (asm_out_file, *d);
       break;
 #endif
 
 #ifdef ASM_OUTPUT_LONG_DOUBLE
     case XFmode:
     case TFmode:
-      ASM_OUTPUT_LONG_DOUBLE (asm_out_file, d);
+      ASM_OUTPUT_LONG_DOUBLE (asm_out_file, *d);
       break;
 #endif
 
     default:
       abort ();
     }
+}
+
+void
+assemble_real (d, mode)
+     REAL_VALUE_TYPE d;
+     enum machine_mode mode;
+{
+  struct assemble_real_args args;
+  args.d = &d;
+  args.mode = mode;
 
-  set_float_handler (NULL_PTR);
+  if (do_float_handler (assemble_real_1, (PTR) &args))
+    return;
+
+  internal_error ("floating point trap outputting a constant");
 }
 \f
 /* Here we combine duplicate floating constants to make
@@ -2066,7 +2009,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);
 
@@ -2136,19 +2079,15 @@ immed_real_const_1 (d, mode)
 
   u.d = 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))
+  /* Detect special cases.  */
+  if (REAL_VALUES_IDENTICAL (dconst0, d))
     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))
-          && (cfun == 0
-              || decl_function_context (current_function_decl) == 0))
+  else if (! REAL_VALUE_ISNAN (d) && REAL_VALUES_EQUAL (dconst1, d))
     return CONST1_RTX (mode);
 
   if (sizeof u == sizeof (HOST_WIDE_INT))
@@ -2164,7 +2103,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;
 
@@ -2176,7 +2115,7 @@ immed_real_const_1 (d, mode)
      freed memory.  */
   r = rtx_alloc (CONST_DOUBLE);
   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.  */
@@ -2215,6 +2154,8 @@ void
 clear_const_double_mem ()
 {
   register rtx r, next;
+  enum machine_mode mode;
+  int i;
 
   for (r = const_double_chain; r; r = next)
     {
@@ -2223,6 +2164,15 @@ clear_const_double_mem ()
       CONST_DOUBLE_MEM (r) = cc0_rtx;
     }
   const_double_chain = 0;
+
+  for (i = 0; i <= 2; i++)
+    for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode;
+         mode = GET_MODE_WIDER_MODE (mode))
+      {
+       r = const_tiny_rtx[i][(int) mode];
+       CONST_DOUBLE_CHAIN (r) = 0;
+       CONST_DOUBLE_MEM (r) = cc0_rtx;
+      }
 }
 \f
 /* Given an expression EXP with a constant value,
@@ -2254,7 +2204,8 @@ decode_addr_const (exp, value)
          offset += int_byte_position (TREE_OPERAND (target, 1));
          target = TREE_OPERAND (target, 0);
        }
-      else if (TREE_CODE (target) == ARRAY_REF)
+      else if (TREE_CODE (target) == ARRAY_REF
+              || TREE_CODE (target) == ARRAY_RANGE_REF)
        {
          offset += (tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (target)), 1)
                     * tree_low_cst (TREE_OPERAND (target, 1), 0));
@@ -2297,15 +2248,11 @@ decode_addr_const (exp, value)
   value->offset = offset;
 }
 \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
+  ENUM_BITFIELD(kind) kind : 16;
+  ENUM_BITFIELD(machine_mode) mode : 16;
   union {
     union real_extract du;
     struct addr_const addr;
@@ -2325,15 +2272,35 @@ struct rtx_const
 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 
@@ -2344,12 +2311,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
@@ -2455,8 +2473,8 @@ const_hash (exp)
       return const_hash (TREE_OPERAND (exp, 0)) * 7 + 2;
       
     default:
-      /* A language specific constant. Just hash the code. */
-      return code % MAX_HASH_TABLE;
+      /* A language specific constant. Just hash the code.  */
+      return (int) code % MAX_HASH_TABLE;
     }
 
   /* Compute hashing function */
@@ -2477,7 +2495,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.
@@ -2531,9 +2549,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;
 
@@ -2555,7 +2573,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;
@@ -2573,7 +2591,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;
@@ -2587,12 +2605,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;
@@ -2600,7 +2618,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;
@@ -2610,7 +2628,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;
@@ -2627,7 +2645,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;
@@ -2636,7 +2654,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;
 
@@ -2651,7 +2669,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,8 +2692,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;
 
@@ -2720,6 +2738,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.  */
@@ -2727,6 +2746,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);
 }
@@ -2740,7 +2767,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);
 
@@ -2765,7 +2792,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));
@@ -3048,18 +3075,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);
@@ -3087,11 +3121,12 @@ 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.  */
@@ -3110,21 +3145,44 @@ 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;
@@ -3132,7 +3190,7 @@ output_constant_def (exp)
 
          p->exp = copy_constant (exp);
          p->reloc = reloc;
-         p->labelno = const_labelno++;
+         p->labelno = labelno;
          if (after_function)
            {
              p->next = after_function_constants;
@@ -3148,8 +3206,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;
+               }
+           }
        }
     }
 
@@ -3198,7 +3278,8 @@ output_constant_def_contents (exp, reloc, labelno)
   /* Output the value of EXP.  */
   output_constant (exp,
                   (TREE_CODE (exp) == STRING_CST
-                   ? TREE_STRING_LENGTH (exp)
+                   ? MAX (TREE_STRING_LENGTH (exp),
+                          int_size_in_bytes (TREE_TYPE (exp)))
                    : int_size_in_bytes (TREE_TYPE (exp))));
 
 }
@@ -3211,25 +3292,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)  */
 
@@ -3249,8 +3321,8 @@ init_varasm_status (f)
     = ((struct constant_descriptor **)
        xcalloc (MAX_RTX_HASH_TABLE, sizeof (struct constant_descriptor *)));
   p->x_const_rtx_sym_hash_table
-    = ((struct pool_sym **)
-       xcalloc (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;
@@ -3271,20 +3343,6 @@ mark_pool_constant (pc)
     }
 }
 
-/* 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
@@ -3295,7 +3353,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);
 }
 
@@ -3316,7 +3373,6 @@ free_varasm_status (f)
   for (i = 0; i < MAX_RTX_HASH_TABLE; ++i)
     {
       struct constant_descriptor* cd;
-      struct pool_sym *ps;
 
       cd = p->x_const_rtx_hash_table[i];
       while (cd) {
@@ -3324,13 +3380,6 @@ free_varasm_status (f)
        free (cd);
        cd = next;
       }
-
-      ps = p->x_const_rtx_sym_hash_table[i];
-      while (ps) {
-       struct pool_sym *next = ps->next;
-       free (ps);
-       ps = next;
-      }
     }
 
   free (p->x_const_rtx_hash_table);
@@ -3339,7 +3388,6 @@ free_varasm_status (f)
   f->varasm = NULL;
 }
 \f
-enum kind { RTX_DOUBLE, RTX_INT };
 
 /* Express an rtx for a constant integer (perhaps symbolic)
    as the sum of a symbol or label plus an explicit integer.
@@ -3352,7 +3400,7 @@ decode_rtx_const (mode, x, value)
      struct rtx_const *value;
 {
   /* Clear the whole structure, including any gaps.  */
-  bzero (value, sizeof (struct rtx_const));
+  memset (value, 0, sizeof (struct rtx_const));
 
   value->kind = RTX_INT;       /* Most usual kind.  */
   value->mode = mode;
@@ -3364,8 +3412,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 +3434,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 +3522,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;
@@ -3503,10 +3550,9 @@ record_constant_rtx (mode, x)
   struct constant_descriptor *ptr;
 
   ptr = ((struct constant_descriptor *) 
-        xcalloc (1, 
-                 (sizeof (struct constant_descriptor) 
-                  + sizeof (struct rtx_const) - 1)));
-  decode_rtx_const (mode, x, (struct rtx_const *) ptr->contents);
+        xcalloc (1, (offsetof (struct constant_descriptor, u)
+                     + sizeof (struct rtx_const))));
+  decode_rtx_const (mode, x, (struct rtx_const *) ptr->u.contents);
 
   return ptr;
 }
@@ -3522,7 +3568,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
@@ -3554,7 +3600,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.
@@ -3567,16 +3612,17 @@ force_const_mem (mode, x)
       const_rtx_hash_table[hash] = desc;
 
       /* Align the location counter as required by EXP's data type.  */
-      align = (mode == VOIDmode) ? UNITS_PER_WORD : GET_MODE_SIZE (mode);
-      if (align > BIGGEST_ALIGNMENT / BITS_PER_UNIT)
-       align = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
+      align = GET_MODE_ALIGNMENT (mode == VOIDmode ? word_mode : mode);
 #ifdef CONSTANT_ALIGNMENT
       align = CONSTANT_ALIGNMENT (make_tree (type_for_mode (mode, 0), x),
-                                align * BITS_PER_UNIT) / BITS_PER_UNIT;
+                                 align);
 #endif
 
-      pool_offset += align - 1;
-      pool_offset &= ~ (align - 1);
+      pool_offset += (align / BITS_PER_UNIT) - 1;
+      pool_offset &= ~ ((align / BITS_PER_UNIT) - 1);
+
+      if (GET_CODE (x) == LABEL_REF)
+       LABEL_PRESERVE_P (XEXP (x, 0)) = 1;
 
       /* Allocate a pool constant descriptor, fill it in, and chain it in.  */
 
@@ -3603,15 +3649,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 *) xmalloc (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.  */
@@ -3645,13 +3689,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 ();
 }
@@ -3784,8 +3828,7 @@ output_constant_pool (fnname, fndecl)
                                     pool->align, pool->labelno, done);
 #endif
 
-      if (pool->align > 1)
-       ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (pool->align));
+      assemble_align (pool->align);
 
       /* Output the label.  */
       ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LC", pool->labelno);
@@ -3797,7 +3840,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;
 
@@ -3825,7 +3868,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 ()
@@ -3833,7 +3877,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)
@@ -3848,41 +3892,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;
@@ -3892,8 +3911,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
@@ -3944,6 +3962,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.
@@ -3955,6 +4022,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:
@@ -3970,7 +4042,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;
@@ -4136,6 +4208,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.  */
@@ -4192,7 +4272,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;
@@ -4311,8 +4394,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
@@ -4348,7 +4466,7 @@ output_constructor (exp, size)
 
      There is always a maximum of one element in the chain LINK for unions
      (even if the initializer in a source program incorrectly contains
-     more one). */
+     more one).  */
   for (link = CONSTRUCTOR_ELTS (exp);
        link;
        link = TREE_CHAIN (link),
@@ -4373,7 +4491,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);
@@ -4395,7 +4513,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;
@@ -4430,7 +4548,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));
 
@@ -4652,11 +4795,7 @@ weak_finish ()
       for (t = weak_decls; t; t = t->next)
        {
          if (t->name)
-           {
-             ASM_WEAKEN_LABEL (asm_out_file, t->name);
-             if (t->value)
-               ASM_OUTPUT_DEF (asm_out_file, t->name, t->value);
-           }
+           ASM_OUTPUT_WEAK_ALIAS (asm_out_file, t->name, t->value);
        }
     }
 #endif
@@ -4690,8 +4829,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.  */
@@ -4731,15 +4873,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
@@ -4784,78 +4917,122 @@ 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);
+  in_named_htab = htab_create (31, in_named_entry_hash,
+                              in_named_entry_eq, NULL);
+
   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)
+/* Select a set of attributes for section NAME based on the properties
+   of DECL and whether or not RELOC indicates that DECL's initializer
+   might contain runtime relocations.
+
+   We make the section read-only and executable for a function decl,
+   read-only for a const data decl, and writable for a non-const data decl.  */
+
+unsigned int
+default_section_type_flags (decl, name, reloc)
+     tree decl;
      const char *name;
+     int reloc;
 {
-#ifdef ASM_OUTPUT_EH_LABEL
-  ASM_OUTPUT_EH_LABEL (asm_out_file, name);
-#else
-  assemble_label (name);
-#endif
+  unsigned int flags;
+
+  if (decl && TREE_CODE (decl) == FUNCTION_DECL)
+    flags = SECTION_CODE;
+  else if (decl && DECL_READONLY_SECTION (decl, reloc))
+    flags = 0;
+  else
+    flags = SECTION_WRITE;
+
+  if (decl && DECL_ONE_ONLY (decl))
+    flags |= SECTION_LINKONCE;
+
+  if (strcmp (name, ".bss") == 0
+      || strncmp (name, ".bss.", 5) == 0
+      || strncmp (name, ".gnu.linkonce.b.", 16) == 0
+      || strcmp (name, ".sbss") == 0
+      || strncmp (name, ".sbss.", 6) == 0
+      || strncmp (name, ".gnu.linkonce.sb.", 17) == 0)
+    flags |= SECTION_BSS;
+
+  return flags;
 }
 
-/* Assemble an alignment pseudo op for an ALIGN-bit boundary.  */
+/* Output assembly to switch to section NAME with attribute FLAGS.
+   Four variants for common object file formats.  */
 
 void
-assemble_eh_align (align)
-     int align;
+default_no_named_section (name, flags)
+     const char *name ATTRIBUTE_UNUSED;
+     unsigned int flags ATTRIBUTE_UNUSED;
 {
-#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
+  /* Some object formats don't support named sections at all.  The
+     front-end should already have flagged this as an error.  */
+  abort ();
 }
 
-
-/* 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;
+void
+default_elf_asm_named_section (name, flags)
+     const char *name;
+     unsigned int flags;
 {
+  char flagchars[8], *f = flagchars;
+  const char *type;
+
+  if (!(flags & SECTION_DEBUG))
+    *f++ = 'a';
+  if (flags & SECTION_WRITE)
+    *f++ = 'w';
+  if (flags & SECTION_CODE)
+    *f++ = 'x';
+  if (flags & SECTION_SMALL)
+    *f++ = 's';
+  *f = '\0';
+
+  if (flags & SECTION_BSS)
+    type = "nobits";
+  else
+    type = "progbits";
 
-  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
+  fprintf (asm_out_file, "\t.section\t%s,\"%s\",@%s\n",
+          name, flagchars, type);
+}
 
-#ifdef ASM_OUTPUT_EH_INT
-    case 4:
-      ASM_OUTPUT_EH_INT (asm_out_file, x);
-      return 1;
-#endif
+void
+default_coff_asm_named_section (name, flags)
+     const char *name;
+     unsigned int flags;
+{
+  char flagchars[8], *f = flagchars;
 
-#ifdef ASM_OUTPUT_EH_DOUBLE_INT
-    case 8:
-      ASM_OUTPUT_EH_DOUBLE_INT (asm_out_file, x);
-      return 1;
-#endif
+  if (flags & SECTION_WRITE)
+    *f++ = 'w';
+  if (flags & SECTION_CODE)
+    *f++ = 'x';
+  *f = '\0';
 
-    default:
-      break;
-    }
-  return (assemble_integer (x, size, force));
+  fprintf (asm_out_file, "\t.section\t%s,\"%s\"\n", name, flagchars);
 }
 
+void
+default_pe_asm_named_section (name, flags)
+     const char *name;
+     unsigned int flags;
+{
+  default_coff_asm_named_section (name, flags);
 
-
+  if (flags & SECTION_LINKONCE)
+    {
+      /* Functions may have been compiled at various levels of
+         optimization so we can't use `same_size' here.
+         Instead, have the linker pick one.  */
+      fprintf (asm_out_file, "\t.linkonce %s\n",
+              (flags & SECTION_CODE ? "discard" : "same_size"));
+    }
+}