OSDN Git Service

* reload1.c (emit_reload_insns): Set reg_has_output_reload to one
[pf3gnuchains/gcc-fork.git] / gcc / varasm.c
index 6b02b34..780bba8 100644 (file)
@@ -1,6 +1,6 @@
 /* Output variables, constants and external declarations, for GNU compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -49,6 +49,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "debug.h"
 #include "target.h"
 #include "cgraph.h"
+#include "cfglayout.h"
 
 #ifdef XCOFF_DEBUGGING_INFO
 #include "xcoffout.h"          /* Needed for external data
@@ -69,44 +70,18 @@ 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
@@ -114,11 +89,6 @@ struct varasm_status GTY(())
 
 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.  */
 
@@ -131,6 +101,14 @@ int size_directive_output;
 
 tree last_assemble_variable_decl;
 
+/* The following global variable indicates if the section label for the
+   "cold" section of code has been output yet to the assembler.  The
+   label is useful when running gdb.  This is part of the optimization that
+   partitions hot and cold basic blocks into separate sections of the .o
+   file.  */
+
+bool unlikely_section_label_printed = false;
+
 /* 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
@@ -142,6 +120,9 @@ static HOST_WIDE_INT const_alias_set;
 
 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 *);
@@ -149,17 +130,7 @@ static hashval_t const_hash_1 (const tree);
 static int compare_constant (const tree, const tree);
 static tree copy_constant (tree);
 static void output_constant_def_contents (rtx);
-static void decode_rtx_const (enum machine_mode, rtx, struct rtx_const *);
-static unsigned int const_hash_rtx (enum machine_mode, rtx);
-static int compare_constant_rtx (enum machine_mode, rtx,
-                                struct constant_descriptor_rtx *);
-static struct constant_descriptor_rtx * record_constant_rtx
-  (enum machine_mode, rtx);
-static struct pool_constant *find_pool_constant (struct function *, rtx);
-static void mark_constant_pool (void);
-static void mark_constants (rtx);
-static int mark_constant (rtx *current_rtx, void *data);
-static int output_addressed_constants (tree);
+static 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);
@@ -183,7 +154,8 @@ static bool asm_emit_uninitialised (tree, const char*,
                                    unsigned HOST_WIDE_INT);
 static void mark_weak (tree);
 \f
-enum in_section { no_section, in_text, in_data, in_named
+enum in_section { no_section, in_text, in_unlikely_executed_text, in_data, 
+                 in_named
 #ifdef BSS_SECTION_ASM_OP
   , in_bss
 #endif
@@ -236,11 +208,35 @@ text_section (void)
   if (in_section != in_text)
     {
       in_section = in_text;
-#ifdef TEXT_SECTION
-      TEXT_SECTION ();
-#else
       fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
-#endif
+      ASM_OUTPUT_ALIGN (asm_out_file, 2);
+    }
+}
+
+/* Tell assembler to switch to unlikely-to-be-executed text section.  */
+
+void
+unlikely_text_section (void)
+{
+  if ((in_section != in_unlikely_executed_text)
+      &&  (in_section != in_named 
+          || strcmp (in_named_name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) != 0))
+    {
+      if (targetm.have_named_sections)
+        named_section (NULL_TREE, UNLIKELY_EXECUTED_TEXT_SECTION_NAME, 0);
+      else
+       {
+         in_section = in_unlikely_executed_text;
+         fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
+         ASM_OUTPUT_ALIGN (asm_out_file, 2);
+       }
+      
+      if (!unlikely_section_label_printed)
+       {
+         fprintf (asm_out_file, "__%s_unlikely_section:\n", 
+                  current_function_name ());
+         unlikely_section_label_printed = true;
+       }
     }
 }
 
@@ -252,16 +248,7 @@ 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);
     }
 }
 
@@ -295,6 +282,14 @@ 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)
+{
+  return in_section == in_unlikely_executed_text;
+}
+
 /* Determine if we're in the data section.  */
 
 int
@@ -377,7 +372,7 @@ set_named_section_flags (const char *section, unsigned int 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;
@@ -399,7 +394,7 @@ named_section_flags (const char *name, unsigned int flags)
       if (! set_named_section_flags (name, flags))
        abort ();
 
-      (*targetm.asm_out.named_section) (name, flags);
+      targetm.asm_out.named_section (name, flags);
 
       if (flags & SECTION_FORGET)
        in_section = no_section;
@@ -426,7 +421,7 @@ named_section (tree decl, const char *name, int reloc)
   if (name == NULL)
     name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
 
-  flags = (* targetm.section_type_flags) (decl, name, reloc);
+  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.
@@ -437,7 +432,7 @@ named_section (tree decl, const char *name, int reloc)
     {
       flags = get_named_section_flags (name);
       if ((flags & SECTION_OVERRIDE) == 0)
-       error_with_decl (decl, "%s causes a section type conflict");
+       error ("%J%D causes a section type conflict", decl, decl);
     }
 
   named_section_flags (name, flags);
@@ -453,7 +448,7 @@ resolve_unique_section (tree decl, int reloc ATTRIBUTE_UNUSED,
       && 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
@@ -465,13 +460,7 @@ 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;
     }
 }
@@ -489,7 +478,7 @@ asm_output_bss (FILE *file, tree decl ATTRIBUTE_UNUSED,
                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;
@@ -540,11 +529,16 @@ asm_output_aligned_bss (FILE *file, tree decl ATTRIBUTE_UNUSED,
 void
 function_section (tree decl)
 {
-  if (decl != NULL_TREE
-      && DECL_SECTION_NAME (decl) != NULL_TREE)
-    named_section (decl, (char *) 0, 0);
+  if (scan_ahead_for_unlikely_executed_note (get_insns()))
+    unlikely_text_section ();
   else
-    text_section ();
+    {
+      if (decl != NULL_TREE
+         && DECL_SECTION_NAME (decl) != NULL_TREE)
+       named_section (decl, (char *) 0, 0);
+      else
+       text_section (); 
+    }
 }
 
 /* Switch to section for variable DECL.  RELOC is the same as the
@@ -556,7 +550,7 @@ 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.  */
@@ -566,8 +560,7 @@ 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
@@ -629,7 +622,7 @@ mergeable_string_section (tree decl ATTRIBUTE_UNUSED,
            }
        }
     }
