OSDN Git Service

2005-11-03 Andrew Pinski <pinskia@physics.uc.edu>
[pf3gnuchains/gcc-fork.git] / gcc / varasm.c
index 82a3e15..83f47ac 100644 (file)
@@ -1,6 +1,7 @@
 /* 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, 2003 Free Software Foundation, Inc.
+   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -16,8 +17,8 @@ for more details.
 
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 
 /* This file handles generation of all the assembler code
@@ -43,77 +44,49 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "toplev.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 "tree-mudflap.h"
+#include "cgraph.h"
+#include "cfglayout.h"
+#include "basic-block.h"
 
 #ifdef XCOFF_DEBUGGING_INFO
 #include "xcoffout.h"          /* Needed for external data
                                   declarations for e.g. AIX 4.x.  */
 #endif
 
-#ifndef TRAMPOLINE_ALIGNMENT
-#define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY
-#endif
-
-#ifndef ASM_STABS_OP
-#define ASM_STABS_OP "\t.stabs\t"
-#endif
-
 /* The (assembler) name of the first globally-visible object output.  */
+extern GTY(()) const char *first_global_object_name;
+extern GTY(()) const char *weak_global_object_name;
+
 const char *first_global_object_name;
 const char *weak_global_object_name;
 
 struct addr_const;
 struct constant_descriptor_rtx;
-struct rtx_const;
-struct pool_constant;
-
-#define MAX_RTX_HASH_TABLE 61
+struct rtx_constant_pool;
 
 struct varasm_status GTY(())
 {
-  /* Hash facility for making memory-constants
-     from constant rtl-expressions.  It is used on RISC machines
-     where immediate integer arguments and constant addresses are restricted
-     so that such constants must be stored in memory.
-
-     This pool of constants is reinitialized for each function
-     so each function gets its own constants-pool that comes right before
-     it.  */
-  struct constant_descriptor_rtx ** GTY ((length ("MAX_RTX_HASH_TABLE")))
-    x_const_rtx_hash_table;
-  struct pool_constant ** GTY ((length ("MAX_RTX_HASH_TABLE")))
-    x_const_rtx_sym_hash_table;
-
-  /* Pointers to first and last constant in pool.  */
-  struct pool_constant *x_first_pool;
-  struct pool_constant *x_last_pool;
-
-  /* Current offset in constant pool (does not include any machine-specific
-     header).  */
-  HOST_WIDE_INT x_pool_offset;
+  /* If we're using a per-function constant pool, this is it.  */
+  struct rtx_constant_pool *pool;
+
+  /* Number of tree-constants deferred during the expansion of this
+     function.  */
+  unsigned int deferred_constants;
 };
 
-#define const_rtx_hash_table (cfun->varasm->x_const_rtx_hash_table)
-#define const_rtx_sym_hash_table (cfun->varasm->x_const_rtx_sym_hash_table)
-#define first_pool (cfun->varasm->x_first_pool)
-#define last_pool (cfun->varasm->x_last_pool)
-#define pool_offset (cfun->varasm->x_pool_offset)
+#define n_deferred_constants (cfun->varasm->deferred_constants)
 
 /* Number for making the label on the next
    constant that is stored in memory.  */
 
 static GTY(()) int const_labelno;
 
-/* Number for making the label on the next
-   static variable internal to a function.  */
-
-static GTY(()) int var_labelno;
-
 /* Carry information from ASM_DECLARE_OBJECT_NAME
    to ASM_FINISH_DECLARE_OBJECT.  */
 
@@ -126,77 +99,55 @@ int size_directive_output;
 
 tree last_assemble_variable_decl;
 
-/* RTX_UNCHANGING_P in a MEM can mean it is stored into, for initialization.
-   So giving constant the alias set for the type will allow such
-   initializations to appear to conflict with the load of the constant.  We
-   avoid this by giving all constants an alias set for just constants.
-   Since there will be no stores to that alias set, nothing will ever
-   conflict with them.  */
+/* The following global variable indicates if the first basic block
+   in a function belongs to the cold partition or not.  */
+
+bool first_function_block_is_cold;
+
+/* We give all constants their own alias set.  Perhaps redundant with
+   MEM_READONLY_P, but pre-dates it.  */
 
 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 unsigned int const_hash         PARAMS ((tree));
-static unsigned int const_hash_1       PARAMS ((tree));
-static int compare_constant            PARAMS ((tree, tree));
-static tree copy_constant              PARAMS ((tree));
-static void maybe_output_constant_def_contents PARAMS ((tree, rtx, int));
-static void output_constant_def_contents  PARAMS ((tree, const char *));
-static void decode_rtx_const           PARAMS ((enum machine_mode, rtx,
-                                              struct rtx_const *));
-static unsigned int const_hash_rtx     PARAMS ((enum machine_mode, rtx));
-static int compare_constant_rtx
-  PARAMS ((enum machine_mode, rtx, struct constant_descriptor_rtx *));
-static struct constant_descriptor_rtx * 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 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));
-#ifdef ASM_OUTPUT_BSS
-static void asm_output_bss             PARAMS ((FILE *, tree, const char *, int, int));
+static const char *strip_reg_name (const char *);
+static int contains_pointers_p (tree);
+#ifdef ASM_OUTPUT_EXTERNAL
+static bool incorporeal_function_p (tree);
 #endif
+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 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 *);
+static void initialize_cold_section_name (void);
 #ifdef BSS_SECTION_ASM_OP
+#ifdef ASM_OUTPUT_BSS
+static void asm_output_bss (FILE *, tree, const char *,
+                           unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT);
+#endif
 #ifdef ASM_OUTPUT_ALIGNED_BSS
-static void asm_output_aligned_bss
-  PARAMS ((FILE *, tree, const char *, int, int)) ATTRIBUTE_UNUSED;
+static void asm_output_aligned_bss (FILE *, tree, const char *,
+                                   unsigned HOST_WIDE_INT, int)
+     ATTRIBUTE_UNUSED;
 #endif
 #endif /* BSS_SECTION_ASM_OP */
-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 bool 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
-enum in_section { no_section, in_text, in_data, in_named
-#ifdef BSS_SECTION_ASM_OP
-  , in_bss
-#endif
-#ifdef CTORS_SECTION_ASM_OP
-  , in_ctors
-#endif
-#ifdef DTORS_SECTION_ASM_OP
-  , in_dtors
-#endif
-#ifdef READONLY_DATA_SECTION_ASM_OP
-  , in_readonly_data
-#endif
-#ifdef EXTRA_SECTIONS
-  , EXTRA_SECTIONS
-#endif
-};
 static GTY(()) enum in_section in_section = no_section;
+enum in_section last_text_section;
 
 /* Return a nonzero value if DECL has a section attribute.  */
 #ifndef IN_NAMED_SECTION
@@ -207,6 +158,7 @@ static GTY(()) enum in_section in_section = no_section;
 
 /* Text of section name when in_section == in_named.  */
 static GTY(()) const char *in_named_name;
+const char *last_text_section_name;
 
 /* Hash table of flags that have been used for a particular named section.  */
 
@@ -224,40 +176,83 @@ static GTY((param_is (struct in_named_entry))) htab_t in_named_htab;
 EXTRA_SECTION_FUNCTIONS
 #endif
 
+static void
+initialize_cold_section_name (void)
+{
+  const char *stripped_name;
+  char *name, *buffer;
+  tree dsn;
+
+  gcc_assert (cfun && current_function_decl);
+  if (cfun->unlikely_text_section_name)
+    return;
+
+  dsn = DECL_SECTION_NAME (current_function_decl);
+  if (flag_function_sections && dsn)
+    {
+      name = alloca (TREE_STRING_LENGTH (dsn) + 1);
+      memcpy (name, TREE_STRING_POINTER (dsn), TREE_STRING_LENGTH (dsn) + 1);
+
+      stripped_name = targetm.strip_name_encoding (name);
+
+      buffer = ACONCAT ((stripped_name, "_unlikely", NULL));
+      cfun->unlikely_text_section_name = ggc_strdup (buffer);
+    }
+  else
+    cfun->unlikely_text_section_name =  UNLIKELY_EXECUTED_TEXT_SECTION_NAME;
+}
+
 /* Tell assembler to switch to text section.  */
 
 void
-text_section ()
+text_section (void)
 {
   if (in_section != in_text)
     {
       in_section = in_text;
-#ifdef TEXT_SECTION
-      TEXT_SECTION ();
-#else
+      last_text_section = in_text;
       fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
-#endif
+    }
+}
+
+/* Tell assembler to switch to unlikely-to-be-executed text section.  */
+
+void
+unlikely_text_section (void)
+{
+  if (cfun)
+    {
+      if (!cfun->unlikely_text_section_name)
+       initialize_cold_section_name ();
+
+      if (flag_function_sections
+         || ((in_section != in_unlikely_executed_text)
+             &&  (in_section != in_named 
+                  || (strcmp (in_named_name, cfun->unlikely_text_section_name) 
+                      != 0))))
+       {
+         named_section (NULL_TREE, cfun->unlikely_text_section_name, 0);
+         in_section = in_unlikely_executed_text;
+         last_text_section = in_unlikely_executed_text;
+       }
+    }
+  else
+    {
+      named_section (NULL_TREE, UNLIKELY_EXECUTED_TEXT_SECTION_NAME, 0);
+      in_section = in_unlikely_executed_text;
+      last_text_section = in_unlikely_executed_text;
     }
 }
 
 /* Tell assembler to switch to data section.  */
 
 void
-data_section ()
+data_section (void)
 {
   if (in_section != in_data)
     {
       in_section = in_data;
-      if (flag_shared_data)
-       {
-#ifdef SHARED_SECTION_ASM_OP
-         fprintf (asm_out_file, "%s\n", SHARED_SECTION_ASM_OP);
-#else
-         fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
-#endif
-       }
-      else
-       fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
+      fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
     }
 }
 
@@ -265,7 +260,7 @@ data_section ()
    the text section.  */
 
 void
-readonly_data_section ()
+readonly_data_section (void)
 {
 #ifdef READONLY_DATA_SECTION
   READONLY_DATA_SECTION ();  /* Note this can call data_section.  */
@@ -286,15 +281,41 @@ readonly_data_section ()
 /* Determine if we're in the text section.  */
 
 int
-in_text_section ()
+in_text_section (void)
 {
   return in_section == in_text;
 }
 
+/* Determine if we're in the unlikely-to-be-executed text section.  */
+
+int
+in_unlikely_text_section (void)
+{
+  bool ret_val;
+
+  if (cfun)
+    {
+      ret_val = ((in_section == in_unlikely_executed_text)
+                || (in_section == in_named
+                    && cfun->unlikely_text_section_name
+                    && strcmp (in_named_name, 
+                               cfun->unlikely_text_section_name) == 0));
+    }
+  else
+    {
+      ret_val = ((in_section == in_unlikely_executed_text)
+                || (in_section == in_named
+                    && strcmp (in_named_name,
+                               UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0));
+    }
+
+  return ret_val;
+}
+
 /* Determine if we're in the data section.  */
 
 int
-in_data_section ()
+in_data_section (void)
 {
   return in_section == in_data;
 }
@@ -302,9 +323,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;
@@ -313,8 +332,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);
@@ -325,9 +343,8 @@ in_named_entry_hash (p)
    set of flags for a section to have, so 0 does not mean that the section
    has not been seen.  */
 
-unsigned int
-get_named_section_flags (section)
-     const char *section;
+static unsigned int
+get_named_section_flags (const char *section)
 {
   struct in_named_entry **slot;
 
@@ -343,8 +360,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;
 
@@ -367,9 +383,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;
 
@@ -380,7 +394,7 @@ set_named_section_flags (section, flags)
 
   if (!entry)
     {
-      entry = (struct in_named_entry *) ggc_alloc (sizeof (*entry));
+      entry = ggc_alloc (sizeof (*entry));
       *slot = entry;
       entry->name = ggc_strdup (section);
       entry->flags = flags;
@@ -392,19 +406,20 @@ set_named_section_flags (section, flags)
   return true;
 }
 
-/* Tell assembler to change to section NAME with attributes FLAGS.  */
+/* Tell assembler to change to section NAME with attributes FLAGS.  If
+   DECL is non-NULL, it is the VAR_DECL or FUNCTION_DECL with which
+   this section is associated.  */
 
 void
-named_section_flags (name, flags)
-     const char *name;
-     unsigned int flags;
+named_section_real (const char *name, unsigned int flags, tree decl)
 {
   if (in_section != in_named || strcmp (name, in_named_name) != 0)
     {
-      if (! set_named_section_flags (name, flags))
-       abort ();
+      bool unchanged = set_named_section_flags (name, flags);
+
+      gcc_assert (unchanged);
 
-      (*targetm.asm_out.named_section) (name, flags);
+      targetm.asm_out.named_section (name, flags, decl);
 
       if (flags & SECTION_FORGET)
        in_section = no_section;
@@ -414,6 +429,12 @@ named_section_flags (name, flags)
          in_section = in_named;
        }
     }
+
+  if (in_text_section () || in_unlikely_text_section ())
+    {
+      last_text_section = in_section;
+      last_text_section_name = name;
+    }
 }
 
 /* Tell assembler to change to section NAME for DECL.
@@ -422,22 +443,23 @@ 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;
 
-  if (decl != NULL_TREE && !DECL_P (decl))
-    abort ();
+  gcc_assert (!decl || DECL_P (decl));
   if (name == NULL)
     name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
 
-  flags = (* targetm.section_type_flags) (decl, name, reloc);
+  if (strcmp (name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0
+      && cfun
+      && ! cfun->unlikely_text_section_name)
+    cfun->unlikely_text_section_name = UNLIKELY_EXECUTED_TEXT_SECTION_NAME;
+
+  flags = targetm.section_type_flags (decl, name, reloc);
 
   /* Sanity check user variables for flag changes.  Non-user
-     section flag changes will abort in named_section_flags.
+     section flag changes will die in named_section_flags.
      However, don't complain if SECTION_OVERRIDE is set.
      We trust that the setter knows that it is safe to ignore
      the default flags for this decl.  */
@@ -445,25 +467,23 @@ 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 ("%+D causes a section type conflict", decl);
     }
 
-  named_section_flags (name, flags);
+  named_section_real (name, flags, decl);
 }
 
 /* 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
       && (flag_function_or_data_sections
          || DECL_ONE_ONLY (decl)))
-    (*targetm.asm_out.unique_section) (decl, reloc);
+    targetm.asm_out.unique_section (decl, reloc);
 }
 
 #ifdef BSS_SECTION_ASM_OP
@@ -471,17 +491,11 @@ 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)
     {
-#ifdef SHARED_BSS_SECTION_ASM_OP
-      if (flag_shared_data)
-       fprintf (asm_out_file, "%s\n", SHARED_BSS_SECTION_ASM_OP);
-      else
-#endif
-       fprintf (asm_out_file, "%s\n", BSS_SECTION_ASM_OP);
-
+      fprintf (asm_out_file, "%s\n", BSS_SECTION_ASM_OP);
       in_section = in_bss;
     }
 }
@@ -494,13 +508,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)
 {
-  (*targetm.asm_out.globalize_label) (file, name);
+  targetm.asm_out.globalize_label (file, name);
   bss_section ();
 #ifdef ASM_DECLARE_OBJECT_NAME
   last_assemble_variable_decl = decl;
@@ -522,11 +535,9 @@ 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)
 {
   bss_section ();
   ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
@@ -546,45 +557,131 @@ asm_output_aligned_bss (file, decl, name, size, align)
 
 /* Switch to the section for function DECL.
 
-   If DECL is NULL_TREE, switch to the text section.
-   ??? It's not clear that we will ever be passed NULL_TREE, but it's
-   safer to handle it.  */
+   If DECL is NULL_TREE, switch to the text section.  We can be passed
+   NULL_TREE under some circumstances by dbxout.c at least.  */
 
 void
-function_section (decl)
-     tree decl;
+function_section (tree decl)
 {
+  int reloc = 0;
+    
+  if (first_function_block_is_cold)
+    reloc = 1;
+  
+#ifdef USE_SELECT_SECTION_FOR_FUNCTIONS
+  targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
+#else
   if (decl != NULL_TREE
-      && DECL_SECTION_NAME (decl) != NULL_TREE)
+      && DECL_SECTION_NAME (decl) != NULL_TREE
+      && targetm.have_named_sections)
     named_section (decl, (char *) 0, 0);
   else
     text_section ();
+#endif
+}
+
+void
+current_function_section (tree decl)
+{
+#ifdef USE_SELECT_SECTION_FOR_FUNCTIONS
+  int reloc = 0; 
+
+  if (in_unlikely_text_section () 
+      || last_text_section == in_unlikely_executed_text)
+    reloc = 1;
+  targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
+#else
+  if (last_text_section == in_unlikely_executed_text)
+    unlikely_text_section ();
+  else if (last_text_section == in_text)
+    text_section ();
+  else if (last_text_section == in_named
+          && targetm.have_named_sections)
+    named_section (NULL_TREE, last_text_section_name, 0);
+  else
+    function_section (decl);
+#endif
+}
+
+/* Switch to read-only data section associated with function DECL.  */
+
+void
+default_function_rodata_section (tree decl)
+{
+  if (decl != NULL_TREE && DECL_SECTION_NAME (decl))
+    {
+      const char *name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
+
+      if (DECL_ONE_ONLY (decl) && HAVE_COMDAT_GROUP)
+        {
+         size_t len = strlen (name) + 3;
+         char* rname = alloca (len);
+         
+         strcpy (rname, ".rodata");
+         strcat (rname, name + 5); 
+          named_section_real (rname, SECTION_LINKONCE, decl);
+         return;
+       }
+      /* For .gnu.linkonce.t.foo we want to use .gnu.linkonce.r.foo.  */
+      else if (DECL_ONE_ONLY (decl)
+              && strncmp (name, ".gnu.linkonce.t.", 16) == 0)
+       {
+         size_t len = strlen (name) + 1;
+         char *rname = alloca (len);
+
+         memcpy (rname, name, len);
+         rname[14] = 'r';
+         named_section_real (rname, SECTION_LINKONCE, decl);
+         return;
+       }
+      /* For .text.foo we want to use .rodata.foo.  */
+      else if (flag_function_sections && flag_data_sections
+              && strncmp (name, ".text.", 6) == 0)
+       {
+         size_t len = strlen (name) + 1;
+         char *rname = alloca (len + 2);
+
+         memcpy (rname, ".rodata", 7);
+         memcpy (rname + 7, name + 5, len - 5);
+         named_section_flags (rname, 0);
+         return;
+       }
+    }
+
+  readonly_data_section ();
+}
+
+/* Switch to read-only data section associated with function DECL
+   for targets where that section should be always the single
+   readonly data section.  */
+
+void
+default_no_function_rodata_section (tree decl ATTRIBUTE_UNUSED)
+{
+  readonly_data_section ();
 }
 
 /* Switch to section for variable DECL.  RELOC is the same as the
    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);
   else
-    (*targetm.asm_out.select_section) (decl, reloc, DECL_ALIGN (decl));
+    targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
 }
 
 /* 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
+  if (HAVE_GAS_SHF_MERGE && flag_merge_constants
       && TREE_CODE (decl) == STRING_CST
       && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
       && align <= 256
@@ -646,22 +743,20 @@ mergeable_string_section (decl, align, flags)
            }
        }
     }
-#endif
+
   readonly_data_section ();
 }
 
 /* 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);
 
-  if (flag_merge_constants
+  if (HAVE_GAS_SHF_MERGE && flag_merge_constants
       && mode != VOIDmode
       && mode != BLKmode
       && modesize <= align
@@ -676,15 +771,14 @@ mergeable_constant_section (mode, align, flags)
       named_section_flags (name, flags);
       return;
     }
-#endif
+
   readonly_data_section ();
 }
 \f
 /* 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)))
@@ -695,6 +789,19 @@ strip_reg_name (name)
   return name;
 }
 \f
+/* The user has asked for a DECL to have a particular name.  Set (or
+   change) it in such a way that we don't prefix an underscore to
+   it.  */
+void
+set_user_assembler_name (tree decl, const char *name)
+{
+  char *starred = alloca (strlen (name) + 2);
+  starred[0] = '*';
+  strcpy (starred + 1, name);
+  change_decl_assembler_name (decl, get_identifier (starred));
+  SET_DECL_RTL (decl, NULL_RTX);
+}
+\f
 /* Decode an `asm' spec for a declaration as a register name.
    Return the register number, or -1 if nothing specified,
    or -2 if the ASMSPEC is not `cc' or `memory' and is not recognized,
@@ -704,8 +811,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)
     {
@@ -738,7 +844,8 @@ decode_reg_name (asmspec)
          = ADDITIONAL_REGISTER_NAMES;
 
        for (i = 0; i < (int) ARRAY_SIZE (table); i++)
-         if (! strcmp (asmspec, table[i].name))
+         if (table[i].name[0]
+             && ! strcmp (asmspec, table[i].name))
            return table[i].number;
       }
 #endif /* ADDITIONAL_REGISTER_NAMES */
@@ -762,36 +869,29 @@ decode_reg_name (asmspec)
    There is, however, one exception: this function handles variables
    explicitly placed in a particular register by the user.
 
-   ASMSPEC, if not 0, is the string which the user specified as the
-   assembler symbol name.
-
    This is never called for PARM_DECL nodes.  */
 
 void
