OSDN Git Service

* alias.c: Follow spelling conventions.
[pf3gnuchains/gcc-fork.git] / gcc / varasm.c
index a055bbf..d7c6068 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, 2001, 2002 Free Software Foundation, Inc.
+   1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -29,6 +29,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "rtl.h"
 #include "tree.h"
 #include "flags.h"
@@ -36,18 +38,17 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "expr.h"
 #include "hard-reg-set.h"
 #include "regs.h"
-#include "output.h"
 #include "real.h"
+#include "output.h"
 #include "toplev.h"
-#include "obstack.h"
 #include "hashtab.h"
 #include "c-pragma.h"
-#include "c-tree.h"
 #include "ggc.h"
 #include "langhooks.h"
 #include "tm_p.h"
 #include "debug.h"
 #include "target.h"
+#include "cgraph.h"
 
 #ifdef XCOFF_DEBUGGING_INFO
 #include "xcoffout.h"          /* Needed for external data
@@ -66,17 +67,14 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 const char *first_global_object_name;
 const char *weak_global_object_name;
 
-extern struct obstack permanent_obstack;
-#define obstack_chunk_alloc xmalloc
-
 struct addr_const;
-struct constant_descriptor;
+struct constant_descriptor_rtx;
 struct rtx_const;
 struct pool_constant;
 
 #define MAX_RTX_HASH_TABLE 61
 
-struct varasm_status
+struct varasm_status GTY(())
 {
   /* Hash facility for making memory-constants
      from constant rtl-expressions.  It is used on RISC machines
@@ -86,15 +84,22 @@ struct varasm_status
      This pool of constants is reinitialized for each function
      so each function gets its own constants-pool that comes right before
      it.  */
-  struct constant_descriptor **x_const_rtx_hash_table;
-  struct pool_constant **x_const_rtx_sym_hash_table;
+  struct constant_descriptor_rtx ** GTY ((length ("MAX_RTX_HASH_TABLE")))
+    x_const_rtx_hash_table;
+  struct pool_constant ** GTY ((length ("MAX_RTX_HASH_TABLE")))
+    x_const_rtx_sym_hash_table;
 
   /* Pointers to first and last constant in pool.  */
-  struct pool_constant *x_first_pool, *x_last_pool;
+  struct pool_constant *x_first_pool;
+  struct pool_constant *x_last_pool;
 
   /* Current offset in constant pool (does not include any machine-specific
      header).  */
   HOST_WIDE_INT x_pool_offset;
+
+  /* Number of tree-constants deferred during the expansion of this
+     function.  */
+  unsigned int deferred_constants;
 };
 
 #define const_rtx_hash_table (cfun->varasm->x_const_rtx_hash_table)
@@ -102,16 +107,12 @@ struct varasm_status
 #define first_pool (cfun->varasm->x_first_pool)
 #define last_pool (cfun->varasm->x_last_pool)
 #define pool_offset (cfun->varasm->x_pool_offset)
+#define n_deferred_constants (cfun->varasm->deferred_constants)
 
 /* Number for making the label on the next
    constant that is stored in memory.  */
 
-int const_labelno;
-
-/* Number for making the label on the next
-   static variable internal to a function.  */
-
-int var_labelno;
+static GTY(()) int const_labelno;
 
 /* Carry information from ASM_DECLARE_OBJECT_NAME
    to ASM_FINISH_DECLARE_OBJECT.  */
@@ -134,59 +135,50 @@ tree last_assemble_variable_decl;
 
 static HOST_WIDE_INT const_alias_set;
 
-static const char *strip_reg_name      PARAMS ((const char *));
-static int contains_pointers_p         PARAMS ((tree));
-static void decode_addr_const          PARAMS ((tree, struct addr_const *));
-static int const_hash                  PARAMS ((tree));
-static int compare_constant            PARAMS ((tree,
-                                              struct constant_descriptor *));
-static const unsigned char *compare_constant_1  PARAMS ((tree, const unsigned char *));
-static struct constant_descriptor *record_constant PARAMS ((tree));
-static void record_constant_1          PARAMS ((tree));
-static tree copy_constant              PARAMS ((tree));
-static void output_constant_def_contents  PARAMS ((tree, int, int));
-static void decode_rtx_const           PARAMS ((enum machine_mode, rtx,
-                                              struct rtx_const *));
-static int const_hash_rtx              PARAMS ((enum machine_mode, rtx));
-static int compare_constant_rtx                PARAMS ((enum machine_mode, rtx,
-                                              struct constant_descriptor *));
-static struct constant_descriptor *record_constant_rtx PARAMS ((enum machine_mode,
-                                                             rtx));
-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 unsigned min_align              PARAMS ((unsigned, unsigned));
-static void output_constructor         PARAMS ((tree, HOST_WIDE_INT,
-                                                unsigned int));
-static void globalize_decl             PARAMS ((tree));
-static void maybe_assemble_visibility  PARAMS ((tree));
-static int in_named_entry_eq           PARAMS ((const PTR, const PTR));
-static hashval_t in_named_entry_hash   PARAMS ((const PTR));
+static const char *strip_reg_name (const char *);
+static int contains_pointers_p (tree);
+static void decode_addr_const (tree, struct addr_const *);
+static hashval_t const_desc_hash (const void *);
+static int const_desc_eq (const void *, const void *);
+static hashval_t const_hash_1 (const tree);
+static int compare_constant (const tree, const tree);
+static tree copy_constant (tree);
+static void output_constant_def_contents (rtx);
+static void decode_rtx_const (enum machine_mode, rtx, struct rtx_const *);
+static unsigned int const_hash_rtx (enum machine_mode, rtx);
+static int compare_constant_rtx (enum machine_mode, rtx,
+                                struct constant_descriptor_rtx *);
+static struct constant_descriptor_rtx * record_constant_rtx
+  (enum machine_mode, rtx);
+static struct pool_constant *find_pool_constant (struct function *, rtx);
+static void mark_constant_pool (void);
+static void mark_constants (rtx);
+static int mark_constant (rtx *current_rtx, void *data);
+static int output_addressed_constants (tree);
+static unsigned HOST_WIDE_INT array_size_for_constructor (tree);
+static unsigned min_align (unsigned, unsigned);
+static void output_constructor (tree, unsigned HOST_WIDE_INT, unsigned int);
+static void globalize_decl (tree);
+static void maybe_assemble_visibility (tree);
+static int in_named_entry_eq (const void *, const void *);
+static hashval_t in_named_entry_hash (const void *);
 #ifdef ASM_OUTPUT_BSS
-static void asm_output_bss             PARAMS ((FILE *, tree, const char *, int, int));
+static void asm_output_bss (FILE *, tree, const char *,
+                           unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT);
 #endif
 #ifdef BSS_SECTION_ASM_OP
 #ifdef ASM_OUTPUT_ALIGNED_BSS
-static void asm_output_aligned_bss     PARAMS ((FILE *, tree, const char *,
-                                                int, int));
+static void asm_output_aligned_bss (FILE *, tree, const char *,
+                                   unsigned HOST_WIDE_INT, int)
+     ATTRIBUTE_UNUSED;
 #endif
 #endif /* BSS_SECTION_ASM_OP */
-static void mark_pool_constant          PARAMS ((struct pool_constant *));
-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, int));
-static void mark_weak                   PARAMS ((tree));
+static bool asm_emit_uninitialised (tree, const char*,
+                                   unsigned HOST_WIDE_INT,
+                                   unsigned HOST_WIDE_INT);
+static void mark_weak (tree);
 \f