-#endif
+
   readonly_data_section ();
 }
 
@@ -640,10 +633,9 @@ 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
@@ -658,7 +650,7 @@ mergeable_constant_section (enum machine_mode mode ATTRIBUTE_UNUSED,
       named_section_flags (name, flags);
       return;
     }
-#endif
+
   readonly_data_section ();
 }
 \f
@@ -750,11 +742,7 @@ decode_reg_name (const char *asmspec)
 void
 make_decl_rtl (tree decl, const char *asmspec)
 {
-  int top_level = (DECL_CONTEXT (decl) == NULL_TREE
-                  || (TREE_CODE (DECL_CONTEXT (decl))
-                      == TRANSLATION_UNIT_DECL));
   const char *name = 0;
-  const char *new_name = 0;
   int reg_number;
   rtx x;
 
@@ -790,12 +778,10 @@ make_decl_rtl (tree decl, const char *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);
       return;
     }
 
-  new_name = name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
-
   reg_number = decode_reg_name (asmspec);
   if (reg_number == -2)
     {
@@ -804,22 +790,24 @@ make_decl_rtl (tree decl, const char *asmspec)
       char *starred = alloca (strlen (asmspec) + 2);
       starred[0] = '*';
       strcpy (starred + 1, asmspec);
-      new_name = starred;
+      change_decl_assembler_name (decl, get_identifier (starred));
     }
 
+  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+
   if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
     {
       /* First detect errors in declaring global registers.  */
       if (reg_number == -1)
-       error_with_decl (decl, "register name not specified for `%s'");
+       error ("%Jregister name not specified for '%D'", decl, decl);
       else if (reg_number < 0)
-       error_with_decl (decl, "invalid register name for `%s'");
+       error ("%Jinvalid register name for '%D'", decl, decl);
       else if (TYPE_MODE (TREE_TYPE (decl)) == BLKmode)
-       error_with_decl (decl,
-                        "data type of `%s' isn't suitable for a register");
+       error ("%Jdata type of '%D' isn't suitable for a register",
+              decl, decl);
       else if (! HARD_REGNO_MODE_OK (reg_number, TYPE_MODE (TREE_TYPE (decl))))
-       error_with_decl (decl,
-                        "register specified for `%s' isn't suitable for data type");
+       error ("%Jregister specified for '%D' isn't suitable for data type",
+               decl, decl);
       /* Now handle properly declared static register variables.  */
       else
        {
@@ -849,7 +837,7 @@ make_decl_rtl (tree decl, const char *asmspec)
 #ifdef ASM_DECLARE_REGISTER_GLOBAL
              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);
            }
@@ -863,8 +851,7 @@ make_decl_rtl (tree decl, const char *asmspec)
      Also handle vars declared register invalidly.  */
 
   if (reg_number >= 0 || reg_number == -3)
-    error_with_decl (decl,
-                    "register name given for non-register variable `%s'");
+    error ("%Jregister name given for non-register variable '%D'", decl, decl);
 
   /* Specifying a section attribute on a variable forces it into a
      non-.bss section, and thus it cannot be common.  */
@@ -878,28 +865,6 @@ make_decl_rtl (tree decl, const char *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;
@@ -913,7 +878,7 @@ make_decl_rtl (tree decl, const char *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 the rtl for variable VAR be volatile.
@@ -1068,6 +1033,44 @@ default_ctor_section_asm_out_constructor (rtx symbol,
 #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))))
+      || GET_CODE (DECL_RTL (decl)) != MEM)
+    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;
+      char *name;
+      rtx decl_rtl = DECL_RTL (decl);
+
+      p = targetm.strip_name_encoding (XSTR (XEXP (decl_rtl, 0), 0));
+      name = xstrdup (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
@@ -1078,6 +1081,8 @@ assemble_start_function (tree decl, const char *fnname)
 {
   int align;
 
+  unlikely_section_label_printed = false;
+
   /* The following code does not need preprocessing in the assembler.  */
 
   app_disable ();
@@ -1121,26 +1126,14 @@ assemble_start_function (tree decl, const char *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 */
+  /* 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
@@ -1177,7 +1170,8 @@ assemble_zeros (unsigned HOST_WIDE_INT 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 ()))
     {
       unsigned HOST_WIDE_INT i;
       for (i = 0; i < size; i++)
@@ -1357,7 +1351,7 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
   rtx decl_rtl;
 
   if (lang_hooks.decls.prepare_assemble_variable)
-    (*lang_hooks.decls.prepare_assemble_variable) (decl);
+    lang_hooks.decls.prepare_assemble_variable (decl);
 
   last_assemble_variable_decl = 0;
 
@@ -1392,9 +1386,7 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
 
   if (!dont_output_data && DECL_SIZE (decl) == 0)
     {
-      error ("%Hstorage size of `%s' isn't known",
-             &DECL_SOURCE_LOCATION (decl),
-             IDENTIFIER_POINTER (DECL_NAME (decl)));
+      error ("%Jstorage size of `%D' isn't known", decl, decl);
       TREE_ASM_WRITTEN (decl) = 1;
       return;
     }
@@ -1422,25 +1414,13 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
   if (! dont_output_data
       && ! host_integerp (DECL_SIZE_UNIT (decl), 1))
     {
-      error_with_decl (decl, "size of variable `%s' is too large");
+      error ("%Jsize of variable '%D' is too large", decl, decl);
       return;
     }
 
   name = XSTR (XEXP (decl_rtl, 0), 0);
-  if (TREE_PUBLIC (decl) && DECL_NAME (decl)
-      && ! first_global_object_name
-      && ! (DECL_COMMON (decl) && (DECL_INITIAL (decl) == 0
-                                  || DECL_INITIAL (decl) == error_mark_node))
-      && ! DECL_WEAK (decl)
-      && ! DECL_ONE_ONLY (decl))
-    {
-      const char *p;
-      char *xname;
-
-      p = (* targetm.strip_name_encoding) (name);
-      xname = xstrdup (p);
-      first_global_object_name = xname;
-    }
+  if (TREE_PUBLIC (decl) && DECL_NAME (decl))
+    notice_global_symbol (decl);
 
   /* Compute the alignment of this data.  */
 
@@ -1460,9 +1440,9 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
 #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 ("%Jalignment of '%D' is greater than maximum object "
+               "file alignment.  Using %d", decl, decl,
+              MAX_OFILE_ALIGNMENT/BITS_PER_UNIT);
       align = MAX_OFILE_ALIGNMENT;
     }
 
@@ -1490,7 +1470,10 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
   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));
+    {
+      reloc = compute_reloc_for_constant (DECL_INITIAL (decl));
+      output_addressed_constants (DECL_INITIAL (decl));
+    }
   resolve_unique_section (decl, reloc, flag_data_sections);
 
   /* Handle uninitialized definitions.  */
@@ -1528,8 +1511,8 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
 
 #if !defined(ASM_OUTPUT_ALIGNED_COMMON) && !defined(ASM_OUTPUT_ALIGNED_DECL_COMMON) && !defined(ASM_OUTPUT_ALIGNED_BSS)
       if ((unsigned HOST_WIDE_INT) DECL_ALIGN (decl) / BITS_PER_UNIT > rounded)
-       warning_with_decl
-         (decl, "requested alignment for %s is greater than implemented alignment of %d",rounded);
+       warning ("%Jrequested alignment for '%D' is greater than "
+                 "implemented alignment of %d", decl, decl, rounded);
 #endif
 
       /* If the target cannot output uninitialized but not common global data
@@ -1550,7 +1533,7 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
   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.  */
@@ -1618,6 +1601,29 @@ contains_pointers_p (tree type)
     }
 }
 