-make_decl_rtl (decl, asmspec)
-     tree decl;
-     const char *asmspec;
+make_decl_rtl (tree decl)
 {
-  int top_level = (DECL_CONTEXT (decl) == NULL_TREE);
   const char *name = 0;
-  const char *new_name = 0;
   int reg_number;
   rtx x;
 
   /* Check that we are not being given an automatic variable.  */
+  gcc_assert (TREE_CODE (decl) != PARM_DECL
+             && TREE_CODE (decl) != RESULT_DECL);
+
   /* A weak alias has TREE_PUBLIC set but not the other bits.  */
-  if (TREE_CODE (decl) == PARM_DECL
-      || TREE_CODE (decl) == RESULT_DECL
-      || (TREE_CODE (decl) == VAR_DECL
-         && !TREE_STATIC (decl)
-         && !TREE_PUBLIC (decl)
-         && !DECL_EXTERNAL (decl)
-         && !DECL_REGISTER (decl)))
-    abort ();
+  gcc_assert (TREE_CODE (decl) != VAR_DECL
+             || TREE_STATIC (decl)
+             || TREE_PUBLIC (decl)
+             || DECL_EXTERNAL (decl)
+             || DECL_REGISTER (decl));
+  
   /* And that we were not given a type or a label.  */
-  else if (TREE_CODE (decl) == TYPE_DECL
-          || TREE_CODE (decl) == LABEL_DECL)
-    abort ();
+  gcc_assert (TREE_CODE (decl) != TYPE_DECL
+             && TREE_CODE (decl) != LABEL_DECL);
 
   /* For a duplicate declaration, we can be called twice on the
      same DECL node.  Don't discard the RTL already made.  */
@@ -802,6 +902,9 @@ make_decl_rtl (decl, asmspec)
        SET_DECL_RTL (decl, adjust_address_nv (DECL_RTL (decl),
                                               DECL_MODE (decl), 0));
 
+      if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
+       return;
+
       /* ??? 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
@@ -810,36 +913,37 @@ make_decl_rtl (decl, asmspec)
       /* 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, DECL_RTL (decl), false);
+      targetm.encode_section_info (decl, DECL_RTL (decl), false);
+
+      /* Make this function static known to the mudflap runtime.  */
+      if (flag_mudflap && TREE_CODE (decl) == VAR_DECL)
+       mudflap_enqueue_decl (decl);
+
       return;
     }
 
-  new_name = name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
-
-  reg_number = decode_reg_name (asmspec);
-  if (reg_number == -2)
+  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+  
+  if (name[0] != '*' && TREE_CODE (decl) != FUNCTION_DECL
+      && DECL_REGISTER (decl))
     {
-      /* ASMSPEC is given, and not the name of a register.  Mark the
-        name with a star so assemble_name won't munge it.  */
-      char *starred = alloca (strlen (asmspec) + 2);
-      starred[0] = '*';
-      strcpy (starred + 1, asmspec);
-      new_name = starred;
+      error ("register name not specified for %q+D", decl);    
     }
-
-  if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
+  else if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
     {
+      const char *asmspec = name+1;
+      reg_number = decode_reg_name (asmspec);
       /* First detect errors in declaring global registers.  */
       if (reg_number == -1)
-       error_with_decl (decl, "register name not specified for `%s'");
+       error ("register name not specified for %q+D", decl);
       else if (reg_number < 0)
-       error_with_decl (decl, "invalid register name for `%s'");
+       error ("invalid register name for %q+D", decl);
       else if (TYPE_MODE (TREE_TYPE (decl)) == BLKmode)
-       error_with_decl (decl,
-                        "data type of `%s' isn't suitable for a register");
+       error ("data type of %q+D isn%'t suitable for a register",
+              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 ("register specified for %q+D isn%'t suitable for data type",
+               decl);
       /* Now handle properly declared static register variables.  */
       else
        {
@@ -851,7 +955,8 @@ make_decl_rtl (decl, asmspec)
              error ("global register variable has initial value");
            }
          if (TREE_THIS_VOLATILE (decl))
-           warning ("volatile register variables don't work as you might wish");
+           warning (0, "volatile register variables don%'t "
+                    "work as you might wish");
 
          /* If the user specified one of the eliminables registers here,
             e.g., FRAME_POINTER_REGNUM, we don't want to get this variable
@@ -867,9 +972,10 @@ make_decl_rtl (decl, asmspec)
              /* Make this register global, so not usable for anything
                 else.  */
 #ifdef ASM_DECLARE_REGISTER_GLOBAL
+             name = IDENTIFIER_POINTER (DECL_NAME (decl));
              ASM_DECLARE_REGISTER_GLOBAL (asm_out_file, decl, reg_number, name);
 #endif
-             nregs = HARD_REGNO_NREGS (reg_number, DECL_MODE (decl));
+             nregs = hard_regno_nregs[reg_number][DECL_MODE (decl)];
              while (nregs > 0)
                globalize_reg (reg_number + --nregs);
            }
@@ -878,13 +984,19 @@ make_decl_rtl (decl, asmspec)
          return;
        }
     }
-
   /* Now handle ordinary static variables and functions (in memory).
      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'");
+  else if (name[0] == '*')
+  {
+#ifdef REGISTER_PREFIX
+    if (strlen (REGISTER_PREFIX) != 0)
+      {
+       reg_number = decode_reg_name (name);
+       if (reg_number >= 0 || reg_number == -3)
+         error ("register name given for non-register variable %q+D", decl);
+      }
+#endif
+  }
 
   /* Specifying a section attribute on a variable forces it into a
      non-.bss section, and thus it cannot be common.  */
@@ -898,32 +1010,10 @@ make_decl_rtl (decl, asmspec)
   if (TREE_CODE (decl) == VAR_DECL && DECL_WEAK (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));
-    }
-
   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), x);
   if (TREE_CODE (decl) != FUNCTION_DECL)
     set_mem_attributes (x, decl, 1);
@@ -933,18 +1023,20 @@ 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, DECL_RTL (decl), true);
+  targetm.encode_section_info (decl, DECL_RTL (decl), true);
+
+  /* Make this function static known to the mudflap runtime.  */
+  if (flag_mudflap && TREE_CODE (decl) == VAR_DECL)
+    mudflap_enqueue_decl (decl);
 }
 
 /* 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 ();
+  gcc_assert (MEM_P (DECL_RTL (var)));
 
   MEM_VOLATILE_P (DECL_RTL (var)) = 1;
 }
@@ -953,8 +1045,7 @@ make_var_volatile (var)
    for an `asm' keyword used between functions.  */
 
 void
-assemble_asm (string)
-     tree string;
+assemble_asm (tree string)
 {
   app_enable ();
 
@@ -969,22 +1060,22 @@ 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 ATTRIBUTE_UNUSED,
+                                 int priority ATTRIBUTE_UNUSED)
 {
+#if defined DBX_DEBUGGING_INFO || defined XCOFF_DEBUGGING_INFO
   /* Tell GNU LD that this is part of the static destructor set.
      This will work for any system that uses stabs, most usefully
      aout systems.  */
-  fprintf (asm_out_file, "%s\"___DTOR_LIST__\",22,0,0,", ASM_STABS_OP);
-  assemble_name (asm_out_file, XSTR (symbol, 0));
-  fputc ('\n', asm_out_file);
+  dbxout_begin_simple_stabs ("___DTOR_LIST__", 22 /* N_SETT */);
+  dbxout_stab_value_label (XSTR (symbol, 0));
+#else
+  sorry ("global destructors not supported on this target");
+#endif
 }
 
 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];
@@ -1007,7 +1098,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)
     {
@@ -1018,9 +1109,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);
@@ -1031,22 +1121,22 @@ 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 ATTRIBUTE_UNUSED,
+                                  int priority ATTRIBUTE_UNUSED)
 {
+#if defined DBX_DEBUGGING_INFO || defined XCOFF_DEBUGGING_INFO
   /* Tell GNU LD that this is part of the static destructor set.
      This will work for any system that uses stabs, most usefully
      aout systems.  */
-  fprintf (asm_out_file, "%s\"___CTOR_LIST__\",22,0,0,", ASM_STABS_OP);
-  assemble_name (asm_out_file, XSTR (symbol, 0));
-  fputc ('\n', asm_out_file);
+  dbxout_begin_simple_stabs ("___CTOR_LIST__", 22 /* N_SETT */);
+  dbxout_stab_value_label (XSTR (symbol, 0));
+#else
+  sorry ("global constructors not supported on this target");
+#endif
 }
 
 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];
@@ -1069,7 +1159,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)
     {
@@ -1080,9 +1170,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);
@@ -1100,17 +1189,78 @@ 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)
+{
+  const char **type = &first_global_object_name;
+
+  if (first_global_object_name
+      || !TREE_PUBLIC (decl) || DECL_EXTERNAL (decl)
+      || !DECL_NAME (decl)
+      || (TREE_CODE (decl) != FUNCTION_DECL
+         && (TREE_CODE (decl) != VAR_DECL
+             || (DECL_COMMON (decl)
+                 && (DECL_INITIAL (decl) == 0
+                     || DECL_INITIAL (decl) == error_mark_node))))
+      || !MEM_P (DECL_RTL (decl)))
+    return;
+
+  /* We win when global object is found, but it is useful to know about weak
+     symbol as well so we can produce nicer unique names.  */
+  if (DECL_WEAK (decl) || DECL_ONE_ONLY (decl))
+    type = &weak_global_object_name;
+
+  if (!*type)
+    {
+      const char *p;
+      const char *name;
+      rtx decl_rtl = DECL_RTL (decl);
+
+      p = targetm.strip_name_encoding (XSTR (XEXP (decl_rtl, 0), 0));
+      name = ggc_strdup (p);
+
+      *type = 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;
+  char tmp_label[100];
+  bool hot_label_written = false;
+
+  cfun->unlikely_text_section_name = NULL;
+  first_function_block_is_cold = false;
+  if (flag_reorder_blocks_and_partition)
+    {
+      ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LHOTB", const_labelno);
+      cfun->hot_section_label = ggc_strdup (tmp_label);
+      ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LCOLDB", const_labelno);
+      cfun->cold_section_label = ggc_strdup (tmp_label);
+      ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LHOTE", const_labelno);
+      cfun->hot_section_end_label = ggc_strdup (tmp_label);
+      ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LCOLDE", const_labelno);
+      cfun->cold_section_end_label = ggc_strdup (tmp_label);
+      const_labelno++;
+    }
+  else
+    {
+      cfun->hot_section_label = NULL;
+      cfun->cold_section_label = NULL;
+      cfun->hot_section_end_label = NULL;
+      cfun->cold_section_end_label = NULL;
+    }
 
   /* The following code does not need preprocessing in the assembler.  */
 
@@ -1120,7 +1270,54 @@ assemble_start_function (decl, fnname)
     output_constant_pool (fnname, decl);
 
   resolve_unique_section (decl, 0, flag_function_sections);
+
+  /* Make sure the not and cold text (code) sections are properly
+     aligned.  This is necessary here in the case where the function
+     has both hot and cold sections, because we don't want to re-set
+     the alignment when the section switch happens mid-function.  */
+
+  if (flag_reorder_blocks_and_partition)
+    {
+      unlikely_text_section ();
+      assemble_align (FUNCTION_BOUNDARY);
+      ASM_OUTPUT_LABEL (asm_out_file, cfun->cold_section_label);
+
+      /* When the function starts with a cold section, we need to explicitly
+        align the hot section and write out the hot section label.
+        But if the current function is a thunk, we do not have a CFG.  */
+      if (!current_function_is_thunk
+         && BB_PARTITION (ENTRY_BLOCK_PTR->next_bb) == BB_COLD_PARTITION)
+       {
+         text_section ();
+         assemble_align (FUNCTION_BOUNDARY);
+         ASM_OUTPUT_LABEL (asm_out_file, cfun->hot_section_label);
+         hot_label_written = true;
+         first_function_block_is_cold = true;
+       }
+    }
+  else if (DECL_SECTION_NAME (decl))
+    {
+      /* Calls to function_section rely on first_function_block_is_cold
+        being accurate.  The first block may be cold even if we aren't
+        doing partitioning, if the entire function was decided by
+        choose_function_section (predict.c) to be cold.  */
+
+      initialize_cold_section_name ();
+
+      if (cfun->unlikely_text_section_name 
+         && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
+                    cfun->unlikely_text_section_name) == 0)
+       first_function_block_is_cold = true;
+    }
+
+  last_text_section = no_section;
+
+  /* Switch to the correct text section for the start of the function.  */
+
   function_section (decl);
+  if (flag_reorder_blocks_and_partition 
+      && !hot_label_written)
+    ASM_OUTPUT_LABEL (asm_out_file, cfun->hot_section_label);
 
   /* Tell assembler to move to target machine's alignment for functions.  */
   align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
@@ -1155,26 +1352,17 @@ 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 = xstrdup (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);
 
       maybe_assemble_visibility (decl);
     }
 
-  /* Do any machine/system dependent processing of the function name */
+  if (DECL_PRESERVE_P (decl))
+    targetm.asm_out.mark_decl_preserved (fnname);
+
+  /* Do any machine/system dependent processing of the function name.  */
 #ifdef ASM_DECLARE_FUNCTION_NAME
   ASM_DECLARE_FUNCTION_NAME (asm_out_file, fnname, current_function_decl);
 #else
@@ -1187,11 +1375,12 @@ 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
+  /* We could have switched section in the middle of the function.  */
+  if (flag_reorder_blocks_and_partition)
+    function_section (decl);
   ASM_DECLARE_FUNCTION_SIZE (asm_out_file, fnname, decl);
 #endif
   if (! CONSTANT_POOL_BEFORE_FUNCTION)
@@ -1199,13 +1388,29 @@ assemble_end_function (decl, fnname)
       output_constant_pool (fnname, decl);
       function_section (decl); /* need to switch back */
     }
+  /* Output labels for end of hot/cold text sections (to be used by
+     debug info.)  */
+  if (flag_reorder_blocks_and_partition)
+    {
+      enum in_section save_text_section;
+
+      save_text_section = in_section;
+      unlikely_text_section ();
+      ASM_OUTPUT_LABEL (asm_out_file, cfun->cold_section_end_label);
+      if (first_function_block_is_cold)
+       text_section ();
+      else
+       function_section (decl);
+      ASM_OUTPUT_LABEL (asm_out_file, cfun->hot_section_end_label);
+      if (save_text_section == in_unlikely_executed_text)
+       unlikely_text_section ();
+    }
 }
 \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)
@@ -1214,9 +1419,10 @@ assemble_zeros (size)
 #ifdef ASM_NO_SKIP_IN_TEXT
   /* The `space' pseudo in the text section outputs nop insns rather than 0s,
      so we must output 0s explicitly in the text section.  */
-  if (ASM_NO_SKIP_IN_TEXT && in_text_section ())
+  if ((ASM_NO_SKIP_IN_TEXT && in_text_section ())
+      || (ASM_NO_SKIP_IN_TEXT && in_unlikely_text_section ()))
     {
-      int i;
+      unsigned HOST_WIDE_INT i;
       for (i = 0; i < size; i++)
        assemble_integer (const0_rtx, 1, BITS_PER_UNIT, 1);
     }
@@ -1229,8 +1435,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)
     {
@@ -1241,9 +1446,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;
@@ -1303,11 +1506,9 @@ assemble_string (p, size)
 #endif
 
 static bool
-asm_emit_uninitialised (decl, name, size, rounded)
-     tree decl;
-     const char *name;
-     int size ATTRIBUTE_UNUSED;
-     int rounded ATTRIBUTE_UNUSED;
+asm_emit_uninitialised (tree decl, const char *name,
+                       unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
+                       unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
 {
   enum
   {
@@ -1331,9 +1532,16 @@ asm_emit_uninitialised (decl, name, size, rounded)
        destination = asm_dest_common;
     }
 
+  if (destination != asm_dest_common)
+    {
+      resolve_unique_section (decl, 0, flag_data_sections);
+      /* Custom sections don't belong here.  */
+      if (DECL_SECTION_NAME (decl))
+        return false;
+    }
+
   if (destination == asm_dest_bss)
     globalize_decl (decl);
-  resolve_unique_section (decl, 0, flag_data_sections);
 
   if (flag_shared_data)
     {
@@ -1373,7 +1581,7 @@ asm_emit_uninitialised (decl, name, size, rounded)
       ASM_EMIT_LOCAL (decl, name, size, rounded);
       break;
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
   return true;
@@ -1390,17 +1598,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,
@@ -1417,7 +1625,7 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
     return;
 
   /* Do nothing for global register variables.  */
-  if (DECL_RTL_SET_P (decl) && GET_CODE (DECL_RTL (decl)) == REG)
+  if (DECL_RTL_SET_P (decl) && REG_P (DECL_RTL (decl)))
     {
       TREE_ASM_WRITTEN (decl) = 1;
       return;
@@ -1434,10 +1642,7 @@ 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 ("storage size of %q+D isn%'t known", decl);
       TREE_ASM_WRITTEN (decl) = 1;
       return;
     }
@@ -1465,25 +1670,13 @@ 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 ("size of variable %q+D is too large", 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 = xstrdup (p);
-      first_global_object_name = xname;
-    }
+  if (TREE_PUBLIC (decl) && DECL_NAME (decl))
+    notice_global_symbol (decl);
 
   /* Compute the alignment of this data.  */
 
@@ -1498,14 +1691,11 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
 
   /* Some object file formats have a maximum alignment which they support.
      In particular, a.out format supports a maximum alignment of 4.  */
-#ifndef MAX_OFILE_ALIGNMENT
-#define MAX_OFILE_ALIGNMENT BIGGEST_ALIGNMENT
-#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 (0, "alignment of %q+D is greater than maximum object "
+               "file alignment.  Using %d", decl,
+              MAX_OFILE_ALIGNMENT/BITS_PER_UNIT);
       align = MAX_OFILE_ALIGNMENT;
     }
 
@@ -1529,12 +1719,8 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
   if (TREE_PUBLIC (decl))
     maybe_assemble_visibility (decl);
 
-  /* Output any data that we will need to use the address of.  */
-  if (DECL_INITIAL (decl) == error_mark_node)
-    reloc = contains_pointers_p (TREE_TYPE (decl)) ? 3 : 0;
-  else if (DECL_INITIAL (decl))
-    reloc = output_addressed_constants (DECL_INITIAL (decl));
-  resolve_unique_section (decl, reloc, flag_data_sections);
+  if (DECL_PRESERVE_P (decl))
+    targetm.asm_out.mark_decl_preserved (name);
 
   /* Handle uninitialized definitions.  */
 
@@ -1543,7 +1729,7 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
   if (DECL_SECTION_NAME (decl) || dont_output_data)
     ;
   /* We don't implement common thread-local data at present.  */
-  else if (DECL_THREAD_LOCAL (decl))
+  else if (DECL_THREAD_LOCAL_P (decl))
     {
       if (DECL_COMMON (decl))
        sorry ("thread-local COMMON data not implemented");
@@ -1570,9 +1756,9 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
                 * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
 
 #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);
+      if ((unsigned HOST_WIDE_INT) DECL_ALIGN_UNIT (decl) > rounded)
+       warning (0, "requested alignment for %q+D is greater than "
+                 "implemented alignment of %wu", decl, rounded);
 #endif
 
       /* If the target cannot output uninitialized but not common global data
@@ -1589,19 +1775,26 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
   if (TREE_PUBLIC (decl) && DECL_NAME (decl))
     globalize_decl (decl);
 
+  /* Output any data that we will need to use the address of.  */
+  if (DECL_INITIAL (decl) == error_mark_node)
+    reloc = contains_pointers_p (TREE_TYPE (decl)) ? 3 : 0;
+  else if (DECL_INITIAL (decl))
+    {
+      reloc = compute_reloc_for_constant (DECL_INITIAL (decl));
+      output_addressed_constants (DECL_INITIAL (decl));
+    }
+
   /* Switch to the appropriate section.  */
+  resolve_unique_section (decl, reloc, flag_data_sections);
   variable_section (decl, reloc);
 
   /* dbxout.c needs to know this.  */
-  if (in_text_section ())
+  if (in_text_section () || in_unlikely_text_section ())
     DECL_IN_TEXT_SECTION (decl) = 1;
 
   /* Output the alignment of this data.  */
   if (align > BITS_PER_UNIT)
-    {
-      ASM_OUTPUT_ALIGN (asm_out_file,
-                       floor_log2 (DECL_ALIGN (decl) / BITS_PER_UNIT));
-    }
+    ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DECL_ALIGN_UNIT (decl)));
 
   /* Do any machine/system dependent processing of the object.  */
 #ifdef ASM_DECLARE_OBJECT_NAME
@@ -1614,7 +1807,9 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
 
   if (!dont_output_data)
     {
-      if (DECL_INITIAL (decl) && DECL_INITIAL (decl) != error_mark_node)
+      if (DECL_INITIAL (decl)
+         && DECL_INITIAL (decl) != error_mark_node
+         && !initializer_zerop (DECL_INITIAL (decl)))
        /* Output the actual data.  */
        output_constant (DECL_INITIAL (decl),
                         tree_low_cst (DECL_SIZE_UNIT (decl), 1),
@@ -1628,8 +1823,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))
     {
@@ -1662,94 +1856,184 @@ contains_pointers_p (type)
     }
 }
 