-static enum in_section { no_section, in_text, in_data, in_named
+enum in_section { no_section, in_text, in_data, in_named
 #ifdef BSS_SECTION_ASM_OP
   , in_bss
 #endif
@@ -202,9 +194,10 @@ static enum in_section { no_section, in_text, in_data, in_named
 #ifdef EXTRA_SECTIONS
   , EXTRA_SECTIONS
 #endif
-} in_section = no_section;
+};
+static GTY(()) enum in_section in_section = no_section;
 
-/* Return a non-zero value if DECL has a section attribute.  */
+/* Return a nonzero value if DECL has a section attribute.  */
 #ifndef IN_NAMED_SECTION
 #define IN_NAMED_SECTION(DECL) \
   ((TREE_CODE (DECL) == FUNCTION_DECL || TREE_CODE (DECL) == VAR_DECL) \
@@ -212,18 +205,18 @@ static enum in_section { no_section, in_text, in_data, in_named
 #endif
 
 /* Text of section name when in_section == in_named.  */
-static const char *in_named_name;
+static GTY(()) const char *in_named_name;
 
 /* Hash table of flags that have been used for a particular named section.  */
 
-struct in_named_entry
+struct in_named_entry GTY(())
 {
   const char *name;
   unsigned int flags;
   bool declared;
 };
 
-static htab_t in_named_htab;
+static GTY((param_is (struct in_named_entry))) htab_t in_named_htab;
 
 /* Define functions like text_section for any extra sections.  */
 #ifdef EXTRA_SECTION_FUNCTIONS
@@ -233,7 +226,7 @@ EXTRA_SECTION_FUNCTIONS
 /* Tell assembler to switch to text section.  */
 
 void
-text_section ()
+text_section (void)
 {
   if (in_section != in_text)
     {
@@ -249,7 +242,7 @@ text_section ()
 /* Tell assembler to switch to data section.  */
 
 void
-data_section ()
+data_section (void)
 {
   if (in_section != in_data)
     {
@@ -267,21 +260,11 @@ data_section ()
     }
 }
 
-/* Tell assembler to ALWAYS switch to data section, in case
-   it's not sure where it is.  */
-
-void
-force_data_section ()
-{
-  in_section = no_section;
-  data_section ();
-}
-
 /* Tell assembler to switch to read-only data section.  This is normally
    the text section.  */
 
 void
-readonly_data_section ()
+readonly_data_section (void)
 {
 #ifdef READONLY_DATA_SECTION
   READONLY_DATA_SECTION ();  /* Note this can call data_section.  */
@@ -302,7 +285,7 @@ readonly_data_section ()
 /* Determine if we're in the text section.  */
 
 int
-in_text_section ()
+in_text_section (void)
 {
   return in_section == in_text;
 }
@@ -310,7 +293,7 @@ in_text_section ()
 /* Determine if we're in the data section.  */
 
 int
-in_data_section ()
+in_data_section (void)
 {
   return in_section == in_data;
 }
@@ -318,9 +301,7 @@ in_data_section ()
 /* Helper routines for maintaining in_named_htab.  */
 
 static int
-in_named_entry_eq (p1, p2)
-     const PTR p1;
-     const PTR p2;
+in_named_entry_eq (const void *p1, const void *p2)
 {
   const struct in_named_entry *old = p1;
   const char *new = p2;
@@ -329,8 +310,7 @@ in_named_entry_eq (p1, p2)
 }
 
 static hashval_t
-in_named_entry_hash (p)
-     const PTR p;
+in_named_entry_hash (const void *p)
 {
   const struct in_named_entry *old = p;
   return htab_hash_string (old->name);
@@ -342,8 +322,7 @@ in_named_entry_hash (p)
    has not been seen.  */
 
 unsigned int
-get_named_section_flags (section)
-     const char *section;
+get_named_section_flags (const char *section)
 {
   struct in_named_entry **slot;
 
@@ -359,8 +338,7 @@ get_named_section_flags (section)
    section will return false.  */
 
 bool
-named_section_first_declaration (name)
-     const char *name;
+named_section_first_declaration (const char *name)
 {
   struct in_named_entry **slot;
 
@@ -383,9 +361,7 @@ named_section_first_declaration (name)
    different set of flags, return false.  */
 
 bool
-set_named_section_flags (section, flags)
-     const char *section;
-     unsigned int flags;
+set_named_section_flags (const char *section, unsigned int flags)
 {
   struct in_named_entry **slot, *entry;
 
@@ -396,7 +372,7 @@ set_named_section_flags (section, flags)
 
   if (!entry)
     {
-      entry = (struct in_named_entry *) xmalloc (sizeof (*entry));
+      entry = ggc_alloc (sizeof (*entry));
       *slot = entry;
       entry->name = ggc_strdup (section);
       entry->flags = flags;
@@ -411,9 +387,7 @@ set_named_section_flags (section, flags)
 /* Tell assembler to change to section NAME with attributes FLAGS.  */
 
 void
-named_section_flags (name, flags)
-     const char *name;
-     unsigned int flags;
+named_section_flags (const char *name, unsigned int flags)
 {
   if (in_section != in_named || strcmp (name, in_named_name) != 0)
     {
@@ -438,10 +412,7 @@ named_section_flags (name, flags)
    If RELOC is 1, the initializer for DECL contains relocs.  */
 
 void
-named_section (decl, name, reloc)
-     tree decl;
-     const char *name;
-     int reloc;
+named_section (tree decl, const char *name, int reloc)
 {
   unsigned int flags;
 
@@ -461,7 +432,8 @@ named_section (decl, name, reloc)
     {
       flags = get_named_section_flags (name);
       if ((flags & SECTION_OVERRIDE) == 0)
-       error_with_decl (decl, "%s causes a section type conflict");
+       error ("%H%D causes a section type conflict",
+               &DECL_SOURCE_LOCATION (decl), decl);
     }
 
   named_section_flags (name, flags);
@@ -469,11 +441,9 @@ named_section (decl, name, reloc)
 
 /* If required, set DECL_SECTION_NAME to a unique name.  */
 
-static void
-resolve_unique_section (decl, reloc, flag_function_or_data_sections)
-     tree decl;
-     int reloc ATTRIBUTE_UNUSED;
-     int flag_function_or_data_sections;
+void
+resolve_unique_section (tree decl, int reloc ATTRIBUTE_UNUSED,
+                       int flag_function_or_data_sections)
 {
   if (DECL_SECTION_NAME (decl) == NULL_TREE
       && targetm.have_named_sections
@@ -487,7 +457,7 @@ resolve_unique_section (decl, reloc, flag_function_or_data_sections)
 /* Tell the assembler to switch to the bss section.  */
 
 void
-bss_section ()
+bss_section (void)
 {
   if (in_section != in_bss)
     {
@@ -510,13 +480,12 @@ bss_section ()
    support is localized here.  */
 
 static void
-asm_output_bss (file, decl, name, size, rounded)
-     FILE *file;
-     tree decl ATTRIBUTE_UNUSED;
-     const char *name;
-     int size ATTRIBUTE_UNUSED, rounded;
+asm_output_bss (FILE *file, tree decl ATTRIBUTE_UNUSED,
+               const char *name,
+               unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
+               unsigned HOST_WIDE_INT rounded)
 {
-  ASM_GLOBALIZE_LABEL (file, name);
+  (*targetm.asm_out.globalize_label) (file, name);
   bss_section ();
 #ifdef ASM_DECLARE_OBJECT_NAME
   last_assemble_variable_decl = decl;
@@ -525,7 +494,7 @@ asm_output_bss (file, decl, name, size, rounded)
   /* Standard thing is just output label for the object.  */
   ASM_OUTPUT_LABEL (file, name);
 #endif /* ASM_DECLARE_OBJECT_NAME */
-  ASM_OUTPUT_SKIP (file, rounded);
+  ASM_OUTPUT_SKIP (file, rounded ? rounded : 1);
 }
 
 #endif
@@ -538,13 +507,10 @@ asm_output_bss (file, decl, name, size, rounded)
    support is localized here.  */
 
 static void
-asm_output_aligned_bss (file, decl, name, size, align)
-     FILE *file;
-     tree decl ATTRIBUTE_UNUSED;
-     const char *name;
-     int size, align;
+asm_output_aligned_bss (FILE *file, tree decl ATTRIBUTE_UNUSED,
+                       const char *name, unsigned HOST_WIDE_INT size,
+                       int align)
 {
-  ASM_GLOBALIZE_LABEL (file, name);
   bss_section ();
   ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
 #ifdef ASM_DECLARE_OBJECT_NAME
@@ -568,8 +534,7 @@ asm_output_aligned_bss (file, decl, name, size, align)
    safer to handle it.  */
 
 void
-function_section (decl)
-     tree decl;
+function_section (tree decl)
 {
   if (decl != NULL_TREE
       && DECL_SECTION_NAME (decl) != NULL_TREE)
@@ -582,9 +547,7 @@ function_section (decl)
    argument to SELECT_SECTION.  */
 
 void
-variable_section (decl, reloc)
-     tree decl;
-     int reloc;
+variable_section (tree decl, int reloc)
 {
   if (IN_NAMED_SECTION (decl))
     named_section (decl, NULL, reloc);
@@ -592,27 +555,12 @@ variable_section (decl, reloc)
     (*targetm.asm_out.select_section) (decl, reloc, DECL_ALIGN (decl));
 }
 
-/* Tell assembler to switch to the section for the exception handling
-   table.  */
-
-void
-default_exception_section ()
-{
-  if (targetm.have_named_sections)
-    named_section (NULL_TREE, ".gcc_except_table", 0);
-  else if (flag_pic)
-    data_section ();
-  else
-    readonly_data_section ();
-}
-
 /* Tell assembler to switch to the section for string merging.  */
 
 void
-mergeable_string_section (decl, align, flags)
-     tree decl ATTRIBUTE_UNUSED;
-     unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED;
-     unsigned int flags ATTRIBUTE_UNUSED;
+mergeable_string_section (tree decl ATTRIBUTE_UNUSED,
+                         unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED,
+                         unsigned int flags ATTRIBUTE_UNUSED)
 {
 #ifdef HAVE_GAS_SHF_MERGE
   if (flag_merge_constants
@@ -684,10 +632,9 @@ mergeable_string_section (decl, align, flags)
 /* Tell assembler to switch to the section for constant merging.  */
 
 void
-mergeable_constant_section (mode, align, flags)
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-     unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED;
-     unsigned int flags ATTRIBUTE_UNUSED;
+mergeable_constant_section (enum machine_mode mode ATTRIBUTE_UNUSED,
+                           unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED,
+                           unsigned int flags ATTRIBUTE_UNUSED)
 {
 #ifdef HAVE_GAS_SHF_MERGE
   unsigned int modesize = GET_MODE_BITSIZE (mode);
@@ -714,8 +661,7 @@ mergeable_constant_section (mode, align, flags)
 /* Given NAME, a putative register name, discard any customary prefixes.  */
 
 static const char *
-strip_reg_name (name)
-     const char *name;
+strip_reg_name (const char *name)
 {
 #ifdef REGISTER_PREFIX
   if (!strncmp (name, REGISTER_PREFIX, strlen (REGISTER_PREFIX)))
@@ -735,8 +681,7 @@ strip_reg_name (name)
    Prefixes such as % are optional.  */
 
 int
-decode_reg_name (asmspec)
-     const char *asmspec;
+decode_reg_name (const char *asmspec)
 {
   if (asmspec != 0)
     {
@@ -799,13 +744,9 @@ decode_reg_name (asmspec)
    This is never called for PARM_DECL nodes.  */
 
 void
-make_decl_rtl (decl, asmspec)
-     tree decl;
-     const char *asmspec;
+make_decl_rtl (tree decl, const char *asmspec)
 {
-  int top_level = (DECL_CONTEXT (decl) == NULL_TREE);
   const char *name = 0;
-  const char *new_name = 0;
   int reg_number;
   rtx x;
 
@@ -833,17 +774,18 @@ make_decl_rtl (decl, asmspec)
        SET_DECL_RTL (decl, adjust_address_nv (DECL_RTL (decl),
                                               DECL_MODE (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 maintain a hashed
+        table of such critters.  Instead of adding stuff to a DECL
+        to give certain attributes to it, we could use an external
+        hash map from DECL to set of attributes.  */
+
       /* Let the target reassign the RTL if it wants.
         This is necessary, for example, when one machine specific
         decl attribute overrides another.  */
-      (* targetm.encode_section_info) (decl, false);
+      (* targetm.encode_section_info) (decl, DECL_RTL (decl), false);
       return;
     }
 
-  new_name = name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
-
   reg_number = decode_reg_name (asmspec);
   if (reg_number == -2)
     {
@@ -852,22 +794,26 @@ make_decl_rtl (decl, asmspec)
       char *starred = alloca (strlen (asmspec) + 2);
       starred[0] = '*';
       strcpy (starred + 1, asmspec);
-      new_name = starred;
+      SET_DECL_ASSEMBLER_NAME (decl, get_identifier (starred));
     }
 
+  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+
   if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
     {
       /* First detect errors in declaring global registers.  */
       if (reg_number == -1)
-       error_with_decl (decl, "register name not specified for `%s'");
+       error ("%Hregister name not specified for '%D'",
+               &DECL_SOURCE_LOCATION (decl), decl);
       else if (reg_number < 0)
-       error_with_decl (decl, "invalid register name for `%s'");
+       error ("%Hinvalid register name for '%D'",
+               &DECL_SOURCE_LOCATION (decl), decl);
       else if (TYPE_MODE (TREE_TYPE (decl)) == BLKmode)
-       error_with_decl (decl,
-                        "data type of `%s' isn't suitable for a register");
+       error ("%Hdata type of '%D' isn't suitable for a register",
+               &DECL_SOURCE_LOCATION (decl), decl);
       else if (! HARD_REGNO_MODE_OK (reg_number, TYPE_MODE (TREE_TYPE (decl))))
-       error_with_decl (decl,
-                        "register specified for `%s' isn't suitable for data type");
+       error ("%Hregister specified for '%D' isn't suitable for data type",
+               &DECL_SOURCE_LOCATION (decl), decl);
       /* Now handle properly declared static register variables.  */
       else
        {
@@ -911,8 +857,8 @@ make_decl_rtl (decl, asmspec)
      Also handle vars declared register invalidly.  */
 
   if (reg_number >= 0 || reg_number == -3)
-    error_with_decl (decl,
-                    "register name given for non-register variable `%s'");
+    error ("%Hregister name given for non-register variable '%D'",
+           &DECL_SOURCE_LOCATION (decl), decl);
 
   /* Specifying a section attribute on a variable forces it into a
      non-.bss section, and thus it cannot be common.  */
@@ -922,38 +868,15 @@ make_decl_rtl (decl, asmspec)
       && DECL_COMMON (decl))
     DECL_COMMON (decl) = 0;
 
-  /* Can't use just the variable's own name for a variable
-     whose scope is less than the whole file, unless it's a member
-     of a local class (which will already be unambiguous).
-     Concatenate a distinguishing number.  */
-  if (!top_level && !TREE_PUBLIC (decl)
-      && ! (DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl)))
-      && asmspec == 0
-      && name == IDENTIFIER_POINTER (DECL_NAME (decl)))
-    {
-      char *label;
-
-      ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno);
-      var_labelno++;
-      new_name = label;
-    }
-
-  if (name != new_name)
-    {
-      SET_DECL_ASSEMBLER_NAME (decl, get_identifier (new_name));
-      name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
-    }
+  /* Variables can't be both common and weak.  */
+  if (TREE_CODE (decl) == VAR_DECL && DECL_WEAK (decl))
+    DECL_COMMON (decl) = 0;
 
-  /* If this variable is to be treated as volatile, show its
-     tree node has side effects.  */
-  if ((flag_volatile_global && TREE_CODE (decl) == VAR_DECL
-       && TREE_PUBLIC (decl))
-      || ((flag_volatile_static && TREE_CODE (decl) == VAR_DECL
-          && (TREE_PUBLIC (decl) || TREE_STATIC (decl)))))
-    TREE_SIDE_EFFECTS (decl) = 1;
+  x = gen_rtx_SYMBOL_REF (Pmode, name);
+  SYMBOL_REF_WEAK (x) = DECL_WEAK (decl);
+  SYMBOL_REF_DECL (x) = decl;
 
-  x = gen_rtx_MEM (DECL_MODE (decl), gen_rtx_SYMBOL_REF (Pmode, name));
-  SYMBOL_REF_WEAK (XEXP (x, 0)) = DECL_WEAK (decl);
+  x = gen_rtx_MEM (DECL_MODE (decl), x);
   if (TREE_CODE (decl) != FUNCTION_DECL)
     set_mem_attributes (x, decl, 1);
   SET_DECL_RTL (decl, x);
@@ -962,15 +885,14 @@ make_decl_rtl (decl, asmspec)
      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.  */
-  (* targetm.encode_section_info) (decl, true);
+  (* targetm.encode_section_info) (decl, DECL_RTL (decl), true);
 }
 
 /* Make the rtl for variable VAR be volatile.
    Use this only for static variables.  */
 
 void
-make_var_volatile (var)
-     tree var;
+make_var_volatile (tree var)
 {
   if (GET_CODE (DECL_RTL (var)) != MEM)
     abort ();
@@ -978,32 +900,11 @@ make_var_volatile (var)
   MEM_VOLATILE_P (DECL_RTL (var)) = 1;
 }
 \f
-/* Output alignment directive to align for constant expression EXP.  */
-
-void
-assemble_constant_align (exp)
-     tree exp;
-{
-  int align;
-
-  /* Align the location counter as required by EXP's data type.  */
-  align = TYPE_ALIGN (TREE_TYPE (exp));
-#ifdef CONSTANT_ALIGNMENT
-  align = CONSTANT_ALIGNMENT (exp, align);
-#endif
-
-  if (align > BITS_PER_UNIT)
-    {
-      ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
-    }
-}
-
 /* Output a string of literal assembler code
    for an `asm' keyword used between functions.  */
 
 void
-assemble_asm (string)
-     tree string;
+assemble_asm (tree string)
 {
   app_enable ();
 
@@ -1018,9 +919,7 @@ assemble_asm (string)
    between 0 and MAX_INIT_PRIORITY.  */
 
 void
-default_stabs_asm_out_destructor (symbol, priority)
-     rtx symbol;
-     int priority ATTRIBUTE_UNUSED;
+default_stabs_asm_out_destructor (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
@@ -1031,9 +930,7 @@ default_stabs_asm_out_destructor (symbol, priority)
 }
 
 void
-default_named_section_asm_out_destructor (symbol, priority)
-     rtx symbol;
-     int priority;
+default_named_section_asm_out_destructor (rtx symbol, int priority)
 {
   const char *section = ".dtors";
   char buf[16];
@@ -1056,7 +953,7 @@ default_named_section_asm_out_destructor (symbol, priority)
 
 #ifdef DTORS_SECTION_ASM_OP
 void
-dtors_section ()
+dtors_section (void)
 {
   if (in_section != in_dtors)
     {
@@ -1067,9 +964,8 @@ dtors_section ()
 }
 
 void
-default_dtor_section_asm_out_destructor (symbol, priority)
-     rtx symbol;
-     int priority ATTRIBUTE_UNUSED;
+default_dtor_section_asm_out_destructor (rtx symbol,
+                                        int priority ATTRIBUTE_UNUSED)
 {
   dtors_section ();
   assemble_align (POINTER_SIZE);
@@ -1080,9 +976,7 @@ default_dtor_section_asm_out_destructor (symbol, priority)
 /* Likewise for global constructors.  */
 
 void
-default_stabs_asm_out_constructor (symbol, priority)
-     rtx symbol;
-     int priority ATTRIBUTE_UNUSED;
+default_stabs_asm_out_constructor (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
@@ -1093,9 +987,7 @@ default_stabs_asm_out_constructor (symbol, priority)
 }
 
 void
-default_named_section_asm_out_constructor (symbol, priority)
-     rtx symbol;
-     int priority;
+default_named_section_asm_out_constructor (rtx symbol, int priority)
 {
   const char *section = ".ctors";
   char buf[16];
@@ -1118,7 +1010,7 @@ default_named_section_asm_out_constructor (symbol, priority)
 
 #ifdef CTORS_SECTION_ASM_OP
 void
-ctors_section ()
+ctors_section (void)
 {
   if (in_section != in_ctors)
     {
@@ -1129,9 +1021,8 @@ ctors_section ()
 }
 
 void
-default_ctor_section_asm_out_constructor (symbol, priority)
-     rtx symbol;
-     int priority ATTRIBUTE_UNUSED;
+default_ctor_section_asm_out_constructor (rtx symbol,
+                                         int priority ATTRIBUTE_UNUSED)
 {
   ctors_section ();
   assemble_align (POINTER_SIZE);
@@ -1140,7 +1031,7 @@ default_ctor_section_asm_out_constructor (symbol, priority)
 #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
+   a nonzero value if the constant pool should be output before the
    start of the function, or a zero value if the pool should output
    after the end of the function.  The default is to put it before the
    start.  */
@@ -1149,15 +1040,41 @@ default_ctor_section_asm_out_constructor (symbol, priority)
 #define CONSTANT_POOL_BEFORE_FUNCTION 1
 #endif
 
+/* DECL is an object (either VAR_DECL or FUNCTION_DECL) which is going
+   to be output to assembler.
+   Set first_global_object_name and weak_global_object_name as appropriate.  */
+
+void
+notice_global_symbol (tree decl)
+{
+  if ((!first_global_object_name || !weak_global_object_name)
+      && TREE_PUBLIC (decl) && !DECL_COMMON (decl)
+      && (TREE_CODE (decl) == FUNCTION_DECL
+         || (TREE_CODE (decl) == VAR_DECL
+             && (DECL_INITIAL (decl) != 0
+                 && DECL_INITIAL (decl) != error_mark_node))))
+    {
+      const char *p;
+      char *name;
+      rtx decl_rtl = DECL_RTL (decl);
+
+      p = (* targetm.strip_name_encoding) (XSTR (XEXP (decl_rtl, 0), 0));
+      name = xstrdup (p);
+
+      if (! DECL_WEAK (decl) && ! DECL_ONE_ONLY (decl))
+       first_global_object_name = name;
+      else
+       weak_global_object_name = name;
+    }
+}
+
 /* Output assembler code for the constant pool of a function and associated
    with defining the name of the function.  DECL describes the function.
    NAME is the function's name.  For the constant pool, we use the current
    constant pool data.  */
 
 void
-assemble_start_function (decl, fnname)
-     tree decl;
-     const char *fnname;
+assemble_start_function (tree decl, const char *fnname)
 {
   int align;
 
@@ -1173,6 +1090,8 @@ assemble_start_function (decl, fnname)
 
   /* Tell assembler to move to target machine's alignment for functions.  */
   align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
+  if (align < force_align_functions_log)
+    align = force_align_functions_log;
   if (align > 0)
     {
       ASM_OUTPUT_ALIGN (asm_out_file, align);
@@ -1202,20 +1121,7 @@ assemble_start_function (decl, fnname)
 
   if (TREE_PUBLIC (decl))
     {
-      if (! first_global_object_name)
-       {
-         const char *p;
-         char *name;
-
-         p = (* targetm.strip_name_encoding) (fnname);
-         name = permalloc (strlen (p) + 1);
-         strcpy (name, p);
-
-         if (! DECL_WEAK (decl) && ! DECL_ONE_ONLY (decl))
-           first_global_object_name = name;
-         else
-           weak_global_object_name = name;
-       }
+      notice_global_symbol (decl);
 
       globalize_decl (decl);
 
@@ -1235,9 +1141,7 @@ assemble_start_function (decl, fnname)
    function.  DECL describes the function.  NAME is the function's name.  */
 
 void
-assemble_end_function (decl, fnname)
-     tree decl;
-     const char *fnname;
+assemble_end_function (tree decl, const char *fnname)
 {
 #ifdef ASM_DECLARE_FUNCTION_SIZE
   ASM_DECLARE_FUNCTION_SIZE (asm_out_file, fnname, decl);
@@ -1247,16 +1151,12 @@ assemble_end_function (decl, fnname)
       output_constant_pool (fnname, decl);
       function_section (decl); /* need to switch back */
     }
-
-  /* Output any constants which should appear after the function.  */
-  output_after_function_constants ();
 }
 \f
 /* Assemble code to leave SIZE bytes of zeros.  */
 
 void
-assemble_zeros (size)
-     int size;
+assemble_zeros (unsigned HOST_WIDE_INT size)
 {
   /* Do no output if -fsyntax-only.  */
   if (flag_syntax_only)
@@ -1267,7 +1167,7 @@ assemble_zeros (size)
      so we must output 0s explicitly in the text section.  */
   if (ASM_NO_SKIP_IN_TEXT && in_text_section ())
     {
-      int i;
+      unsigned HOST_WIDE_INT i;
       for (i = 0; i < size; i++)
        assemble_integer (const0_rtx, 1, BITS_PER_UNIT, 1);
     }
@@ -1280,8 +1180,7 @@ assemble_zeros (size)
 /* Assemble an alignment pseudo op for an ALIGN-bit boundary.  */
 
 void
-assemble_align (align)
-     int align;
+assemble_align (int align)
 {
   if (align > BITS_PER_UNIT)
     {
@@ -1292,9 +1191,7 @@ assemble_align (align)
 /* Assemble a string constant with the specified C string as contents.  */
 
 void
-assemble_string (p, size)
-     const char *p;
-     int size;
+assemble_string (const char *p, int size)
 {
   int pos = 0;
   int maximum = 2000;
@@ -1353,12 +1250,10 @@ assemble_string (p, size)
 #endif
 #endif
 
-static void
-asm_emit_uninitialised (decl, name, size, rounded)
-     tree decl;
-     const char *name;
-     int size ATTRIBUTE_UNUSED;
-     int rounded ATTRIBUTE_UNUSED;
+static bool
+asm_emit_uninitialised (tree decl, const char *name,
+                       unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
+                       unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
 {
   enum
   {
@@ -1368,13 +1263,17 @@ asm_emit_uninitialised (decl, name, size, rounded)
   }
   destination = asm_dest_local;
 
+  /* ??? We should handle .bss via select_section mechanisms rather than
+     via special target hooks.  That would eliminate this special case.  */
   if (TREE_PUBLIC (decl))
     {
-#if defined ASM_EMIT_BSS
-      if (! DECL_COMMON (decl))
+      if (!DECL_COMMON (decl))
+#ifdef ASM_EMIT_BSS
        destination = asm_dest_bss;
-      else
+#else
+       return false;
 #endif
+      else
        destination = asm_dest_common;
     }
 
@@ -1423,7 +1322,7 @@ asm_emit_uninitialised (decl, name, size, rounded)
       abort ();
     }
 
-  return;
+  return true;
 }
 
 /* Assemble everything that is needed for a variable or function declaration.
@@ -1437,17 +1336,17 @@ asm_emit_uninitialised (decl, name, size, rounded)
    initial value (that will be done by the caller).  */
 
 void
-assemble_variable (decl, top_level, at_end, dont_output_data)
-     tree decl;
-     int top_level ATTRIBUTE_UNUSED;
-     int at_end ATTRIBUTE_UNUSED;
-     int dont_output_data;
+assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
+                  int at_end ATTRIBUTE_UNUSED, int dont_output_data)
 {
   const char *name;
   unsigned int align;
   int reloc = 0;
   rtx decl_rtl;
 
+  if (lang_hooks.decls.prepare_assemble_variable)
+    (*lang_hooks.decls.prepare_assemble_variable) (decl);
+
   last_assemble_variable_decl = 0;
 
   /* Normally no need to say anything here for external references,
@@ -1481,10 +1380,9 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
 
   if (!dont_output_data && DECL_SIZE (decl) == 0)
     {
-      error_with_file_and_line (DECL_SOURCE_FILE (decl),
-                               DECL_SOURCE_LINE (decl),
-                               "storage size of `%s' isn't known",
-                               IDENTIFIER_POINTER (DECL_NAME (decl)));
+      error ("%Hstorage size of `%s' isn't known",
+             &DECL_SOURCE_LOCATION (decl),
+             IDENTIFIER_POINTER (DECL_NAME (decl)));
       TREE_ASM_WRITTEN (decl) = 1;
       return;
     }
@@ -1512,26 +1410,14 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
   if (! dont_output_data
       && ! host_integerp (DECL_SIZE_UNIT (decl), 1))
     {
-      error_with_decl (decl, "size of variable `%s' is too large");
+      error ("%Hsize of variable '%D' is too large",
+             &DECL_SOURCE_LOCATION (decl), decl);
       return;
     }
 
   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
-                                  || DECL_INITIAL (decl) == error_mark_node))
-      && ! DECL_WEAK (decl)
-      && ! DECL_ONE_ONLY (decl))
-    {
-      const char *p;
-      char *xname;
-
-      p = (* targetm.strip_name_encoding) (name);
-      xname = permalloc (strlen (p) + 1);
-      strcpy (xname, p);
-      first_global_object_name = xname;
-    }
+  if (TREE_PUBLIC (decl) && DECL_NAME (decl))
+    notice_global_symbol (decl);
 
   /* Compute the alignment of this data.  */
 
@@ -1551,9 +1437,9 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
 #endif
   if (align > MAX_OFILE_ALIGNMENT)
     {
-      warning_with_decl (decl,
-       "alignment of `%s' is greater than maximum object file alignment. Using %d",
-                    MAX_OFILE_ALIGNMENT/BITS_PER_UNIT);
+      warning ("%Halignment of '%D' is greater than maximum object "
+               "file alignment.  Using %d", &DECL_SOURCE_LOCATION (decl),
+               decl, MAX_OFILE_ALIGNMENT/BITS_PER_UNIT);
       align = MAX_OFILE_ALIGNMENT;
     }
 
@@ -1565,7 +1451,7 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
 #endif
 #ifdef CONSTANT_ALIGNMENT
       if (DECL_INITIAL (decl) != 0 && DECL_INITIAL (decl) != error_mark_node)
-        align = CONSTANT_ALIGNMENT (DECL_INITIAL (decl), align);
+       align = CONSTANT_ALIGNMENT (DECL_INITIAL (decl), align);
 #endif
     }
 
@@ -1596,17 +1482,11 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
       if (DECL_COMMON (decl))
        sorry ("thread-local COMMON data not implemented");
     }
-#ifndef ASM_EMIT_BSS
-  /* If the target can't output uninitialized but not common global data
-     in .bss, then we have to use .data.  */
-  /* ??? We should handle .bss via select_section mechanisms rather than
-     via special target hooks.  That would eliminate this special case.  */
-  else if (!DECL_COMMON (decl))
-    ;
-#endif
   else if (DECL_INITIAL (decl) == 0
           || DECL_INITIAL (decl) == error_mark_node
-           || (flag_zero_initialized_in_bss
+          || (flag_zero_initialized_in_bss
+              /* Leave constant zeroes in .rodata so they can be shared.  */
+              && !TREE_READONLY (decl)
               && initializer_zerop (DECL_INITIAL (decl))))
     {
       unsigned HOST_WIDE_INT size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
@@ -1623,16 +1503,17 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
       rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
                 * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
 
-/* Don't continue this line--convex cc version 4.1 would lose.  */
 #if !defined(ASM_OUTPUT_ALIGNED_COMMON) && !defined(ASM_OUTPUT_ALIGNED_DECL_COMMON) && !defined(ASM_OUTPUT_ALIGNED_BSS)
       if ((unsigned HOST_WIDE_INT) DECL_ALIGN (decl) / BITS_PER_UNIT > rounded)
-         warning_with_decl
-           (decl, "requested alignment for %s is greater than implemented alignment of %d",rounded);
+       warning ("%Hrequested alignment for '%D' is greater than "
+                 "implemented alignment of %d", &DECL_SOURCE_LOCATION (decl),
+                 decl, rounded);
 #endif
 
-      asm_emit_uninitialised (decl, name, size, rounded);
-
-      return;
+      /* If the target cannot output uninitialized but not common global data
+        in .bss, then we have to use .data, so fall through.  */
+      if (asm_emit_uninitialised (decl, name, size, rounded))
+       return;
     }
 
   /* Handle initialized definitions.
@@ -1682,8 +1563,7 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
 /* Return 1 if type TYPE contains any pointers.  */
 
 static int
-contains_pointers_p (type)
-     tree type;
+contains_pointers_p (tree type)
 {
   switch (TREE_CODE (type))
     {
@@ -1721,8 +1601,7 @@ contains_pointers_p (type)
    Do nothing if DECL is not external.  */
 
 void
-assemble_external (decl)
-     tree decl ATTRIBUTE_UNUSED;
+assemble_external (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
@@ -1750,8 +1629,7 @@ assemble_external (decl)
 /* Similar, for calling a library function FUN.  */
 
 void
-assemble_external_libcall (fun)
-     rtx fun ATTRIBUTE_UNUSED;
+assemble_external_libcall (rtx fun ATTRIBUTE_UNUSED)
 {
 #ifdef ASM_OUTPUT_EXTERNAL_LIBCALL
   /* Declare library function name external when first used, if nec.  */
@@ -1763,22 +1641,35 @@ assemble_external_libcall (fun)
 #endif
 }
 
-/* Declare the label NAME global.  */
+/* Assemble a label named NAME.  */
 
 void
-assemble_global (name)
-     const char *name ATTRIBUTE_UNUSED;
+assemble_label (const char *name)
 {
-  ASM_GLOBALIZE_LABEL (asm_out_file, name);
+  ASM_OUTPUT_LABEL (asm_out_file, name);
 }
 
-/* Assemble a label named NAME.  */
-
+/* Set the symbol_referenced flag for ID and notify callgraph code.  */
 void
-assemble_label (name)
-     const char *name;
+mark_referenced (tree id)
 {
-  ASM_OUTPUT_LABEL (asm_out_file, name);
+  if (!TREE_SYMBOL_REFERENCED (id))
+    {
+      struct cgraph_node *node;
+      struct cgraph_varpool_node *vnode;
+
+      if (!cgraph_global_info_ready)
+       {
+         node = cgraph_node_for_identifier (id);
+         if (node)
+           cgraph_mark_needed_node (node);
+       }
+
+      vnode = cgraph_varpool_node_for_identifier (id);
+      if (vnode)
+       cgraph_varpool_mark_needed_node (vnode);
+    }
+  TREE_SYMBOL_REFERENCED (id) = 1;
 }
 
 /* Output to FILE a reference to the assembler name of a C-level name NAME.
@@ -1788,9 +1679,7 @@ assemble_label (name)
    Many macros in the tm file are defined to call this function.  */
 
 void
-assemble_name (file, name)
-     FILE *file;
-     const char *name;
+assemble_name (FILE *file, const char *name)
 {
   const char *real_name;
   tree id;
@@ -1799,7 +1688,7 @@ assemble_name (file, name)
 
   id = maybe_get_identifier (real_name);
   if (id)
-    TREE_SYMBOL_REFERENCED (id) = 1;
+    mark_referenced (id);
 
   if (name[0] == '*')
     fputs (&name[1], file);
@@ -1811,8 +1700,7 @@ assemble_name (file, name)
    and return an RTX to refer to its address.  */
 
 rtx
-assemble_static_space (size)
-     int size;
+assemble_static_space (unsigned HOST_WIDE_INT size)
 {
   char name[12];
   const char *namestring;
@@ -1828,6 +1716,7 @@ assemble_static_space (size)
   namestring = ggc_strdup (name);
 
   x = gen_rtx_SYMBOL_REF (Pmode, namestring);
+  SYMBOL_REF_FLAGS (x) = SYMBOL_FLAG_LOCAL;
 
 #ifdef ASM_OUTPUT_ALIGNED_DECL_LOCAL
   ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, NULL_TREE, name, size,
@@ -1840,7 +1729,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.  */
-    int rounded ATTRIBUTE_UNUSED
+    unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED
       = ((size + (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1)
         / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
         * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
@@ -1857,11 +1746,12 @@ assemble_static_space (size)
 
 #ifdef TRAMPOLINE_TEMPLATE
 rtx
-assemble_trampoline_template ()
+assemble_trampoline_template (void)
 {
   char label[256];
   const char *name;
   int align;
+  rtx symbol;
 
   /* By default, put trampoline templates in read-only data section.  */
 
@@ -1878,13 +1768,16 @@ assemble_trampoline_template ()
       ASM_OUTPUT_ALIGN (asm_out_file, align);
     }
 
-  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LTRAMP", 0);
+  (*targetm.asm_out.internal_label) (asm_out_file, "LTRAMP", 0);
   TRAMPOLINE_TEMPLATE (asm_out_file);
 
   /* Record the rtl to refer to it.  */
   ASM_GENERATE_INTERNAL_LABEL (label, "LTRAMP", 0);
   name = ggc_strdup (label);
-  return gen_rtx_SYMBOL_REF (Pmode, name);
+  symbol = gen_rtx_SYMBOL_REF (Pmode, name);
+  SYMBOL_REF_FLAGS (symbol) = SYMBOL_FLAG_LOCAL;
+
+  return symbol;
 }
 #endif
 \f
@@ -1892,8 +1785,7 @@ assemble_trampoline_template ()
    that may be assumed after adding the two together.  */
 
 static inline unsigned
-min_align (a, b)
-     unsigned int a, b;
+min_align (unsigned int a, unsigned int b)
 {
   return (a | b) & -(a | b);
 }
@@ -1907,9 +1799,7 @@ min_align (a, b)
    be followed immediately by the object's initial value.  */
 
 const char *
-integer_asm_op (size, aligned_p)
-     int size;
-     int aligned_p;
+integer_asm_op (int size, int aligned_p)
 {
   struct asm_int_op *ops;
 
@@ -1939,9 +1829,7 @@ integer_asm_op (size, aligned_p)
    start of the line, followed immediately by the value of X.  */
 
 void
-assemble_integer_with_op (op, x)
-     const char *op;
-     rtx x;
+assemble_integer_with_op (const char *op, rtx x)
 {
   fputs (op, asm_out_file);
   output_addr_const (asm_out_file, x);
@@ -1951,10 +1839,9 @@ assemble_integer_with_op (op, x)
 /* The default implementation of the asm_out.integer target hook.  */
 
 bool
-default_assemble_integer (x, size, aligned_p)
-     rtx x ATTRIBUTE_UNUSED;
-     unsigned int size ATTRIBUTE_UNUSED;
-     int aligned_p ATTRIBUTE_UNUSED;
+default_assemble_integer (rtx x ATTRIBUTE_UNUSED,
+                         unsigned int size ATTRIBUTE_UNUSED,
+                         int aligned_p ATTRIBUTE_UNUSED)
 {
   const char *op = integer_asm_op (size, aligned_p);
   return op && (assemble_integer_with_op (op, x), true);
@@ -1962,15 +1849,11 @@ default_assemble_integer (x, size, aligned_p)
 
 /* Assemble the integer constant X into an object of SIZE bytes.  ALIGN is
    the alignment of the integer in bits.  Return 1 if we were able to output
-   the constant, otherwise 0.  If FORCE is non-zero, abort if we can't output
+   the constant, otherwise 0.  If FORCE is nonzero, abort if we can't output
    the constant.  */
 
 bool
-assemble_integer (x, size, align, force)
-     rtx x;
-     unsigned int size;
-     unsigned int align;
-     int force;
+assemble_integer (rtx x, unsigned int size, unsigned int align, int force)
 {
   int aligned_p;
 
@@ -2015,10 +1898,7 @@ assemble_integer (x, size, align, force)
 }
 \f
 void
-assemble_real (d, mode, align)
-     REAL_VALUE_TYPE d;
-     enum machine_mode mode;
-     unsigned int align;
+assemble_real (REAL_VALUE_TYPE d, enum machine_mode mode, unsigned int align)
 {
   long data[4];
   long l;
@@ -2100,16 +1980,14 @@ assemble_real (d, mode, align)
    Store them both in the structure *VALUE.
    Abort if EXP does not reduce.  */
 
-struct addr_const
+struct addr_const GTY(())
 {
   rtx base;
   HOST_WIDE_INT offset;
 };
 
 static void
-decode_addr_const (exp, value)
-     tree exp;
-     struct addr_const *value;
+decode_addr_const (tree exp, struct addr_const *value)
 {
   tree target = TREE_OPERAND (exp, 0);
   int offset = 0;
@@ -2144,8 +2022,7 @@ decode_addr_const (exp, value)
 
     case LABEL_DECL:
       x = gen_rtx_MEM (FUNCTION_MODE,
-                      gen_rtx_LABEL_REF (VOIDmode,
-                                         label_rtx (TREE_OPERAND (exp, 0))));
+                      gen_rtx_LABEL_REF (VOIDmode, force_label_rtx (target)));
       break;
 
     case REAL_CST:
@@ -2153,8 +2030,6 @@ decode_addr_const (exp, value)
     case COMPLEX_CST:
     case CONSTRUCTOR:
     case INTEGER_CST:
-      /* This constant should have been output already, but we can't simply
-        use TREE_CST_RTL since INTEGER_CST doesn't have one.  */
       x = output_constant_def (target, 1);
       break;
 
@@ -2171,143 +2046,68 @@ decode_addr_const (exp, value)
 }
 \f
 /* We do RTX_UNSPEC + XINT (blah), so nothing can go after RTX_UNSPEC.  */
-enum kind { RTX_UNKNOWN, RTX_DOUBLE, RTX_INT, RTX_VECTOR, RTX_UNSPEC };
-struct rtx_const
+enum kind { RTX_UNKNOWN, RTX_DOUBLE, RTX_VECTOR, RTX_INT, RTX_UNSPEC };
+struct rtx_const GTY(())
 {
   ENUM_BITFIELD(kind) kind : 16;
   ENUM_BITFIELD(machine_mode) mode : 16;
-  union {
-    REAL_VALUE_TYPE du;
-    struct addr_const addr;
-    struct {HOST_WIDE_INT high, low;} di;
-
-    /* The max vector size we have is 8 wide.  This should be enough.  */
-    HOST_WIDE_INT veclo[16];
-    HOST_WIDE_INT vechi[16];
-  } un;
+  union rtx_const_un {
+    REAL_VALUE_TYPE GTY ((tag ("4"))) du;
+    struct rtx_const_u_addr {
+      rtx base;
+      const char *symbol;
+      HOST_WIDE_INT offset;
+    } GTY ((tag ("1"))) addr;
+    struct rtx_const_u_di {
+      HOST_WIDE_INT high;
+      HOST_WIDE_INT low;
+    } GTY ((tag ("0"))) di;
+
+    /* The max vector size we have is 16 wide; two variants for
+       integral and floating point vectors.  */
+    struct rtx_const_int_vec {
+      HOST_WIDE_INT high;
+      HOST_WIDE_INT low;
+    } GTY ((tag ("2"))) int_vec[16];
+
+    REAL_VALUE_TYPE GTY ((tag ("3"))) fp_vec[8];
+
+  } GTY ((desc ("%1.kind >= RTX_INT"), descbits ("1"))) un;
 };
 
 /* Uniquize all constants that appear in memory.
    Each constant in memory thus far output is recorded
-   in `const_hash_table' with a `struct constant_descriptor'
-   that contains a polish representation of the value of
-   the constant.
-
-   We cannot store the trees in the hash table
-   because the trees may be temporary.  */
+   in `const_hash_table'.  */
 
-struct constant_descriptor
+struct constant_descriptor_tree GTY(())
 {
-  struct constant_descriptor *next;
-  const char *label;
+  /* A MEM for the constant.  */
   rtx rtl;
-  /* 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];
-
-/* We maintain a hash table of STRING_CST values.  Unless we are asked to force
-   out a string constant, we defer output of the constants until we know
-   they are actually used.  This will be if something takes its address or if
-   there is a usage of the string in the RTL of a function.  */
-
-#define STRHASH(x) ((hashval_t) ((long) (x) >> 3))
 
-struct deferred_string
-{
-  const char *label;
-  tree exp;
-  int labelno;
+  /* The value of the constant.  */
+  tree value;
 };
 
-static htab_t const_str_htab;
-
-/* Mark a const_hash_table descriptor for GC.  */
-
-static void
-mark_const_hash_entry (ptr)
-     void *ptr;
-{
-  struct constant_descriptor *desc = * (struct constant_descriptor **) ptr;
-
-  while (desc)
-    {
-      ggc_mark_rtx (desc->rtl);
-      desc = desc->next;
-    }
-}
+static GTY((param_is (struct constant_descriptor_tree)))
+     htab_t const_desc_htab;
 
-/* Mark the hash-table element X (which is really a pointer to an
-   struct deferred_string *).  */
+static struct constant_descriptor_tree * build_constant_desc (tree);
+static void maybe_output_constant_def_contents (struct constant_descriptor_tree *, int);
 
-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 *).  */
+/* Compute a hash code for a constant expression.  */
 
 static hashval_t
-const_str_htab_hash (x)
-     const void *x;
+const_desc_hash (const void *ptr)
 {
-  return STRHASH (((const struct deferred_string *) x)->label);
+  return const_hash_1 (((struct constant_descriptor_tree *)ptr)->value);
 }
 
-/* Returns non-zero if the value represented by X (which is really a
-   struct deferred_string *) is the same as that given by Y
-   (which is really a char *).  */
-
-static int
-const_str_htab_eq (x, y)
-     const void *x;
-     const void *y;
-{
-  return (((const struct deferred_string *) x)->label == (const char *) y);
-}
-
-/* Delete the hash table entry dfsp.  */
-
-static void
-const_str_htab_del (dfsp)
-     void *dfsp;
-{
-  free (dfsp);
-}
-
-/* Compute a hash code for a constant expression.  */
-
-static int
-const_hash (exp)
-     tree exp;
+static hashval_t
+const_hash_1 (const tree exp)
 {
   const char *p;
-  int len, hi, i;
+  hashval_t hi;
+  int len, i;
   enum tree_code code = TREE_CODE (exp);
 
   /* Either set P and LEN to the address and len of something to hash and
@@ -2321,18 +2121,15 @@ const_hash (exp)
       break;
 
     case REAL_CST:
-      p = (char *) &TREE_REAL_CST (exp);
-      len = sizeof TREE_REAL_CST (exp);
-      break;
+      return real_hash (TREE_REAL_CST_PTR (exp));
 
     case STRING_CST:
       p = TREE_STRING_POINTER (exp);
       len = TREE_STRING_LENGTH (exp);
       break;
-
     case COMPLEX_CST:
-      return (const_hash (TREE_REALPART (exp)) * 5
-             + const_hash (TREE_IMAGPART (exp)));
+      return (const_hash_1 (TREE_REALPART (exp)) * 5
+             + const_hash_1 (TREE_IMAGPART (exp)));
 
     case CONSTRUCTOR:
       if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
@@ -2340,7 +2137,7 @@ const_hash (exp)
          char *tmp;
 
          len = int_size_in_bytes (TREE_TYPE (exp));
-         tmp = (char *) alloca (len);
+         tmp = alloca (len);
          get_set_constructor_bytes (exp, (unsigned char *) tmp, len);
          p = tmp;
          break;
@@ -2349,28 +2146,17 @@ const_hash (exp)
        {
          tree link;
 
-         /* For record type, include the type in the hashing.
-            We do not do so for array types
-            because (1) the sizes of the elements are sufficient
-            and (2) distinct array types can have the same constructor.
-            Instead, we include the array size because the constructor could
-            be shorter.  */
-         if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
-           hi = ((unsigned long) TREE_TYPE (exp) & ((1 << HASHBITS) - 1))
-             % MAX_HASH_TABLE;
-         else
-           hi = ((5 + int_size_in_bytes (TREE_TYPE (exp)))
-                 & ((1 << HASHBITS) - 1)) % MAX_HASH_TABLE;
+         hi = 5 + int_size_in_bytes (TREE_TYPE (exp));
 
          for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
            if (TREE_VALUE (link))
-             hi
-               = (hi * 603 + const_hash (TREE_VALUE (link))) % MAX_HASH_TABLE;
+             hi = hi * 603 + const_hash_1 (TREE_VALUE (link));
 
          return hi;
        }
 
     case ADDR_EXPR:
+    case FDESC_EXPR:
       {
        struct addr_const value;
 
@@ -2388,565 +2174,197 @@ const_hash (exp)
          hi = value.offset + CODE_LABEL_NUMBER (XEXP (value.base, 0)) * 13;
        else
          abort ();
-
-       hi &= (1 << HASHBITS) - 1;
-       hi %= MAX_HASH_TABLE;
       }
       return hi;
 
     case PLUS_EXPR:
     case MINUS_EXPR:
-      return (const_hash (TREE_OPERAND (exp, 0)) * 9
-             + const_hash (TREE_OPERAND (exp, 1)));
+      return (const_hash_1 (TREE_OPERAND (exp, 0)) * 9
+             + const_hash_1 (TREE_OPERAND (exp, 1)));
 
     case NOP_EXPR:
     case CONVERT_EXPR:
     case NON_LVALUE_EXPR:
-      return const_hash (TREE_OPERAND (exp, 0)) * 7 + 2;
+      return const_hash_1 (TREE_OPERAND (exp, 0)) * 7 + 2;
 
     default:
       /* A language specific constant. Just hash the code.  */
-      return (int) code % MAX_HASH_TABLE;
+      return code;
     }
 
-  /* Compute hashing function */
+  /* Compute hashing function */
   hi = len;
   for (i = 0; i < len; i++)
     hi = ((hi * 613) + (unsigned) (p[i]));
 
-  hi &= (1 << HASHBITS) - 1;
-  hi %= MAX_HASH_TABLE;
   return hi;
 }
-\f
-/* Compare a constant expression EXP with a constant-descriptor DESC.
-   Return 1 if DESC describes a constant with the same value as EXP.  */
 
+/* Wrapper of compare_constant, for the htab interface.  */
 static int
-compare_constant (exp, desc)
-     tree exp;
-     struct constant_descriptor *desc;
+const_desc_eq (const void *p1, const void *p2)
 {
-  return 0 != compare_constant_1 (exp, desc->u.contents);
+  return compare_constant (((struct constant_descriptor_tree *)p1)->value,
+                          ((struct constant_descriptor_tree *)p2)->value);
 }
 
-/* Compare constant expression EXP with a substring P of a constant descriptor.
-   If they match, return a pointer to the end of the substring matched.
-   If they do not match, return 0.
+/* Compare t1 and t2, and return 1 only if they are known to result in
+   the same bit pattern on output.  */
 
-   Since descriptors are written in polish prefix notation,
-   this function can be used recursively to test one operand of EXP
-   against a subdescriptor, and if it succeeds it returns the
-   address of the subdescriptor for the next operand.  */
-
-static const unsigned char *
-compare_constant_1 (exp, p)
-     tree exp;
-     const unsigned char *p;
+static int
+compare_constant (const tree t1, const tree t2)
 {
-  const unsigned char *strp;
-  int len;
-  enum tree_code code = TREE_CODE (exp);
+  enum tree_code typecode;
 
-  if (code != (enum tree_code) *p++)
+  if (t1 == NULL_TREE)
+    return t2 == NULL_TREE;
+  if (t2 == NULL_TREE)
     return 0;
 
-  /* Either set STRP, P and LEN to pointers and length to compare and exit the
-     switch, or return the result of the comparison.  */
+  if (TREE_CODE (t1) != TREE_CODE (t2))
+    return 0;
 
-  switch (code)
+  switch (TREE_CODE (t1))
     {
     case INTEGER_CST:
       /* Integer constants are the same only if the same width of type.  */
-      if (*p++ != TYPE_PRECISION (TREE_TYPE (exp)))
+      if (TYPE_PRECISION (TREE_TYPE (t1)) != TYPE_PRECISION (TREE_TYPE (t2)))
        return 0;
-
-      strp = (unsigned char *) &TREE_INT_CST (exp);
-      len = sizeof TREE_INT_CST (exp);
-      break;
+      return tree_int_cst_equal (t1, t2);
 
     case REAL_CST:
       /* Real constants are the same only if the same width of type.  */
-      if (*p++ != TYPE_PRECISION (TREE_TYPE (exp)))
+      if (TYPE_PRECISION (TREE_TYPE (t1)) != TYPE_PRECISION (TREE_TYPE (t2)))
        return 0;
 
-      strp = (unsigned char *) &TREE_REAL_CST (exp);
-      len = sizeof TREE_REAL_CST (exp);
-      break;
+      return REAL_VALUES_IDENTICAL (TREE_REAL_CST (t1), TREE_REAL_CST (t2));
 
     case STRING_CST:
       if (flag_writable_strings)
        return 0;
 
-      if ((enum machine_mode) *p++ != TYPE_MODE (TREE_TYPE (exp)))
+      if (TYPE_MODE (TREE_TYPE (t1)) != TYPE_MODE (TREE_TYPE (t2)))
        return 0;
 
-      strp = (const unsigned char *) TREE_STRING_POINTER (exp);
-      len = TREE_STRING_LENGTH (exp);
-      if (memcmp ((char *) &TREE_STRING_LENGTH (exp), p,
-                 sizeof TREE_STRING_LENGTH (exp)))
-       return 0;
-
-      p += sizeof TREE_STRING_LENGTH (exp);
-      break;
+      return (TREE_STRING_LENGTH (t1) == TREE_STRING_LENGTH (t2)
+             && ! memcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2),
+                        TREE_STRING_LENGTH (t1)));
 
     case COMPLEX_CST:
-      p = compare_constant_1 (TREE_REALPART (exp), p);
-      if (p == 0)
-       return 0;
-
-      return compare_constant_1 (TREE_IMAGPART (exp), p);
+      return (compare_constant (TREE_REALPART (t1), TREE_REALPART (t2))
+             && compare_constant (TREE_IMAGPART (t1), TREE_IMAGPART (t2)));
 
     case CONSTRUCTOR:
-      if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
-       {
-         int xlen = len = int_size_in_bytes (TREE_TYPE (exp));
-         unsigned char *tmp = (unsigned char *) alloca (len);
-
-         get_set_constructor_bytes (exp, tmp, len);
-         strp = (unsigned char *) tmp;
-         if (memcmp ((char *) &xlen, p, sizeof xlen))
-           return 0;
+      typecode = TREE_CODE (TREE_TYPE (t1));
+      if (typecode != TREE_CODE (TREE_TYPE (t2)))
+       return 0;
 
-         p += sizeof xlen;
-         break;
-       }
-      else
+      if (typecode == SET_TYPE)
        {
-         tree link;
-         int length = list_length (CONSTRUCTOR_ELTS (exp));
-         tree type;
-         enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
-         int have_purpose = 0;
-
-         for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
-           if (TREE_PURPOSE (link))
-             have_purpose = 1;
+         int len = int_size_in_bytes (TREE_TYPE (t2));
+         unsigned char *tmp1, *tmp2;
 
-         if (memcmp ((char *) &length, p, sizeof length))
+         if (int_size_in_bytes (TREE_TYPE (t1)) != len)
            return 0;
 
-         p += sizeof length;
+         tmp1 = alloca (len);
+         tmp2 = alloca (len);
 
-         /* For record constructors, insist that the types match.
-            For arrays, just verify both constructors are for arrays.
-            Then insist that either both or none have any TREE_PURPOSE
-            values.  */
-         if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
-           type = TREE_TYPE (exp);
-         else
-           type = 0;
-
-         if (memcmp ((char *) &type, p, sizeof type))
+         if (get_set_constructor_bytes (t1, tmp1, len) != NULL_TREE)
+           return 0;
+         if (get_set_constructor_bytes (t2, tmp2, len) != NULL_TREE)
            return 0;
 
-         if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
+         return memcmp (tmp1, tmp2, len) != 0;
+       }
+      else
+       {
+         tree l1, l2;
+
+         if (typecode == ARRAY_TYPE)
            {
-             if (memcmp ((char *) &mode, p, sizeof mode))
+             HOST_WIDE_INT size_1 = int_size_in_bytes (TREE_TYPE (t1));
+             /* For arrays, check that the sizes all match.  */
+             if (TYPE_MODE (TREE_TYPE (t1)) != TYPE_MODE (TREE_TYPE (t2))
+                 || size_1 == -1
+                 || size_1 != int_size_in_bytes (TREE_TYPE (t2)))
                return 0;
-
-             p += sizeof mode;
            }
-
-         p += sizeof type;
-
-         if (memcmp ((char *) &have_purpose, p, sizeof have_purpose))
-           return 0;
-
-         p += sizeof have_purpose;
-
-         /* For arrays, insist that the size in bytes match.  */
-         if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
+         else
            {
-             HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp));
-
-             if (memcmp ((char *) &size, p, sizeof size))
+             /* For record and union constructors, require exact type
+                 equality.  */
+             if (TREE_TYPE (t1) != TREE_TYPE (t2))
                return 0;
-
-             p += sizeof size;
            }
 
-         for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
+         for (l1 = CONSTRUCTOR_ELTS (t1), l2 = CONSTRUCTOR_ELTS (t2);
+              l1 && l2;
+              l1 = TREE_CHAIN (l1), l2 = TREE_CHAIN (l2))
            {
-             if (TREE_VALUE (link))
+             /* Check that each value is the same...  */
+             if (! compare_constant (TREE_VALUE (l1), TREE_VALUE (l2)))
+               return 0;
+             /* ... and that they apply to the same fields!  */
+             if (typecode == ARRAY_TYPE)
                {
-                 if ((p = compare_constant_1 (TREE_VALUE (link), p)) == 0)
+                 if (! compare_constant (TREE_PURPOSE (l1),
+                                         TREE_PURPOSE (l2)))
                    return 0;
                }
              else
                {
-                 tree zero = 0;
-
-                 if (memcmp ((char *) &zero, p, sizeof zero))
-                   return 0;
-
-                 p += sizeof zero;
-               }
-
-             if (TREE_PURPOSE (link)
-                 && TREE_CODE (TREE_PURPOSE (link)) == FIELD_DECL)
-               {
-                 if (memcmp ((char *) &TREE_PURPOSE (link), p,
-                             sizeof TREE_PURPOSE (link)))
+                 if (TREE_PURPOSE (l1) != TREE_PURPOSE (l2))
                    return 0;
-
-                 p += sizeof TREE_PURPOSE (link);
-               }
-             else if (TREE_PURPOSE (link))
-               {
-                 if ((p = compare_constant_1 (TREE_PURPOSE (link), p)) == 0)
-                   return 0;
-               }
-             else if (have_purpose)
-               {
-                 int zero = 0;
-
-                 if (memcmp ((char *) &zero, p, sizeof zero))
-                   return 0;
-
-                 p += sizeof zero;
                }
            }
 
-         return p;
+         return l1 == NULL_TREE && l2 == NULL_TREE;
        }
 
     case ADDR_EXPR:
+    case FDESC_EXPR:
       {
-       struct addr_const value;
+       struct addr_const value1, value2;
 
-       decode_addr_const (exp, &value);
-       strp = (unsigned char *) &value.offset;
-       len = sizeof value.offset;
-       /* Compare the offset.  */
-       while (--len >= 0)
-         if (*p++ != *strp++)
-           return 0;
-
-       /* Compare symbol name.  */
-       strp = (const unsigned char *) XSTR (value.base, 0);
-       len = strlen ((const char *) strp) + 1;
+       decode_addr_const (t1, &value1);
+       decode_addr_const (t2, &value2);
+       return (value1.offset == value2.offset
+               && strcmp (XSTR (value1.base, 0), XSTR (value2.base, 0)) == 0);
       }
-      break;
 
     case PLUS_EXPR:
     case MINUS_EXPR:
     case RANGE_EXPR:
-      p = compare_constant_1 (TREE_OPERAND (exp, 0), p);
-      if (p == 0)
-       return 0;
-
-      return compare_constant_1 (TREE_OPERAND (exp, 1), p);
+      return (compare_constant (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0))
+             && compare_constant(TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1)));
 
     case NOP_EXPR:
     case CONVERT_EXPR:
     case NON_LVALUE_EXPR:
-      return compare_constant_1 (TREE_OPERAND (exp, 0), p);
+      return compare_constant (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
 
     default:
       {
-       tree new = (*lang_hooks.expand_constant) (exp);
-
-       if (new != exp)
-         return compare_constant_1 (new, p);
+       tree nt1, nt2;
+       nt1 = (*lang_hooks.expand_constant) (t1);
+       nt2 = (*lang_hooks.expand_constant) (t2);
+       if (nt1 != t1 || nt2 != t2)
+         return compare_constant (nt1, nt2);
        else
          return 0;
       }
     }
 
-  /* Compare constant contents.  */
-  while (--len >= 0)
-    if (*p++ != *strp++)
-      return 0;
-
-  return p;
-}
-\f
-/* Construct a constant descriptor for the expression EXP.
-   It is up to the caller to enter the descriptor in the hash table.  */
-
-static struct constant_descriptor *
-record_constant (exp)
-     tree 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.  */
-
-  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);
-}
-
-/* Add a description of constant expression EXP
-   to the object growing in `permanent_obstack'.
-   No need to return its address; the caller will get that
-   from the obstack when the object is complete.  */
-
-static void
-record_constant_1 (exp)
-     tree exp;
-{
-  const unsigned char *strp;
-  int len;
-  enum tree_code code = TREE_CODE (exp);
-
-  obstack_1grow (&permanent_obstack, (unsigned int) code);
-
-  switch (code)
-    {
-    case INTEGER_CST:
-      obstack_1grow (&permanent_obstack, TYPE_PRECISION (TREE_TYPE (exp)));
-      strp = (unsigned char *) &TREE_INT_CST (exp);
-      len = sizeof TREE_INT_CST (exp);
-      break;
-
-    case REAL_CST:
-      obstack_1grow (&permanent_obstack, TYPE_PRECISION (TREE_TYPE (exp)));
-      strp = (unsigned char *) &TREE_REAL_CST (exp);
-      len = sizeof TREE_REAL_CST (exp);
-      break;
-
-    case STRING_CST:
-      if (flag_writable_strings)
-       return;
-
-      obstack_1grow (&permanent_obstack, TYPE_MODE (TREE_TYPE (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));
-      break;
-
-    case COMPLEX_CST:
-      record_constant_1 (TREE_REALPART (exp));
-      record_constant_1 (TREE_IMAGPART (exp));
-      return;
-
-    case CONSTRUCTOR:
-      if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
-       {
-         int nbytes = int_size_in_bytes (TREE_TYPE (exp));
-         obstack_grow (&permanent_obstack, &nbytes, sizeof (nbytes));
-         obstack_blank (&permanent_obstack, nbytes);
-         get_set_constructor_bytes
-           (exp, (unsigned char *) permanent_obstack.next_free - nbytes,
-            nbytes);
-         return;
-       }
-      else
-       {
-         tree link;
-         int length = list_length (CONSTRUCTOR_ELTS (exp));
-         enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
-         tree type;
-         int have_purpose = 0;
-
-         for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
-           if (TREE_PURPOSE (link))
-             have_purpose = 1;
-
-         obstack_grow (&permanent_obstack, (char *) &length, sizeof length);
-
-         /* For record constructors, insist that the types match.
-            For arrays, just verify both constructors are for arrays
-            of the same mode.  Then insist that either both or none
-            have any TREE_PURPOSE values.  */
-         if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
-           type = TREE_TYPE (exp);
-         else
-           type = 0;
-
-         obstack_grow (&permanent_obstack, (char *) &type, sizeof type);
-         if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
-           obstack_grow (&permanent_obstack, &mode, sizeof mode);
-
-         obstack_grow (&permanent_obstack, (char *) &have_purpose,
-                       sizeof have_purpose);
-
-         /* For arrays, insist that the size in bytes match.  */
-         if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
-           {
-             HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp));
-             obstack_grow (&permanent_obstack, (char *) &size, sizeof size);
-           }
-
-         for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
-           {
-             if (TREE_VALUE (link))
-               record_constant_1 (TREE_VALUE (link));
-             else
-               {
-                 tree zero = 0;
-
-                 obstack_grow (&permanent_obstack,
-                               (char *) &zero, sizeof zero);
-               }
-
-             if (TREE_PURPOSE (link)
-                 && TREE_CODE (TREE_PURPOSE (link)) == FIELD_DECL)
-               obstack_grow (&permanent_obstack,
-                             (char *) &TREE_PURPOSE (link),
-                             sizeof TREE_PURPOSE (link));
-             else if (TREE_PURPOSE (link))
-               record_constant_1 (TREE_PURPOSE (link));
-             else if (have_purpose)
-               {
-                 int zero = 0;
-
-                 obstack_grow (&permanent_obstack,
-                               (char *) &zero, sizeof zero);
-               }
-           }
-       }
-      return;
-
-    case ADDR_EXPR:
-      {
-       struct addr_const value;
-
-       decode_addr_const (exp, &value);
-       /* Record the offset.  */
-       obstack_grow (&permanent_obstack,
-                     (char *) &value.offset, sizeof value.offset);
-
-       switch (GET_CODE (value.base))
-         {
-         case SYMBOL_REF:
-           /* Record the symbol name.  */
-           obstack_grow (&permanent_obstack, XSTR (value.base, 0),
-                         strlen (XSTR (value.base, 0)) + 1);
-           break;
-         case LABEL_REF:
-           /* Record the address of the CODE_LABEL.  It may not have
-              been emitted yet, so it's UID may be zero.  But pointer
-              identity is good enough.  */
-           obstack_grow (&permanent_obstack, &XEXP (value.base, 0),
-                         sizeof (rtx));
-           break;
-         default:
-           abort ();
-         }
-      }
-      return;
-
-    case PLUS_EXPR:
-    case MINUS_EXPR:
-    case RANGE_EXPR:
-      record_constant_1 (TREE_OPERAND (exp, 0));
-      record_constant_1 (TREE_OPERAND (exp, 1));
-      return;
-
-    case NOP_EXPR:
-    case CONVERT_EXPR:
-    case NON_LVALUE_EXPR:
-      record_constant_1 (TREE_OPERAND (exp, 0));
-      return;
-
-    default:
-      {
-       tree new = (*lang_hooks.expand_constant) (exp);
-
-       if (new != exp)
-         record_constant_1 (new);
-       return;
-      }
-    }
-
-  /* Record constant contents.  */
-  obstack_grow (&permanent_obstack, strp, len);
+  /* Should not get here.  */
+  abort ();
 }
 \f
-/* Record a list of constant expressions that were passed to
-   output_constant_def but that could not be output right away.  */
-
-struct deferred_constant
-{
-  struct deferred_constant *next;
-  tree exp;
-  int reloc;
-  int labelno;
-};
-
-static struct deferred_constant *deferred_constants;
-
-/* Another list of constants which should be output after the
-   function.  */
-static struct deferred_constant *after_function_constants;
-
-/* Nonzero means defer output of addressed subconstants
-   (i.e., those for which output_constant_def is called.)  */
-static int defer_addressed_constants_flag;
-
-/* Start deferring output of subconstants.  */
-
-void
-defer_addressed_constants ()
-{
-  defer_addressed_constants_flag++;
-}
-
-/* Stop deferring output of subconstants,
-   and output now all those that have been deferred.  */
-
-void
-output_deferred_addressed_constants ()
-{
-  struct deferred_constant *p, *next;
-
-  defer_addressed_constants_flag--;
-
-  if (defer_addressed_constants_flag > 0)
-    return;
-
-  for (p = deferred_constants; p; p = next)
-    {
-      output_constant_def_contents (p->exp, p->reloc, p->labelno);
-      next = p->next;
-      free (p);
-    }
-
-  deferred_constants = 0;
-}
-
-/* Output any constants which should appear after a function.  */
-
-static void
-output_after_function_constants ()
-{
-  struct deferred_constant *p, *next;
-
-  for (p = after_function_constants; p; p = next)
-    {
-      output_constant_def_contents (p->exp, p->reloc, p->labelno);
-      next = p->next;
-      free (p);
-    }
-
-  after_function_constants = 0;
-}
-
-/* Make a copy of the whole tree structure for a constant.
-   This handles the same types of nodes that compare_constant
-   and record_constant handle.  */
+/* Make a copy of the whole tree structure for a constant.  This
+   handles the same types of nodes that compare_constant handles.  */
 
 static tree
-copy_constant (exp)
-     tree exp;
+copy_constant (tree exp)
 {
   switch (TREE_CODE (exp))
     {
@@ -2978,6 +2396,7 @@ copy_constant (exp)
     case NOP_EXPR:
     case CONVERT_EXPR:
     case NON_LVALUE_EXPR:
+    case VIEW_CONVERT_EXPR:
       return build1 (TREE_CODE (exp), TREE_TYPE (exp),
                     copy_constant (TREE_OPERAND (exp, 0)));
 
@@ -2998,208 +2417,155 @@ copy_constant (exp)
       }
 
     default:
-      abort ();
+      {
+       tree t;
+       t = (*lang_hooks.expand_constant) (exp);
+       if (t != exp)
+         return copy_constant (t);
+       else
+         abort ();
+      }
     }
 }
 \f
+/* Subroutine of output_constant_def:
+   No constant equal to EXP is known to have been output.
+   Make a constant descriptor to enter EXP in the hash table.
+   Assign the label number and construct RTL to refer to the
+   constant's location in memory.
+   Caller is responsible for updating the hash table.  */
+
+static struct constant_descriptor_tree *
+build_constant_desc (tree exp)
+{
+  rtx symbol;
+  rtx rtl;
+  char label[256];
+  int labelno;
+  struct constant_descriptor_tree *desc;
+
+  desc = ggc_alloc (sizeof (*desc));
+  desc->value = copy_constant (exp);
+
+  /* Create a string containing the label name, in LABEL.  */
+  labelno = const_labelno++;
+  ASM_GENERATE_INTERNAL_LABEL (label, "LC", labelno);
+
+  /* We have a symbol name; construct the SYMBOL_REF and the MEM.  */
+  symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label));
+  SYMBOL_REF_FLAGS (symbol) = SYMBOL_FLAG_LOCAL;
+  SYMBOL_REF_DECL (symbol) = desc->value;
+  TREE_CONSTANT_POOL_ADDRESS_P (symbol) = 1;
+
+  rtl = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)), symbol);
+  set_mem_attributes (rtl, exp, 1);
+  set_mem_alias_set (rtl, 0);
+  set_mem_alias_set (rtl, const_alias_set);
+
+  /* Set flags or add text to the name to record information, such as
+     that it is a local symbol.  If the name is changed, the macro
+     ASM_OUTPUT_LABELREF will have to know how to strip this
+     information.  This call might invalidate our local variable
+     SYMBOL; we can't use it afterward.  */
+
+  (*targetm.encode_section_info) (exp, rtl, true);
+
+  desc->rtl = rtl;
+
+  return desc;
+}
+
 /* Return an rtx representing a reference to constant data in memory
    for the constant expression EXP.
 
    If assembler code for such a constant has already been output,
    return an rtx to refer to it.
-   Otherwise, output such a constant in memory (or defer it for later)
+   Otherwise, output such a constant in memory
    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.
+   If DEFER is nonzero, this constant 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, defer)
-     tree exp;
-     int defer;
+output_constant_def (tree exp, int defer)
 {
-  int hash;
-  struct constant_descriptor *desc;
-  struct deferred_string **defstr;
-  char label[256];
-  int reloc;
-  int found = 1;
-  int after_function = 0;
-  int labelno = -1;
-  rtx rtl;
-
-  /* We can't just use the saved RTL if this is a defererred string constant
-     and we are not to defer anymore.  */
-  if (TREE_CODE (exp) != INTEGER_CST && TREE_CST_RTL (exp)
-      && (defer || !STRING_POOL_ADDRESS_P (XEXP (TREE_CST_RTL (exp), 0))))
-    return TREE_CST_RTL (exp);
-
-  /* Make sure any other constants whose addresses appear in EXP
-     are assigned label numbers.  */
-
-  reloc = output_addressed_constants (exp);
+  struct constant_descriptor_tree *desc;
+  struct constant_descriptor_tree key;
+  void **loc;
 
-  /* Compute hash code of EXP.  Search the descriptors for that hash code
-     to see if any of them describes EXP.  If yes, the descriptor records
-     the label number already assigned.  */
-
-  hash = const_hash (exp) % MAX_HASH_TABLE;
-
-  for (desc = const_hash_table[hash]; desc; desc = desc->next)
-    if (compare_constant (exp, desc))
-      break;
+  /* Look up EXP in the table of constant descriptors.  If we didn't find
+     it, create a new one.  */
+  key.value = exp;
+  loc = htab_find_slot (const_desc_htab, &key, INSERT);
 
+  desc = *loc;
   if (desc == 0)
     {
-      /* No constant equal to EXP is known to have been output.
-        Make a constant descriptor to enter EXP in the hash table.
-        Assign the label number and record it in the descriptor for
-        future calls to this function to find.  */
-
-      /* Create a string containing the label name, in LABEL.  */
-      labelno = const_labelno++;
-      ASM_GENERATE_INTERNAL_LABEL (label, "LC", labelno);
-
-      desc = record_constant (exp);
-      desc->next = const_hash_table[hash];
-      desc->label = ggc_strdup (label);
-      const_hash_table[hash] = desc;
-
-      /* We have a symbol name; construct the SYMBOL_REF and the MEM.  */
-      rtl = desc->rtl
-       = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)),
-                      gen_rtx_SYMBOL_REF (Pmode, desc->label));
-
-      set_mem_attributes (rtl, exp, 1);
-      set_mem_alias_set (rtl, 0);
-      set_mem_alias_set (rtl, const_alias_set);
-
-      found = 0;
+      desc = build_constant_desc (exp);
+      *loc = desc;
     }
-  else
-    rtl = desc->rtl;
-
-  if (TREE_CODE (exp) != INTEGER_CST)
-    TREE_CST_RTL (exp) = rtl;
 
-  /* 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.  */
-  /* A previously-processed constant would already have section info
-     encoded in it.  */
-  if (! found)
-    {
-      /* Take care not to invoke targetm.encode_section_info for
-        constants which don't have a TREE_CST_RTL.  */
-      if (TREE_CODE (exp) != INTEGER_CST)
-       (*targetm.encode_section_info) (exp, true);
+  maybe_output_constant_def_contents (desc, defer);
+  return desc->rtl;
+}
 
-      desc->rtl = rtl;
-      desc->label = XSTR (XEXP (desc->rtl, 0), 0);
-    }
+/* Subroutine of output_constant_def: Decide whether or not we need to
+   output the constant DESC now, and if so, do it.  */
+static void
+maybe_output_constant_def_contents (struct constant_descriptor_tree *desc,
+                                   int defer)
+{
+  rtx symbol = XEXP (desc->rtl, 0);
+  tree exp = desc->value;
 
-#ifdef CONSTANT_AFTER_FUNCTION_P
-  if (current_function_decl != 0
-      && CONSTANT_AFTER_FUNCTION_P (exp))
-    after_function = 1;
-#endif
+  if (flag_syntax_only)
+    return;
 
-  if (found
-      && STRING_POOL_ADDRESS_P (XEXP (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 (rtl, 0)) = 0;
-         htab_clear_slot (const_str_htab, (void **) defstr);
-       }
-    }
+  if (TREE_ASM_WRITTEN (exp))
+    /* Already output; don't do it again.  */
+    return;
 
-  /* If this is the first time we've seen this particular constant,
-     output it (or defer its output for later).  */
-  if (! found)
+  /* The only constants that cannot safely be deferred, assuming the
+     context allows it, are strings under flag_writable_strings.  */
+  if (defer && (TREE_CODE (exp) != STRING_CST || !flag_writable_strings))
     {
-      if (defer_addressed_constants_flag || after_function)
-       {
-         struct deferred_constant *p
-           = (struct deferred_constant *)
-             xmalloc (sizeof (struct deferred_constant));
-
-         p->exp = copy_constant (exp);
-         p->reloc = reloc;
-         p->labelno = labelno;
-         if (after_function)
-           {
-             p->next = after_function_constants;
-             after_function_constants = p;
-           }
-         else
-           {
-             p->next = deferred_constants;
-             deferred_constants = p;
-           }
-       }
-      else
-       {
-         /* Do no output if -fsyntax-only.  */
-         if (! flag_syntax_only)
-           {
-             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 (rtl, 0)) = 1;
-               }
-           }
-       }
+      /* Increment n_deferred_constants if it exists.  It needs to be at
+        least as large as the number of constants actually referred to
+        by the function.  If it's too small we'll stop looking too early
+        and fail to emit constants; if it's too large we'll only look
+        through the entire function when we could have stopped earlier.  */
+      if (cfun)
+       n_deferred_constants++;
+      return;
     }
 
-  return rtl;
+  output_constant_def_contents (symbol);
 }
 
-/* Now output assembler code to define the label for EXP,
-   and follow it with the data of EXP.  */
+/* We must output the constant data referred to by SYMBOL; do so.  */
 
 static void
-output_constant_def_contents (exp, reloc, labelno)
-     tree exp;
-     int reloc;
-     int labelno;
+output_constant_def_contents (rtx symbol)
 {
-  int align;
+  tree exp = SYMBOL_REF_DECL (symbol);
+  const char *label = XSTR (symbol, 0);
+  HOST_WIDE_INT size;
+
+  /* Make sure any other constants whose addresses appear in EXP
+     are assigned label numbers.  */
+  int reloc = output_addressed_constants (exp);
 
   /* Align the location counter as required by EXP's data type.  */
-  align = TYPE_ALIGN (TREE_TYPE (exp));
+  int align = TYPE_ALIGN (TREE_TYPE (exp));
 #ifdef CONSTANT_ALIGNMENT
   align = CONSTANT_ALIGNMENT (exp, align);
 #endif
 
+  /* We are no longer deferring this constant.  */
+  TREE_ASM_WRITTEN (exp) = 1;
+
   if (IN_NAMED_SECTION (exp))
     named_section (exp, NULL, reloc);
   else
@@ -3210,28 +2576,73 @@ output_constant_def_contents (exp, reloc, labelno)
       ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
     }
 
-  /* Output the label itself.  */
-  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LC", labelno);
+  size = int_size_in_bytes (TREE_TYPE (exp));
+  if (TREE_CODE (exp) == STRING_CST)
+    size = MAX (TREE_STRING_LENGTH (exp), size);
+
+  /* Do any machine/system dependent processing of the constant.  */
+#ifdef ASM_DECLARE_CONSTANT_NAME
+  ASM_DECLARE_CONSTANT_NAME (asm_out_file, label, exp, size);
+#else
+  /* Standard thing is just output label for the constant.  */
+  ASM_OUTPUT_LABEL (asm_out_file, label);
+#endif /* ASM_DECLARE_CONSTANT_NAME */
 
   /* Output the value of EXP.  */
-  output_constant (exp,
-                  (TREE_CODE (exp) == STRING_CST
-                   ? MAX (TREE_STRING_LENGTH (exp),
-                          int_size_in_bytes (TREE_TYPE (exp)))
-                   : int_size_in_bytes (TREE_TYPE (exp))),
-                  align);
+  output_constant (exp, size, align);
+}
+
+/* A constant which was deferred in its original location has been
+   inserted by the RTL inliner into a different function.  The
+   current function's deferred constant count must be incremented.  */
+void
+notice_rtl_inlining_of_deferred_constant (void)
+{
+  n_deferred_constants++;
+}
+
+/* Look up EXP in the table of constant descriptors.  Return the rtl
+   if it has been emitted, else null.  */
+
+rtx
+lookup_constant_def (tree exp)
+{
+  struct constant_descriptor_tree *desc;
+  struct constant_descriptor_tree key;
 
+  key.value = exp;
+  desc = htab_find (const_desc_htab, &key);
+
+  return (desc ? desc->rtl : NULL_RTX);
 }
 \f
+/* Used in the hash tables to avoid outputting the same constant
+   twice.  Unlike 'struct constant_descriptor_tree', RTX constants
+   are output once per function, not once per file; there seems
+   to be no reason for the difference.  */
+
+struct constant_descriptor_rtx GTY(())
+{
+  /* More constant_descriptors with the same hash code.  */
+  struct constant_descriptor_rtx *next;
+
+  /* A MEM for the constant.  */
+  rtx rtl;
+
+  /* The value of the constant.  */
+  struct rtx_const value;
+};
+
 /* Structure to represent sufficient information about a constant so that
    it can be output when the constant pool is output, so that function
    integration can be done, and to simplify handling on machines that reference
    constant pool as base+displacement.  */
 
-struct pool_constant
+struct pool_constant GTY(())
 {
-  struct constant_descriptor *desc;
-  struct pool_constant *next, *next_sym;
+  struct constant_descriptor_rtx *desc;
+  struct pool_constant *next;
+  struct pool_constant *next_sym;
   rtx constant;
   enum machine_mode mode;
   int labelno;
@@ -3243,89 +2654,26 @@ struct pool_constant
 /* Hash code for a SYMBOL_REF with CONSTANT_POOL_ADDRESS_P true.
    The argument is XSTR (... , 0)  */
 
-#define SYMHASH(LABEL) \
-  ((((unsigned long) (LABEL)) & ((1 << HASHBITS) - 1))  % MAX_RTX_HASH_TABLE)
+#define SYMHASH(LABEL) (((unsigned long) (LABEL)) % MAX_RTX_HASH_TABLE)
 \f
 /* Initialize constant pool hashing for a new function.  */
 
 void
-init_varasm_status (f)
-     struct function *f;
+init_varasm_status (struct function *f)
 {
   struct varasm_status *p;
-  p = (struct varasm_status *) xmalloc (sizeof (struct varasm_status));
+  p = ggc_alloc (sizeof (struct varasm_status));
   f->varasm = p;
   p->x_const_rtx_hash_table
-    = ((struct constant_descriptor **)
-       xcalloc (MAX_RTX_HASH_TABLE, sizeof (struct constant_descriptor *)));
+    = ggc_alloc_cleared (MAX_RTX_HASH_TABLE
+                        * sizeof (struct constant_descriptor_rtx *));
   p->x_const_rtx_sym_hash_table
-    = ((struct pool_constant **)
-       xcalloc (MAX_RTX_HASH_TABLE, sizeof (struct pool_constant *)));
+    = ggc_alloc_cleared (MAX_RTX_HASH_TABLE
+                        * sizeof (struct pool_constant *));
 
   p->x_first_pool = p->x_last_pool = 0;
   p->x_pool_offset = 0;
-}
-
-/* Mark PC for GC.  */
-
-static void
-mark_pool_constant (pc)
-     struct pool_constant *pc;
-{
-  while (pc)
-    {
-      ggc_mark (pc);
-      ggc_mark_rtx (pc->constant);
-      ggc_mark_rtx (pc->desc->rtl);
-      pc = pc->next;
-    }
-}
-
-/* Mark P for GC.  */
-
-void
-mark_varasm_status (p)
-     struct varasm_status *p;
-{
-  if (p == NULL)
-    return;
-
-  mark_pool_constant (p->x_first_pool);
-}
-
-/* Clear out all parts of the state in F that can safely be discarded
-   after the function has been compiled, to let garbage collection
-   reclaim the memory.  */
-
-void
-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;
+  p->deferred_constants = 0;
 }
 \f
 
@@ -3334,10 +2682,7 @@ free_varasm_status (f)
    They are stored into VALUE.  */
 
 static void
-decode_rtx_const (mode, x, value)
-     enum machine_mode mode;
-     rtx x;
-     struct rtx_const *value;
+decode_rtx_const (enum machine_mode mode, rtx x, struct rtx_const *value)
 {
   /* Clear the whole structure, including any gaps.  */
   memset (value, 0, sizeof (struct rtx_const));
@@ -3351,8 +2696,29 @@ decode_rtx_const (mode, x, value)
       value->kind = RTX_DOUBLE;
       if (GET_MODE (x) != VOIDmode)
        {
+         const REAL_VALUE_TYPE *r = CONST_DOUBLE_REAL_VALUE (x);
+
          value->mode = GET_MODE (x);
-         REAL_VALUE_FROM_CONST_DOUBLE (value->un.du, x);
+
+         /* Copy the REAL_VALUE_TYPE by members so that we don't
+            copy garbage from the original structure into our
+            carefully cleaned hashing structure.  */
+         value->un.du.class = r->class;
+         value->un.du.sign = r->sign;
+         switch (r->class)
+           {
+           case rvc_zero:
+           case rvc_inf:
+             break;
+           case rvc_normal:
+             value->un.du.exp = r->exp;
+             /* FALLTHRU */
+           case rvc_nan:
+             memcpy (value->un.du.sig, r->sig, sizeof (r->sig));
+             break;
+           default:
+             abort ();
+           }
        }
       else
        {
@@ -3364,28 +2730,59 @@ decode_rtx_const (mode, x, value)
     case CONST_VECTOR:
       {
        int units, i;
-       rtx elt;
 
        units = CONST_VECTOR_NUNITS (x);
        value->kind = RTX_VECTOR;
        value->mode = mode;
 
-       for (i = 0; i < units; ++i)
+       if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT)
          {
-           elt = CONST_VECTOR_ELT (x, i);
-           if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT)
+           for (i = 0; i < units; ++i)
              {
-               value->un.veclo[i] = (HOST_WIDE_INT) INTVAL (elt);
-               value->un.vechi[i] = 0;
+               rtx elt = CONST_VECTOR_ELT (x, i);
+               if (GET_CODE (elt) == CONST_INT)
+                 {
+                   value->un.int_vec[i].low = INTVAL (elt);
+                   value->un.int_vec[i].high = 0;
+                 }
+               else
+                 {
+                   value->un.int_vec[i].low = CONST_DOUBLE_LOW (elt);
+                   value->un.int_vec[i].high = CONST_DOUBLE_HIGH (elt);
+                 }
              }
-           else if (GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
+         }
+       else if (GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
+         {
+           for (i = 0; i < units; ++i)
              {
-               value->un.veclo[i] = (HOST_WIDE_INT) CONST_DOUBLE_LOW (elt);
-               value->un.vechi[i] = (HOST_WIDE_INT) CONST_DOUBLE_HIGH (elt);
+               const REAL_VALUE_TYPE *r
+                 = CONST_DOUBLE_REAL_VALUE (CONST_VECTOR_ELT (x, i));
+               REAL_VALUE_TYPE *d = &value->un.fp_vec[i];
+
+               /* Copy the REAL_VALUE_TYPE by members so that we don't
+                  copy garbage from the original structure into our
+                  carefully cleaned hashing structure.  */
+               d->class = r->class;
+               d->sign = r->sign;
+               switch (r->class)
+                 {
+                 case rvc_zero:
+                 case rvc_inf:
+                   break;
+                 case rvc_normal:
+                   d->exp = r->exp;
+                   /* FALLTHRU */
+                 case rvc_nan:
+                   memcpy (d->sig, r->sig, sizeof (r->sig));
+                   break;
+                 default:
+                   abort ();
+                 }
              }
-           else
-             abort ();
          }
+       else
+         abort ();
       }
       break;
 
@@ -3440,13 +2837,14 @@ decode_rtx_const (mode, x, value)
        }
     }
 
-  if (value->kind > RTX_DOUBLE && value->un.addr.base != 0)
+  if (value->kind >= RTX_INT && value->un.addr.base != 0)
     switch (GET_CODE (value->un.addr.base))
       {
       case SYMBOL_REF:
        /* Use the string's address, not the SYMBOL_REF's address,
           for the sake of addresses of library routines.  */
-       value->un.addr.base = (rtx) XSTR (value->un.addr.base, 0);
+       value->un.addr.symbol = XSTR (value->un.addr.base, 0);
+       value->un.addr.base = NULL_RTX;
        break;
 
       case LABEL_REF:
@@ -3462,17 +2860,17 @@ decode_rtx_const (mode, x, value)
    include the same symbol.  */
 
 rtx
-simplify_subtraction (x)
-     rtx x;
+simplify_subtraction (rtx x)
 {
   struct rtx_const val0, val1;
 
   decode_rtx_const (GET_MODE (x), XEXP (x, 0), &val0);
   decode_rtx_const (GET_MODE (x), XEXP (x, 1), &val1);
 
-  if (val0.kind > RTX_DOUBLE
+  if (val0.kind >= RTX_INT
       && val0.kind == val1.kind
-      && val0.un.addr.base == val1.un.addr.base)
+      && val0.un.addr.base == val1.un.addr.base
+      && val0.un.addr.symbol == val1.un.addr.symbol)
     return GEN_INT (val0.un.addr.offset - val1.un.addr.offset);
 
   return x;
@@ -3480,104 +2878,73 @@ simplify_subtraction (x)
 
 /* Compute a hash code for a constant RTL expression.  */
 
-static int
-const_hash_rtx (mode, x)
-     enum machine_mode mode;
-     rtx x;
+static unsigned int
+const_hash_rtx (enum machine_mode mode, rtx x)
 {
-  int hi;
+  union {
+    struct rtx_const value;
+    unsigned int data[sizeof(struct rtx_const) / sizeof (unsigned int)];
+  } u;
+
+  unsigned int hi;
   size_t i;
 
-  struct rtx_const value;
-  decode_rtx_const (mode, x, &value);
+  decode_rtx_const (mode, x, &u.value);
 
-  /* Compute hashing function */
+  /* Compute hashing function */
   hi = 0;
-  for (i = 0; i < sizeof value / sizeof (int); i++)
-    hi += ((int *) &value)[i];
+  for (i = 0; i < ARRAY_SIZE (u.data); i++)
+    hi = hi * 613 + u.data[i];
 
-  hi &= (1 << HASHBITS) - 1;
-  hi %= MAX_RTX_HASH_TABLE;
-  return hi;
+  return hi % MAX_RTX_HASH_TABLE;
 }
 
 /* Compare a constant rtl object X with a constant-descriptor DESC.
    Return 1 if DESC describes a constant with the same value as X.  */
 
 static int
-compare_constant_rtx (mode, x, desc)
-     enum machine_mode mode;
-     rtx x;
-     struct constant_descriptor *desc;
-{
-  int *p = (int *) desc->u.contents;
-  int *strp;
-  int len;
+compare_constant_rtx (enum machine_mode mode, rtx x,
+                     struct constant_descriptor_rtx *desc)
+{
   struct rtx_const value;
 
   decode_rtx_const (mode, x, &value);
-  strp = (int *) &value;
-  len = sizeof value / sizeof (int);
 
   /* Compare constant contents.  */
-  while (--len >= 0)
-    if (*p++ != *strp++)
-      return 0;
-
-  return 1;
+  return memcmp (&value, &desc->value, sizeof (struct rtx_const)) == 0;
 }
 
 /* Construct a constant descriptor for the rtl-expression X.
    It is up to the caller to enter the descriptor in the hash table.  */
 
-static struct constant_descriptor *
-record_constant_rtx (mode, x)
-     enum machine_mode mode;
-     rtx x;
+static struct constant_descriptor_rtx *
+record_constant_rtx (enum machine_mode mode, rtx x)
 {
-  struct constant_descriptor *ptr;
+  struct constant_descriptor_rtx *ptr;
 
-  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);
+  ptr = ggc_alloc (sizeof (*ptr));
+  decode_rtx_const (mode, x, &ptr->value);
 
   return ptr;
 }
 \f
-/* Given a constant rtx X, return a MEM for the location in memory at which
-   this constant has been placed.  Return 0 if it not has been placed yet.  */
-
-rtx
-mem_for_const_double (x)
-     rtx x;
-{
-  enum machine_mode mode = GET_MODE (x);
-  struct constant_descriptor *desc;
-
-  for (desc = const_rtx_hash_table[const_hash_rtx (mode, x)]; desc;
-       desc = desc->next)
-    if (compare_constant_rtx (mode, x, desc))
-      return desc->rtl;
-
-  return 0;
-}
-
 /* Given a constant rtx X, make (or find) a memory constant for its value
    and return a MEM rtx to refer to it in memory.  */
 
 rtx
-force_const_mem (mode, x)
-     enum machine_mode mode;
-     rtx x;
+force_const_mem (enum machine_mode mode, rtx x)
 {
   int hash;
-  struct constant_descriptor *desc;
+  struct constant_descriptor_rtx *desc;
   char label[256];
-  rtx def;
+  rtx def, symbol;
   struct pool_constant *pool;
   unsigned int align;
 
+  /* If we're not allowed to drop X into the constant pool, don't.  */
+  if ((*targetm.cannot_force_const_mem) (x))
+    return NULL_RTX;
+
   /* Compute hash code of X.  Search the descriptors for that hash code
      to see if any of them describes X.  If yes, we have an rtx to use.  */
   hash = const_hash_rtx (mode, x);
@@ -3595,8 +2962,11 @@ force_const_mem (mode, x)
   /* Align the location counter as required by EXP's data type.  */
   align = GET_MODE_ALIGNMENT (mode == VOIDmode ? word_mode : mode);
 #ifdef CONSTANT_ALIGNMENT
-  align = CONSTANT_ALIGNMENT (make_tree ((*lang_hooks.types.type_for_mode)
-                                        (mode, 0), x), align);
+  {
+    tree type = (*lang_hooks.types.type_for_mode) (mode, 0);
+    if (type != NULL_TREE)
+      align = CONSTANT_ALIGNMENT (make_tree (type, x), align);
+  }
 #endif
 
   pool_offset += (align / BITS_PER_UNIT) - 1;
@@ -3606,7 +2976,7 @@ force_const_mem (mode, x)
     LABEL_PRESERVE_P (XEXP (x, 0)) = 1;
 
   /* Allocate a pool constant descriptor, fill it in, and chain it in.  */
-  pool = (struct pool_constant *) ggc_alloc (sizeof (struct pool_constant));
+  pool = ggc_alloc (sizeof (struct pool_constant));
   pool->desc = desc;
   pool->constant = x;
   pool->mode = mode;
@@ -3631,19 +3001,21 @@ force_const_mem (mode, x)
 
   /* Construct the SYMBOL_REF and the MEM.  */
 
-  pool->desc->rtl = def
-    = gen_rtx_MEM (mode, gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label)));
-  set_mem_alias_set (def, const_alias_set);
+  symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label));
+  SYMBOL_REF_FLAGS (symbol) = SYMBOL_FLAG_LOCAL;
+
+  pool->desc->rtl = def = gen_rtx_MEM (mode, symbol);
   set_mem_attributes (def, (*lang_hooks.types.type_for_mode) (mode, 0), 1);
   RTX_UNCHANGING_P (def) = 1;
 
   /* Add label to symbol hash table.  */
-  hash = SYMHASH (XSTR (XEXP (def, 0), 0));
+  hash = SYMHASH (XSTR (symbol, 0));
   pool->next_sym = const_rtx_sym_hash_table[hash];
   const_rtx_sym_hash_table[hash] = pool;
 
   /* Mark the symbol_ref as belonging to this constants pool.  */
-  CONSTANT_POOL_ADDRESS_P (XEXP (def, 0)) = 1;
+  CONSTANT_POOL_ADDRESS_P (symbol) = 1;
+  SYMBOL_REF_FLAGS (symbol) = SYMBOL_FLAG_LOCAL;
   current_function_uses_const_pool = 1;
 
   return def;
@@ -3653,9 +3025,7 @@ force_const_mem (mode, x)
    the corresponding pool_constant structure.  */
 
 static struct pool_constant *
-find_pool_constant (f, addr)
-     struct function *f;
-     rtx addr;
+find_pool_constant (struct function *f, rtx addr)
 {
   struct pool_constant *pool;
   const char *label = XSTR (addr, 0);
@@ -3671,8 +3041,7 @@ find_pool_constant (f, addr)
 /* Given a constant pool SYMBOL_REF, return the corresponding constant.  */
 
 rtx
-get_pool_constant (addr)
-     rtx addr;
+get_pool_constant (rtx addr)
 {
   return (find_pool_constant (cfun, addr))->constant;
 }
@@ -3681,9 +3050,7 @@ get_pool_constant (addr)
    and whether it has been output or not.  */
 
 rtx
-get_pool_constant_mark (addr, pmarked)
-     rtx addr;
-     bool *pmarked;
+get_pool_constant_mark (rtx addr, bool *pmarked)
 {
   struct pool_constant *pool = find_pool_constant (cfun, addr);
   *pmarked = (pool->mark != 0);
@@ -3693,9 +3060,7 @@ get_pool_constant_mark (addr, pmarked)
 /* Likewise, but for the constant pool of a specific function.  */
 
 rtx
-get_pool_constant_for_function (f, addr)
-     struct function *f;
-     rtx addr;
+get_pool_constant_for_function (struct function *f, rtx addr)
 {
   return (find_pool_constant (f, addr))->constant;
 }
@@ -3703,16 +3068,13 @@ get_pool_constant_for_function (f, addr)
 /* Similar, return the mode.  */
 
 enum machine_mode
-get_pool_mode (addr)
-     rtx addr;
+get_pool_mode (rtx addr)
 {
   return (find_pool_constant (cfun, addr))->mode;
 }
 
 enum machine_mode
-get_pool_mode_for_function (f, addr)
-     struct function *f;
-     rtx addr;
+get_pool_mode_for_function (struct function *f, rtx addr)
 {
   return (find_pool_constant (f, addr))->mode;
 }
@@ -3720,8 +3082,7 @@ get_pool_mode_for_function (f, addr)
 /* Similar, return the offset in the constant pool.  */
 
 int
-get_pool_offset (addr)
-     rtx addr;
+get_pool_offset (rtx addr)
 {
   return (find_pool_constant (cfun, addr))->offset;
 }
@@ -3729,7 +3090,7 @@ get_pool_offset (addr)
 /* Return the size of the constant pool.  */
 
 int
-get_pool_size ()
+get_pool_size (void)
 {
   return pool_offset;
 }
@@ -3737,9 +3098,8 @@ get_pool_size ()
 /* Write all the constants in the constant pool.  */
 
 void
-output_constant_pool (fnname, fndecl)
-     const char *fnname ATTRIBUTE_UNUSED;
-     tree fndecl ATTRIBUTE_UNUSED;
+output_constant_pool (const char *fnname ATTRIBUTE_UNUSED,
+                     tree fndecl ATTRIBUTE_UNUSED)
 {
   struct pool_constant *pool;
   rtx x;
@@ -3808,7 +3168,7 @@ output_constant_pool (fnname, fndecl)
       assemble_align (pool->align);
 
       /* Output the label.  */
-      ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LC", pool->labelno);
+      (*targetm.asm_out.internal_label) (asm_out_file, "LC", pool->labelno);
 
       /* Output the value of the constant itself.  */
       switch (GET_MODE_CLASS (pool->mode))
@@ -3868,6 +3228,13 @@ output_constant_pool (fnname, fndecl)
          abort ();
        }
 
+      /* Make sure all constants in SECTION_MERGE and not SECTION_STRINGS
+        sections have proper size.  */
+      if (pool->align > GET_MODE_BITSIZE (pool->mode)
+         && in_section == in_named
+         && get_named_section_flags (in_named_name) & SECTION_MERGE)
+       assemble_align (pool->align);
+
 #ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
     done: ;
 #endif
@@ -3882,16 +3249,17 @@ 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.
-   Emit used deferred strings.  */
+   entries in the constant pool which are actually being used.  Emit
+   deferred constants which have indeed been used.  */
 
 static void
-mark_constant_pool ()
+mark_constant_pool (void)
 {
   rtx insn;
+  rtx link;
   struct pool_constant *pool;
 
-  if (first_pool == 0 && htab_elements (const_str_htab) == 0)
+  if (first_pool == 0 && n_deferred_constants == 0)
     return;
 
   for (pool = first_pool; pool; pool = pool->next)
@@ -3901,11 +3269,15 @@ mark_constant_pool ()
     if (INSN_P (insn))
       mark_constants (PATTERN (insn));
 
-  for (insn = current_function_epilogue_delay_list;
-       insn;
-       insn = XEXP (insn, 1))
-    if (INSN_P (insn))
-      mark_constants (PATTERN (insn));
+  for (link = current_function_epilogue_delay_list;
+       link;
+       link = XEXP (link, 1))
+    {
+      insn = XEXP (link, 0);
+
+      if (INSN_P (insn))
+       mark_constants (PATTERN (insn));
+    }
 }
 
 /* Look through appropriate parts of X, marking all entries in the
@@ -3914,8 +3286,7 @@ mark_constant_pool ()
    deferred strings that are used.  */
 
 static void
-mark_constants (x)
-     rtx x;
+mark_constants (rtx x)
 {
   int i;
   const char *format_ptr;
@@ -3965,6 +3336,7 @@ mark_constants (x)
        case 'w':
        case 'n':
        case 'u':
+       case 'B':
          break;
 
        default:
@@ -3978,9 +3350,7 @@ mark_constants (x)
    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;
+mark_constant (rtx *current_rtx, void *data ATTRIBUTE_UNUSED)
 {
   rtx x = *current_rtx;
 
@@ -4000,20 +3370,13 @@ mark_constant (current_rtx, data)
          else
            return -1;
        }
-      else if (STRING_POOL_ADDRESS_P (x))
+      else if (TREE_CONSTANT_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)
+         tree exp = SYMBOL_REF_DECL (x);
+         if (!TREE_ASM_WRITTEN (exp))
            {
-             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);
+             n_deferred_constants--;
+             output_constant_def_contents (x);
            }
        }
     }
@@ -4025,10 +3388,9 @@ mark_constant (current_rtx, data)
    Indicate whether an ADDR_EXPR has been encountered.  */
 
 static int
-output_addressed_constants (exp)
-     tree exp;
+output_addressed_constants (tree exp)
 {
-  int reloc = 0;
+  int reloc = 0, reloc2;
   tree tem;
 
   /* Give the front-end a chance to convert VALUE to something that
@@ -4038,6 +3400,7 @@ output_addressed_constants (exp)
   switch (TREE_CODE (exp))
     {
     case ADDR_EXPR:
+    case FDESC_EXPR:
       /* Go inside any operations that get_inner_reference can handle and see
         if what's inside is a constant: no need to do anything here for
         addresses of variables or functions.  */
@@ -4046,8 +3409,8 @@ output_addressed_constants (exp)
        ;
 
       if (TREE_CODE_CLASS (TREE_CODE (tem)) == 'c'
-           || TREE_CODE (tem) == CONSTRUCTOR)
-         output_constant_def (tem, 0);
+         || TREE_CODE (tem) == CONSTRUCTOR)
+       output_constant_def (tem, 0);
 
       if (TREE_PUBLIC (tem))
        reloc |= 2;
@@ -4056,11 +3419,20 @@ output_addressed_constants (exp)
       break;
 
     case PLUS_EXPR:
-    case MINUS_EXPR:
       reloc = output_addressed_constants (TREE_OPERAND (exp, 0));
       reloc |= output_addressed_constants (TREE_OPERAND (exp, 1));
       break;
 
+    case MINUS_EXPR:
+      reloc = output_addressed_constants (TREE_OPERAND (exp, 0));
+      reloc2 = output_addressed_constants (TREE_OPERAND (exp, 1));
+      /* The difference of two local labels is computable at link time.  */
+      if (reloc == 1 && reloc2 == 1)
+       reloc = 0;
+      else
+       reloc |= reloc2;
+      break;
+
     case NOP_EXPR:
     case CONVERT_EXPR:
     case NON_LVALUE_EXPR:
@@ -4091,9 +3463,7 @@ output_addressed_constants (exp)
    arithmetic-combinations of integers.  */
 
 tree
-initializer_constant_valid_p (value, endtype)
-     tree value;
-     tree endtype;
+initializer_constant_valid_p (tree value, tree endtype)
 {
   /* Give the front-end a chance to convert VALUE to something that
      looks more like a constant to the back-end.  */
@@ -4106,11 +3476,27 @@ initializer_constant_valid_p (value, endtype)
           || TREE_CODE (TREE_TYPE (value)) == RECORD_TYPE)
          && TREE_CONSTANT (value)
          && CONSTRUCTOR_ELTS (value))
-       return
-         initializer_constant_valid_p (TREE_VALUE (CONSTRUCTOR_ELTS (value)),
-                                       endtype);
+       {
+         tree elt;
+         bool absolute = true;
+
+         for (elt = CONSTRUCTOR_ELTS (value); elt; elt = TREE_CHAIN (elt))
+           {
+             tree reloc;
+             value = TREE_VALUE (elt);
+             reloc = initializer_constant_valid_p (value, TREE_TYPE (value));
+             if (!reloc)
+               return NULL_TREE;
+             if (reloc != null_pointer_node)
+               absolute = false;
+           }
+         /* For a non-absolute relocation, there is no single
+            variable that can be "the variable that determines the
+            relocation."  */
+         return absolute ? null_pointer_node : error_mark_node;
+       }
 
-      return TREE_STATIC (value) ? null_pointer_node : 0;
+      return TREE_STATIC (value) ? null_pointer_node : NULL_TREE;
 
     case INTEGER_CST:
     case VECTOR_CST:
@@ -4234,7 +3620,7 @@ initializer_constant_valid_p (value, endtype)
          op1 = TREE_OPERAND (value, 1);
 
          /* Like STRIP_NOPS except allow the operand mode to widen.
-            This works around a feature of fold that simplfies
+            This works around a feature of fold that simplifies
             (int)(p1 - p2) to ((int)p1 - (int)p2) under the theory
             that the narrower operation is cheaper.  */
 
@@ -4300,15 +3686,12 @@ initializer_constant_valid_p (value, endtype)
    ALIGN is the alignment of the data in bits.  */
 
 void
-output_constant (exp, size, align)
-     tree exp;
-     HOST_WIDE_INT size;
-     unsigned int align;
+output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align)
 {
   enum tree_code code;
-  HOST_WIDE_INT thissize;
+  unsigned HOST_WIDE_INT thissize;
 
-  /* Some front-ends use constants other than the standard language-indepdent
+  /* Some front-ends use constants other than the standard language-independent
      varieties, but which may still be output directly.  Give the front-end a
      chance to convert EXP to a language-independent representation.  */
   exp = (*lang_hooks.expand_constant) (exp);
@@ -4356,6 +3739,7 @@ output_constant (exp, size, align)
     case ENUMERAL_TYPE:
     case POINTER_TYPE:
     case REFERENCE_TYPE:
+    case OFFSET_TYPE:
       if (! assemble_integer (expand_expr (exp, NULL_RTX, VOIDmode,
                                           EXPAND_INITIALIZER),
                              size, align, 0))
@@ -4386,9 +3770,27 @@ output_constant (exp, size, align)
        }
       else if (TREE_CODE (exp) == STRING_CST)
        {
-         thissize = MIN (TREE_STRING_LENGTH (exp), size);
+         thissize = MIN ((unsigned HOST_WIDE_INT)TREE_STRING_LENGTH (exp),
+                         size);
          assemble_string (TREE_STRING_POINTER (exp), thissize);
        }
+      else if (TREE_CODE (exp) == VECTOR_CST)
+       {
+         int elt_size;
+         tree link;
+         unsigned int nalign;
+         enum machine_mode inner;
+
+         inner = GET_MODE_INNER (TYPE_MODE (TREE_TYPE (exp)));
+         nalign = MIN (align, GET_MODE_ALIGNMENT (inner));
+
+         elt_size = GET_MODE_UNIT_SIZE (TYPE_MODE (TREE_TYPE (exp)));
+
+         link = TREE_VECTOR_CST_ELTS (exp);
+         output_constant (TREE_VALUE (link), elt_size, align);
+         while ((link = TREE_CHAIN (link)) != NULL)
+           output_constant (TREE_VALUE (link), elt_size, nalign);
+       }
       else
        abort ();
       break;
@@ -4408,7 +3810,7 @@ output_constant (exp, size, align)
                          thissize, align, 1);
       else if (TREE_CODE (exp) == CONSTRUCTOR)
        {
-         unsigned char *buffer = (unsigned char *) alloca (thissize);
+         unsigned char *buffer = alloca (thissize);
          if (get_set_constructor_bytes (exp, buffer, thissize))
            abort ();
          assemble_string ((char *) buffer, thissize);
@@ -4424,9 +3826,8 @@ output_constant (exp, size, align)
       abort ();
     }
 
-  size -= thissize;
-  if (size > 0)
-    assemble_zeros (size);
+  if (size > thissize)
+    assemble_zeros (size - thissize);
 }
 
 \f
@@ -4435,8 +3836,7 @@ output_constant (exp, size, align)
    type with an unspecified upper bound.  */
 
 static unsigned HOST_WIDE_INT
-array_size_for_constructor (val)
-     tree val;
+array_size_for_constructor (tree val)
 {
   tree max_index, i;
 
@@ -4476,10 +3876,8 @@ array_size_for_constructor (val)
    Generate at least SIZE bytes, padding if necessary.  */
 
 static void
-output_constructor (exp, size, align)
-     tree exp;
-     HOST_WIDE_INT size;
-     unsigned int align;
+output_constructor (tree exp, unsigned HOST_WIDE_INT size,
+                   unsigned int align)
 {
   tree type = TREE_TYPE (exp);
   tree link, field = 0;
@@ -4487,7 +3885,7 @@ output_constructor (exp, size, align)
   /* Number of bytes output or skipped so far.
      In other words, current position within the constructor.  */
   HOST_WIDE_INT total_bytes = 0;
-  /* Non-zero means BYTE contains part of a byte, to be output.  */
+  /* Nonzero means BYTE contains part of a byte, to be output.  */
   int byte_buffer_in_use = 0;
   int byte = 0;
 
@@ -4774,19 +4172,18 @@ output_constructor (exp, size, align)
       total_bytes++;
     }
 
-  if (total_bytes < size)
+  if ((unsigned HOST_WIDE_INT)total_bytes < size)
     assemble_zeros (size - total_bytes);
 }
 
 /* This TREE_LIST contains any weak symbol declarations waiting
    to be emitted.  */
-static tree weak_decls;
+static GTY(()) tree weak_decls;
 
 /* Mark DECL as weak.  */
 
 static void
-mark_weak (decl)
-     tree decl;
+mark_weak (tree decl)
 {
   DECL_WEAK (decl) = 1;
 
@@ -4796,13 +4193,11 @@ mark_weak (decl)
       && GET_CODE (XEXP (DECL_RTL (decl), 0)) == SYMBOL_REF)
     SYMBOL_REF_WEAK (XEXP (DECL_RTL (decl), 0)) = 1;
 }
+
 /* Merge weak status between NEWDECL and OLDDECL.  */
 
 void
-merge_weak (newdecl, olddecl)
-     tree newdecl;
-     tree olddecl;
+merge_weak (tree newdecl, tree olddecl)
 {
   if (DECL_WEAK (newdecl) == DECL_WEAK (olddecl))
     return;
@@ -4810,7 +4205,7 @@ merge_weak (newdecl, olddecl)
   if (DECL_WEAK (newdecl))
     {
       tree wd;
-      
+
       /* NEWDECL is weak, but OLDDECL is not.  */
 
       /* If we already output the OLDDECL, we're in trouble; we can't
@@ -4818,15 +4213,17 @@ merge_weak (newdecl, olddecl)
         declare_weak because the NEWDECL and OLDDECL was not yet
         been merged; therefore, TREE_ASM_WRITTEN was not set.  */
       if (TREE_ASM_WRITTEN (olddecl))
-       error_with_decl (newdecl, 
-                        "weak declaration of `%s' must precede definition");
+       error ("%Hweak declaration of '%D' must precede definition",
+               &DECL_SOURCE_LOCATION (newdecl), newdecl);
 
       /* If we've already generated rtl referencing OLDDECL, we may
         have done so in a way that will not function properly with
         a weak symbol.  */
       else if (TREE_USED (olddecl)
               && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (olddecl)))
-       warning_with_decl (newdecl, "weak declaration of `%s' after first use results in unspecified behavior");
+       warning ("%Hweak declaration of '%D' after first use results "
+                 "in unspecified behavior",
+                 &DECL_SOURCE_LOCATION (newdecl), newdecl);
 
       if (SUPPORTS_WEAK)
        {
@@ -4856,20 +4253,22 @@ merge_weak (newdecl, olddecl)
 /* Declare DECL to be a weak symbol.  */
 
 void
-declare_weak (decl)
-     tree decl;
+declare_weak (tree decl)
 {
   if (! TREE_PUBLIC (decl))
-    error_with_decl (decl, "weak declaration of `%s' must be public");
+    error ("%Hweak declaration of '%D' must be public",
+           &DECL_SOURCE_LOCATION (decl), decl);
   else if (TREE_CODE (decl) == FUNCTION_DECL && TREE_ASM_WRITTEN (decl))
-    error_with_decl (decl, "weak declaration of `%s' must precede definition");
+    error ("%Hweak declaration of '%D' must precede definition",
+           &DECL_SOURCE_LOCATION (decl), decl);
   else if (SUPPORTS_WEAK)
     {
       if (! DECL_WEAK (decl))
        weak_decls = tree_cons (NULL, decl, weak_decls);
     }
   else
-    warning_with_decl (decl, "weak declaration of `%s' not supported");
+    warning ("%Hweak declaration of '%D' not supported",
+             &DECL_SOURCE_LOCATION (decl), decl);
 
   mark_weak (decl);
 }
@@ -4877,14 +4276,16 @@ declare_weak (decl)
 /* Emit any pending weak declarations.  */
 
 void
-weak_finish ()
+weak_finish (void)
 {
   tree t;
 
   for (t = weak_decls; t; t = TREE_CHAIN (t))
     {
       tree decl = TREE_VALUE (t);
-      const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+#if defined (ASM_WEAKEN_DECL) || defined (ASM_WEAKEN_LABEL)
+      const char *const name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+#endif
 
       if (! TREE_USED (decl))
        continue;
@@ -4907,8 +4308,7 @@ weak_finish ()
 /* Emit the assembly bits to indicate that DECL is globally visible.  */
 
 static void
-globalize_decl (decl)
-     tree decl;
+globalize_decl (tree decl)
 {
   const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
 
@@ -4936,15 +4336,14 @@ globalize_decl (decl)
     }
 #endif
 
-  ASM_GLOBALIZE_LABEL (asm_out_file, name);
+  (*targetm.asm_out.globalize_label) (asm_out_file, name);
 }
 
 /* Emit an assembler directive to make the symbol for DECL an alias to
    the symbol for TARGET.  */
 
 void
-assemble_alias (decl, target)
-     tree decl, target ATTRIBUTE_UNUSED;
+assemble_alias (tree decl, tree target ATTRIBUTE_UNUSED)
 {
   const char *name;
 
@@ -4989,19 +4388,24 @@ assemble_alias (decl, target)
 }
 
 /* Emit an assembler directive to set symbol for DECL visibility to
-   VISIBILITY_TYPE.  */
+   the visibility type VIS, which must not be VISIBILITY_DEFAULT.  */
 
 void
-assemble_visibility (decl, visibility_type)
-     tree decl;
-     const char *visibility_type ATTRIBUTE_UNUSED;
+default_assemble_visibility (tree decl, int vis)
 {
-  const char *name;
+  static const char * const visibility_types[] = {
+    NULL, "internal", "hidden", "protected"
+  };
 
-  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+  const char *name, *type;
+
+  name = (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
+  type = visibility_types[vis];
 
 #ifdef HAVE_GAS_HIDDEN
-  fprintf (asm_out_file, "\t.%s\t%s\n", visibility_type, name);
+  fprintf (asm_out_file, "\t.%s\t", type);
+  assemble_name (asm_out_file, name);
+  fprintf (asm_out_file, "\n");
 #else
   warning ("visibility attribute not supported in this configuration; ignored");
 #endif
@@ -5010,16 +4414,12 @@ assemble_visibility (decl, visibility_type)
 /* A helper function to call assemble_visibility when needed for a decl.  */
 
 static void
-maybe_assemble_visibility (decl)
-     tree decl;
+maybe_assemble_visibility (tree decl)
 {
-  tree visibility = lookup_attribute ("visibility", DECL_ATTRIBUTES (decl));
-  if (visibility)
-    {
-      const char *type
-       = TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (visibility)));
-      assemble_visibility (decl, type);
-    }
+  enum symbol_visibility vis = decl_visibility (decl);
+
+  if (vis != VISIBILITY_DEFAULT)
+    (* targetm.asm_out.visibility) (decl, vis);
 }
 
 /* Returns 1 if the target configuration supports defining public symbols
@@ -5028,7 +4428,7 @@ maybe_assemble_visibility (decl)
    a target-specific mechanism for having duplicates discarded.  */
 
 int
-supports_one_only ()
+supports_one_only (void)
 {
   if (SUPPORTS_ONE_ONLY)
     return 1;
@@ -5039,8 +4439,7 @@ supports_one_only ()
    translation units without generating a linker error.  */
 
 void
-make_decl_one_only (decl)
-     tree decl;
+make_decl_one_only (tree decl)
 {
   if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL)
     abort ();
@@ -5064,22 +4463,85 @@ make_decl_one_only (decl)
 }
 
 void
-init_varasm_once ()
+init_varasm_once (void)
 {
-  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_root (&const_str_htab, 1, sizeof const_str_htab,
-               mark_const_str_htab);
-  ggc_add_tree_root (&weak_decls, 1);
+  in_named_htab = htab_create_ggc (31, in_named_entry_hash,
+                                  in_named_entry_eq, NULL);
+  const_desc_htab = htab_create_ggc (1009, const_desc_hash,
+                                    const_desc_eq, NULL);
 
   const_alias_set = new_alias_set ();
 }
 
+enum tls_model
+decl_tls_model (tree decl)
+{
+  enum tls_model kind;
+  tree attr = lookup_attribute ("tls_model", DECL_ATTRIBUTES (decl));
+  bool is_local;
+
+  if (attr)
+    {
+      attr = TREE_VALUE (TREE_VALUE (attr));
+      if (TREE_CODE (attr) != STRING_CST)
+       abort ();
+      if (!strcmp (TREE_STRING_POINTER (attr), "local-exec"))
+       kind = TLS_MODEL_LOCAL_EXEC;
+      else if (!strcmp (TREE_STRING_POINTER (attr), "initial-exec"))
+       kind = TLS_MODEL_INITIAL_EXEC;
+      else if (!strcmp (TREE_STRING_POINTER (attr), "local-dynamic"))
+       kind = optimize ? TLS_MODEL_LOCAL_DYNAMIC : TLS_MODEL_GLOBAL_DYNAMIC;
+      else if (!strcmp (TREE_STRING_POINTER (attr), "global-dynamic"))
+       kind = TLS_MODEL_GLOBAL_DYNAMIC;
+      else
+       abort ();
+      return kind;
+    }
+
+  is_local = (*targetm.binds_local_p) (decl);
+  if (!flag_pic)
+    {
+      if (is_local)
+       kind = TLS_MODEL_LOCAL_EXEC;
+      else
+       kind = TLS_MODEL_INITIAL_EXEC;
+    }
+  /* Local dynamic is inefficient when we're not combining the
+     parts of the address.  */
+  else if (optimize && is_local)
+    kind = TLS_MODEL_LOCAL_DYNAMIC;
+  else
+    kind = TLS_MODEL_GLOBAL_DYNAMIC;
+  if (kind < flag_tls_default)
+    kind = flag_tls_default;
+
+  return kind;
+}
+
+enum symbol_visibility
+decl_visibility (tree decl)
+{
+  tree attr = lookup_attribute ("visibility", DECL_ATTRIBUTES (decl));
+
+  if (attr)
+    {
+      const char *which = TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr)));
+
+      if (strcmp (which, "default") == 0)
+       return VISIBILITY_DEFAULT;
+      if (strcmp (which, "internal") == 0)
+       return VISIBILITY_INTERNAL;
+      if (strcmp (which, "hidden") == 0)
+       return VISIBILITY_HIDDEN;
+      if (strcmp (which, "protected") == 0)
+       return VISIBILITY_PROTECTED;
+
+      abort ();
+    }
+
+  return VISIBILITY_DEFAULT;
+}
+
 /* 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.
@@ -5088,16 +4550,20 @@ init_varasm_once ()
    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;
+default_section_type_flags (tree decl, const char *name, int reloc)
+{
+  return default_section_type_flags_1 (decl, name, reloc, flag_pic);
+}
+
+unsigned int
+default_section_type_flags_1 (tree decl, const char *name, int reloc,
+                             int shlib)
 {
   unsigned int flags;
 
   if (decl && TREE_CODE (decl) == FUNCTION_DECL)
     flags = SECTION_CODE;
-  else if (decl && DECL_READONLY_SECTION (decl, reloc))
+  else if (decl && decl_readonly_section_1 (decl, reloc, shlib))
     flags = 0;
   else
     flags = SECTION_WRITE;
@@ -5124,6 +4590,17 @@ default_section_type_flags (decl, name, reloc)
       || strncmp (name, ".gnu.linkonce.tb.", 17) == 0)
     flags |= SECTION_TLS;
 
+  /* These three sections have special ELF types.  They are neither
+     SHT_PROGBITS nor SHT_NOBITS, so when changing sections we don't
+     want to print a section type (@progbits or @nobits).  If someone
+     is silly enough to emit code or TLS variables to one of these
+     sections, then don't handle them specially.  */
+  if (!(flags & (SECTION_CODE | SECTION_BSS | SECTION_TLS))
+      && (strcmp (name, ".init_array") == 0
+         || strcmp (name, ".fini_array") == 0
+         || strcmp (name, ".preinit_array") == 0))
+    flags |= SECTION_NOTYPE;
+
   return flags;
 }
 
@@ -5131,9 +4608,8 @@ default_section_type_flags (decl, name, reloc)
    Four variants for common object file formats.  */
 
 void
-default_no_named_section (name, flags)
-     const char *name ATTRIBUTE_UNUSED;
-     unsigned int flags ATTRIBUTE_UNUSED;
+default_no_named_section (const char *name ATTRIBUTE_UNUSED,
+                         unsigned int flags ATTRIBUTE_UNUSED)
 {
   /* Some object formats don't support named sections at all.  The
      front-end should already have flagged this as an error.  */
@@ -5141,12 +4617,9 @@ default_no_named_section (name, flags)
 }
 
 void
-default_elf_asm_named_section (name, flags)
-     const char *name;
-     unsigned int flags;
+default_elf_asm_named_section (const char *name, unsigned int flags)
 {
   char flagchars[10], *f = flagchars;
-  const char *type;
 
   if (! named_section_first_declaration (name))
     {
@@ -5170,23 +4643,28 @@ default_elf_asm_named_section (name, flags)
     *f++ = 'T';
   *f = '\0';
 
-  if (flags & SECTION_BSS)
-    type = "nobits";
-  else
-    type = "progbits";
+  fprintf (asm_out_file, "\t.section\t%s,\"%s\"", name, flagchars);
 
-  if (flags & SECTION_ENTSIZE)
-    fprintf (asm_out_file, "\t.section\t%s,\"%s\",@%s,%d\n",
-            name, flagchars, type, flags & SECTION_ENTSIZE);
-  else
-    fprintf (asm_out_file, "\t.section\t%s,\"%s\",@%s\n",
-            name, flagchars, type);
+  if (!(flags & SECTION_NOTYPE))
+    {
+      const char *type;
+
+      if (flags & SECTION_BSS)
+       type = "nobits";
+      else
+       type = "progbits";
+
+      fprintf (asm_out_file, ",@%s", type);
+
+      if (flags & SECTION_ENTSIZE)
+       fprintf (asm_out_file, ",%d", flags & SECTION_ENTSIZE);
+    }
+
+  putc ('\n', asm_out_file);
 }
 
 void
-default_coff_asm_named_section (name, flags)
-     const char *name;
-     unsigned int flags;
+default_coff_asm_named_section (const char *name, unsigned int flags)
 {
   char flagchars[8], *f = flagchars;
 
@@ -5200,9 +4678,7 @@ default_coff_asm_named_section (name, flags)
 }
 
 void
-default_pe_asm_named_section (name, flags)
-     const char *name;
-     unsigned int flags;
+default_pe_asm_named_section (const char *name, unsigned int flags)
 {
   default_coff_asm_named_section (name, flags);
 
@@ -5216,48 +4692,17 @@ default_pe_asm_named_section (name, flags)
     }
 }
 \f
-/* Used for vtable gc in GNU binutils.  Record that the pointer at OFFSET
-   from SYMBOL is used in all classes derived from SYMBOL.  */
-
-void
-assemble_vtable_entry (symbol, offset)
-     rtx symbol;
-     HOST_WIDE_INT offset;
-{
-  fputs ("\t.vtable_entry ", asm_out_file);
-  output_addr_const (asm_out_file, symbol);
-  fputs (", ", asm_out_file);
-  fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC, offset);
-  fputc ('\n', asm_out_file);
-}
-
-/* Used for vtable gc in GNU binutils.  Record the class hierarchy by noting
-   that the vtable symbol CHILD is derived from the vtable symbol PARENT.  */
-
-void
-assemble_vtable_inherit (child, parent)
-     rtx child, parent;
-{
-  fputs ("\t.vtable_inherit ", asm_out_file);
-  output_addr_const (asm_out_file, child);
-  fputs (", ", asm_out_file);
-  output_addr_const (asm_out_file, parent);
-  fputc ('\n', asm_out_file);
-}
-\f
 /* The lame default section selector.  */
 
 void
-default_select_section (decl, reloc, align)
-     tree decl;
-     int reloc;
-     unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED;
+default_select_section (tree decl, int reloc,
+                       unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
 {
   bool readonly = false;
 
   if (DECL_P (decl))
     {
-      if (DECL_READONLY_SECTION (decl, reloc))
+      if (decl_readonly_section (decl, reloc))
        readonly = true;
     }
   else if (TREE_CODE (decl) == CONSTRUCTOR)
@@ -5290,6 +4735,7 @@ enum section_category
   SECCAT_RODATA_MERGE_STR,
   SECCAT_RODATA_MERGE_STR_INIT,
   SECCAT_RODATA_MERGE_CONST,
+  SECCAT_SRODATA,
 
   SECCAT_DATA,
 
@@ -5315,12 +4761,11 @@ enum section_category
   SECCAT_TBSS
 };
 
-static enum section_category categorize_decl_for_section PARAMS ((tree, int));
+static enum section_category
+categorize_decl_for_section (tree, int, int);
 
 static enum section_category
-categorize_decl_for_section (decl, reloc)
-     tree decl;
-     int reloc;
+categorize_decl_for_section (tree decl, int reloc, int shlib)
 {
   enum section_category ret;
 
@@ -5342,18 +4787,18 @@ categorize_decl_for_section (decl, reloc)
               || TREE_SIDE_EFFECTS (decl)
               || ! TREE_CONSTANT (DECL_INITIAL (decl)))
        {
-         if (flag_pic && (reloc & 2))
+         if (shlib && (reloc & 2))
            ret = SECCAT_DATA_REL;
-         else if (flag_pic && reloc)
+         else if (shlib && reloc)
            ret = SECCAT_DATA_REL_LOCAL;
          else
            ret = SECCAT_DATA;
        }
-      else if (flag_pic && (reloc & 2))
+      else if (shlib && (reloc & 2))
        ret = SECCAT_DATA_REL_RO;
-      else if (flag_pic && reloc)
+      else if (shlib && reloc)
        ret = SECCAT_DATA_REL_RO_LOCAL;
-      else if (flag_merge_constants < 2)
+      else if (reloc || flag_merge_constants < 2)
        /* C and C++ don't allow different variables to share the same
           location.  -fmerge-all-constants allows even that (at the
           expense of not conforming).  */
@@ -5365,7 +4810,7 @@ categorize_decl_for_section (decl, reloc)
     }
   else if (TREE_CODE (decl) == CONSTRUCTOR)
     {
-      if ((flag_pic && reloc)
+      if ((shlib && reloc)
          || TREE_SIDE_EFFECTS (decl)
          || ! TREE_CONSTANT (decl))
        ret = SECCAT_DATA;
@@ -5389,6 +4834,8 @@ categorize_decl_for_section (decl, reloc)
     {
       if (ret == SECCAT_BSS)
        ret = SECCAT_SBSS;
+      else if (targetm.have_srodata_section && ret == SECCAT_RODATA)
+       ret = SECCAT_SRODATA;
       else
        ret = SECCAT_SDATA;
     }
@@ -5396,15 +4843,44 @@ categorize_decl_for_section (decl, reloc)
   return ret;
 }
 
+bool
+decl_readonly_section (tree decl, int reloc)
+{
+  return decl_readonly_section_1 (decl, reloc, flag_pic);
+}
+
+bool
+decl_readonly_section_1 (tree decl, int reloc, int shlib)
+{
+  switch (categorize_decl_for_section (decl, reloc, shlib))
+    {
+    case SECCAT_RODATA:
+    case SECCAT_RODATA_MERGE_STR:
+    case SECCAT_RODATA_MERGE_STR_INIT:
+    case SECCAT_RODATA_MERGE_CONST:
+    case SECCAT_SRODATA:
+      return true;
+      break;
+    default:
+      return false;
+      break;
+    }
+}
+
 /* Select a section based on the above categorization.  */
 
 void
-default_elf_select_section (decl, reloc, align)
-     tree decl;
-     int reloc;
-     unsigned HOST_WIDE_INT align;
+default_elf_select_section (tree decl, int reloc,
+                           unsigned HOST_WIDE_INT align)
+{
+  default_elf_select_section_1 (decl, reloc, align, flag_pic);
+}
+
+void
+default_elf_select_section_1 (tree decl, int reloc,
+                             unsigned HOST_WIDE_INT align, int shlib)
 {
-  switch (categorize_decl_for_section (decl, reloc))
+  switch (categorize_decl_for_section (decl, reloc, shlib))
     {
     case SECCAT_TEXT:
       /* We're not supposed to be called on FUNCTION_DECLs.  */
@@ -5421,6 +4897,9 @@ default_elf_select_section (decl, reloc, align)
     case SECCAT_RODATA_MERGE_CONST:
       mergeable_constant_section (DECL_MODE (decl), align, 0);
       break;
+    case SECCAT_SRODATA:
+      named_section (NULL_TREE, ".sdata2", reloc);
+      break;
     case SECCAT_DATA:
       data_section ();
       break;
@@ -5460,20 +4939,24 @@ default_elf_select_section (decl, reloc, align)
     }
 }
 
-/* Construct a unique section name based on the decl name and the 
+/* Construct a unique section name based on the decl name and the
    categorization performed above.  */
 
 void
-default_unique_section (decl, reloc)
-     tree decl;
-     int reloc;
+default_unique_section (tree decl, int reloc)
+{
+  default_unique_section_1 (decl, reloc, flag_pic);
+}
+
+void
+default_unique_section_1 (tree decl, int reloc, int shlib)
 {
   bool one_only = DECL_ONE_ONLY (decl);
   const char *prefix, *name;
   size_t nlen, plen;
   char *string;
 
-  switch (categorize_decl_for_section (decl, reloc))
+  switch (categorize_decl_for_section (decl, reloc, shlib))
     {
     case SECCAT_TEXT:
       prefix = one_only ? ".gnu.linkonce.t." : ".text.";
@@ -5484,6 +4967,9 @@ default_unique_section (decl, reloc)
     case SECCAT_RODATA_MERGE_CONST:
       prefix = one_only ? ".gnu.linkonce.r." : ".rodata.";
       break;
+    case SECCAT_SRODATA:
+      prefix = one_only ? ".gnu.linkonce.s2." : ".sdata2.";
+      break;
     case SECCAT_DATA:
     case SECCAT_DATA_REL:
     case SECCAT_DATA_REL_LOCAL:
@@ -5523,10 +5009,9 @@ default_unique_section (decl, reloc)
 }
 
 void
-default_select_rtx_section (mode, x, align)
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-     rtx x;
-     unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED;
+default_select_rtx_section (enum machine_mode mode ATTRIBUTE_UNUSED,
+                           rtx x,
+                           unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
 {
   if (flag_pic)
     switch (GET_CODE (x))
@@ -5545,10 +5030,8 @@ default_select_rtx_section (mode, x, align)
 }
 
 void
-default_elf_select_rtx_section (mode, x, align)
-     enum machine_mode mode;
-     rtx x;
-     unsigned HOST_WIDE_INT align;
+default_elf_select_rtx_section (enum machine_mode mode, rtx x,
+                               unsigned HOST_WIDE_INT align)
 {
   /* ??? Handle small data here somehow.  */
 
@@ -5571,12 +5054,44 @@ default_elf_select_rtx_section (mode, x, align)
   mergeable_constant_section (mode, align, 0);
 }
 
+/* Set the generally applicable flags on the SYMBOL_REF for EXP.  */
+
+void
+default_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
+{
+  rtx symbol;
+  int flags;
+
+  /* Careful not to prod global register variables.  */
+  if (GET_CODE (rtl) != MEM)
+    return;
+  symbol = XEXP (rtl, 0);
+  if (GET_CODE (symbol) != SYMBOL_REF)
+    return;
+
+  flags = 0;
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    flags |= SYMBOL_FLAG_FUNCTION;
+  if ((*targetm.binds_local_p) (decl))
+    flags |= SYMBOL_FLAG_LOCAL;
+  if ((*targetm.in_small_data_p) (decl))
+    flags |= SYMBOL_FLAG_SMALL;
+  if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
+    flags |= decl_tls_model (decl) << SYMBOL_FLAG_TLS_SHIFT;
+  /* ??? Why is DECL_EXTERNAL ever set for non-PUBLIC names?  Without
+     being PUBLIC, the thing *must* be defined in this translation unit.
+     Prevent this buglet from being propagated into rtl code as well.  */
+  if (DECL_P (decl) && DECL_EXTERNAL (decl) && TREE_PUBLIC (decl))
+    flags |= SYMBOL_FLAG_EXTERNAL;
+
+  SYMBOL_REF_FLAGS (symbol) = flags;
+}
+
 /* By default, we do nothing for encode_section_info, so we need not
    do anything but discard the '*' marker.  */
 
 const char *
-default_strip_name_encoding (str)
-     const char *str;
+default_strip_name_encoding (const char *str)
 {
   return str + (*str == '*');
 }
@@ -5585,16 +5100,24 @@ default_strip_name_encoding (str)
    wrt cross-module name binding.  */
 
 bool
-default_binds_local_p (exp)
-     tree exp;
+default_binds_local_p (tree exp)
+{
+  return default_binds_local_p_1 (exp, flag_shlib);
+}
+
+bool
+default_binds_local_p_1 (tree exp, int shlib)
 {
   bool local_p;
 
   /* A non-decl is an entry in the constant pool.  */
   if (!DECL_P (exp))
     local_p = true;
-  /* A variable is considered "local" if it is defined by this module.  */
-  else if (MODULE_LOCAL_P (exp))
+  /* Static variables are always local.  */
+  else if (! TREE_PUBLIC (exp))
+    local_p = true;
+  /* A variable is local if the user tells us so.  */
+  else if (decl_visibility (exp) != VISIBILITY_DEFAULT)
     local_p = true;
   /* Otherwise, variables defined outside this object may not be local.  */
   else if (DECL_EXTERNAL (exp))
@@ -5602,12 +5125,9 @@ default_binds_local_p (exp)
   /* Linkonce and weak data are never local.  */
   else if (DECL_ONE_ONLY (exp) || DECL_WEAK (exp))
     local_p = false;
-  /* Static variables are always local.  */
-  else if (! TREE_PUBLIC (exp))
-    local_p = true;
   /* If PIC, then assume that any global name can be overridden by
      symbols resolved from other modules.  */
-  else if (flag_pic)
+  else if (shlib)
     local_p = false;
   /* Uninitialized COMMON variable may be unified with symbols
      resolved from other modules.  */
@@ -5622,3 +5142,64 @@ default_binds_local_p (exp)
 
   return local_p;
 }
+
+/* Determine whether or not a pointer mode is valid. Assume defaults
+   of ptr_mode or Pmode - can be overridden.  */
+bool
+default_valid_pointer_mode (enum machine_mode mode)
+{
+  return (mode == ptr_mode || mode == Pmode);
+}
+
+/* Default function to output code that will globalize a label.  A
+   target must define GLOBAL_ASM_OP or provide it's own function to
+   globalize a label.  */
+#ifdef GLOBAL_ASM_OP
+void
+default_globalize_label (FILE * stream, const char *name)
+{
+  fputs (GLOBAL_ASM_OP, stream);
+  assemble_name (stream, name);
+  putc ('\n', stream);
+}
+#endif /* GLOBAL_ASM_OP */
+
+/* This is how to output an internal numbered label where PREFIX is
+   the class of label and LABELNO is the number within the class.  */
+
+void
+default_internal_label (FILE *stream, const char *prefix,
+                       unsigned long labelno)
+{
+  char *const buf = alloca (40 + strlen (prefix));
+  ASM_GENERATE_INTERNAL_LABEL (buf, prefix, labelno);
+  ASM_OUTPUT_LABEL (stream, buf);
+}
+
+/* This is the default behavior at the beginning of a file.  It's
+   controlled by two other target-hook toggles.  */
+void
+default_file_start (void)
+{
+  if (targetm.file_start_app_off && !flag_verbose_asm)
+    fputs (ASM_APP_OFF, asm_out_file);
+
+  if (targetm.file_start_file_directive)
+    output_file_directive (asm_out_file, main_input_filename);
+}
+
+/* This is a generic routine suitable for use as TARGET_ASM_FILE_END
+   which emits a special section directive used to indicate whether or
+   not this object file needs an executable stack.  This is primarily
+   a GNU extension to ELF but could be used on other targets.  */
+void
+file_end_indicate_exec_stack (void)
+{
+  unsigned int flags = SECTION_DEBUG;
+  if (trampolines_created)
+    flags |= SECTION_CODE;
+
+  named_section_flags (".note.GNU-stack", flags);
+}
+
+#include "gt-varasm.h"