+#ifdef ASM_OUTPUT_EXTERNAL
+/* 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))
+    {
+      const char *name;
+
+      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;
+    }
+  return false;
+}
+#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.  */
@@ -1638,7 +1644,8 @@ assemble_external (tree decl ATTRIBUTE_UNUSED)
       rtx rtl = DECL_RTL (decl);
 
       if (GET_CODE (rtl) == MEM && GET_CODE (XEXP (rtl, 0)) == SYMBOL_REF
-         && ! SYMBOL_REF_USED (XEXP (rtl, 0)))
+         && !SYMBOL_REF_USED (XEXP (rtl, 0))
+         && !incorporeal_function_p (decl))
        {
          /* Some systems do require some output.  */
          SYMBOL_REF_USED (XEXP (rtl, 0)) = 1;
@@ -1651,16 +1658,14 @@ assemble_external (tree decl ATTRIBUTE_UNUSED)
 /* Similar, for calling a library function FUN.  */
 
 void
-assemble_external_libcall (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.  */
@@ -1684,7 +1689,7 @@ mark_referenced (tree id)
        {
          node = cgraph_node_for_identifier (id);
          if (node)
-           cgraph_mark_needed_node (node, 1);
+           cgraph_mark_needed_node (node);
        }
 
       vnode = cgraph_varpool_node_for_identifier (id);
@@ -1706,7 +1711,7 @@ 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)
@@ -1790,7 +1795,7 @@ assemble_trampoline_template (void)
       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.  */
@@ -1882,7 +1887,7 @@ assemble_integer (rtx x, unsigned int size, unsigned int align, int force)
   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
@@ -1923,77 +1928,39 @@ void
 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
@@ -2067,39 +2034,9 @@ decode_addr_const (tree exp, struct addr_const *value)
   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(())
 {
@@ -2149,6 +2086,7 @@ const_hash_1 (const tree exp)
       p = TREE_STRING_POINTER (exp);
       len = TREE_STRING_LENGTH (exp);
       break;
+
     case COMPLEX_CST:
       return (const_hash_1 (TREE_REALPART (exp)) * 5
              + const_hash_1 (TREE_IMAGPART (exp)));
@@ -2159,7 +2097,7 @@ const_hash_1 (const tree exp)
          char *tmp;
 
          len = int_size_in_bytes (TREE_TYPE (exp));
-         tmp = (char *) alloca (len);
+         tmp = alloca (len);
          get_set_constructor_bytes (exp, (unsigned char *) tmp, len);
          p = tmp;
          break;
@@ -2262,9 +2200,6 @@ compare_constant (const tree t1, const tree 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;
 
@@ -2289,15 +2224,15 @@ compare_constant (const tree t1, const tree t2)
          if (int_size_in_bytes (TREE_TYPE (t1)) != len)
            return 0;
 
-         tmp1 = (unsigned char *) alloca (len);
-         tmp2 = (unsigned char *) alloca (len);
+         tmp1 = alloca (len);
+         tmp2 = alloca (len);
 
          if (get_set_constructor_bytes (t1, tmp1, len) != NULL_TREE)
            return 0;
          if (get_set_constructor_bytes (t2, tmp2, len) != NULL_TREE)
            return 0;
 
-         return memcmp (tmp1, tmp2, len) != 0;
+         return memcmp (tmp1, tmp2, len) == 0;
        }
       else
        {
@@ -2369,8 +2304,8 @@ compare_constant (const tree t1, const tree t2)
     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
@@ -2441,7 +2376,7 @@ copy_constant (tree exp)
     default:
       {
        tree t;
-       t = (*lang_hooks.expand_constant) (exp);
+       t = lang_hooks.expand_constant (exp);
        if (t != exp)
          return copy_constant (t);
        else
@@ -2490,7 +2425,7 @@ build_constant_desc (tree exp)
      information.  This call might invalidate our local variable
      SYMBOL; we can't use it afterward.  */
 
-  (*targetm.encode_section_info) (exp, rtl, true);
+  targetm.encode_section_info (exp, rtl, true);
 
   desc->rtl = rtl;
 
@@ -2508,7 +2443,7 @@ build_constant_desc (tree exp)
    If DEFER is nonzero, this constant can be deferred and output only
    if referenced in the function after all optimizations.
 
-   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 (tree exp, int defer)
@@ -2549,9 +2484,9 @@ maybe_output_constant_def_contents (struct constant_descriptor_tree *desc,
     /* Already output; don't do it again.  */
     return;
 
-  /* The only constants that cannot safely be deferred, assuming the
-     context allows it, are strings under flag_writable_strings.  */
-  if (defer && (TREE_CODE (exp) != STRING_CST || !flag_writable_strings))
+  /* We can always defer constants as long as the context allows
+     doing so.  */
+  if (defer)
     {
       /* Increment n_deferred_constants if it exists.  It needs to be at
         least as large as the number of constants actually referred to
@@ -2573,10 +2508,11 @@ 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));
@@ -2584,30 +2520,35 @@ output_constant_def_contents (rtx symbol)
   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);
 }
 
 /* A constant which was deferred in its original location has been
@@ -2618,319 +2559,207 @@ notice_rtl_inlining_of_deferred_constant (void)
 {
   n_deferred_constants++;
 }
-\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;
+  desc = htab_find (const_desc_htab, &key);
 
-  /* 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)  */
+/* Hash and compare functions for const_rtx_htab.  */
 
-#define SYMHASH(LABEL) (((unsigned long) (LABEL)) % MAX_RTX_HASH_TABLE)
-\f
-/* Initialize constant pool hashing for a new function.  */
+static hashval_t
+const_desc_rtx_hash (const void *ptr)
+{
+  const struct constant_descriptor_rtx *desc = ptr;
+  return desc->hash;
+}
 
-void
-init_varasm_status (struct function *f)
+static int
+const_desc_rtx_eq (const void *a, const void *b)
 {
-  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;
-  p->deferred_constants = 0;
+  const struct constant_descriptor_rtx *x = a;
+  const struct constant_descriptor_rtx *y = b;
+
+  if (x->mode != y->mode)
+    return 0;
+  return rtx_equal_p (x->constant, y->constant);
 }
-\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.  */
+/* Hash and compare functions for const_rtx_sym_htab.  */
 
-static void
-decode_rtx_const (enum machine_mode mode, rtx x, struct rtx_const *value)
+static hashval_t
+const_desc_rtx_sym_hash (const void *ptr)
 {
-  /* Clear the whole structure, including any gaps.  */
-  memset (value, 0, sizeof (struct rtx_const));
+  const struct constant_descriptor_rtx *desc = ptr;
+  return htab_hash_string (XSTR (desc->sym, 0));
+}
 
-  value->kind = RTX_INT;       /* Most usual kind.  */
-  value->mode = mode;
+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);
+}
 
-  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);
+/* This is the worker function for const_rtx_hash, called via for_each_rtx.  */
 
-         value->mode = GET_MODE (x);
+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;
 
-         /* 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;
+  x = *xp;
+  code = GET_CODE (x);
+  mode = GET_MODE (x);
+  h = (hashval_t) code * 1048573 + mode;
 
-    case CONST_VECTOR:
+  switch (code)
+    {
+    case CONST_INT:
+      hwi = INTVAL (x);
+    fold_hwi:
       {
-       int units, i;
-
-       units = CONST_VECTOR_NUNITS (x);
-       value->kind = RTX_VECTOR;
-       value->mode = mode;
+       const int shift = sizeof (hashval_t) * CHAR_BIT;
+       const int n = sizeof (HOST_WIDE_INT) / sizeof (hashval_t);
+       int i;
 
-       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)
+       h ^= (hashval_t) hwi;
+       for (i = 1; i < n; ++i)
          {
-           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 ();
-                 }
-             }
+           hwi >>= shift;
+           h ^= (hashval_t) hwi;
          }
-       else
-         abort ();
       }
       break;
 
-    case CONST_INT:
-      value->un.addr.offset = INTVAL (x);
+    case CONST_DOUBLE:
+      if (mode == VOIDmode)
+       {
+         hwi = CONST_DOUBLE_LOW (x) ^ CONST_DOUBLE_HIGH (x);
+         goto fold_hwi;
+       }
+      else
+       h ^= real_hash (CONST_DOUBLE_REAL_VALUE (x));
       break;
 
     case SYMBOL_REF:
+      h ^= htab_hash_string (XSTR (x, 0));
+      break;
+
     case LABEL_REF:
-    case PC:
-      value->un.addr.base = x;
+      h = h * 251 + CODE_LABEL_NUMBER (XEXP (x, 0));
       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)
-       {
-         value->un.addr.base = XEXP (x, 0);
-         value->un.addr.offset = - INTVAL (XEXP (x, 1));
-       }
-      else
-       {
-         value->un.addr.base = x;
-         value->un.addr.offset = 0;
-       }
+    case UNSPEC:
+    case UNSPEC_VOLATILE:
+      h = h * 251 + XINT (x, 1);
       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 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;
-      }
+  hp = data;
+  *hp = *hp * 509 + h;
+  return 0;
 }
 
-/* Given a MINUS expression, simplify it if both sides
-   include the same symbol.  */
+/* Compute a hash value for X, which should be a constant.  */
 
-rtx
-simplify_subtraction (rtx x)
+static hashval_t
+const_rtx_hash (rtx x)
 {
-  struct rtx_const val0, val1;
-
-  decode_rtx_const (GET_MODE (x), XEXP (x, 0), &val0);
-  decode_rtx_const (GET_MODE (x), XEXP (x, 1), &val1);
-
-  if (val0.kind >= RTX_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);
-
-  return x;
+  hashval_t h = 0;
+  for_each_rtx (&x, const_rtx_hash_1, &h);
+  return h;
 }
 
-/* Compute a hash code for a constant RTL expression.  */
+\f
+/* Initialize constant pool hashing for a new function.  */
 
-static unsigned int
-const_hash_rtx (enum machine_mode mode, rtx x)
+void
+init_varasm_status (struct function *f)
 {
-  union {
-    struct rtx_const value;
-    unsigned int data[sizeof(struct rtx_const) / sizeof (unsigned int)];
-  } u;
+  struct varasm_status *p;
+  struct rtx_constant_pool *pool;
 
-  unsigned int hi;
-  size_t i;
+  p = ggc_alloc (sizeof (struct varasm_status));
+  f->varasm = p;
 
-  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;
-}
-
-/* Compare a constant rtl object X with a constant-descriptor DESC.
-   Return 1 if DESC describes a constant with the same value as X.  */
-
-static int
-compare_constant_rtx (enum machine_mode mode, rtx x,
-                     struct constant_descriptor_rtx *desc)
-{
-  struct rtx_const value;
-
-  decode_rtx_const (mode, x, &value);
+  pool = ggc_alloc (sizeof (struct rtx_constant_pool));
+  p->pool = pool;
+  p->deferred_constants = 0;
 
-  /* Compare constant contents.  */
-  return memcmp (&value, &desc->value, sizeof (struct rtx_const)) == 0;
+  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 MINUS expression, simplify it if both sides
+   include the same symbol.  */
 
-/* Construct a constant descriptor for the rtl-expression X.
-   It is up to the caller to enter the descriptor in the hash table.  */
-
-static struct constant_descriptor_rtx *
-record_constant_rtx (enum machine_mode mode, rtx x)
+rtx
+simplify_subtraction (rtx x)
 {
-  struct constant_descriptor_rtx *ptr;
-
-  ptr = (struct constant_descriptor_rtx *) ggc_alloc (sizeof (*ptr));
-  decode_rtx_const (mode, x, &ptr->value);
-
-  return ptr;
+  rtx r = simplify_rtx (x);
+  return r ? r : x;
 }
 \f
 /* Given a constant rtx X, make (or find) a memory constant for its value
@@ -2939,108 +2768,101 @@ record_constant_rtx (enum machine_mode mode, rtx x)
 rtx
 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;
-
-  /* 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;
+  /* 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);
+
+  /* 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
   {
-    tree type = (*lang_hooks.types.type_for_mode) (mode, 0);
+    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);
+  if (*slot)
+    abort ();
+  *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_rtx_MEM (mode, symbol);
+  set_mem_attributes (def, lang_hooks.types.type_for_mode (mode, 0), 1);
+  RTX_UNCHANGING_P (def) = 1;
 
-  /* Mark the symbol_ref as belonging to this constants pool.  */
-  CONSTANT_POOL_ADDRESS_P (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 (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.  */
@@ -3048,7 +2870,7 @@ find_pool_constant (struct function *f, rtx addr)
 rtx
 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
@@ -3057,9 +2879,11 @@ get_pool_constant (rtx addr)
 rtx
 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.  */
@@ -3067,7 +2891,7 @@ get_pool_constant_mark (rtx addr, bool *pmarked)
 rtx
 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.  */
@@ -3075,13 +2899,13 @@ get_pool_constant_for_function (struct function *f, rtx addr)
 enum machine_mode
 get_pool_mode (rtx addr)
 {
-  return (find_pool_constant (cfun, addr))->mode;
+  return find_pool_constant (cfun->varasm->pool, addr)->mode;
 }
 
 enum machine_mode
 get_pool_mode_for_function (struct function *f, rtx addr)
 {
-  return (find_pool_constant (f, addr))->mode;
+  return find_pool_constant (f->varasm->pool, addr)->mode;
 }
 
 /* Similar, return the offset in the constant pool.  */
@@ -3089,7 +2913,7 @@ get_pool_mode_for_function (struct function *f, rtx addr)
 int
 get_pool_offset (rtx addr)
 {
-  return (find_pool_constant (cfun, addr))->offset;
+  return find_pool_constant (cfun->varasm->pool, addr)->offset;
 }
 
 /* Return the size of the constant pool.  */
@@ -3097,310 +2921,253 @@ get_pool_offset (rtx addr)
 int
 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 (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;
-
-      x = pool->constant;
-
-      if (! pool->mark)
-       continue;
-
-      /* 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 MODE_FLOAT:
+      if (GET_CODE (x) != CONST_DOUBLE)
+       abort ();
+      else
        {
-       case CONST:
-         if (GET_CODE (XEXP (x, 0)) != PLUS
-             || GET_CODE (XEXP (XEXP (x, 0), 0)) != LABEL_REF)
-           break;
-         tmp = XEXP (XEXP (x, 0), 0);
-         /* FALLTHRU */
-
-       case LABEL_REF:
-         tmp = XEXP (x, 0);
-         if (INSN_DELETED_P (tmp)
-             || (GET_CODE (tmp) == NOTE
-                 && NOTE_LINE_NUMBER (tmp) == NOTE_INSN_DELETED))
-           {
-             abort ();
-             x = const0_rtx;
-           }
-         break;
-
-       default:
-         break;
+         REAL_VALUE_TYPE r;
+         REAL_VALUE_FROM_CONST_DOUBLE (r, x);
+         assemble_real (r, mode, align);
        }
+      break;
 
-      /* First switch to correct section.  */
-      (*targetm.asm_out.select_rtx_section) (pool->mode, x, pool->align);
-
-#ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
-      ASM_OUTPUT_SPECIAL_POOL_ENTRY (asm_out_file, x, pool->mode,
-                                    pool->align, pool->labelno, done);
-#endif
-
-      assemble_align (pool->align);
-
-      /* Output the label.  */
-      (*targetm.asm_out.internal_label) (asm_out_file, "LC", pool->labelno);
-
-      /* Output the value of the constant itself.  */
-      switch (GET_MODE_CLASS (pool->mode))
-       {
-       case MODE_FLOAT:
-         if (GET_CODE (x) != CONST_DOUBLE)
-           abort ();
+    case MODE_INT:
+    case MODE_PARTIAL_INT:
+      assemble_integer (x, GET_MODE_SIZE (mode), align, 1);
+      break;
 
-         REAL_VALUE_FROM_CONST_DOUBLE (r, x);
-         assemble_real (r, pool->mode, pool->align);
-         break;
+    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));
 
-       case MODE_INT:
-       case MODE_PARTIAL_INT:
-         assemble_integer (x, GET_MODE_SIZE (pool->mode), pool->align, 1);
-         break;
+       if (GET_CODE (x) != CONST_VECTOR)
+         abort ();
+       units = CONST_VECTOR_NUNITS (x);
 
-       case MODE_VECTOR_FLOAT:
+       for (i = 0; i < units; i++)
          {
-           int i, units;
-           rtx elt;
-
-           if (GET_CODE (x) != CONST_VECTOR)
-             abort ();
-
-           units = CONST_VECTOR_NUNITS (x);
-
-           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);
-             }
+           rtx elt = CONST_VECTOR_ELT (x, i);
+           output_constant_pool_2 (submode, elt, i ? subalign : align);
          }
-         break;
+      }
+      break;
 
-       case MODE_VECTOR_INT:
-         {
-           int i, units;
-           rtx elt;
+    default:
+      abort ();
+    }
+}
 
-           if (GET_CODE (x) != CONST_VECTOR)
-             abort ();
+/* Worker function for output_constant_pool.  Emit POOL.  */
 
-           units = CONST_VECTOR_NUNITS (x);
+static void
+output_constant_pool_1 (struct constant_descriptor_rtx *desc)
+{
+  rtx x, tmp;
 
-           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 (!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  */
 
-       default:
+    case LABEL_REF:
+      tmp = XEXP (x, 0);
+      if (INSN_DELETED_P (tmp)
+         || (GET_CODE (tmp) == NOTE
+             && NOTE_LINE_NUMBER (tmp) == NOTE_INSN_DELETED))
+       {
          abort ();
+         x = const0_rtx;
        }
+      break;
+
+    default:
+      break;
+    }
 
-      /* 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);
+  /* First switch to correct section.  */
+  targetm.asm_out.select_rtx_section (desc->mode, x, desc->align);
 
 #ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
-    done: ;
+  ASM_OUTPUT_SPECIAL_POOL_ENTRY (asm_out_file, x, desc->mode,
+                                desc->align, desc->labelno, done);
 #endif
-    }
 
-#ifdef ASM_OUTPUT_POOL_EPILOGUE
-  ASM_OUTPUT_POOL_EPILOGUE (asm_out_file, fnname, fndecl, pool_offset);
-#endif
+  assemble_align (desc->align);
 
-  /* Done with this pool.  */
-  first_pool = last_pool = 0;
-}
+  /* Output the label.  */
+  targetm.asm_out.internal_label (asm_out_file, "LC", desc->labelno);
 