-/* Output something to declare an external symbol to the assembler.
-   (Most assemblers don't need this, so we normally output nothing.)
-   Do nothing if DECL is not external.  */
-
-void
-assemble_external (decl)
-     tree decl ATTRIBUTE_UNUSED;
-{
-  /* Because most platforms do not define ASM_OUTPUT_EXTERNAL, the
-     main body of this code is only rarely exercised.  To provide some
-     testing, on all platforms, we make sure that the ASM_OUT_FILE is
-     open.  If it's not, we should not be calling this function.  */
-  if (!asm_out_file)
-    abort ();
+/* In unit-at-a-time mode, we delay assemble_external processing until
+   the compilation unit is finalized.  This is the best we can do for
+   right now (i.e. stage 3 of GCC 4.0) - the right thing is to delay
+   it all the way to final.  See PR 17982 for further discussion.  */
+static GTY(()) tree pending_assemble_externals;
 
 #ifdef ASM_OUTPUT_EXTERNAL
-  if (DECL_P (decl) && DECL_EXTERNAL (decl) && TREE_PUBLIC (decl))
+/* True if DECL is a function decl for which no out-of-line copy exists.
+   It is assumed that DECL's assembler name has been set.  */
+
+static bool
+incorporeal_function_p (tree decl)
+{
+  if (TREE_CODE (decl) == FUNCTION_DECL && DECL_BUILT_IN (decl))
     {
-      rtx rtl = DECL_RTL (decl);
+      const char *name;
 
-      if (GET_CODE (rtl) == MEM && GET_CODE (XEXP (rtl, 0)) == SYMBOL_REF
-         && ! SYMBOL_REF_USED (XEXP (rtl, 0)))
-       {
-         /* Some systems do require some output.  */
-         SYMBOL_REF_USED (XEXP (rtl, 0)) = 1;
-         ASM_OUTPUT_EXTERNAL (asm_out_file, decl, XSTR (XEXP (rtl, 0), 0));
-       }
+      if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
+         && DECL_FUNCTION_CODE (decl) == BUILT_IN_ALLOCA)
+       return true;
+
+      name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+      if (strncmp (name, "__builtin_", strlen ("__builtin_")) == 0)
+       return true;
     }
-#endif
+  return false;
 }
 
-/* Similar, for calling a library function FUN.  */
+/* Actually do the tests to determine if this is necessary, and invoke
+   ASM_OUTPUT_EXTERNAL.  */
+static void
+assemble_external_real (tree decl)
+{
+  rtx rtl = DECL_RTL (decl);
+
+  if (MEM_P (rtl) && GET_CODE (XEXP (rtl, 0)) == SYMBOL_REF
+      && !SYMBOL_REF_USED (XEXP (rtl, 0))
+      && !incorporeal_function_p (decl))
+    {
+      /* Some systems do require some output.  */
+      SYMBOL_REF_USED (XEXP (rtl, 0)) = 1;
+      ASM_OUTPUT_EXTERNAL (asm_out_file, decl, XSTR (XEXP (rtl, 0), 0));
+    }
+}
+#endif
+
+void
+process_pending_assemble_externals (void)
+{
+#ifdef ASM_OUTPUT_EXTERNAL
+  tree list;
+  for (list = pending_assemble_externals; list; list = TREE_CHAIN (list))
+    assemble_external_real (TREE_VALUE (list));
+
+  pending_assemble_externals = 0;
+#endif
+}
+
+/* Output something to declare an external symbol to the assembler.
+   (Most assemblers don't need this, so we normally output nothing.)
+   Do nothing if DECL is not external.  */
+
+void
+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
+     testing, on all platforms, we make sure that the ASM_OUT_FILE is
+     open.  If it's not, we should not be calling this function.  */
+  gcc_assert (asm_out_file);
+
+#ifdef ASM_OUTPUT_EXTERNAL
+  if (!DECL_P (decl) || !DECL_EXTERNAL (decl) || !TREE_PUBLIC (decl))
+    return;
+
+  if (flag_unit_at_a_time)
+    pending_assemble_externals = tree_cons (0, decl,
+                                           pending_assemble_externals);
+  else
+    assemble_external_real (decl);
+#endif
+}
+
+/* Similar, for calling a library function FUN.  */
 
 void
-assemble_external_libcall (fun)
-     rtx fun ATTRIBUTE_UNUSED;
+assemble_external_libcall (rtx fun)
 {
-#ifdef ASM_OUTPUT_EXTERNAL_LIBCALL
   /* Declare library function name external when first used, if nec.  */
   if (! SYMBOL_REF_USED (fun))
     {
       SYMBOL_REF_USED (fun) = 1;
-      ASM_OUTPUT_EXTERNAL_LIBCALL (asm_out_file, fun);
+      targetm.asm_out.external_libcall (fun);
     }
-#endif
 }
 
 /* Assemble a label named NAME.  */
 
 void
-assemble_label (name)
-     const char *name;
+assemble_label (const char *name)
 {
   ASM_OUTPUT_LABEL (asm_out_file, name);
 }
 
-/* Output to FILE a reference to the assembler name of a C-level name NAME.
-   If NAME starts with a *, the rest of NAME is output verbatim.
-   Otherwise NAME is transformed in an implementation-defined way
-   (usually by the addition of an underscore).
-   Many macros in the tm file are defined to call this function.  */
+/* Set the symbol_referenced flag for ID.  */
+void
+mark_referenced (tree id)
+{
+  TREE_SYMBOL_REFERENCED (id) = 1;
+}
+
+/* Set the symbol_referenced flag for DECL and notify callgraph.  */
+void
+mark_decl_referenced (tree decl)
+{
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    {
+      /* Extern inline functions don't become needed when referenced.
+        If we know a method will be emitted in other TU and no new
+        functions can be marked reachable, just use the external
+        definition.  */
+      struct cgraph_node *node = cgraph_node (decl);
+      if (!DECL_EXTERNAL (decl)
+         && (!node->local.vtable_method || !cgraph_global_info_ready
+             || !node->local.finalized))
+       cgraph_mark_needed_node (node);
+    }
+  else if (TREE_CODE (decl) == VAR_DECL)
+    {
+      struct cgraph_varpool_node *node = cgraph_varpool_node (decl);
+      cgraph_varpool_mark_needed_node (node);
+      /* C++ frontend use mark_decl_references to force COMDAT variables
+         to be output that might appear dead otherwise.  */
+      node->force_output = true;
+    }
+  /* else do nothing - we can get various sorts of CST nodes here,
+     which do not need to be marked.  */
+}
+
+/* Output to FILE (an assembly file) a reference to NAME.  If NAME
+   starts with a *, the rest of NAME is output verbatim.  Otherwise
+   NAME is transformed in a target-specific way (usually by the
+   addition of an underscore).  */
+
+void
+assemble_name_raw (FILE *file, const char *name)
+{
+  if (name[0] == '*')
+    fputs (&name[1], file);
+  else
+    ASM_OUTPUT_LABELREF (file, name);
+}
+
+/* Like assemble_name_raw, but should be used when NAME might refer to
+   an entity that is also represented as a tree (like a function or
+   variable).  If NAME does refer to such an entity, that entity will
+   be marked as referenced.  */
 
 void
-assemble_name (file, name)
-     FILE *file;
-     const char *name;
+assemble_name (FILE *file, const char *name)
 {
   const char *real_name;
   tree id;
 
-  real_name = (* targetm.strip_name_encoding) (name);
+  real_name = targetm.strip_name_encoding (name);
 
   id = maybe_get_identifier (real_name);
   if (id)
-    TREE_SYMBOL_REFERENCED (id) = 1;
+    mark_referenced (id);
 
-  if (name[0] == '*')
-    fputs (&name[1], file);
-  else
-    ASM_OUTPUT_LABELREF (file, name);
+  assemble_name_raw (file, name);
 }
 
 /* Allocate SIZE bytes writable static space with a gensym 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;
@@ -1778,7 +2062,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));
@@ -1793,15 +2077,20 @@ assemble_static_space (size)
    This is done at most once per compilation.
    Returns an RTX for the address of the template.  */
 
+static GTY(()) rtx initial_trampoline;
+
 #ifdef TRAMPOLINE_TEMPLATE
 rtx
-assemble_trampoline_template ()
+assemble_trampoline_template (void)
 {
   char label[256];
   const char *name;
   int align;
   rtx symbol;
 
+  if (initial_trampoline)
+    return initial_trampoline;
+
   /* By default, put trampoline templates in read-only data section.  */
 
 #ifdef TRAMPOLINE_SECTION
@@ -1817,7 +2106,7 @@ assemble_trampoline_template ()
       ASM_OUTPUT_ALIGN (asm_out_file, align);
     }
 
-  (*targetm.asm_out.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.  */
@@ -1826,7 +2115,10 @@ assemble_trampoline_template ()
   symbol = gen_rtx_SYMBOL_REF (Pmode, name);
   SYMBOL_REF_FLAGS (symbol) = SYMBOL_FLAG_LOCAL;
 
-  return symbol;
+  initial_trampoline = gen_rtx_MEM (BLKmode, symbol);
+  set_mem_align (initial_trampoline, TRAMPOLINE_ALIGNMENT);
+
+  return initial_trampoline;
 }
 #endif
 \f
@@ -1834,8 +2126,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);
 }
@@ -1849,9 +2140,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;
 
@@ -1881,9 +2170,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);
@@ -1893,33 +2180,32 @@ 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);
+  /* Avoid GAS bugs for large values.  Specifically negative values whose
+     absolute value fits in a bfd_vma, but not in a bfd_signed_vma.  */
+  if (size > UNITS_PER_WORD && size > POINTER_SIZE / BITS_PER_UNIT)
+    return false;
   return op && (assemble_integer_with_op (op, x), true);
 }
 
 /* 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 nonzero, abort if we can't output
-   the constant.  */
+   the constant, otherwise 0.  We must be able to output the constant,
+   if FORCE is nonzero.  */
 
 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;
 
   aligned_p = (align >= MIN (size * BITS_PER_UNIT, BIGGEST_ALIGNMENT));
 
   /* See if the target hook can handle this kind of object.  */
-  if ((*targetm.asm_out.integer) (x, size, aligned_p))
+  if (targetm.asm_out.integer (x, size, aligned_p))
     return true;
 
   /* If the object is a multi-byte one, try splitting it up.  Split
@@ -1946,101 +2232,58 @@ assemble_integer (x, size, align, force)
 
       /* If we've printed some of it, but not all of it, there's no going
         back now.  */
-      if (i > 0)
-       abort ();
+      gcc_assert (!i);
     }
 
-  if (force)
-    abort ();
-
+  gcc_assert (!force);
+  
   return false;
 }
 \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;
-  unsigned int nalign = min_align (align, 32);
+  int i;
+  int bitsize, nelts, nunits, units_per;
 
-  switch (BITS_PER_UNIT)
-    {
-    case 8:
-      switch (mode)
-       {
-       case SFmode:
-         REAL_VALUE_TO_TARGET_SINGLE (d, l);
-         assemble_integer (GEN_INT (l), 4, align, 1);
-         break;
-       case DFmode:
-         REAL_VALUE_TO_TARGET_DOUBLE (d, data);
-         assemble_integer (GEN_INT (data[0]), 4, align, 1);
-         assemble_integer (GEN_INT (data[1]), 4, nalign, 1);
-         break;
-       case XFmode:
-         REAL_VALUE_TO_TARGET_LONG_DOUBLE (d, data);
-         assemble_integer (GEN_INT (data[0]), 4, align, 1);
-         assemble_integer (GEN_INT (data[1]), 4, nalign, 1);
-         assemble_integer (GEN_INT (data[2]), 4, nalign, 1);
-         break;
-       case TFmode:
-         REAL_VALUE_TO_TARGET_LONG_DOUBLE (d, data);
-         assemble_integer (GEN_INT (data[0]), 4, align, 1);
-         assemble_integer (GEN_INT (data[1]), 4, nalign, 1);
-         assemble_integer (GEN_INT (data[2]), 4, nalign, 1);
-         assemble_integer (GEN_INT (data[3]), 4, nalign, 1);
-         break;
-       default:
-         abort ();
-       }
-      break;
+  /* This is hairy.  We have a quantity of known size.  real_to_target
+     will put it into an array of *host* longs, 32 bits per element
+     (even if long is more than 32 bits).  We need to determine the
+     number of array elements that are occupied (nelts) and the number
+     of *target* min-addressable units that will be occupied in the
+     object file (nunits).  We cannot assume that 32 divides the
+     mode's bitsize (size * BITS_PER_UNIT) evenly.
 
-    case 16:
-      switch (mode)
-       {
-       case HFmode:
-         REAL_VALUE_TO_TARGET_SINGLE (d, l);
-         assemble_integer (GEN_INT (l), 2, align, 1);
-         break;
-       case TQFmode:
-         REAL_VALUE_TO_TARGET_DOUBLE (d, data);
-         assemble_integer (GEN_INT (data[0]), 2, align, 1);
-         assemble_integer (GEN_INT (data[1]), 1, nalign, 1);
-         break;
-       default:
-         abort ();
-       }
-      break;
+     size * BITS_PER_UNIT is used here to make sure that padding bits
+     (which might appear at either end of the value; real_to_target
+     will include the padding bits in its output array) are included.  */
 
-    case 32:
-      switch (mode)
-       {
-       case QFmode:
-         REAL_VALUE_TO_TARGET_SINGLE (d, l);
-         assemble_integer (GEN_INT (l), 1, align, 1);
-         break;
-       case HFmode:
-         REAL_VALUE_TO_TARGET_DOUBLE (d, data);
-         assemble_integer (GEN_INT (data[0]), 1, align, 1);
-         assemble_integer (GEN_INT (data[1]), 1, nalign, 1);
-         break;
-       default:
-         abort ();
-       }
-      break;
+  nunits = GET_MODE_SIZE (mode);
+  bitsize = nunits * BITS_PER_UNIT;
+  nelts = CEIL (bitsize, 32);
+  units_per = 32 / BITS_PER_UNIT;
 
-    default:
-      abort ();
+  real_to_target (data, &d, mode);
+
+  /* Put out the first word with the specified alignment.  */
+  assemble_integer (GEN_INT (data[0]), MIN (nunits, units_per), align, 1);
+  nunits -= units_per;
+
+  /* Subsequent words need only 32-bit alignment.  */
+  align = min_align (align, 32);
+
+  for (i = 1; i < nelts; i++)
+    {
+      assemble_integer (GEN_INT (data[i]), MIN (nunits, units_per), align, 1);
+      nunits -= units_per;
     }
 }
 \f
 /* Given an expression EXP with a constant value,
    reduce it to the sum of an assembler symbol and an integer.
    Store them both in the structure *VALUE.
-   Abort if EXP does not reduce.  */
+   EXP must be reducible.  */
 
 struct addr_const GTY(())
 {
@@ -2049,9 +2292,7 @@ struct addr_const GTY(())
 };
 
 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;
@@ -2086,8 +2327,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 (Pmode, force_label_rtx (target)));
       break;
 
     case REAL_CST:
@@ -2095,130 +2335,57 @@ 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;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
-  if (GET_CODE (x) != MEM)
-    abort ();
+  gcc_assert (MEM_P (x));
   x = XEXP (x, 0);
 
   value->base = x;
   value->offset = offset;
 }
 \f