-/* Look through the instructions for this function, and mark all the
-   entries in the constant pool which are actually being used.  Emit
-   deferred constants which have indeed been used.  */
+  /* Output the data.  */
+  output_constant_pool_2 (desc->mode, x, desc->align);
 
-static void
-mark_constant_pool (void)
-{
-  rtx insn;
-  rtx link;
-  struct pool_constant *pool;
+  /* 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);
 
-  if (first_pool == 0 && n_deferred_constants == 0)
-    return;
+#ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
+ done:
+#endif
+  return;
+}
 
-  for (pool = first_pool; pool; pool = pool->next)
-    pool->mark = 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.  */
 
-  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
-    if (INSN_P (insn))
-      mark_constants (PATTERN (insn));
+static int
+mark_constant (rtx *current_rtx, void *data)
+{
+  struct rtx_constant_pool *pool = data;
+  rtx x = *current_rtx;
 
-  for (link = current_function_epilogue_delay_list;
-       link;
-       link = XEXP (link, 1))
-    {
-      insn = XEXP (link, 0);
+  if (x == NULL_RTX || GET_CODE (x) != SYMBOL_REF)
+    return 0;
 
-      if (INSN_P (insn))
-       mark_constants (PATTERN (insn));
+  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);
+       }
+    }
+
+  return -1;
+} 
 
-/* Look through appropriate parts of X, marking all entries in the
+/* 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.  */
 
 static void
-mark_constants (rtx x)
+mark_constants (struct rtx_constant_pool *pool, rtx insn)
 {
-  int i;
-  const char *format_ptr;
-
-  if (x == 0)
+  if (!INSN_P (insn))
     return;
 
-  if (GET_CODE (x) == SYMBOL_REF)
-    {
-      mark_constant (&x, NULL);
-      return;
-    }
-
   /* 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))
+  if (GET_CODE (PATTERN (insn)) == SEQUENCE)
     {
-      mark_constants (PATTERN (x));
-      return;
+      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);
+}
 
-  format_ptr = GET_RTX_FORMAT (GET_CODE (x));
-
-  for (i = 0; i < GET_RTX_LENGTH (GET_CODE (x)); i++)
-    {
-      switch (*format_ptr++)
-       {
-       case 'e':
-         mark_constants (XEXP (x, i));
-         break;
+/* Look through the instructions for this function, and mark all the
+   entries in POOL which are actually being used.  Emit deferred constants
+   which have indeed been used.  */
 
-       case 'E':
-         if (XVEC (x, i) != 0)
-           {
-             int j;
+static void
+mark_constant_pool (struct rtx_constant_pool *pool)
+{
+  rtx insn, link;
 
-             for (j = 0; j < XVECLEN (x, i); j++)
-               mark_constants (XVECEXP (x, i, j));
-           }
-         break;
+  if (pool->first == 0 && n_deferred_constants == 0)
+    return;
 
-       case 'S':
-       case 's':
-       case '0':
-       case 'i':
-       case 'w':
-       case 'n':
-       case 'u':
-       case 'B':
-         break;
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    mark_constants (pool, insn);
 
-       default:
-         abort ();
-       }
-    }
+  for (link = current_function_epilogue_delay_list;
+       link;
+       link = XEXP (link, 1))
+    mark_constants (pool, XEXP (link, 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.  */
+/* Write all the constants in the constant pool.  */
 
-static int
-mark_constant (rtx *current_rtx, void *data ATTRIBUTE_UNUSED)
+void
+output_constant_pool (const char *fnname ATTRIBUTE_UNUSED,
+                     tree fndecl ATTRIBUTE_UNUSED)
 {
-  rtx x = *current_rtx;
+  struct rtx_constant_pool *pool = cfun->varasm->pool;
+  struct constant_descriptor_rtx *desc;
 
-  if (x == NULL_RTX)
-    return 0;
+  /* 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);
 
-  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 (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);
-           }
-       }
-    }
-  return 0;
+#ifdef ASM_OUTPUT_POOL_PROLOGUE
+  ASM_OUTPUT_POOL_PROLOGUE (asm_out_file, fnname, fndecl, pool->offset);
+#endif
+
+  for (desc = pool->first; desc ; desc = desc->next)
+    output_constant_pool_1 (desc);
+
+#ifdef ASM_OUTPUT_POOL_EPILOGUE
+  ASM_OUTPUT_POOL_EPILOGUE (asm_out_file, fnname, fndecl, pool->offset);
+#endif
 }
 \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.  */
+/* Determine what kind of relocations EXP may need.  */
 
-static int
-output_addressed_constants (tree exp)
+int
+compute_reloc_for_constant (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))
     {
@@ -3413,10 +3180,6 @@ output_addressed_constants (tree exp)
           tem = TREE_OPERAND (tem, 0))
        ;
 
-      if (TREE_CODE_CLASS (TREE_CODE (tem)) == 'c'
-         || TREE_CODE (tem) == CONSTRUCTOR)
-       output_constant_def (tem, 0);
-
       if (TREE_PUBLIC (tem))
        reloc |= 2;
       else
@@ -3424,13 +3187,13 @@ output_addressed_constants (tree exp)
       break;
 
     case PLUS_EXPR:
-      reloc = output_addressed_constants (TREE_OPERAND (exp, 0));
-      reloc |= output_addressed_constants (TREE_OPERAND (exp, 1));
+      reloc = compute_reloc_for_constant (TREE_OPERAND (exp, 0));
+      reloc |= compute_reloc_for_constant (TREE_OPERAND (exp, 1));
       break;
 
     case MINUS_EXPR:
-      reloc = output_addressed_constants (TREE_OPERAND (exp, 0));
-      reloc2 = output_addressed_constants (TREE_OPERAND (exp, 1));
+      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;
@@ -3441,13 +3204,13 @@ output_addressed_constants (tree exp)
     case NOP_EXPR:
     case CONVERT_EXPR:
     case NON_LVALUE_EXPR:
-      reloc = output_addressed_constants (TREE_OPERAND (exp, 0));
+      reloc = compute_reloc_for_constant (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));
+         reloc |= compute_reloc_for_constant (TREE_VALUE (tem));
 
       break;
 
@@ -3456,6 +3219,58 @@ output_addressed_constants (tree exp)
     }
   return reloc;
 }