-/* We do RTX_UNSPEC + XINT (blah), so nothing can go after RTX_UNSPEC.  */
-enum kind { RTX_UNKNOWN, RTX_DOUBLE, RTX_VECTOR, RTX_INT, RTX_UNSPEC };
-struct rtx_const GTY(())
-{
-  ENUM_BITFIELD(kind) kind : 16;
-  ENUM_BITFIELD(machine_mode) mode : 16;
-  union rtx_const_un {
-    REAL_VALUE_TYPE GTY ((tag ("4"))) du;
-    struct rtx_const_u_addr {
-      rtx base;
-      const char *symbol;
-      HOST_WIDE_INT offset;
-    } GTY ((tag ("1"))) addr;
-    struct rtx_const_u_di {
-      HOST_WIDE_INT high;
-      HOST_WIDE_INT low;
-    } GTY ((tag ("0"))) di;
-
-    /* The max vector size we have is 16 wide; two variants for
-       integral and floating point vectors.  */
-    struct rtx_const_int_vec {
-      HOST_WIDE_INT high;
-      HOST_WIDE_INT low;
-    } GTY ((tag ("2"))) int_vec[16];
-
-    REAL_VALUE_TYPE GTY ((tag ("3"))) fp_vec[8];
-
-  } GTY ((desc ("%1.kind >= RTX_INT"), descbits ("1"))) un;
-};
-
 /* Uniquize all constants that appear in memory.
    Each constant in memory thus far output is recorded
-   in `const_hash_table'.  */
+   in `const_desc_table'.  */
 
 struct constant_descriptor_tree GTY(())
 {
-  /* More constant_descriptors with the same hash code.  */
-  struct constant_descriptor_tree *next;
-
-  /* The label of the constant.  */
-  const char *label;
-
   /* A MEM for the constant.  */
   rtx rtl;
 
   /* The value of the constant.  */
   tree value;
-};
-
-#define MAX_HASH_TABLE 1009
-static GTY(()) struct constant_descriptor_tree *
-  const_hash_table[MAX_HASH_TABLE];
-
-static struct constant_descriptor_tree * build_constant_desc PARAMS ((tree));
-
-/* 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) htab_hash_pointer (x)
 
-struct deferred_string GTY(())
-{
-  const char *label;
-  tree exp;
+  /* Hash of value.  Computing the hash from value each time
+     hashfn is called can't work properly, as that means recursive
+     use of the hash table during hash table expansion.  */
+  hashval_t hash;
 };
 
-static GTY ((param_is (struct deferred_string))) htab_t const_str_htab;
-
-/* Returns a hash code for X (which is a really a
-   struct deferred_string *).  */
-
-static hashval_t
-const_str_htab_hash (x)
-     const void *x;
-{
-  return STRHASH (((const struct deferred_string *) x)->label);
-}
-
-/* Returns nonzero 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 GTY((param_is (struct constant_descriptor_tree)))
+     htab_t const_desc_htab;
 
-static int
-const_str_htab_eq (x, y)
-     const void *x;
-     const void *y;
-{
-  return (((const struct deferred_string *) x)->label == (const char *) y);
-}
+static struct constant_descriptor_tree * build_constant_desc (tree);
+static void maybe_output_constant_def_contents (struct constant_descriptor_tree *, int);
 
 /* Compute a hash code for a constant expression.  */
 
-static unsigned int
-const_hash (exp)
-     tree exp;
+static hashval_t
+const_desc_hash (const void *ptr)
 {
-  return const_hash_1 (exp) % MAX_HASH_TABLE;
+  return ((struct constant_descriptor_tree *)ptr)->hash;
 }
 
-static unsigned int
-const_hash_1 (exp)
-     tree exp;
+static hashval_t
+const_hash_1 (const tree exp)
 {
   const char *p;
-  unsigned int hi;
+  hashval_t hi;
   int len, i;
   enum tree_code code = TREE_CODE (exp);
 
@@ -2245,28 +2412,18 @@ const_hash_1 (exp)
              + const_hash_1 (TREE_IMAGPART (exp)));
 
     case CONSTRUCTOR:
-      if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
-       {
-         char *tmp;
-
-         len = int_size_in_bytes (TREE_TYPE (exp));
-         tmp = (char *) alloca (len);
-         get_set_constructor_bytes (exp, (unsigned char *) tmp, len);
-         p = tmp;
-         break;
-       }
-      else
-       {
-         tree link;
-
-         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_1 (TREE_VALUE (link));
-
-         return hi;
-       }
+      {
+       unsigned HOST_WIDE_INT idx;
+       tree value;
+       
+       hi = 5 + int_size_in_bytes (TREE_TYPE (exp));
+       
+       FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, value)
+         if (value)
+           hi = hi * 603 + const_hash_1 (value);
+       
+       return hi;
+      }
 
     case ADDR_EXPR:
     case FDESC_EXPR:
@@ -2274,19 +2431,24 @@ const_hash_1 (exp)
        struct addr_const value;
 
        decode_addr_const (exp, &value);
-       if (GET_CODE (value.base) == SYMBOL_REF)
+       switch (GET_CODE (value.base))
          {
+         case SYMBOL_REF:
            /* Don't hash the address of the SYMBOL_REF;
               only use the offset and the symbol name.  */
            hi = value.offset;
            p = XSTR (value.base, 0);
            for (i = 0; p[i] != 0; i++)
              hi = ((hi * 613) + (unsigned) (p[i]));
+           break;
+
+         case LABEL_REF:
+           hi = value.offset + CODE_LABEL_NUMBER (XEXP (value.base, 0)) * 13;
+           break;
+
+         default:
+           gcc_unreachable ();
          }
-       else if (GET_CODE (value.base) == LABEL_REF)
-         hi = value.offset + CODE_LABEL_NUMBER (XEXP (value.base, 0)) * 13;
-       else
-         abort ();
       }
       return hi;
 
@@ -2305,7 +2467,7 @@ const_hash_1 (exp)
       return code;
     }
 
-  /* Compute hashing function */
+  /* Compute hashing function */
   hi = len;
   for (i = 0; i < len; i++)
     hi = ((hi * 613) + (unsigned) (p[i]));
@@ -2313,13 +2475,22 @@ const_hash_1 (exp)
   return hi;
 }
 
+/* Wrapper of compare_constant, for the htab interface.  */
+static int
+const_desc_eq (const void *p1, const void *p2)
+{
+  const struct constant_descriptor_tree *c1 = p1;
+  const struct constant_descriptor_tree *c2 = p2;
+  if (c1->hash != c2->hash)
+    return 0;
+  return compare_constant (c1->value, c2->value);
+}
+
 /* Compare t1 and t2, and return 1 only if they are known to result in
    the same bit pattern on output.  */
 
 static int
-compare_constant (t1, t2)
-     tree t1;
-     tree t2;
+compare_constant (const tree t1, const tree t2)
 {
   enum tree_code typecode;
 
@@ -2347,9 +2518,6 @@ compare_constant (t1, t2)
       return REAL_VALUES_IDENTICAL (TREE_REAL_CST (t1), TREE_REAL_CST (t2));
 
     case STRING_CST:
-      if (flag_writable_strings)
-       return 0;
-
       if (TYPE_MODE (TREE_TYPE (t1)) != TYPE_MODE (TREE_TYPE (t2)))
        return 0;
 
@@ -2362,72 +2530,60 @@ compare_constant (t1, t2)
              && compare_constant (TREE_IMAGPART (t1), TREE_IMAGPART (t2)));
 
     case CONSTRUCTOR:
-      typecode = TREE_CODE (TREE_TYPE (t1));
-      if (typecode != TREE_CODE (TREE_TYPE (t2)))
-       return 0;
-
-      if (typecode == SET_TYPE)
-       {
-         int len = int_size_in_bytes (TREE_TYPE (t2));
-         unsigned char *tmp1, *tmp2;
-
-         if (int_size_in_bytes (TREE_TYPE (t1)) != len)
-           return 0;
+      {
+       VEC(constructor_elt, gc) *v1, *v2;
+       unsigned HOST_WIDE_INT idx;
+       
+       typecode = TREE_CODE (TREE_TYPE (t1));
+       if (typecode != TREE_CODE (TREE_TYPE (t2)))
+         return 0;
 
-         tmp1 = (unsigned char *) alloca (len);
-         tmp2 = (unsigned char *) alloca (len);
+       if (typecode == ARRAY_TYPE)
+         {
+           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;
+         }
+       else
+         {
+           /* For record and union constructors, require exact type
+               equality.  */
+           if (TREE_TYPE (t1) != TREE_TYPE (t2))
+             return 0;
+         }
 
-         if (get_set_constructor_bytes (t1, tmp1, len) != NULL_TREE)
+       v1 = CONSTRUCTOR_ELTS (t1);
+       v2 = CONSTRUCTOR_ELTS (t2);
+       if (VEC_length (constructor_elt, v1)
+           != VEC_length (constructor_elt, v2))
            return 0;
-         if (get_set_constructor_bytes (t2, tmp2, len) != NULL_TREE)
-           return 0;
-
-         return memcmp (tmp1, tmp2, len) != 0;
-       }
-      else
-       {
-         tree l1, l2;
-
-         if (typecode == ARRAY_TYPE)
-           {
-             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;
-           }
-         else
-           {
-             /* For record and union constructors, require exact type
-                 equality.  */
-             if (TREE_TYPE (t1) != TREE_TYPE (t2))
-               return 0;
-           }
-
-         for (l1 = CONSTRUCTOR_ELTS (t1), l2 = CONSTRUCTOR_ELTS (t2);
-              l1 && l2;
-              l1 = TREE_CHAIN (l1), l2 = TREE_CHAIN (l2))
-           {
-             /* 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 (! compare_constant (TREE_PURPOSE (l1),
-                                         TREE_PURPOSE (l2)))
-                   return 0;
-               }
-             else
-               {
-                 if (TREE_PURPOSE (l1) != TREE_PURPOSE (l2))
-                   return 0;
-               }
-           }
 
-         return l1 == NULL_TREE && l2 == NULL_TREE;
-       }
+       for (idx = 0; idx < VEC_length (constructor_elt, v1); ++idx)
+         {
+           constructor_elt *c1 = VEC_index (constructor_elt, v1, idx);
+           constructor_elt *c2 = VEC_index (constructor_elt, v2, idx);
+
+           /* Check that each value is the same...  */
+           if (!compare_constant (c1->value, c2->value))
+             return 0;
+           /* ... and that they apply to the same fields!  */
+           if (typecode == ARRAY_TYPE)
+             {
+               if (!compare_constant (c1->index, c2->index))
+                 return 0;
+             }
+           else
+             {
+               if (c1->index != c2->index)
+                 return 0;
+             }
+         }
+       
+       return 1;
+      }
 
     case ADDR_EXPR:
     case FDESC_EXPR:
@@ -2449,13 +2605,14 @@ compare_constant (t1, t2)
     case NOP_EXPR:
     case CONVERT_EXPR:
     case NON_LVALUE_EXPR:
+    case VIEW_CONVERT_EXPR:
       return compare_constant (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
 
     default:
       {
        tree nt1, nt2;
-       nt1 = (*lang_hooks.expand_constant) (t1);
-       nt2 = (*lang_hooks.expand_constant) (t2);
+       nt1 = lang_hooks.expand_constant (t1);
+       nt2 = lang_hooks.expand_constant (t2);
        if (nt1 != t1 || nt2 != t2)
          return compare_constant (nt1, nt2);
        else
@@ -2463,23 +2620,21 @@ compare_constant (t1, t2)
       }
     }
 
-  /* Should not get here.  */
-  abort ();
+  gcc_unreachable ();
 }
 \f
 /* 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))
     {
     case ADDR_EXPR:
       /* For ADDR_EXPR, we do not want to copy the decl whose address
         is requested.  We do want to copy constants though.  */
-      if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == 'c')
+      if (CONSTANT_CLASS_P (TREE_OPERAND (exp, 0)))
        return build1 (TREE_CODE (exp), TREE_TYPE (exp),
                       copy_constant (TREE_OPERAND (exp, 0)));
       else
@@ -2497,40 +2652,42 @@ copy_constant (exp)
 
     case PLUS_EXPR:
     case MINUS_EXPR:
-      return build (TREE_CODE (exp), TREE_TYPE (exp),
-                   copy_constant (TREE_OPERAND (exp, 0)),
-                   copy_constant (TREE_OPERAND (exp, 1)));
+      return build2 (TREE_CODE (exp), TREE_TYPE (exp),
+                    copy_constant (TREE_OPERAND (exp, 0)),
+                    copy_constant (TREE_OPERAND (exp, 1)));
 
     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)));
 
     case CONSTRUCTOR:
       {
        tree copy = copy_node (exp);
-       tree list = copy_list (CONSTRUCTOR_ELTS (exp));
-       tree tail;
-
-       CONSTRUCTOR_ELTS (copy) = list;
-       for (tail = list; tail; tail = TREE_CHAIN (tail))
-         TREE_VALUE (tail) = copy_constant (TREE_VALUE (tail));
-       if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
-         for (tail = list; tail; tail = TREE_CHAIN (tail))
-           TREE_PURPOSE (tail) = copy_constant (TREE_PURPOSE (tail));
-
+       VEC(constructor_elt, gc) *v;
+       unsigned HOST_WIDE_INT idx;
+       tree purpose, value;
+       
+       v = VEC_alloc(constructor_elt, gc, VEC_length(constructor_elt,
+                                                     CONSTRUCTOR_ELTS (exp)));
+       FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (exp), idx, purpose, value)
+         {
+           constructor_elt *ce = VEC_quick_push (constructor_elt, v, NULL);
+           ce->index = purpose;
+           ce->value = copy_constant (value);
+         }
+       CONSTRUCTOR_ELTS (copy) = v;
        return copy;
       }
 
     default:
       {
-       tree t;
-       t = (*lang_hooks.expand_constant) (exp);
-       if (t != exp)
-         return copy_constant (t);
-       else
-         abort ();
+       tree t = lang_hooks.expand_constant (exp);
+       
+       gcc_assert (t == exp);
+       return copy_constant (t);
       }
     }
 }
@@ -2543,8 +2700,7 @@ copy_constant (exp)
    Caller is responsible for updating the hash table.  */
 
 static struct constant_descriptor_tree *
-build_constant_desc (exp)
-     tree exp;
+build_constant_desc (tree exp)
 {
   rtx symbol;
   rtx rtl;
@@ -2555,6 +2711,10 @@ build_constant_desc (exp)
   desc = ggc_alloc (sizeof (*desc));
   desc->value = copy_constant (exp);
 
+  /* Propagate marked-ness to copied constant.  */
+  if (flag_mudflap && mf_marked_p (exp))
+    mf_mark (desc->value);
+
   /* Create a string containing the label name, in LABEL.  */
   labelno = const_labelno++;
   ASM_GENERATE_INTERNAL_LABEL (label, "LC", labelno);
@@ -2562,6 +2722,8 @@ build_constant_desc (exp)
   /* 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);
@@ -2571,11 +2733,12 @@ build_constant_desc (exp)
   /* 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.  */
-  (*targetm.encode_section_info) (exp, rtl, true);
+     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;
-  desc->label = XSTR (XEXP (desc->rtl, 0), 0);
 
   return desc;
 }
@@ -2588,982 +2751,784 @@ build_constant_desc (exp)
    Otherwise, output such a constant in memory
    and generate an rtx for it.
 
-   If DEFER is nonzero, 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.  */
+   `const_desc_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_tree *desc;
+  struct constant_descriptor_tree key;
+  void **loc;
 
-  /* We can't just use the saved RTL if this is a deferred 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);
-
-  /* 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);
-  for (desc = const_hash_table[hash]; desc; desc = desc->next)
-    if (compare_constant (exp, desc->value))
-      break;
+  /* Look up EXP in the table of constant descriptors.  If we didn't find
+     it, create a new one.  */
+  key.value = exp;
+  key.hash = const_hash_1 (exp);
+  loc = htab_find_slot_with_hash (const_desc_htab, &key, key.hash, INSERT);
 
+  desc = *loc;
   if (desc == 0)
     {
       desc = build_constant_desc (exp);
-      desc->next = const_hash_table[hash];
-      const_hash_table[hash] = desc;
-
-      maybe_output_constant_def_contents (exp, desc->rtl, defer);
-    }
-  else if (!defer && STRING_POOL_ADDRESS_P (XEXP (desc->rtl, 0)))
-    {
-      /* If the string is currently deferred but we need to output it
-        now, remove it from the deferred string hash table.  */
-      struct deferred_string **defstr;
-
-      defstr = (struct deferred_string **)
-       htab_find_slot_with_hash (const_str_htab, desc->label,
-                                 STRHASH (desc->label), NO_INSERT);
-#ifdef ENABLE_CHECKING
-      if (!defstr)
-       abort ();
-#endif
-
-      STRING_POOL_ADDRESS_P (XEXP (desc->rtl, 0)) = 0;
-      htab_clear_slot (const_str_htab, (void **) defstr);
-      maybe_output_constant_def_contents (exp, desc->rtl, 0);
+      desc->hash = key.hash;
+      *loc = desc;
     }
 
-  TREE_CST_RTL (exp) = desc->rtl;
+  maybe_output_constant_def_contents (desc, defer);
   return desc->rtl;
 }
 
-/* Subroutine of output_constant_def:
-   Decide whether or not to defer the output of EXP, which can be
-   accesed through rtl RTL, and either do the output or record EXP in
-   the table of deferred strings.  */
+/* 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 (exp, rtl, defer)
-     tree exp;
-     rtx rtl;
-     int defer;
+maybe_output_constant_def_contents (struct constant_descriptor_tree *desc,
+                                   int defer)
 {
-  const char *label;
+  rtx symbol = XEXP (desc->rtl, 0);
+  tree exp = desc->value;
 
   if (flag_syntax_only)
     return;
 
-  label = XSTR (XEXP (rtl, 0), 0);
+  if (TREE_ASM_WRITTEN (exp))
+    /* Already output; don't do it again.  */
+    return;
 
-  if (defer && TREE_CODE (exp) == STRING_CST && !flag_writable_strings)
+  /* We can always defer constants as long as the context allows
+     doing so.  */
+  if (defer)
     {
-      struct deferred_string **defstr;
-      defstr = (struct deferred_string **)
-       htab_find_slot_with_hash (const_str_htab, label,
-                                 STRHASH (label), INSERT);
-      if (defstr)
-       {
-         struct deferred_string *p;
-
-         p = (struct deferred_string *)
-           ggc_alloc (sizeof (struct deferred_string));
-
-         p->exp = exp;
-         p->label = label;
-
-         *defstr = p;
-         STRING_POOL_ADDRESS_P (XEXP (rtl, 0)) = 1;
-         return;
-       }
+      /* 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;
     }
 
-  output_constant_def_contents (exp, label);
+  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, label)
-     tree exp;
-     const char *label;
+output_constant_def_contents (rtx symbol)
 {
+  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);
+  int reloc = compute_reloc_for_constant (exp);
 
   /* Align the location counter as required by EXP's data type.  */
-  int align = TYPE_ALIGN (TREE_TYPE (exp));
+  unsigned int align = TYPE_ALIGN (TREE_TYPE (exp));
 #ifdef CONSTANT_ALIGNMENT
   align = CONSTANT_ALIGNMENT (exp, align);
 #endif
 
+  output_addressed_constants (exp);
+
+  /* We are no longer deferring this constant.  */
+  TREE_ASM_WRITTEN (exp) = 1;
+
   if (IN_NAMED_SECTION (exp))
     named_section (exp, NULL, reloc);
   else
-    (*targetm.asm_out.select_section) (exp, reloc, align);
+    targetm.asm_out.select_section (exp, reloc, align);
 
   if (align > BITS_PER_UNIT)
     {
       ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
     }
 
-  /* Output the label itself.  */
+  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);
+  if (flag_mudflap)
+    mudflap_enqueue_constant (exp);
 }
-\f
-/* Used in the hash tables to avoid outputting the same constant
-   twice.  Unlike 'struct constant_descriptor_tree', RTX constants
-   are output once per function, not once per file; there seems
-   to be no reason for the difference.  */
 
-struct constant_descriptor_rtx GTY(())
+/* 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)
 {
-  /* More constant_descriptors with the same hash code.  */
-  struct constant_descriptor_rtx *next;
+  struct constant_descriptor_tree *desc;
+  struct constant_descriptor_tree key;
 
-  /* A MEM for the constant.  */
-  rtx rtl;
+  key.value = exp;
+  key.hash = const_hash_1 (exp);
+  desc = htab_find_with_hash (const_desc_htab, &key, key.hash);
 
-  /* The value of the constant.  */
-  struct rtx_const value;
+  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.  */
+/* ??? Only a few targets need per-function constant pools.  Most
+   can use one per-file pool.  Should add a targetm bit to tell the
+   difference.  */
+
+struct rtx_constant_pool GTY(())
+{
+  /* Pointers to first and last constant in pool, as ordered by offset.  */
+  struct constant_descriptor_rtx *first;
+  struct constant_descriptor_rtx *last;
+
+  /* Hash facility for making memory-constants from constant rtl-expressions.
+     It is used on RISC machines where immediate integer arguments and
+     constant addresses are restricted so that such constants must be stored
+     in memory.  */
+  htab_t GTY((param_is (struct constant_descriptor_rtx))) const_rtx_htab;
+  htab_t GTY((param_is (struct constant_descriptor_rtx))) const_rtx_sym_htab;
+
+  /* Current offset in constant pool (does not include any
+     machine-specific header).  */
+  HOST_WIDE_INT offset;
 };
 
-/* Structure to represent sufficient information about a constant so that
-   it can be output when the constant pool is output, so that function
-   integration can be done, and to simplify handling on machines that reference
-   constant pool as base+displacement.  */
-
-struct pool_constant GTY(())
+struct constant_descriptor_rtx GTY((chain_next ("%h.next")))
 {
-  struct constant_descriptor_rtx *desc;
-  struct pool_constant *next;
-  struct pool_constant *next_sym;
+  struct constant_descriptor_rtx *next;
+  rtx mem;
+  rtx sym;
   rtx constant;
+  HOST_WIDE_INT offset;
+  hashval_t hash;
   enum machine_mode mode;
-  int labelno;
   unsigned int align;
-  HOST_WIDE_INT offset;
+  int labelno;
   int mark;
 };
 
-/* Hash code for a SYMBOL_REF with CONSTANT_POOL_ADDRESS_P true.
-   The argument is XSTR (... , 0)  */
-
-#define SYMHASH(LABEL) (((unsigned long) (LABEL)) % MAX_RTX_HASH_TABLE)
-\f
-/* Initialize constant pool hashing for a new function.  */
+/* Hash and compare functions for const_rtx_htab.  */
 
-void
-init_varasm_status (f)
-     struct function *f;
+static hashval_t
+const_desc_rtx_hash (const void *ptr)
 {
-  struct varasm_status *p;
-  p = (struct varasm_status *) ggc_alloc (sizeof (struct varasm_status));
-  f->varasm = p;
-  p->x_const_rtx_hash_table
-    = ((struct constant_descriptor_rtx **)
-       ggc_alloc_cleared (MAX_RTX_HASH_TABLE
-                         * sizeof (struct constant_descriptor_rtx *)));
-  p->x_const_rtx_sym_hash_table
-    = ((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;
+  const struct constant_descriptor_rtx *desc = ptr;
+  return desc->hash;
 }
-\f
-
-/* Express an rtx for a constant integer (perhaps symbolic)
-   as the sum of a symbol or label plus an explicit integer.
-   They are stored into VALUE.  */
 
-static void
-decode_rtx_const (mode, x, value)
-     enum machine_mode mode;
-     rtx x;
-     struct rtx_const *value;
+static int
+const_desc_rtx_eq (const void *a, const void *b)
 {
-  /* Clear the whole structure, including any gaps.  */
-  memset (value, 0, sizeof (struct rtx_const));
+  const struct constant_descriptor_rtx *x = a;
+  const struct constant_descriptor_rtx *y = b;
 
-  value->kind = RTX_INT;       /* Most usual kind.  */
-  value->mode = mode;
+  if (x->mode != y->mode)
+    return 0;
+  return rtx_equal_p (x->constant, y->constant);
+}
 
-  switch (GET_CODE (x))
-    {
-    case CONST_DOUBLE:
-      value->kind = RTX_DOUBLE;
-      if (GET_MODE (x) != VOIDmode)
-       {
-         const REAL_VALUE_TYPE *r = CONST_DOUBLE_REAL_VALUE (x);
+/* Hash and compare functions for const_rtx_sym_htab.  */
 
-         value->mode = GET_MODE (x);
+static hashval_t
+const_desc_rtx_sym_hash (const void *ptr)
+{
+  const struct constant_descriptor_rtx *desc = ptr;
+  return htab_hash_string (XSTR (desc->sym, 0));
+}
 
-         /* 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
-       {
-         value->un.di.low = CONST_DOUBLE_LOW (x);
-         value->un.di.high = CONST_DOUBLE_HIGH (x);
-       }
-      break;
+static int
+const_desc_rtx_sym_eq (const void *a, const void *b)
+{
+  const struct constant_descriptor_rtx *x = a;
+  const struct constant_descriptor_rtx *y = b;
+  return XSTR (x->sym, 0) == XSTR (y->sym, 0);
+}
 
-    case CONST_VECTOR:
-      {
-       int units, i;
+/* This is the worker function for const_rtx_hash, called via for_each_rtx.  */
 
-       units = CONST_VECTOR_NUNITS (x);
-       value->kind = RTX_VECTOR;
-       value->mode = mode;
+static int
+const_rtx_hash_1 (rtx *xp, void *data)
+{
+  unsigned HOST_WIDE_INT hwi;
+  enum machine_mode mode;
+  enum rtx_code code;
+  hashval_t h, *hp;
+  rtx x;
 
-       if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT)
-         {
-           for (i = 0; i < units; ++i)
-             {
-               rtx elt = CONST_VECTOR_ELT (x, i);
-               if (GET_CODE (elt) == CONST_INT)
-                 {
-                   value->un.int_vec[i].low = INTVAL (elt);
-                   value->un.int_vec[i].high = 0;
-                 }
-               else
-                 {
-                   value->un.int_vec[i].low = CONST_DOUBLE_LOW (elt);
-                   value->un.int_vec[i].high = CONST_DOUBLE_HIGH (elt);
-                 }
-             }
-         }
-       else if (GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
-         {
-           for (i = 0; i < units; ++i)
-             {
-               const REAL_VALUE_TYPE *r
-                 = CONST_DOUBLE_REAL_VALUE (CONST_VECTOR_ELT (x, i));
-               REAL_VALUE_TYPE *d = &value->un.fp_vec[i];
-
-               /* Copy the REAL_VALUE_TYPE by members so that we don't
-                  copy garbage from the original structure into our
-                  carefully cleaned hashing structure.  */
-               d->class = r->class;
-               d->sign = r->sign;
-               switch (r->class)
-                 {
-                 case rvc_zero:
-                 case rvc_inf:
-                   break;
-                 case rvc_normal:
-                   d->exp = r->exp;
-                   /* FALLTHRU */
-                 case rvc_nan:
-                   memcpy (d->sig, r->sig, sizeof (r->sig));
-                   break;
-                 default:
-                   abort ();
-                 }
-             }
-         }
-       else
-         abort ();
-      }
-      break;
+  x = *xp;
+  code = GET_CODE (x);
+  mode = GET_MODE (x);
+  h = (hashval_t) code * 1048573 + mode;
 
+  switch (code)
+    {
     case CONST_INT:
-      value->un.addr.offset = INTVAL (x);
-      break;
+      hwi = INTVAL (x);
+    fold_hwi:
+      {
+       const int shift = sizeof (hashval_t) * CHAR_BIT;
+       const int n = sizeof (HOST_WIDE_INT) / sizeof (hashval_t);
+       int i;
 
-    case SYMBOL_REF:
-    case LABEL_REF:
-    case PC:
-      value->un.addr.base = x;
+       h ^= (hashval_t) hwi;
+       for (i = 1; i < n; ++i)
+         {
+           hwi >>= shift;
+           h ^= (hashval_t) hwi;
+         }
+      }
       break;
 
-    case CONST:
-      x = XEXP (x, 0);
-      if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
-       {
-         value->un.addr.base = XEXP (x, 0);
-         value->un.addr.offset = INTVAL (XEXP (x, 1));
-       }
-      else if (GET_CODE (x) == MINUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
+    case CONST_DOUBLE:
+      if (mode == VOIDmode)
        {
-         value->un.addr.base = XEXP (x, 0);
-         value->un.addr.offset = - INTVAL (XEXP (x, 1));
+         hwi = CONST_DOUBLE_LOW (x) ^ CONST_DOUBLE_HIGH (x);
+         goto fold_hwi;
        }
       else
-       {
-         value->un.addr.base = x;
-         value->un.addr.offset = 0;
-       }
+       h ^= real_hash (CONST_DOUBLE_REAL_VALUE (x));
       break;
 
-    default:
-      value->kind = RTX_UNKNOWN;
-      break;
-    }
-
-  if (value->kind == RTX_INT && value->un.addr.base != 0
-      && GET_CODE (value->un.addr.base) == UNSPEC)
-    {
-      /* For a simple UNSPEC, the base is set to the
-        operand, the kind field is set to the index of
-        the unspec expression.
-        Together with the code below, in case that
-        the operand is a SYMBOL_REF or LABEL_REF,
-        the address of the string or the code_label
-        is taken as base.  */
-      if (XVECLEN (value->un.addr.base, 0) == 1)
-       {
-         value->kind = RTX_UNSPEC + XINT (value->un.addr.base, 1);
-         value->un.addr.base = XVECEXP (value->un.addr.base, 0, 0);
-       }
-    }
-
-  if (value->kind >= RTX_INT && value->un.addr.base != 0)
-    switch (GET_CODE (value->un.addr.base))
+    case CONST_VECTOR:
       {
-      case SYMBOL_REF:
-       /* Use the string's address, not the SYMBOL_REF's address,
-          for the sake of addresses of library routines.  */
-       value->un.addr.symbol = XSTR (value->un.addr.base, 0);
-       value->un.addr.base = NULL_RTX;
-       break;
-
-      case LABEL_REF:
-       /* For a LABEL_REF, compare labels.  */
-       value->un.addr.base = XEXP (value->un.addr.base, 0);
-
-      default:
-       break;
+       int i;
+       for (i = XVECLEN (x, 0); i-- > 0; )
+         h = h * 251 + const_rtx_hash_1 (&XVECEXP (x, 0, i), data);
       }
-}
+      break;
 
-/* Given a MINUS expression, simplify it if both sides
-   include the same symbol.  */
+    case SYMBOL_REF:
+      h ^= htab_hash_string (XSTR (x, 0));
+      break;
 
-rtx
-simplify_subtraction (x)
-     rtx x;
-{
-  struct rtx_const val0, val1;
+    case LABEL_REF:
+      h = h * 251 + CODE_LABEL_NUMBER (XEXP (x, 0));
+      break;
 
-  decode_rtx_const (GET_MODE (x), XEXP (x, 0), &val0);
-  decode_rtx_const (GET_MODE (x), XEXP (x, 1), &val1);
+    case UNSPEC:
+    case UNSPEC_VOLATILE:
+      h = h * 251 + XINT (x, 1);
+      break;
 
-  if (val0.kind >= RTX_INT
-      && val0.kind == val1.kind
-      && val0.un.addr.base == val1.un.addr.base
-      && val0.un.addr.symbol == val1.un.addr.symbol)
-    return GEN_INT (val0.un.addr.offset - val1.un.addr.offset);
+    default:
+      break;
+    }
 
-  return x;
+  hp = data;
+  *hp = *hp * 509 + h;
+  return 0;
 }
 
-/* Compute a hash code for a constant RTL expression.  */
+/* Compute a hash value for X, which should be a constant.  */
 
-static unsigned int
-const_hash_rtx (mode, x)
-     enum machine_mode mode;
-     rtx x;
+static hashval_t
+const_rtx_hash (rtx x)
 {
-  union {
-    struct rtx_const value;
-    unsigned int data[sizeof(struct rtx_const) / sizeof (unsigned int)];
-  } u;
-
-  unsigned int hi;
-  size_t i;
-
-  decode_rtx_const (mode, x, &u.value);
-
-  /* Compute hashing function */
-  hi = 0;
-  for (i = 0; i < ARRAY_SIZE (u.data); i++)
-    hi = hi * 613 + u.data[i];
-
-  return hi % MAX_RTX_HASH_TABLE;
+  hashval_t h = 0;
+  for_each_rtx (&x, const_rtx_hash_1, &h);
+  return h;
 }
 
-/* Compare a constant rtl object X with a constant-descriptor DESC.
-   Return 1 if DESC describes a constant with the same value as X.  */
+\f
+/* Initialize constant pool hashing for a new function.  */
 
-static int
-compare_constant_rtx (mode, x, desc)
-     enum machine_mode mode;
-     rtx x;
-     struct constant_descriptor_rtx *desc;
+void
+init_varasm_status (struct function *f)
 {
-  struct rtx_const value;
-
-  decode_rtx_const (mode, x, &value);
-
-  /* Compare constant contents.  */
-  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.  */
+  struct varasm_status *p;
+  struct rtx_constant_pool *pool;
 
-static struct constant_descriptor_rtx *
-record_constant_rtx (mode, x)
-     enum machine_mode mode;
-     rtx x;
-{
-  struct constant_descriptor_rtx *ptr;
+  p = ggc_alloc (sizeof (struct varasm_status));
+  f->varasm = p;
 
-  ptr = (struct constant_descriptor_rtx *) ggc_alloc (sizeof (*ptr));
-  decode_rtx_const (mode, x, &ptr->value);
+  pool = ggc_alloc (sizeof (struct rtx_constant_pool));
+  p->pool = pool;
+  p->deferred_constants = 0;
 
-  return ptr;
+  pool->const_rtx_htab = htab_create_ggc (31, const_desc_rtx_hash,
+                                         const_desc_rtx_eq, NULL);
+  pool->const_rtx_sym_htab = htab_create_ggc (31, const_desc_rtx_sym_hash,
+                                             const_desc_rtx_sym_eq, NULL);
+  pool->first = pool->last = NULL;
+  pool->offset = 0;
 }
 \f
-/* Given a 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.  */
+/* Given a MINUS expression, simplify it if both sides
+   include the same symbol.  */
 
 rtx
-mem_for_const_double (x)
-     rtx x;
+simplify_subtraction (rtx x)
 {
-  enum machine_mode mode = GET_MODE (x);
-  struct constant_descriptor_rtx *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;
+  rtx r = simplify_rtx (x);
+  return r ? r : x;
 }
-
+\f
 /* 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_rtx *desc;
+  struct constant_descriptor_rtx *desc, tmp;
+  struct rtx_constant_pool *pool = cfun->varasm->pool;
   char label[256];
   rtx def, symbol;
-  struct pool_constant *pool;
+  hashval_t hash;
   unsigned int align;
+  void **slot;
 
   /* If we're not allowed to drop X into the constant pool, don't.  */
-  if ((*targetm.cannot_force_const_mem) (x))
+  if (targetm.cannot_force_const_mem (x))
     return NULL_RTX;
 
-  /* Compute hash code of X.  Search the descriptors for that hash code
-     to see if any of them describes X.  If yes, we have an rtx to use.  */
-  hash = const_hash_rtx (mode, x);
-  for (desc = const_rtx_hash_table[hash]; desc; desc = desc->next)
-    if (compare_constant_rtx (mode, x, desc))
-      return desc->rtl;
+  /* Lookup the value in the hashtable.  */
+  tmp.constant = x;
+  tmp.mode = mode;
+  hash = const_rtx_hash (x);
+  slot = htab_find_slot_with_hash (pool->const_rtx_htab, &tmp, hash, INSERT);
+  desc = *slot;
+  
+  /* If the constant was already present, return its memory.  */
+  if (desc)
+    return copy_rtx (desc->mem);
 
-  /* No constant equal to X is known to have been output.
-     Make a constant descriptor to enter X in the hash table
-     and make a MEM for it.  */
-  desc = record_constant_rtx (mode, x);
-  desc->next = const_rtx_hash_table[hash];
-  const_rtx_hash_table[hash] = desc;
+  /* Otherwise, create a new descriptor.  */
+  desc = ggc_alloc (sizeof (*desc));
+  *slot = desc;
 
   /* Align the location counter as required by EXP's data type.  */
   align = GET_MODE_ALIGNMENT (mode == VOIDmode ? word_mode : mode);
 #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;
-  pool_offset &= ~ ((align / BITS_PER_UNIT) - 1);
-
-  if (GET_CODE (x) == LABEL_REF)
-    LABEL_PRESERVE_P (XEXP (x, 0)) = 1;
-
-  /* Allocate a pool constant descriptor, fill it in, and chain it in.  */
-  pool = (struct pool_constant *) ggc_alloc (sizeof (struct pool_constant));
-  pool->desc = desc;
-  pool->constant = x;
-  pool->mode = mode;
-  pool->labelno = const_labelno;
-  pool->align = align;
-  pool->offset = pool_offset;
-  pool->mark = 1;
-  pool->next = 0;
-
-  if (last_pool == 0)
-    first_pool = pool;
+  pool->offset += (align / BITS_PER_UNIT) - 1;
+  pool->offset &= ~ ((align / BITS_PER_UNIT) - 1);
+
+  desc->next = NULL;
+  desc->constant = tmp.constant;
+  desc->offset = pool->offset;
+  desc->hash = hash;
+  desc->mode = mode;
+  desc->align = align;
+  desc->labelno = const_labelno;
+  desc->mark = 0;
+
+  pool->offset += GET_MODE_SIZE (mode);
+  if (pool->last)
+    pool->last->next = desc;
   else
-    last_pool->next = pool;
-
-  last_pool = pool;
-  pool_offset += GET_MODE_SIZE (mode);
+    pool->first = pool->last = desc;
+  pool->last = desc;
 
   /* Create a string containing the label name, in LABEL.  */
   ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
-
   ++const_labelno;
 
-  /* Construct the SYMBOL_REF and the MEM.  */
-
-  symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label));
+  /* Construct the SYMBOL_REF.  Make sure to mark it as belonging to
+     the constants pool.  */
+  desc->sym = symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label));
   SYMBOL_REF_FLAGS (symbol) = SYMBOL_FLAG_LOCAL;
+  CONSTANT_POOL_ADDRESS_P (symbol) = 1;
+  current_function_uses_const_pool = 1;
 
-  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;
+  /* Insert the descriptor into the symbol cross-reference table too.  */
+  slot = htab_find_slot (pool->const_rtx_sym_htab, desc, INSERT);
+  gcc_assert (!*slot);
+  *slot = desc;
 
-  /* Add label to symbol hash table.  */
-  hash = SYMHASH (XSTR (symbol, 0));
-  pool->next_sym = const_rtx_sym_hash_table[hash];
-  const_rtx_sym_hash_table[hash] = pool;
+  /* Construct the MEM.  */
+  desc->mem = def = gen_const_mem (mode, symbol);
+  set_mem_attributes (def, lang_hooks.types.type_for_mode (mode, 0), 1);
+  set_mem_align (def, align);
 
-  /* Mark the symbol_ref as belonging to this constants pool.  */
-  CONSTANT_POOL_ADDRESS_P (symbol) = 1;
-  SYMBOL_REF_FLAGS (symbol) = SYMBOL_FLAG_LOCAL;
-  current_function_uses_const_pool = 1;
+  /* If we're dropping a label to the constant pool, make sure we
+     don't delete it.  */
+  if (GET_CODE (x) == LABEL_REF)
+    LABEL_PRESERVE_P (XEXP (x, 0)) = 1;
 
-  return def;
+  return copy_rtx (def);
 }
 \f
 /* Given a SYMBOL_REF with CONSTANT_POOL_ADDRESS_P true, return a pointer to
-   the corresponding pool_constant structure.  */
+   the corresponding constant_descriptor_rtx structure.  */
 
-static struct pool_constant *
-find_pool_constant (f, addr)
-     struct function *f;
-     rtx addr;
+static struct constant_descriptor_rtx *
+find_pool_constant (struct rtx_constant_pool *pool, rtx sym)
 {
-  struct pool_constant *pool;
-  const char *label = XSTR (addr, 0);
-
-  for (pool = f->varasm->x_const_rtx_sym_hash_table[SYMHASH (label)]; pool;
-       pool = pool->next_sym)
-    if (XSTR (XEXP (pool->desc->rtl, 0), 0) == label)
-      return pool;
-
-  abort ();
+  struct constant_descriptor_rtx tmp;
+  tmp.sym = sym;
+  return htab_find (pool->const_rtx_sym_htab, &tmp);
 }
 
 /* Given a constant pool SYMBOL_REF, return the corresponding constant.  */
 
 rtx
-get_pool_constant (addr)
-     rtx addr;
+get_pool_constant (rtx addr)
 {
-  return (find_pool_constant (cfun, addr))->constant;
+  return find_pool_constant (cfun->varasm->pool, addr)->constant;
 }
 
 /* Given a constant pool SYMBOL_REF, return the corresponding constant
    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);
-  return pool->constant;
+  struct constant_descriptor_rtx *desc;
+
+  desc = find_pool_constant (cfun->varasm->pool, addr);
+  *pmarked = (desc->mark != 0);
+  return desc->constant;
 }
 
 /* Likewise, but for the constant pool of a specific function.  */
 
 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;
+  return find_pool_constant (f->varasm->pool, addr)->constant;
 }
 
 /* Similar, return the mode.  */
 
 enum machine_mode
-get_pool_mode (addr)
-     rtx addr;
-{
-  return (find_pool_constant (cfun, addr))->mode;
-}
-
-enum machine_mode
-get_pool_mode_for_function (f, addr)
-     struct function *f;
-     rtx addr;
-{
-  return (find_pool_constant (f, addr))->mode;
-}
-
-/* Similar, return the offset in the constant pool.  */
-
-int
-get_pool_offset (addr)
-     rtx addr;
+get_pool_mode (rtx addr)
 {
-  return (find_pool_constant (cfun, addr))->offset;
+  return find_pool_constant (cfun->varasm->pool, addr)->mode;
 }
 
 /* Return the size of the constant pool.  */
 
 int
-get_pool_size ()
+get_pool_size (void)
 {
-  return pool_offset;
+  return cfun->varasm->pool->offset;
 }
 \f
-/* Write all the constants in the constant pool.  */
+/* Worker function for output_constant_pool_1.  Emit assembly for X
+   in MODE with known alignment ALIGN.  */
 
-void
-output_constant_pool (fnname, fndecl)
-     const char *fnname ATTRIBUTE_UNUSED;
-     tree fndecl ATTRIBUTE_UNUSED;
+static void
+output_constant_pool_2 (enum machine_mode mode, rtx x, unsigned int align)
 {
-  struct pool_constant *pool;
-  rtx x;
-  REAL_VALUE_TYPE r;
-
-  /* It is possible for gcc to call force_const_mem and then to later
-     discard the instructions which refer to the constant.  In such a
-     case we do not need to output the constant.  */
-  mark_constant_pool ();
-
-#ifdef ASM_OUTPUT_POOL_PROLOGUE
-  ASM_OUTPUT_POOL_PROLOGUE (asm_out_file, fnname, fndecl, pool_offset);
-#endif
-
-  for (pool = first_pool; pool; pool = pool->next)
+  switch (GET_MODE_CLASS (mode))
     {
-      rtx tmp;
+    case MODE_FLOAT:
+      {
+       REAL_VALUE_TYPE r;
+       
+       gcc_assert (GET_CODE (x) == CONST_DOUBLE);
+       REAL_VALUE_FROM_CONST_DOUBLE (r, x);
+       assemble_real (r, mode, align);
+       break;
+      }
+      
+    case MODE_INT:
+    case MODE_PARTIAL_INT:
+      assemble_integer (x, GET_MODE_SIZE (mode), align, 1);
+      break;
 
-      x = pool->constant;
+    case MODE_VECTOR_FLOAT:
+    case MODE_VECTOR_INT:
+      {
+       int i, units;
+        enum machine_mode submode = GET_MODE_INNER (mode);
+       unsigned int subalign = MIN (align, GET_MODE_BITSIZE (submode));
 
-      if (! pool->mark)
-       continue;
+       gcc_assert (GET_CODE (x) == CONST_VECTOR);
+       units = CONST_VECTOR_NUNITS (x);
 
-      /* See if X is a LABEL_REF (or a CONST referring to a LABEL_REF)
-        whose CODE_LABEL has been deleted.  This can occur if a jump table
-        is eliminated by optimization.  If so, write a constant of zero
-        instead.  Note that this can also happen by turning the
-        CODE_LABEL into a NOTE.  */
-      /* ??? This seems completely and utterly wrong.  Certainly it's
-        not true for NOTE_INSN_DELETED_LABEL, but I disbelieve proper
-        functioning even with INSN_DELETED_P and friends.  */
-
-      tmp = x;
-      switch (GET_CODE (x))
-       {
-       case CONST:
-         if (GET_CODE (XEXP (x, 0)) != PLUS
-             || GET_CODE (XEXP (XEXP (x, 0), 0)) != LABEL_REF)
-           break;
-         tmp = XEXP (XEXP (x, 0), 0);
-         /* FALLTHRU */
-
-       case LABEL_REF:
-         tmp = XEXP (x, 0);
-         if (INSN_DELETED_P (tmp)
-             || (GET_CODE (tmp) == NOTE
-                 && NOTE_LINE_NUMBER (tmp) == NOTE_INSN_DELETED))
-           {
-             abort ();
-             x = const0_rtx;
-           }
-         break;
+       for (i = 0; i < units; i++)
+         {
+           rtx elt = CONST_VECTOR_ELT (x, i);
+           output_constant_pool_2 (submode, elt, i ? subalign : align);
+         }
+      }
+      break;
 
-       default:
-         break;
-       }
+    default:
+      gcc_unreachable ();
+    }
+}
 
-      /* First switch to correct section.  */
-      (*targetm.asm_out.select_rtx_section) (pool->mode, x, pool->align);
+/* Worker function for output_constant_pool.  Emit POOL.  */
 
-#ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
-      ASM_OUTPUT_SPECIAL_POOL_ENTRY (asm_out_file, x, pool->mode,
-                                    pool->align, pool->labelno, done);
-#endif
+static void
+output_constant_pool_1 (struct constant_descriptor_rtx *desc)
+{
+  rtx x, tmp;
 
-      assemble_align (pool->align);
+  if (!desc->mark)
+    return;
+  x = desc->constant;
+
+  /* See if X is a LABEL_REF (or a CONST referring to a LABEL_REF)
+     whose CODE_LABEL has been deleted.  This can occur if a jump table
+     is eliminated by optimization.  If so, write a constant of zero
+     instead.  Note that this can also happen by turning the
+     CODE_LABEL into a NOTE.  */
+  /* ??? This seems completely and utterly wrong.  Certainly it's
+     not true for NOTE_INSN_DELETED_LABEL, but I disbelieve proper
+     functioning even with INSN_DELETED_P and friends.  */
+
+  tmp = x;
+  switch (GET_CODE (x))
+    {
+    case CONST:
+      if (GET_CODE (XEXP (x, 0)) != PLUS
+         || GET_CODE (XEXP (XEXP (x, 0), 0)) != LABEL_REF)
+       break;
+      tmp = XEXP (XEXP (x, 0), 0);
+      /* FALLTHRU  */
 
-      /* Output the label.  */
-      (*targetm.asm_out.internal_label) (asm_out_file, "LC", pool->labelno);
+    case LABEL_REF:
+      tmp = XEXP (x, 0);
+      gcc_assert (!INSN_DELETED_P (tmp));
+      gcc_assert (!NOTE_P (tmp)
+                 || NOTE_LINE_NUMBER (tmp) != NOTE_INSN_DELETED);
+      break;
 
-      /* Output the value of the constant itself.  */
-      switch (GET_MODE_CLASS (pool->mode))
-       {
-       case MODE_FLOAT:
-         if (GET_CODE (x) != CONST_DOUBLE)
-           abort ();
+    default:
+      break;
+    }
 
-         REAL_VALUE_FROM_CONST_DOUBLE (r, x);
-         assemble_real (r, pool->mode, pool->align);
-         break;
+  /* First switch to correct section.  */
+  targetm.asm_out.select_rtx_section (desc->mode, x, desc->align);
 
-       case MODE_INT:
-       case MODE_PARTIAL_INT:
-         assemble_integer (x, GET_MODE_SIZE (pool->mode), pool->align, 1);
-         break;
+#ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
+  ASM_OUTPUT_SPECIAL_POOL_ENTRY (asm_out_file, x, desc->mode,
+                                desc->align, desc->labelno, done);
+#endif
 
-       case MODE_VECTOR_FLOAT:
-         {
-           int i, units;
-           rtx elt;
+  assemble_align (desc->align);
 
-           if (GET_CODE (x) != CONST_VECTOR)
-             abort ();
+  /* Output the label.  */
+  targetm.asm_out.internal_label (asm_out_file, "LC", desc->labelno);
 
-           units = CONST_VECTOR_NUNITS (x);
+  /* Output the data.  */
+  output_constant_pool_2 (desc->mode, x, desc->align);
 
-           for (i = 0; i < units; i++)
-             {
-               elt = CONST_VECTOR_ELT (x, i);
-               REAL_VALUE_FROM_CONST_DOUBLE (r, elt);
-               assemble_real (r, GET_MODE_INNER (pool->mode), pool->align);
-             }
-         }
-         break;
+  /* Make sure all constants in SECTION_MERGE and not SECTION_STRINGS
+     sections have proper size.  */
+  if (desc->align > GET_MODE_BITSIZE (desc->mode)
+      && in_section == in_named
+      && get_named_section_flags (in_named_name) & SECTION_MERGE)
+    assemble_align (desc->align);
 
-       case MODE_VECTOR_INT:
-         {
-           int i, units;
-           rtx elt;
+#ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
+ done:
+#endif
+  return;
+}
 
-           if (GET_CODE (x) != CONST_VECTOR)
-             abort ();
+/* Given a SYMBOL_REF CURRENT_RTX, mark it and all constants it refers
+   to as used.  Emit referenced deferred strings.  This function can
+   be used with for_each_rtx to mark all SYMBOL_REFs in an rtx.  */
 
-           units = CONST_VECTOR_NUNITS (x);
+static int
+mark_constant (rtx *current_rtx, void *data)
+{
+  struct rtx_constant_pool *pool = data;
+  rtx x = *current_rtx;
 
-           for (i = 0; i < units; i++)
-             {
-               elt = CONST_VECTOR_ELT (x, i);
-               assemble_integer (elt, GET_MODE_UNIT_SIZE (pool->mode),
-                                 pool->align, 1);
-             }
-         }
-         break;
+  if (x == NULL_RTX || GET_CODE (x) != SYMBOL_REF)
+    return 0;
 
-       default:
-         abort ();
+  if (CONSTANT_POOL_ADDRESS_P (x))
+    {
+      struct constant_descriptor_rtx *desc = find_pool_constant (pool, x);
+      if (desc->mark == 0)
+       {
+         desc->mark = 1;
+         for_each_rtx (&desc->constant, mark_constant, pool);
        }
+    }
+  else if (TREE_CONSTANT_POOL_ADDRESS_P (x))
+    {
+      tree exp = SYMBOL_REF_DECL (x);
+      if (!TREE_ASM_WRITTEN (exp))
+       {
+         n_deferred_constants--;
+         output_constant_def_contents (x);
+       }
+    }
 
-      /* 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);
+  return -1;
+} 
 
-#ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
-    done: ;
-#endif
-    }
+/* Look through appropriate parts of INSN, marking all entries in the
+   constant pool which are actually being used.  Entries that are only
+   referenced by other constants are also marked as used.  Emit
+   deferred strings that are used.  */
 
-#ifdef ASM_OUTPUT_POOL_EPILOGUE
-  ASM_OUTPUT_POOL_EPILOGUE (asm_out_file, fnname, fndecl, pool_offset);
-#endif
+static void
+mark_constants (struct rtx_constant_pool *pool, rtx insn)
+{
+  if (!INSN_P (insn))
+    return;
 
-  /* Done with this pool.  */
-  first_pool = last_pool = 0;
+  /* Insns may appear inside a SEQUENCE.  Only check the patterns of
+     insns, not any notes that may be attached.  We don't want to mark
+     a constant just because it happens to appear in a REG_EQUIV note.  */
+  if (GET_CODE (PATTERN (insn)) == SEQUENCE)
+    {
+      rtx seq = PATTERN (insn);
+      int i, n = XVECLEN (seq, 0);
+      for (i = 0; i < n; ++i)
+       {
+         rtx subinsn = XVECEXP (seq, 0, i);
+         if (INSN_P (subinsn))
+           for_each_rtx (&PATTERN (subinsn), mark_constant, pool);
+       }
+    }
+  else
+    for_each_rtx (&PATTERN (insn), mark_constant, pool);
 }
 
 /* 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 POOL which are actually being used.  Emit deferred constants
+   which have indeed been used.  */
 
 static void
-mark_constant_pool ()
+mark_constant_pool (struct rtx_constant_pool *pool)
 {
-  rtx insn;
-  rtx link;
-  struct pool_constant *pool;
+  rtx insn, link;
 
-  if (first_pool == 0 && htab_elements (const_str_htab) == 0)
+  if (pool->first == 0 && n_deferred_constants == 0)
     return;
 
-  for (pool = first_pool; pool; pool = pool->next)
-    pool->mark = 0;
-
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
-    if (INSN_P (insn))
-      mark_constants (PATTERN (insn));
+    mark_constants (pool, 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));
-    }
+    mark_constants (pool, XEXP (link, 0));
 }
 