+
+/* 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 void
+output_addressed_constants (tree exp)
+{
+  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);
+
+  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))
+       ;
+
+      if (TREE_CODE_CLASS (TREE_CODE (tem)) == 'c'
+         || TREE_CODE (tem) == CONSTRUCTOR)
+       output_constant_def (tem, 0);
+      break;
+
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+      output_addressed_constants (TREE_OPERAND (exp, 1));
+      /* Fall through.  */
+
+    case NOP_EXPR:
+    case CONVERT_EXPR:
+    case NON_LVALUE_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)
+         output_addressed_constants (TREE_VALUE (tem));
+
+      break;
+
+    default:
+      break;
+    }
+}
 \f
 /* Return nonzero if VALUE is a valid constant-valued expression
    for use in initializing a static variable; one that can be an
@@ -3472,7 +3287,7 @@ 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))
     {
@@ -3481,11 +3296,27 @@ initializer_constant_valid_p (tree value, tree endtype)
           || TREE_CODE (TREE_TYPE (value)) == RECORD_TYPE)
          && TREE_CONSTANT (value)
          && CONSTRUCTOR_ELTS (value))
-       return
-         initializer_constant_valid_p (TREE_VALUE (CONSTRUCTOR_ELTS (value)),
-                                       endtype);
+       {
+         tree elt;
+         bool absolute = true;
 
-      return TREE_STATIC (value) ? null_pointer_node : 0;
+         for (elt = CONSTRUCTOR_ELTS (value); elt; elt = TREE_CHAIN (elt))
+           {
+             tree reloc;
+             value = TREE_VALUE (elt);
+             reloc = initializer_constant_valid_p (value, TREE_TYPE (value));
+             if (!reloc)
+               return NULL_TREE;
+             if (reloc != null_pointer_node)
+               absolute = false;
+           }
+         /* For a non-absolute relocation, there is no single
+            variable that can be "the variable that determines the
+            relocation."  */
+         return absolute ? null_pointer_node : error_mark_node;
+       }
+
+      return TREE_STATIC (value) ? null_pointer_node : NULL_TREE;
 
     case INTEGER_CST:
     case VECTOR_CST:
@@ -3543,7 +3374,8 @@ initializer_constant_valid_p (tree value, tree endtype)
 
       /* Likewise conversions from int to pointers, but also allow
         conversions from 0.  */
-      if (POINTER_TYPE_P (TREE_TYPE (value))
+      if ((POINTER_TYPE_P (TREE_TYPE (value))
+          || TREE_CODE (TREE_TYPE (value)) == OFFSET_TYPE)
          && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
        {
          if (integer_zerop (TREE_OPERAND (value, 0)))
@@ -3554,8 +3386,10 @@ initializer_constant_valid_p (tree value, tree endtype)
                                                 endtype);
        }
 
-      /* Allow conversions to union types if the value inside is okay.  */
-      if (TREE_CODE (TREE_TYPE (value)) == UNION_TYPE)
+      /* Allow conversions to struct or union types if the value
+        inside is okay.  */
+      if (TREE_CODE (TREE_TYPE (value)) == RECORD_TYPE
+         || TREE_CODE (TREE_TYPE (value)) == UNION_TYPE)
        return initializer_constant_valid_p (TREE_OPERAND (value, 0),
                                             endtype);
       break;
@@ -3683,7 +3517,7 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align)
   /* 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;
@@ -3728,6 +3562,7 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int 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))
@@ -3738,9 +3573,7 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int 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:
@@ -3798,7 +3631,7 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align)
                          thissize, align, 1);
       else if (TREE_CODE (exp) == CONSTRUCTOR)
        {
-         unsigned char *buffer = (unsigned char *) alloca (thissize);
+         unsigned char *buffer = alloca (thissize);
          if (get_set_constructor_bytes (exp, buffer, thissize))
            abort ();
          assemble_string ((char *) buffer, thissize);
@@ -3914,6 +3747,15 @@ output_constructor (tree exp, unsigned HOST_WIDE_INT size,
       else if (TREE_CODE (type) == ARRAY_TYPE)
        index = TREE_PURPOSE (link);
 
+#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)
        STRIP_NOPS (val);
@@ -4201,15 +4043,16 @@ merge_weak (tree newdecl, tree 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 ("%Jweak declaration of '%D' must precede definition",
+              newdecl, newdecl);
 
       /* If we've already generated rtl referencing OLDDECL, we may
         have done so in a way that will not function properly with
         a weak symbol.  */
       else if (TREE_USED (olddecl)
               && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (olddecl)))