-/* Look through appropriate parts of X, marking all entries in the
-   constant pool which are actually being used.  Entries that are only
-   referenced by other constants are also marked as used.  Emit
-   deferred strings that are used.  */
+/* Write all the constants in the constant pool.  */
 
-static void
-mark_constants (x)
-     rtx x;
+void
+output_constant_pool (const char *fnname ATTRIBUTE_UNUSED,
+                     tree fndecl ATTRIBUTE_UNUSED)
 {
-  int i;
-  const char *format_ptr;
-
-  if (x == 0)
-    return;
-
-  if (GET_CODE (x) == SYMBOL_REF)
-    {
-      mark_constant (&x, NULL);
-      return;
-    }
+  struct rtx_constant_pool *pool = cfun->varasm->pool;
+  struct constant_descriptor_rtx *desc;
 
-  /* Insns may appear inside a SEQUENCE.  Only check the patterns of
-     insns, not any notes that may be attached.  We don't want to mark
-     a constant just because it happens to appear in a REG_EQUIV note.  */
-  if (INSN_P (x))
-    {
-      mark_constants (PATTERN (x));
-      return;
-    }
+  /* It is possible for gcc to call force_const_mem and then to later
+     discard the instructions which refer to the constant.  In such a
+     case we do not need to output the constant.  */
+  mark_constant_pool (pool);
 
-  format_ptr = GET_RTX_FORMAT (GET_CODE (x));
+#ifdef ASM_OUTPUT_POOL_PROLOGUE
+  ASM_OUTPUT_POOL_PROLOGUE (asm_out_file, fnname, fndecl, pool->offset);
+#endif
 
-  for (i = 0; i < GET_RTX_LENGTH (GET_CODE (x)); i++)
-    {
-      switch (*format_ptr++)
-       {
-       case 'e':
-         mark_constants (XEXP (x, i));
-         break;
+  for (desc = pool->first; desc ; desc = desc->next)
+    output_constant_pool_1 (desc);
 
-       case 'E':
-         if (XVEC (x, i) != 0)
-           {
-             int j;
+#ifdef ASM_OUTPUT_POOL_EPILOGUE
+  ASM_OUTPUT_POOL_EPILOGUE (asm_out_file, fnname, fndecl, pool->offset);
+#endif
+}
+\f
+/* Determine what kind of relocations EXP may need.  */
 
-             for (j = 0; j < XVECLEN (x, i); j++)
-               mark_constants (XVECEXP (x, i, j));
-           }
-         break;
+int
+compute_reloc_for_constant (tree exp)
+{
+  int reloc = 0, reloc2;
+  tree tem;
 
-       case 'S':
-       case 's':
-       case '0':
-       case 'i':
-       case 'w':
-       case 'n':
-       case 'u':
-       case 'B':
-         break;
+  /* Give the front-end a chance to convert VALUE to something that
+     looks more like a constant to the back-end.  */
+  exp = lang_hooks.expand_constant (exp);
 
-       default:
-         abort ();
-       }
-    }
-}
+  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.  */
+      for (tem = TREE_OPERAND (exp, 0); handled_component_p (tem);
+          tem = TREE_OPERAND (tem, 0))
+       ;
 
-/* Given a SYMBOL_REF CURRENT_RTX, mark it and all constants it refers
-   to as used.  Emit referenced deferred strings.  This function can
-   be used with for_each_rtx to mark all SYMBOL_REFs in an rtx.  */
+      if (TREE_PUBLIC (tem))
+       reloc |= 2;
+      else
+       reloc |= 1;
+      break;
 
-static int
-mark_constant (current_rtx, data)
-     rtx *current_rtx;
-     void *data ATTRIBUTE_UNUSED;
-{
-  rtx x = *current_rtx;
+    case PLUS_EXPR:
+      reloc = compute_reloc_for_constant (TREE_OPERAND (exp, 0));
+      reloc |= compute_reloc_for_constant (TREE_OPERAND (exp, 1));
+      break;
 
-  if (x == NULL_RTX)
-    return 0;
+    case MINUS_EXPR:
+      reloc = compute_reloc_for_constant (TREE_OPERAND (exp, 0));
+      reloc2 = compute_reloc_for_constant (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;
 
-  else if (GET_CODE (x) == SYMBOL_REF)
-    {
-      if (CONSTANT_POOL_ADDRESS_P (x))
-       {
-         struct pool_constant *pool = find_pool_constant (cfun, x);
-         if (pool->mark == 0)
-           {
-             pool->mark = 1;
-             for_each_rtx (&(pool->constant), &mark_constant, NULL);
-           }
-         else
-           return -1;
-       }
-      else if (STRING_POOL_ADDRESS_P (x))
-       {
-         struct deferred_string *p, **defstr;
-
-         defstr = (struct deferred_string **)
-           htab_find_slot_with_hash (const_str_htab, XSTR (x, 0),
-                                     STRHASH (XSTR (x, 0)), NO_INSERT);
-#ifdef ENABLE_CHECKING
-         if (!defstr)
-           abort ();
-#endif
+    case NOP_EXPR:
+    case CONVERT_EXPR:
+    case NON_LVALUE_EXPR:
+    case VIEW_CONVERT_EXPR:
+      reloc = compute_reloc_for_constant (TREE_OPERAND (exp, 0));
+      break;
 
-         p = *defstr;
-         STRING_POOL_ADDRESS_P (x) = 0;
-         output_constant_def_contents (p->exp, p->label);
-         htab_clear_slot (const_str_htab, (void **) defstr);
-       }
+    case CONSTRUCTOR:
+      {
+       unsigned HOST_WIDE_INT idx;
+       FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, tem)
+         if (tem != 0)
+           reloc |= compute_reloc_for_constant (tem);
+      }
+      break;
+
+    default:
+      break;
     }
-  return 0;
+  return reloc;
 }
-\f
+
 /* Find all the constants whose addresses are referenced inside of EXP,
    and make sure assembler code with a label has been output for each one.
    Indicate whether an ADDR_EXPR has been encountered.  */
 
-static int
-output_addressed_constants (exp)
-     tree exp;
+static void
+output_addressed_constants (tree exp)
 {
-  int reloc = 0, reloc2;
   tree tem;
 
   /* Give the front-end a chance to convert VALUE to something that
      looks more like a constant to the back-end.  */
-  exp = (*lang_hooks.expand_constant) (exp);
+  exp = lang_hooks.expand_constant (exp);
 
   switch (TREE_CODE (exp))
     {
@@ -3576,48 +3541,38 @@ output_addressed_constants (exp)
           tem = TREE_OPERAND (tem, 0))
        ;
 
-      if (TREE_CODE_CLASS (TREE_CODE (tem)) == 'c'
-         || TREE_CODE (tem) == CONSTRUCTOR)
-       output_constant_def (tem, 0);
+      /* If we have an initialized CONST_DECL, retrieve the initializer.  */
+      if (TREE_CODE (tem) == CONST_DECL && DECL_INITIAL (tem))
+       tem = DECL_INITIAL (tem);
 
-      if (TREE_PUBLIC (tem))
-       reloc |= 2;
-      else
-       reloc |= 1;
+      if (CONSTANT_CLASS_P (tem) || TREE_CODE (tem) == CONSTRUCTOR)
+       output_constant_def (tem, 0);
       break;
 
     case PLUS_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;
+      output_addressed_constants (TREE_OPERAND (exp, 1));
+      /* Fall through.  */
 
     case NOP_EXPR:
     case CONVERT_EXPR:
     case NON_LVALUE_EXPR:
-      reloc = output_addressed_constants (TREE_OPERAND (exp, 0));
+    case VIEW_CONVERT_EXPR:
+      output_addressed_constants (TREE_OPERAND (exp, 0));
       break;
 
     case CONSTRUCTOR:
-      for (tem = CONSTRUCTOR_ELTS (exp); tem; tem = TREE_CHAIN (tem))
-       if (TREE_VALUE (tem) != 0)
-         reloc |= output_addressed_constants (TREE_VALUE (tem));
-
+      {
+       unsigned HOST_WIDE_INT idx;
+       FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, tem)
+         if (tem != 0)
+           output_addressed_constants (tem);
+      }
       break;
 
     default:
       break;
     }
-  return reloc;
 }
 \f
 /* Return nonzero if VALUE is a valid constant-valued expression
@@ -3631,13 +3586,11 @@ 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.  */
-  value = (*lang_hooks.expand_constant) (value);
+  value = lang_hooks.expand_constant (value);
 
   switch (TREE_CODE (value))
     {
@@ -3645,12 +3598,28 @@ initializer_constant_valid_p (value, endtype)
       if ((TREE_CODE (TREE_TYPE (value)) == UNION_TYPE
           || TREE_CODE (TREE_TYPE (value)) == RECORD_TYPE)
          && TREE_CONSTANT (value)
-         && CONSTRUCTOR_ELTS (value))
-       return
-         initializer_constant_valid_p (TREE_VALUE (CONSTRUCTOR_ELTS (value)),
-                                       endtype);
+         && !VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (value)))
+       {
+         unsigned HOST_WIDE_INT idx;
+         tree elt;
+         bool absolute = true;
+
+         FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (value), idx, elt)
+           {
+             tree reloc;
+             reloc = initializer_constant_valid_p (elt, TREE_TYPE (elt));
+             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:
@@ -3661,7 +3630,20 @@ initializer_constant_valid_p (value, endtype)
 
     case ADDR_EXPR:
     case FDESC_EXPR:
-      return staticp (TREE_OPERAND (value, 0)) ? TREE_OPERAND (value, 0) : 0;
+      value = staticp (TREE_OPERAND (value, 0));
+      /* "&(*a).f" is like unto pointer arithmetic.  If "a" turns out to
+        be a constant, this is old-skool offsetof-like nonsense.  */
+      if (value
+         && TREE_CODE (value) == INDIRECT_REF
+         && TREE_CONSTANT (TREE_OPERAND (value, 0)))
+       return null_pointer_node;
+      /* Taking the address of a nested function involves a trampoline.  */
+      if (value
+         && TREE_CODE (value) == FUNCTION_DECL
+         && ((decl_function_context (value) && !DECL_NO_STATIC_CHAIN (value))
+             || DECL_DLLIMPORT_P (value)))
+       return NULL_TREE;
+      return value;
 
     case VIEW_CONVERT_EXPR:
     case NON_LVALUE_EXPR:
@@ -3669,60 +3651,61 @@ initializer_constant_valid_p (value, endtype)
 
     case CONVERT_EXPR:
     case NOP_EXPR:
-      /* Allow conversions between pointer types.  */
-      if (POINTER_TYPE_P (TREE_TYPE (value))
-         && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
-       return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
-
-      /* Allow conversions between real types.  */
-      if (FLOAT_TYPE_P (TREE_TYPE (value))
-         && FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
-       return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
-
-      /* Allow length-preserving conversions between integer types.  */
-      if (INTEGRAL_TYPE_P (TREE_TYPE (value))
-         && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0)))
-         && (TYPE_PRECISION (TREE_TYPE (value))
-             == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
-       return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
-
-      /* Allow conversions between other integer types only if
-        explicit value.  */
-      if (INTEGRAL_TYPE_P (TREE_TYPE (value))
-         && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
-       {
-         tree inner = initializer_constant_valid_p (TREE_OPERAND (value, 0),
-                                                    endtype);
-         if (inner == null_pointer_node)
-           return null_pointer_node;
-         break;
-       }
+      {
+       tree src;
+       tree src_type;
+       tree dest_type;
+
+       src = TREE_OPERAND (value, 0);
+       src_type = TREE_TYPE (src);
+       dest_type = TREE_TYPE (value);
+
+       /* Allow conversions between pointer types, floating-point
+          types, and offset types.  */
+       if ((POINTER_TYPE_P (dest_type) && POINTER_TYPE_P (src_type))
+           || (FLOAT_TYPE_P (dest_type) && FLOAT_TYPE_P (src_type))
+           || (TREE_CODE (dest_type) == OFFSET_TYPE
+               && TREE_CODE (src_type) == OFFSET_TYPE))
+         return initializer_constant_valid_p (src, endtype);
+
+       /* Allow length-preserving conversions between integer types.  */
+       if (INTEGRAL_TYPE_P (dest_type) && INTEGRAL_TYPE_P (src_type)
+           && (TYPE_PRECISION (dest_type) == TYPE_PRECISION (src_type)))
+         return initializer_constant_valid_p (src, endtype);
+
+       /* Allow conversions between other integer types only if
+          explicit value.  */
+       if (INTEGRAL_TYPE_P (dest_type) && INTEGRAL_TYPE_P (src_type))
+         {
+           tree inner = initializer_constant_valid_p (src, endtype);
+           if (inner == null_pointer_node)
+             return null_pointer_node;
+           break;
+         }
 
-      /* Allow (int) &foo provided int is as wide as a pointer.  */
-      if (INTEGRAL_TYPE_P (TREE_TYPE (value))
-         && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0)))
-         && (TYPE_PRECISION (TREE_TYPE (value))
-             >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
-       return initializer_constant_valid_p (TREE_OPERAND (value, 0),
-                                            endtype);
-
-      /* Likewise conversions from int to pointers, but also allow
-        conversions from 0.  */
-      if (POINTER_TYPE_P (TREE_TYPE (value))
-         && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
-       {
-         if (integer_zerop (TREE_OPERAND (value, 0)))
-           return null_pointer_node;
-         else if (TYPE_PRECISION (TREE_TYPE (value))
-                  <= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0))))
-           return initializer_constant_valid_p (TREE_OPERAND (value, 0),
-                                                endtype);
-       }
+       /* Allow (int) &foo provided int is as wide as a pointer.  */
+       if (INTEGRAL_TYPE_P (dest_type) && POINTER_TYPE_P (src_type)
+           && (TYPE_PRECISION (dest_type) >= TYPE_PRECISION (src_type)))
+         return initializer_constant_valid_p (src, endtype);
+
+       /* Likewise conversions from int to pointers, but also allow
+          conversions from 0.  */
+       if ((POINTER_TYPE_P (dest_type)
+            || TREE_CODE (dest_type) == OFFSET_TYPE)
+           && INTEGRAL_TYPE_P (src_type))
+         {
+           if (integer_zerop (src))
+             return null_pointer_node;
+           else if (TYPE_PRECISION (dest_type) <= TYPE_PRECISION (src_type))
+             return initializer_constant_valid_p (src, endtype);
+         }
 
-      /* Allow conversions to union types if the value inside is okay.  */
-      if (TREE_CODE (TREE_TYPE (value)) == UNION_TYPE)
-       return initializer_constant_valid_p (TREE_OPERAND (value, 0),
-                                            endtype);
+       /* Allow conversions to struct or union types if the value
+          inside is okay.  */
+       if (TREE_CODE (dest_type) == RECORD_TYPE
+           || TREE_CODE (dest_type) == UNION_TYPE)
+         return initializer_constant_valid_p (src, endtype);
+      }
       break;
 
     case PLUS_EXPR:
@@ -3760,16 +3743,17 @@ initializer_constant_valid_p (value, endtype)
          /* Since GCC guarantees that string constants are unique in the
             generated code, a subtraction between two copies of the same
             constant string is absolute.  */
-         if (valid0 && TREE_CODE (valid0) == STRING_CST &&
-             valid1 && TREE_CODE (valid1) == STRING_CST &&
-             TREE_STRING_POINTER (valid0) == TREE_STRING_POINTER (valid1))
+         if (valid0 && TREE_CODE (valid0) == STRING_CST
+             && valid1 && TREE_CODE (valid1) == STRING_CST
+             && operand_equal_p (valid0, valid1, 1))
            return null_pointer_node;
        }
 
-      /* Support differences between labels.  */
+      /* Support narrowing differences.  */
       if (INTEGRAL_TYPE_P (endtype))
        {
          tree op0, op1;
+
          op0 = TREE_OPERAND (value, 0);
          op1 = TREE_OPERAND (value, 1);
 
@@ -3804,11 +3788,25 @@ initializer_constant_valid_p (value, endtype)
              op1 = inner;
            }
 
-         if (TREE_CODE (op0) == ADDR_EXPR
-             && TREE_CODE (TREE_OPERAND (op0, 0)) == LABEL_DECL
-             && TREE_CODE (op1) == ADDR_EXPR
-             && TREE_CODE (TREE_OPERAND (op1, 0)) == LABEL_DECL)
-           return null_pointer_node;
+         op0 = initializer_constant_valid_p (op0, endtype);
+         op1 = initializer_constant_valid_p (op1, endtype);
+
+         /* Both initializers must be known.  */
+         if (op0 && op1)
+           {
+             if (op0 == op1)
+               return null_pointer_node;
+
+             /* Support differences between labels.  */
+             if (TREE_CODE (op0) == LABEL_DECL
+                 && TREE_CODE (op1) == LABEL_DECL)
+               return null_pointer_node;
+
+             if (TREE_CODE (op0) == STRING_CST
+                 && TREE_CODE (op1) == STRING_CST
+                 && operand_equal_p (op0, op1, 1))
+               return null_pointer_node;
+           }
        }
       break;
 
@@ -3840,35 +3838,71 @@ 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-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);
+  exp = lang_hooks.expand_constant (exp);
 
   if (size == 0 || flag_syntax_only)
     return;
 
+  /* See if we're trying to initialize a pointer in a non-default mode
+     to the address of some declaration somewhere.  If the target says
+     the mode is valid for pointers, assume the target has a way of
+     resolving it.  */
+  if (TREE_CODE (exp) == NOP_EXPR
+      && POINTER_TYPE_P (TREE_TYPE (exp))
+      && targetm.valid_pointer_mode (TYPE_MODE (TREE_TYPE (exp))))
+    {
+      tree saved_type = TREE_TYPE (exp);
+
+      /* Peel off any intermediate conversions-to-pointer for valid
+        pointer modes.  */
+      while (TREE_CODE (exp) == NOP_EXPR
+            && POINTER_TYPE_P (TREE_TYPE (exp))
+            && targetm.valid_pointer_mode (TYPE_MODE (TREE_TYPE (exp))))
+       exp = TREE_OPERAND (exp, 0);
+
+      /* If what we're left with is the address of something, we can
+        convert the address to the final type and output it that
+        way.  */
+      if (TREE_CODE (exp) == ADDR_EXPR)
+       exp = build1 (ADDR_EXPR, saved_type, TREE_OPERAND (exp, 0));
+    }
+
   /* Eliminate any conversions since we'll be outputting the underlying
      constant.  */
   while (TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR
         || TREE_CODE (exp) == NON_LVALUE_EXPR
         || TREE_CODE (exp) == VIEW_CONVERT_EXPR)
-    exp = TREE_OPERAND (exp, 0);
+    {
+      HOST_WIDE_INT type_size = int_size_in_bytes (TREE_TYPE (exp));
+      HOST_WIDE_INT op_size = int_size_in_bytes (TREE_TYPE (TREE_OPERAND (exp, 0)));
+
+      /* Make sure eliminating the conversion is really a no-op, except with
+        VIEW_CONVERT_EXPRs to allow for wild Ada unchecked conversions and
+        union types to allow for Ada unchecked unions.  */
+      if (type_size > op_size
+         && TREE_CODE (exp) != VIEW_CONVERT_EXPR
+         && TREE_CODE (TREE_TYPE (exp)) != UNION_TYPE)
+       internal_error ("no-op convert from %wd to %wd bytes in initializer",
+                       op_size, type_size);
+
+      exp = TREE_OPERAND (exp, 0);
+    }
 
   code = TREE_CODE (TREE_TYPE (exp));
   thissize = int_size_in_bytes (TREE_TYPE (exp));
 
   /* Allow a constructor with no elements for any data type.
      This means to fill the space with zeros.  */
-  if (TREE_CODE (exp) == CONSTRUCTOR && CONSTRUCTOR_ELTS (exp) == 0)
+  if (TREE_CODE (exp) == CONSTRUCTOR
+      && VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (exp)))
     {
       assemble_zeros (size);
       return;
@@ -3881,13 +3915,13 @@ output_constant (exp, size, align)
       tree decl = TREE_OPERAND (exp, 0);
       ASM_OUTPUT_FDESC (asm_out_file, decl, part);
 #else
-      abort ();
+      gcc_unreachable ();
 #endif
       return;
     }
 
   /* Now output the underlying data.  If we've handling the padding, return.
-     Otherwise, break and ensure THISSIZE is the size written.  */
+     Otherwise, break and ensure SIZE is the size written.  */
   switch (code)
     {
     case CHAR_TYPE:
@@ -3896,9 +3930,10 @@ 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))
+                             MIN (size, thissize), align, 0))
        error ("initializer for integer value is too complicated");
       break;
 
@@ -3906,9 +3941,7 @@ output_constant (exp, size, align)
       if (TREE_CODE (exp) != REAL_CST)
        error ("initializer for floating value is not a floating constant");
 
-      assemble_real (TREE_REAL_CST (exp),
-                    mode_for_size (size * BITS_PER_UNIT, MODE_FLOAT, 0),
-                    align);
+      assemble_real (TREE_REAL_CST (exp), TYPE_MODE (TREE_TYPE (exp)), align);
       break;
 
     case COMPLEX_TYPE:
@@ -3919,71 +3952,55 @@ output_constant (exp, size, align)
 
     case ARRAY_TYPE:
     case VECTOR_TYPE:
-      if (TREE_CODE (exp) == CONSTRUCTOR)
+      switch (TREE_CODE (exp))
        {
+       case CONSTRUCTOR:
          output_constructor (exp, size, align);
          return;
-       }
-      else if (TREE_CODE (exp) == STRING_CST)
-       {
-         thissize = MIN (TREE_STRING_LENGTH (exp), size);
+       case STRING_CST:
+         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)));
+         break;
 
-         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);
+       case VECTOR_CST:
+         {
+           int elt_size;
+           tree link;
+           unsigned int nalign;
+           enum machine_mode inner;
+           
+           inner = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
+           nalign = MIN (align, GET_MODE_ALIGNMENT (inner));
+           
+           elt_size = GET_MODE_SIZE (inner);
+           
+           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);
+           break;
+         }
+       default:
+         gcc_unreachable ();
        }
-      else
-       abort ();
       break;
 
     case RECORD_TYPE:
     case UNION_TYPE:
-      if (TREE_CODE (exp) == CONSTRUCTOR)
-       output_constructor (exp, size, align);
-      else
-       abort ();
-      return;
-
-    case SET_TYPE:
-      if (TREE_CODE (exp) == INTEGER_CST)
-       assemble_integer (expand_expr (exp, NULL_RTX,
-                                      VOIDmode, EXPAND_INITIALIZER),
-                         thissize, align, 1);
-      else if (TREE_CODE (exp) == CONSTRUCTOR)
-       {
-         unsigned char *buffer = (unsigned char *) alloca (thissize);
-         if (get_set_constructor_bytes (exp, buffer, thissize))
-           abort ();
-         assemble_string ((char *) buffer, thissize);
-       }
-      else
-       error ("unknown set constructor type");
+      gcc_assert (TREE_CODE (exp) == CONSTRUCTOR);
+      output_constructor (exp, size, align);
       return;
 
     case ERROR_MARK:
       return;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
-  size -= thissize;
-  if (size > 0)
-    assemble_zeros (size);
+  if (size > thissize)
+    assemble_zeros (size - thissize);
 }
 
 \f
@@ -3992,10 +4009,11 @@ 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;
+  unsigned HOST_WIDE_INT cnt;
+  tree index, value;
 
   /* This code used to attempt to handle string constants that are not
      arrays of single-bytes, but nothing else does, so there's no point in
@@ -4004,10 +4022,8 @@ array_size_for_constructor (val)
     return TREE_STRING_LENGTH (val);
 
   max_index = NULL_TREE;
-  for (i = CONSTRUCTOR_ELTS (val); i; i = TREE_CHAIN (i))
+  FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (val), cnt, index, value)
     {
-      tree index = TREE_PURPOSE (i);
-
       if (TREE_CODE (index) == RANGE_EXPR)
        index = TREE_OPERAND (index, 1);
       if (max_index == NULL_TREE || tree_int_cst_lt (max_index, index))
@@ -4033,13 +4049,11 @@ 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;
+  tree field = 0;
   tree min_index = 0;
   /* Number of bytes output or skipped so far.
      In other words, current position within the constructor.  */
@@ -4047,9 +4061,10 @@ output_constructor (exp, size, align)
   /* Nonzero means BYTE contains part of a byte, to be output.  */
   int byte_buffer_in_use = 0;
   int byte = 0;
+  unsigned HOST_WIDE_INT cnt;
+  constructor_elt *ce;
 
-  if (HOST_BITS_PER_WIDE_INT < BITS_PER_UNIT)
-    abort ();
+  gcc_assert (HOST_BITS_PER_WIDE_INT >= BITS_PER_UNIT);
 
   if (TREE_CODE (type) == RECORD_TYPE)
     field = TYPE_FIELDS (type);
@@ -4067,23 +4082,31 @@ output_constructor (exp, size, align)
      There is always a maximum of one element in the chain LINK for unions
      (even if the initializer in a source program incorrectly contains
      more one).  */
-  for (link = CONSTRUCTOR_ELTS (exp);
-       link;
-       link = TREE_CHAIN (link),
-       field = field ? TREE_CHAIN (field) : 0)
+  for (cnt = 0;
+       VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (exp), cnt, ce);
+       cnt++, field = field ? TREE_CHAIN (field) : 0)
     {
-      tree val = TREE_VALUE (link);
+      tree val = ce->value;
       tree index = 0;
 
       /* The element in a union constructor specifies the proper field
         or index.  */
       if ((TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE
           || TREE_CODE (type) == QUAL_UNION_TYPE)
-         && TREE_PURPOSE (link) != 0)
-       field = TREE_PURPOSE (link);
+         && ce->index != 0)
+       field = ce->index;
 
       else if (TREE_CODE (type) == ARRAY_TYPE)
-       index = TREE_PURPOSE (link);
+       index = ce->index;
+
+#ifdef ASM_COMMENT_START
+      if (field && flag_verbose_asm)
+       fprintf (asm_out_file, "%s %s:\n",
+                ASM_COMMENT_START, 
+                DECL_NAME (field) 
+                ? IDENTIFIER_POINTER (DECL_NAME (field))
+                : "<anonymous>");
+#endif
 
       /* Eliminate the marker that makes a cast not be an lvalue.  */
       if (val != 0)
@@ -4137,6 +4160,7 @@ output_constructor (exp, size, align)
             if each element has the proper size.  */
          if ((field != 0 || index != 0) && pos != total_bytes)
            {
+             gcc_assert (pos >= total_bytes);
              assemble_zeros (pos - total_bytes);
              total_bytes = pos;
            }
@@ -4161,8 +4185,7 @@ output_constructor (exp, size, align)
                  fieldsize = array_size_for_constructor (val);
                  /* Given a non-empty initialization, this field had
                     better be last.  */
-                 if (fieldsize != 0 && TREE_CHAIN (field) != NULL_TREE)
-                   abort ();
+                 gcc_assert (!fieldsize || !TREE_CHAIN (field));
                }
              else if (DECL_SIZE_UNIT (field))
                {
@@ -4185,7 +4208,7 @@ output_constructor (exp, size, align)
          total_bytes += fieldsize;
        }
       else if (val != 0 && TREE_CODE (val) != INTEGER_CST)
-       error ("invalid initial value for member `%s'",
+       error ("invalid initial value for member %qs",
               IDENTIFIER_POINTER (DECL_NAME (field)));
       else
        {
@@ -4213,6 +4236,7 @@ output_constructor (exp, size, align)
              /* If still not at proper byte, advance to there.  */
              if (next_offset / BITS_PER_UNIT != total_bytes)
                {
+                 gcc_assert (next_offset / BITS_PER_UNIT >= total_bytes);
                  assemble_zeros (next_offset / BITS_PER_UNIT - total_bytes);
                  total_bytes = next_offset / BITS_PER_UNIT;
                }
@@ -4271,13 +4295,12 @@ output_constructor (exp, size, align)
                  /* Now get the bits from the appropriate constant word.  */
                  if (shift < HOST_BITS_PER_WIDE_INT)
                    value = TREE_INT_CST_LOW (val);
-                 else if (shift < 2 * HOST_BITS_PER_WIDE_INT)
+                 else
                    {
+                     gcc_assert (shift < 2 * HOST_BITS_PER_WIDE_INT);
                      value = TREE_INT_CST_HIGH (val);
                      shift -= HOST_BITS_PER_WIDE_INT;
                    }
-                 else
-                   abort ();
 
                  /* Get the result. This works only when:
                     1 <= this_time <= HOST_BITS_PER_WIDE_INT.  */
@@ -4304,13 +4327,12 @@ output_constructor (exp, size, align)
                  /* Now get the bits from the appropriate constant word.  */
                  if (shift < HOST_BITS_PER_WIDE_INT)
                    value = TREE_INT_CST_LOW (val);
-                 else if (shift < 2 * HOST_BITS_PER_WIDE_INT)
+                 else
                    {
+                     gcc_assert (shift < 2 * HOST_BITS_PER_WIDE_INT);
                      value = TREE_INT_CST_HIGH (val);
                      shift -= HOST_BITS_PER_WIDE_INT;
                    }
-                 else
-                   abort ();
 
                  /* Get the result. This works only when:
                     1 <= this_time <= HOST_BITS_PER_WIDE_INT.  */
@@ -4331,7 +4353,7 @@ output_constructor (exp, size, align)
       total_bytes++;
     }
 
-  if (total_bytes < size)
+  if ((unsigned HOST_WIDE_INT)total_bytes < size)
     assemble_zeros (size - total_bytes);
 }
 
@@ -4342,13 +4364,12 @@ static GTY(()) tree weak_decls;
 /* Mark DECL as weak.  */
 
 static void
-mark_weak (decl)
-     tree decl;
+mark_weak (tree decl)
 {
   DECL_WEAK (decl) = 1;
 
   if (DECL_RTL_SET_P (decl)
-      && GET_CODE (DECL_RTL (decl)) == MEM
+      && MEM_P (DECL_RTL (decl))
       && XEXP (DECL_RTL (decl), 0)
       && GET_CODE (XEXP (DECL_RTL (decl), 0)) == SYMBOL_REF)
     SYMBOL_REF_WEAK (XEXP (DECL_RTL (decl), 0)) = 1;
@@ -4357,12 +4378,24 @@ mark_weak (decl)
 /* 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;
+    {
+      if (DECL_WEAK (newdecl) && SUPPORTS_WEAK)
+        {
+          tree *pwd;
+          /* We put the NEWDECL on the weak_decls list at some point
+             and OLDDECL as well.  Keep just OLDDECL on the list.  */
+         for (pwd = &weak_decls; *pwd; pwd = &TREE_CHAIN (*pwd))
+           if (TREE_VALUE (*pwd) == newdecl)
+             {
+               *pwd = TREE_CHAIN (*pwd);
+               break;
+             }
+        }
+      return;
+    }
 
   if (DECL_WEAK (newdecl))
     {
@@ -4375,15 +4408,16 @@ 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 ("weak declaration of %q+D must precede definition",
+              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 (0, "weak declaration of %q+D after first use results "
+                 "in unspecified behavior", newdecl);
 
       if (SUPPORTS_WEAK)
        {
@@ -4413,20 +4447,19 @@ 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 ("weak declaration of %q+D must be public", decl);
   else if (TREE_CODE (decl) == FUNCTION_DECL && TREE_ASM_WRITTEN (decl))
-    error_with_decl (decl, "weak declaration of `%s' must precede definition");
+    error ("weak declaration of %q+D must precede definition", 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 (0, "weak declaration of %q+D not supported", decl);
 
   mark_weak (decl);
 }
@@ -4434,7 +4467,7 @@ declare_weak (decl)
 /* Emit any pending weak declarations.  */
 
 void
-weak_finish ()
+weak_finish (void)
 {
   tree t;
 
@@ -4455,7 +4488,7 @@ weak_finish ()
       ASM_WEAKEN_LABEL (asm_out_file, name);
 #else
 #ifdef ASM_OUTPUT_WEAK_ALIAS
-      warning ("only weak aliases are supported in this configuration");
+      warning (0, "only weak aliases are supported in this configuration");
       return;
 #endif
 #endif
@@ -4466,8 +4499,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);
 
@@ -4493,25 +4525,84 @@ globalize_decl (decl)
        }
       return;
     }
+#elif defined(ASM_MAKE_LABEL_LINKONCE)
+  if (DECL_ONE_ONLY (decl))
+    ASM_MAKE_LABEL_LINKONCE (asm_out_file, name);
 #endif
 
-  (*targetm.asm_out.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.  */
+/* We have to be able to tell cgraph about the needed-ness of the target
+   of an alias.  This requires that the decl have been defined.  Aliases
+   that precede their definition have to be queued for later processing.  */
 
-void
-assemble_alias (decl, target)
-     tree decl, target ATTRIBUTE_UNUSED;
+typedef struct alias_pair GTY(())
 {
-  const char *name;
+  tree decl;
+  tree target;
+} alias_pair;
 
-  /* We must force creation of DECL_RTL for debug info generation, even though
-     we don't use it here.  */
-  make_decl_rtl (decl, NULL);
+/* Define gc'd vector type.  */
+DEF_VEC_O(alias_pair);
+DEF_VEC_ALLOC_O(alias_pair,gc);
 
-  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+static GTY(()) VEC(alias_pair,gc) *alias_pairs;
+
+/* Given an assembly name, find the decl it is associated with.  At the
+   same time, mark it needed for cgraph.  */
+
+static tree
+find_decl_and_mark_needed (tree decl, tree target)
+{
+  struct cgraph_node *fnode = NULL;
+  struct cgraph_varpool_node *vnode = NULL;
+
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    {
+      fnode = cgraph_node_for_asm (target);
+      if (fnode == NULL)
+       vnode = cgraph_varpool_node_for_asm (target);
+    }
+  else
+    {
+      vnode = cgraph_varpool_node_for_asm (target);
+      if (vnode == NULL)
+       fnode = cgraph_node_for_asm (target);
+    }
+
+  if (fnode)
+    {
+      /* We can't mark function nodes as used after cgraph global info
+        is finished.  This wouldn't generally be necessary, but C++
+        virtual table thunks are introduced late in the game and
+        might seem like they need marking, although in fact they
+        don't.  */
+      if (! cgraph_global_info_ready)
+       cgraph_mark_needed_node (fnode);
+      return fnode->decl;
+    }
+  else if (vnode)
+    {
+      cgraph_varpool_mark_needed_node (vnode);
+      return vnode->decl;
+    }
+  else 
+    return NULL_TREE;
+}
+
+/* Output the assembler code for a define (equate) using ASM_OUTPUT_DEF
+   or ASM_OUTPUT_DEF_FROM_DECLS.  The function defines the symbol whose
+   tree node is DECL to have the value of the tree node TARGET.  */
+
+static void
+do_assemble_alias (tree decl, tree target ATTRIBUTE_UNUSED)
+{
+  if (TREE_ASM_WRITTEN (decl))
+    return;
+
+  TREE_ASM_WRITTEN (decl) = 1;
+  TREE_ASM_WRITTEN (DECL_ASSEMBLER_NAME (decl)) = 1;
 
 #ifdef ASM_OUTPUT_DEF
   /* Make name accessible from other files, if appropriate.  */
@@ -4522,38 +4613,129 @@ assemble_alias (decl, target)
       maybe_assemble_visibility (decl);
     }
 
-#ifdef ASM_OUTPUT_DEF_FROM_DECLS
+# ifdef ASM_OUTPUT_DEF_FROM_DECLS
   ASM_OUTPUT_DEF_FROM_DECLS (asm_out_file, decl, target);
-#else
-  ASM_OUTPUT_DEF (asm_out_file, name, IDENTIFIER_POINTER (target));
+# else
+  ASM_OUTPUT_DEF (asm_out_file,
+                 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
+                 IDENTIFIER_POINTER (target));
+# endif
+#elif defined (ASM_OUTPUT_WEAK_ALIAS) || defined (ASM_WEAKEN_DECL)
+  {
+    const char *name;
+    tree *p, t;
+
+    name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+# ifdef ASM_WEAKEN_DECL
+    ASM_WEAKEN_DECL (asm_out_file, decl, name, IDENTIFIER_POINTER (target));
+# else
+    ASM_OUTPUT_WEAK_ALIAS (asm_out_file, name, IDENTIFIER_POINTER (target));
+# endif
+    /* Remove this function from the pending weak list so that
+       we do not emit multiple .weak directives for it.  */
+    for (p = &weak_decls; (t = *p) ; )
+      if (DECL_ASSEMBLER_NAME (decl) == DECL_ASSEMBLER_NAME (TREE_VALUE (t)))
+       *p = TREE_CHAIN (t);
+      else
+       p = &TREE_CHAIN (t);
+  }
 #endif
-#else /* !ASM_OUTPUT_DEF */
-#if defined (ASM_OUTPUT_WEAK_ALIAS) || defined (ASM_WEAKEN_DECL)
-  if (! DECL_WEAK (decl))
-    warning ("only weak aliases are supported in this configuration");
+}
 
-#ifdef ASM_WEAKEN_DECL
-  ASM_WEAKEN_DECL (asm_out_file, decl, name, IDENTIFIER_POINTER (target));
-#else
-  ASM_OUTPUT_WEAK_ALIAS (asm_out_file, name, IDENTIFIER_POINTER (target));
-#endif
-#else
-  warning ("alias definitions not supported in this configuration; ignored");
-#endif
+/* First pass of completing pending aliases.  Make sure that cgraph knows
+   which symbols will be required.  */
+
+void
+finish_aliases_1 (void)
+{
+  unsigned i;
+  alias_pair *p;
+
+  for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); i++)
+    {
+      tree target_decl;
+
+      target_decl = find_decl_and_mark_needed (p->decl, p->target);
+      if (target_decl == NULL)
+       error ("%q+D aliased to undefined symbol %qs",
+              p->decl, IDENTIFIER_POINTER (p->target));
+      else if (DECL_EXTERNAL (target_decl))
+       error ("%q+D aliased to external symbol %qs",
+              p->decl, IDENTIFIER_POINTER (p->target));
+    }
+}
+
+/* Second pass of completing pending aliases.  Emit the actual assembly.
+   This happens at the end of compilation and thus it is assured that the
+   target symbol has been emitted.  */
+
+void
+finish_aliases_2 (void)
+{
+  unsigned i;
+  alias_pair *p;
+
+  for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); i++)
+    do_assemble_alias (p->decl, p->target);
+
+  VEC_truncate (alias_pair, alias_pairs, 0);
+}
+
+/* Emit an assembler directive to make the symbol for DECL an alias to
+   the symbol for TARGET.  */
+
+void
+assemble_alias (tree decl, tree target)
+{
+  tree target_decl;
+
+#if !defined (ASM_OUTPUT_DEF)
+# if !defined(ASM_OUTPUT_WEAK_ALIAS) && !defined (ASM_WEAKEN_DECL)
+  error ("%Jalias definitions not supported in this configuration", decl);
+  return;
+# else
+  if (!DECL_WEAK (decl))
+    {
+      error ("%Jonly weak aliases are supported in this configuration", decl);
+      return;
+    }
+# endif
 #endif
 
+  /* We must force creation of DECL_RTL for debug info generation, even though
+     we don't use it here.  */
+  make_decl_rtl (decl);
   TREE_USED (decl) = 1;
-  TREE_ASM_WRITTEN (decl) = 1;
-  TREE_ASM_WRITTEN (DECL_ASSEMBLER_NAME (decl)) = 1;
+
+  /* A quirk of the initial implementation of aliases required that the user
+     add "extern" to all of them.  Which is silly, but now historical.  Do
+     note that the symbol is in fact locally defined.  */
+  DECL_EXTERNAL (decl) = 0;
+
+  /* Allow aliases to aliases.  */
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    cgraph_node (decl)->alias = true;
+  else
+    cgraph_varpool_node (decl)->alias = true;
+
+  /* If the target has already been emitted, we don't have to queue the
+     alias.  This saves a tad o memory.  */
+  target_decl = find_decl_and_mark_needed (decl, target);
+  if (target_decl && TREE_ASM_WRITTEN (target_decl))
+    do_assemble_alias (decl, target);
+  else
+    {
+      alias_pair *p = VEC_safe_push (alias_pair, gc, alias_pairs, NULL);
+      p->decl = decl;
+      p->target = target;
+    }
 }
 
 /* Emit an assembler directive to set symbol for DECL visibility to
    the visibility type VIS, which must not be VISIBILITY_DEFAULT.  */
 
 void