-       warning_with_decl (newdecl, "weak declaration of `%s' after first use results in unspecified behavior");
+       warning ("%Jweak declaration of '%D' after first use results "
+                 "in unspecified behavior", newdecl, newdecl);
 
       if (SUPPORTS_WEAK)
        {
@@ -4242,16 +4085,16 @@ void
 declare_weak (tree decl)
 {
   if (! TREE_PUBLIC (decl))
-    error_with_decl (decl, "weak declaration of `%s' must be public");
+    error ("%Jweak declaration of '%D' must be public", decl, decl);
   else if (TREE_CODE (decl) == FUNCTION_DECL && TREE_ASM_WRITTEN (decl))
-    error_with_decl (decl, "weak declaration of `%s' must precede definition");
+    error ("%Jweak declaration of '%D' must precede definition", decl, decl);
   else if (SUPPORTS_WEAK)
     {
       if (! DECL_WEAK (decl))
        weak_decls = tree_cons (NULL, decl, weak_decls);
     }
   else
-    warning_with_decl (decl, "weak declaration of `%s' not supported");
+    warning ("%Jweak declaration of '%D' not supported", decl, decl);
 
   mark_weak (decl);
 }
@@ -4317,9 +4160,12 @@ globalize_decl (tree 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
@@ -4352,14 +4198,26 @@ assemble_alias (tree decl, tree target ATTRIBUTE_UNUSED)
 #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");
-
+  if (DECL_WEAK (decl))
+    {
+      tree *p, t;
 #ifdef ASM_WEAKEN_DECL
-  ASM_WEAKEN_DECL (asm_out_file, decl, name, IDENTIFIER_POINTER (target));
+      ASM_WEAKEN_DECL (asm_out_file, decl, name, IDENTIFIER_POINTER (target));
 #else
-  ASM_OUTPUT_WEAK_ALIAS (asm_out_file, name, IDENTIFIER_POINTER (target));
+      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);
+    }
+  else
+    warning ("only weak aliases are supported in this configuration");
+
 #else
   warning ("alias definitions not supported in this configuration; ignored");
 #endif
@@ -4399,10 +4257,10 @@ default_assemble_visibility (tree decl, int vis)
 static void
 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
@@ -4429,16 +4287,16 @@ make_decl_one_only (tree 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 (TREE_CODE (decl) == VAR_DECL
+      && (DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node))
+    DECL_COMMON (decl) = 1;
   else if (SUPPORTS_WEAK)
     DECL_WEAK (decl) = 1;
   else
@@ -4481,7 +4339,7 @@ decl_tls_model (tree decl)
       return kind;
     }
 
-  is_local = (*targetm.binds_local_p) (decl);
+  is_local = targetm.binds_local_p (decl);
   if (!flag_pic)
     {
       if (is_local)
@@ -4501,30 +4359,6 @@ decl_tls_model (tree decl)
   return kind;
 }
 
-enum symbol_visibility
-decl_visibility (tree decl)
-{
-  tree attr = lookup_attribute ("visibility", DECL_ATTRIBUTES (decl));
-
-  if (attr)
-    {
-      const char *which = TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr)));
-
-      if (strcmp (which, "default") == 0)
-       return VISIBILITY_DEFAULT;
-      if (strcmp (which, "internal") == 0)
-       return VISIBILITY_INTERNAL;
-      if (strcmp (which, "hidden") == 0)
-       return VISIBILITY_HIDDEN;
-      if (strcmp (which, "protected") == 0)
-       return VISIBILITY_PROTECTED;
-
-      abort ();
-    }
-
-  return VISIBILITY_DEFAULT;
-}
-
 /* Select a set of attributes for section NAME based on the properties
    of DECL and whether or not RELOC indicates that DECL's initializer
    might contain runtime relocations.
@@ -4548,6 +4382,8 @@ default_section_type_flags_1 (tree decl, const char *name, int reloc,
     flags = SECTION_CODE;
   else if (decl && decl_readonly_section_1 (decl, reloc, shlib))
     flags = 0;
+  else if (strcmp (name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0)
+    flags = SECTION_CODE;
   else
     flags = SECTION_WRITE;
 
@@ -4675,30 +4511,6 @@ default_pe_asm_named_section (const char *name, unsigned int 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 (rtx symbol, HOST_WIDE_INT offset)
-{
-  fputs ("\t.vtable_entry ", asm_out_file);
-  output_addr_const (asm_out_file, symbol);
-  fprintf (asm_out_file, ", " HOST_WIDE_INT_PRINT_DEC "\n", offset);
-}
-
-/* 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 (rtx child, rtx 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
@@ -4721,7 +4533,7 @@ default_select_section (tree decl, int reloc,
        readonly = true;
     }
   else if (TREE_CODE (decl) == STRING_CST)
-    readonly = !flag_writable_strings;
+    readonly = true;
   else if (! (flag_pic && reloc))
     readonly = true;
 
@@ -4779,12 +4591,7 @@ categorize_decl_for_section (tree decl, int reloc, int shlib)
   if (TREE_CODE (decl) == FUNCTION_DECL)
     return SECCAT_TEXT;
   else if (TREE_CODE (decl) == STRING_CST)
-    {
-      if (flag_writable_strings)
-       return SECCAT_DATA;
-      else
-       return SECCAT_RODATA_MERGE_STR;
-    }
+    return SECCAT_RODATA_MERGE_STR;
   else if (TREE_CODE (decl) == VAR_DECL)
     {
       if (DECL_INITIAL (decl) == NULL
@@ -4837,7 +4644,7 @@ categorize_decl_for_section (tree decl, int reloc, int shlib)
     }
 
   /* 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;
@@ -5005,7 +4812,7 @@ default_unique_section_1 (tree decl, int reloc, int shlib)
   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);
@@ -5079,9 +4886,9 @@ default_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
   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 (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;
@@ -5124,7 +4931,7 @@ default_binds_local_p_1 (tree exp, int shlib)
   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)
+  else if (DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
     local_p = true;
   /* Otherwise, variables defined outside this object may not be local.  */
   else if (DECL_EXTERNAL (exp))
@@ -5171,6 +4978,16 @@ default_globalize_label (FILE * stream, const char *name)
 }
 #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 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.  */