-default_assemble_visibility (decl, vis)
-     tree decl;
-     int vis;
+default_assemble_visibility (tree decl, int vis)
 {
   static const char * const visibility_types[] = {
     NULL, "internal", "hidden", "protected"
@@ -4561,27 +4743,28 @@ default_assemble_visibility (decl, vis)
 
   const char *name, *type;
 
-  name = (* targetm.strip_name_encoding)
-        (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
+  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
   type = visibility_types[vis];
 
 #ifdef HAVE_GAS_HIDDEN
-  fprintf (asm_out_file, "\t.%s\t%s\n", 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");
+  warning (OPT_Wattributes, "visibility attribute not supported "
+          "in this configuration; ignored");
 #endif
 }
 
 /* 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)
 {
-  enum symbol_visibility vis = decl_visibility (decl);
+  enum symbol_visibility vis = DECL_VISIBILITY (decl);
 
   if (vis != VISIBILITY_DEFAULT)
-    (* targetm.asm_out.visibility) (decl, vis);
+    targetm.asm_out.visibility (decl, vis);
 }
 
 /* Returns 1 if the target configuration supports defining public symbols
@@ -4590,7 +4773,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;
@@ -4601,75 +4784,56 @@ 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 ();
+  gcc_assert (TREE_CODE (decl) == VAR_DECL
+             || TREE_CODE (decl) == FUNCTION_DECL);
 
   TREE_PUBLIC (decl) = 1;
 
-  if (TREE_CODE (decl) == VAR_DECL
-      && (DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node))
-    DECL_COMMON (decl) = 1;
-  else if (SUPPORTS_ONE_ONLY)
+  if (SUPPORTS_ONE_ONLY)
     {
 #ifdef MAKE_DECL_ONE_ONLY
       MAKE_DECL_ONE_ONLY (decl);
 #endif
       DECL_ONE_ONLY (decl) = 1;
     }
-  else if (SUPPORTS_WEAK)
-    DECL_WEAK (decl) = 1;
+  else if (TREE_CODE (decl) == VAR_DECL
+      && (DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node))
+    DECL_COMMON (decl) = 1;
   else
-    abort ();
+    {
+      gcc_assert (SUPPORTS_WEAK);
+      DECL_WEAK (decl) = 1;
+    }
 }
 
 void
-init_varasm_once ()
+init_varasm_once (void)
 {
-  const_str_htab = htab_create_ggc (128, const_str_htab_hash,
-                                   const_str_htab_eq, NULL);
   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 (decl)
-     tree decl;
+decl_default_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)
+  is_local = targetm.binds_local_p (decl);
+  if (!flag_shlib)
     {
       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)
@@ -4682,31 +4846,6 @@ decl_tls_model (decl)
   return kind;
 }
 
-enum symbol_visibility
-decl_visibility (decl)
-     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.
@@ -4715,20 +4854,14 @@ decl_visibility (decl)
    read-only for a const data decl, and writable for a non-const data decl.  */
 
 unsigned int
-default_section_type_flags (decl, name, reloc)
-     tree decl;
-     const char *name;
-     int reloc;
+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 (decl, name, reloc, shlib)
-     tree decl;
-     const char *name;
-     int reloc;
-     int shlib;
+default_section_type_flags_1 (tree decl, const char *name, int reloc,
+                             int shlib)
 {
   unsigned int flags;
 
@@ -4736,13 +4869,22 @@ default_section_type_flags_1 (decl, name, reloc, shlib)
     flags = SECTION_CODE;
   else if (decl && decl_readonly_section_1 (decl, reloc, shlib))
     flags = 0;
+  else if (current_function_decl
+          && cfun
+          && cfun->unlikely_text_section_name
+          && strcmp (name, cfun->unlikely_text_section_name) == 0)
+    flags = SECTION_CODE;
+  else if (!decl 
+          && (!current_function_decl || !cfun)
+          && strcmp (name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0)
+    flags = SECTION_CODE; 
   else
     flags = SECTION_WRITE;
 
   if (decl && DECL_ONE_ONLY (decl))
     flags |= SECTION_LINKONCE;
 
-  if (decl && TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
+  if (decl && TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl))
     flags |= SECTION_TLS | SECTION_WRITE;
 
   if (strcmp (name, ".bss") == 0
@@ -4750,17 +4892,19 @@ default_section_type_flags_1 (decl, name, reloc, shlib)
       || strncmp (name, ".gnu.linkonce.b.", 16) == 0
       || strcmp (name, ".sbss") == 0
       || strncmp (name, ".sbss.", 6) == 0
-      || strncmp (name, ".gnu.linkonce.sb.", 17) == 0
-      || strcmp (name, ".tbss") == 0
-      || strncmp (name, ".gnu.linkonce.tb.", 17) == 0)
+      || strncmp (name, ".gnu.linkonce.sb.", 17) == 0)
     flags |= SECTION_BSS;
 
   if (strcmp (name, ".tdata") == 0
-      || strcmp (name, ".tbss") == 0
-      || strncmp (name, ".gnu.linkonce.td.", 17) == 0
-      || strncmp (name, ".gnu.linkonce.tb.", 17) == 0)
+      || strncmp (name, ".tdata.", 7) == 0
+      || strncmp (name, ".gnu.linkonce.td.", 17) == 0)
     flags |= SECTION_TLS;
 
+  if (strcmp (name, ".tbss") == 0
+      || strncmp (name, ".tbss.", 6) == 0
+      || strncmp (name, ".gnu.linkonce.tb.", 17) == 0)
+    flags |= SECTION_TLS | SECTION_BSS;
+
   /* 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
@@ -4779,23 +4923,27 @@ default_section_type_flags_1 (decl, name, reloc, shlib)
    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,
+                         tree decl ATTRIBUTE_UNUSED)
 {
   /* Some object formats don't support named sections at all.  The
      front-end should already have flagged this as an error.  */
-  abort ();
+  gcc_unreachable ();
 }
 
 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,
+                              tree decl ATTRIBUTE_UNUSED)
 {
   char flagchars[10], *f = flagchars;
 
-  if (! named_section_first_declaration (name))
+  /* If we have already declared this section, we can use an
+     abbreviated form to switch back to it -- unless this section is
+     part of a COMDAT groups, in which case GAS requires the full
+     declaration every time.  */
+  if (!(HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))
+      && ! named_section_first_declaration (name))
     {
       fprintf (asm_out_file, "\t.section\t%s\n", name);
       return;
@@ -4815,6 +4963,8 @@ default_elf_asm_named_section (name, flags)
     *f++ = 'S';
   if (flags & SECTION_TLS)
     *f++ = 'T';
+  if (HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))
+    *f++ = 'G';
   *f = '\0';
 
   fprintf (asm_out_file, "\t.section\t%s,\"%s\"", name, flagchars);
@@ -4822,25 +4972,35 @@ default_elf_asm_named_section (name, flags)
   if (!(flags & SECTION_NOTYPE))
     {
       const char *type;
+      const char *format;
 
       if (flags & SECTION_BSS)
        type = "nobits";
       else
        type = "progbits";
 
-      fprintf (asm_out_file, ",@%s", type);
+      format = ",@%s";
+#ifdef ASM_COMMENT_START
+      /* On platforms that use "@" as the assembly comment character,
+        use "%" instead.  */
+      if (strcmp (ASM_COMMENT_START, "@") == 0)
+       format = ",%%%s";
+#endif
+      fprintf (asm_out_file, format, type);
 
       if (flags & SECTION_ENTSIZE)
        fprintf (asm_out_file, ",%d", flags & SECTION_ENTSIZE);
+      if (HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))
+       fprintf (asm_out_file, ",%s,comdat", 
+                lang_hooks.decls.comdat_group (decl));
     }
 
   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, 
+                               tree decl ATTRIBUTE_UNUSED)
 {
   char flagchars[8], *f = flagchars;
 
@@ -4854,11 +5014,10 @@ 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,
+                             tree decl)
 {
-  default_coff_asm_named_section (name, flags);
+  default_coff_asm_named_section (name, flags, decl);
 
   if (flags & SECTION_LINKONCE)
     {
@@ -4870,42 +5029,11 @@ 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;
 
@@ -4923,7 +5051,7 @@ default_select_section (decl, reloc, align)
        readonly = true;
     }
   else if (TREE_CODE (decl) == STRING_CST)
-    readonly = !flag_writable_strings;
+    readonly = true;
   else if (! (flag_pic && reloc))
     readonly = true;
 
@@ -4933,51 +5061,8 @@ default_select_section (decl, reloc, align)
     data_section ();
 }
 
-/* A helper function for default_elf_select_section and
-   default_elf_unique_section.  Categorizes the DECL.  */
-
 enum section_category
-{
-  SECCAT_TEXT,
-
-  SECCAT_RODATA,
-  SECCAT_RODATA_MERGE_STR,
-  SECCAT_RODATA_MERGE_STR_INIT,
-  SECCAT_RODATA_MERGE_CONST,
-  SECCAT_SRODATA,
-
-  SECCAT_DATA,
-
-  /* To optimize loading of shared programs, define following subsections
-     of data section:
-       _REL    Contains data that has relocations, so they get grouped
-               together and dynamic linker will visit fewer pages in memory.
-       _RO     Contains data that is otherwise read-only.  This is useful
-               with prelinking as most relocations won't be dynamically
-               linked and thus stay read only.
-       _LOCAL  Marks data containing relocations only to local objects.
-               These relocations will get fully resolved by prelinking.  */
-  SECCAT_DATA_REL,
-  SECCAT_DATA_REL_LOCAL,
-  SECCAT_DATA_REL_RO,
-  SECCAT_DATA_REL_RO_LOCAL,
-
-  SECCAT_SDATA,
-  SECCAT_TDATA,
-
-  SECCAT_BSS,
-  SECCAT_SBSS,
-  SECCAT_TBSS
-};
-
-static enum section_category
-categorize_decl_for_section PARAMS ((tree, int, int));
-
-static enum section_category
-categorize_decl_for_section (decl, reloc, shlib)
-     tree decl;
-     int reloc;
-     int shlib;
+categorize_decl_for_section (tree decl, int reloc, int shlib)
 {
   enum section_category ret;
 
@@ -4985,15 +5070,19 @@ categorize_decl_for_section (decl, reloc, shlib)
     return SECCAT_TEXT;
   else if (TREE_CODE (decl) == STRING_CST)
     {
-      if (flag_writable_strings)
-       return SECCAT_DATA;
+      if (flag_mudflap) /* or !flag_merge_constants */
+        return SECCAT_RODATA;
       else
        return SECCAT_RODATA_MERGE_STR;
     }
   else if (TREE_CODE (decl) == VAR_DECL)
     {
       if (DECL_INITIAL (decl) == NULL
-         || DECL_INITIAL (decl) == error_mark_node)
+         || DECL_INITIAL (decl) == error_mark_node
+         || (flag_zero_initialized_in_bss
+             /* Leave constant zeroes in .rodata so they can be shared.  */
+             && !TREE_READONLY (decl)
+             && initializer_zerop (DECL_INITIAL (decl))))
        ret = SECCAT_BSS;
       else if (! TREE_READONLY (decl)
               || TREE_SIDE_EFFECTS (decl)
@@ -5033,16 +5122,20 @@ categorize_decl_for_section (decl, reloc, shlib)
     ret = SECCAT_RODATA;
 
   /* There are no read-only thread-local sections.  */
-  if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
+  if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl))
     {
-      if (ret == SECCAT_BSS)
+      /* Note that this would be *just* SECCAT_BSS, except that there's
+        no concept of a read-only thread-local-data section.  */
+      if (ret == SECCAT_BSS
+         || (flag_zero_initialized_in_bss
+             && initializer_zerop (DECL_INITIAL (decl))))
        ret = SECCAT_TBSS;
       else
        ret = SECCAT_TDATA;
     }
 
   /* If the target uses small data sections, select it.  */
-  else if ((*targetm.in_small_data_p) (decl))
+  else if (targetm.in_small_data_p (decl))
     {
       if (ret == SECCAT_BSS)
        ret = SECCAT_SBSS;
@@ -5056,18 +5149,13 @@ categorize_decl_for_section (decl, reloc, shlib)
 }
 
 bool
-decl_readonly_section (decl, reloc)
-     tree decl;
-     int reloc;
+decl_readonly_section (tree decl, int reloc)
 {
   return decl_readonly_section_1 (decl, reloc, flag_pic);
 }
 
 bool
-decl_readonly_section_1 (decl, reloc, shlib)
-     tree decl;
-     int reloc;
-     int shlib;
+decl_readonly_section_1 (tree decl, int reloc, int shlib)
 {
   switch (categorize_decl_for_section (decl, reloc, shlib))
     {
@@ -5087,98 +5175,95 @@ decl_readonly_section_1 (decl, reloc, shlib)
 /* 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 (decl, reloc, align, shlib)
-     tree decl;
-     int reloc;
-     unsigned HOST_WIDE_INT align;
-     int shlib;
+default_elf_select_section_1 (tree decl, int reloc,
+                             unsigned HOST_WIDE_INT align, int shlib)
 {
+  const char *sname;
   switch (categorize_decl_for_section (decl, reloc, shlib))
     {
     case SECCAT_TEXT:
       /* We're not supposed to be called on FUNCTION_DECLs.  */
-      abort ();
+      gcc_unreachable ();
     case SECCAT_RODATA:
       readonly_data_section ();
-      break;
+      return;
     case SECCAT_RODATA_MERGE_STR:
       mergeable_string_section (decl, align, 0);
-      break;
+      return;
     case SECCAT_RODATA_MERGE_STR_INIT:
       mergeable_string_section (DECL_INITIAL (decl), align, 0);
-      break;
+      return;
     case SECCAT_RODATA_MERGE_CONST:
       mergeable_constant_section (DECL_MODE (decl), align, 0);
-      break;
+      return;
     case SECCAT_SRODATA:
-      named_section (NULL_TREE, ".sdata2", reloc);
+      sname = ".sdata2";
       break;
     case SECCAT_DATA:
       data_section ();
-      break;
+      return;
     case SECCAT_DATA_REL:
-      named_section (NULL_TREE, ".data.rel", reloc);
+      sname = ".data.rel";
       break;
     case SECCAT_DATA_REL_LOCAL:
-      named_section (NULL_TREE, ".data.rel.local", reloc);
+      sname = ".data.rel.local";
       break;
     case SECCAT_DATA_REL_RO:
-      named_section (NULL_TREE, ".data.rel.ro", reloc);
+      sname = ".data.rel.ro";
       break;
     case SECCAT_DATA_REL_RO_LOCAL:
-      named_section (NULL_TREE, ".data.rel.ro.local", reloc);
+      sname = ".data.rel.ro.local";
       break;
     case SECCAT_SDATA:
-      named_section (NULL_TREE, ".sdata", reloc);
+      sname = ".sdata";
       break;
     case SECCAT_TDATA:
-      named_section (NULL_TREE, ".tdata", reloc);
+      sname = ".tdata";
       break;
     case SECCAT_BSS:
 #ifdef BSS_SECTION_ASM_OP
       bss_section ();
+      return;
 #else
-      named_section (NULL_TREE, ".bss", reloc);
-#endif
+      sname = ".bss";
       break;
+#endif
     case SECCAT_SBSS:
-      named_section (NULL_TREE, ".sbss", reloc);
+      sname = ".sbss";
       break;
     case SECCAT_TBSS:
-      named_section (NULL_TREE, ".tbss", reloc);
+      sname = ".tbss";
       break;
     default:
-      abort ();
+      gcc_unreachable ();
     }
+
+  if (!DECL_P (decl))
+    decl = NULL_TREE;
+  named_section (decl, sname, reloc);
 }
 
 /* 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 (decl, reloc, shlib)
-     tree decl;
-     int reloc;
-     int shlib;
+default_unique_section_1 (tree decl, int reloc, int shlib)
 {
-  bool one_only = DECL_ONE_ONLY (decl);
+  /* We only need to use .gnu.linkonce if we don't have COMDAT groups.  */
+  bool one_only = DECL_ONE_ONLY (decl) && !HAVE_COMDAT_GROUP;
   const char *prefix, *name;
   size_t nlen, plen;
   char *string;
@@ -5220,12 +5305,12 @@ default_unique_section_1 (decl, reloc, shlib)
       prefix = one_only ? ".gnu.linkonce.tb." : ".tbss.";
       break;
     default:
-      abort ();
+      gcc_unreachable ();
     }
   plen = strlen (prefix);
 
   name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
-  name = (* targetm.strip_name_encoding) (name);
+  name = targetm.strip_name_encoding (name);
   nlen = strlen (name);
 
   string = alloca (nlen + plen + 1);
@@ -5236,10 +5321,9 @@ default_unique_section_1 (decl, reloc, shlib)
 }
 
 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))
@@ -5258,10 +5342,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.  */
 
@@ -5287,16 +5369,13 @@ default_elf_select_rtx_section (mode, x, align)
 /* Set the generally applicable flags on the SYMBOL_REF for EXP.  */
 
 void
-default_encode_section_info (decl, rtl, first)
-     tree decl;
-     rtx rtl;
-     int first ATTRIBUTE_UNUSED;
+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)
+  if (!MEM_P (rtl))
     return;
   symbol = XEXP (rtl, 0);
   if (GET_CODE (symbol) != SYMBOL_REF)
@@ -5305,12 +5384,12 @@ default_encode_section_info (decl, rtl, first)
   flags = 0;
   if (TREE_CODE (decl) == FUNCTION_DECL)
     flags |= SYMBOL_FLAG_FUNCTION;
-  if ((*targetm.binds_local_p) (decl))
+  if (targetm.binds_local_p (decl))
     flags |= SYMBOL_FLAG_LOCAL;
-  if ((*targetm.in_small_data_p) (decl))
+  if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl))
+    flags |= DECL_TLS_MODEL (decl) << SYMBOL_FLAG_TLS_SHIFT;
+  else 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.  */
@@ -5324,8 +5403,7 @@ default_encode_section_info (decl, rtl, first)
    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 == '*');
 }
@@ -5334,16 +5412,13 @@ 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_pic);
+  return default_binds_local_p_1 (exp, flag_shlib);
 }
 
 bool
-default_binds_local_p_1 (exp, shlib)
-     tree exp;
-     int shlib;
+default_binds_local_p_1 (tree exp, int shlib)
 {
   bool local_p;
 
@@ -5353,8 +5428,8 @@ default_binds_local_p_1 (exp, shlib)
   /* 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)
+  /* A variable is local if the user explicitly tells us so.  */
+  else if (DECL_VISIBILITY_SPECIFIED (exp) && DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
     local_p = true;
   /* Otherwise, variables defined outside this object may not be local.  */
   else if (DECL_EXTERNAL (exp))
@@ -5362,6 +5437,9 @@ default_binds_local_p_1 (exp, shlib)
   /* Linkonce and weak data are never local.  */
   else if (DECL_ONE_ONLY (exp) || DECL_WEAK (exp))
     local_p = false;
+  /* If none of the above and visibility is not default, make local.  */
+  else if (DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
+    local_p = true;
   /* If PIC, then assume that any global name can be overridden by
      symbols resolved from other modules.  */
   else if (shlib)
@@ -5383,39 +5461,74 @@ default_binds_local_p_1 (exp, shlib)
 /* Determine whether or not a pointer mode is valid. Assume defaults
    of ptr_mode or Pmode - can be overridden.  */
 bool
-default_valid_pointer_mode (mode)
-     enum machine_mode mode;
+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
+   target must define GLOBAL_ASM_OP or provide its own function to
    globalize a label.  */
 #ifdef GLOBAL_ASM_OP
 void
-default_globalize_label (stream, name)
-     FILE * stream;
-     const char *name;
+default_globalize_label (FILE * stream, const char *name)
 {
   fputs (GLOBAL_ASM_OP, stream);
   assemble_name (stream, name);
   putc ('\n', stream);
 }
 #endif /* GLOBAL_ASM_OP */
-  
+
+/* Default function to output a label for unwind information.  The
+   default is to do nothing.  A target that needs nonlocal labels for
+   unwind information must provide its own function to do this.  */
+void
+default_emit_unwind_label (FILE * stream ATTRIBUTE_UNUSED,
+                          tree decl ATTRIBUTE_UNUSED,
+                          int for_eh ATTRIBUTE_UNUSED,
+                          int empty ATTRIBUTE_UNUSED)
+{ 
+}
+
 /* 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 (stream, prefix, labelno)
-     FILE *stream;
-     const char *prefix;
-     unsigned long labelno;
+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);
+  ASM_OUTPUT_INTERNAL_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.  */
+
+int trampolines_created;
+
+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"