OSDN Git Service

2004-08-04 Geoffrey Keating <geoffk@apple.com>
[pf3gnuchains/gcc-fork.git] / gcc / varasm.c
index 21b76b9..0fc9375 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.
 
@@ -48,17 +48,15 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "tm_p.h"
 #include "debug.h"
 #include "target.h"
+#include "tree-mudflap.h"
 #include "cgraph.h"
+#include "cfglayout.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
@@ -69,44 +67,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
@@ -126,6 +98,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
@@ -137,6 +117,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 *);
@@ -144,16 +127,6 @@ 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 void output_addressed_constants (tree);
 static unsigned HOST_WIDE_INT array_size_for_constructor (tree);
 static unsigned min_align (unsigned, unsigned);
@@ -162,11 +135,11 @@ static void globalize_decl (tree);
 static void maybe_assemble_visibility (tree);
 static int in_named_entry_eq (const void *, const void *);
 static hashval_t in_named_entry_hash (const void *);
+#ifdef 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 BSS_SECTION_ASM_OP
 #ifdef ASM_OUTPUT_ALIGNED_BSS
 static void asm_output_aligned_bss (FILE *, tree, const char *,
                                    unsigned HOST_WIDE_INT, int)
@@ -178,7 +151,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
@@ -231,11 +205,38 @@ 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);
+       }
+      
+      if (!unlikely_section_label_printed)
+       {
+         fprintf (asm_out_file, "__%s_unlikely_section:\n", 
+                  current_function_name ());
+         unlikely_section_label_printed = true;
+
+         /* Make sure that we have appropriate alignment for instructions
+            in this section.  */
+         assemble_align (FUNCTION_BOUNDARY);
+       }
     }
 }
 
@@ -247,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);
     }
 }
 
@@ -290,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
@@ -394,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;
@@ -421,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.
@@ -448,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
@@ -460,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;
     }
 }
@@ -484,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;
@@ -535,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
@@ -551,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.  */
@@ -669,6 +668,19 @@ strip_reg_name (const char *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,
@@ -735,13 +747,10 @@ decode_reg_name (const char *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 (tree decl, const char *asmspec)
+make_decl_rtl (tree decl)
 {
   const char *name = 0;
   int reg_number;
@@ -771,6 +780,9 @@ make_decl_rtl (tree decl, const char *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
@@ -779,23 +791,19 @@ 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);
-      return;
-    }
+      targetm.encode_section_info (decl, DECL_RTL (decl), false);
 
-  reg_number = decode_reg_name (asmspec);
-  if (reg_number == -2)
-    {
-      /* 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);
-      SET_DECL_ASSEMBLER_NAME (decl, get_identifier (starred));
+      /* Make this function static known to the mudflap runtime.  */
+      if (flag_mudflap && TREE_CODE (decl) == VAR_DECL)
+       mudflap_enqueue_decl (decl);
+
+      return;
     }
 
   name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
 
+  reg_number = decode_reg_name (name);
+
   if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
     {
       /* First detect errors in declaring global registers.  */
@@ -838,7 +846,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);
            }
@@ -851,7 +859,7 @@ make_decl_rtl (tree decl, const char *asmspec)
   /* Now handle ordinary static variables and functions (in memory).
      Also handle vars declared register invalidly.  */
 
-  if (reg_number >= 0 || reg_number == -3)
+  if (name[0] == '*' && (reg_number >= 0 || reg_number == -3))
     error ("%Jregister name given for non-register variable '%D'", decl, decl);
 
   /* Specifying a section attribute on a variable forces it into a
@@ -879,7 +887,11 @@ 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 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.
@@ -888,7 +900,7 @@ make_decl_rtl (tree decl, const char *asmspec)
 void
 make_var_volatile (tree var)
 {
-  if (GET_CODE (DECL_RTL (var)) != MEM)
+  if (!MEM_P (DECL_RTL (var)))
     abort ();
 
   MEM_VOLATILE_P (DECL_RTL (var)) = 1;
@@ -1051,10 +1063,10 @@ notice_global_symbol (tree decl)
              || (DECL_COMMON (decl)
                  && (DECL_INITIAL (decl) == 0
                      || DECL_INITIAL (decl) == error_mark_node))))
-      || GET_CODE (DECL_RTL (decl)) != MEM)
+      || !MEM_P (DECL_RTL (decl)))
     return;
 
-  /* We win when global object is found, but it is usefull to know about weak
+  /* 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;
@@ -1065,7 +1077,7 @@ notice_global_symbol (tree decl)
       char *name;
       rtx decl_rtl = DECL_RTL (decl);
 
-      p = (* targetm.strip_name_encoding) (XSTR (XEXP (decl_rtl, 0), 0));
+      p = targetm.strip_name_encoding (XSTR (XEXP (decl_rtl, 0), 0));
       name = xstrdup (p);
 
       *type = name;
@@ -1082,6 +1094,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 ();
@@ -1132,7 +1146,7 @@ assemble_start_function (tree decl, const char *fnname)
       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
@@ -1169,7 +1183,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++)
@@ -1349,7 +1364,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;
 
@@ -1367,7 +1382,7 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
     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;
@@ -1531,7 +1546,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.  */
@@ -1552,7 +1567,9 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
 
   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),
@@ -1599,6 +1616,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.  */
@@ -1618,8 +1658,9 @@ 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)))
+      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;
@@ -1638,7 +1679,7 @@ assemble_external_libcall (rtx fun)
   if (! SYMBOL_REF_USED (fun))
     {
       SYMBOL_REF_USED (fun) = 1;
-      (*targetm.asm_out.external_libcall) (fun);
+      targetm.asm_out.external_libcall (fun);
     }
 }
 
@@ -1650,29 +1691,25 @@ assemble_label (const char *name)
   ASM_OUTPUT_LABEL (asm_out_file, name);
 }
 
-/* Set the symbol_referenced flag for ID and notify callgraph code.  */
+/* Set the symbol_referenced flag for ID.  */
 void
 mark_referenced (tree id)
 {
-  if (!TREE_SYMBOL_REFERENCED (id))
-    {
-      struct cgraph_node *node;
-      struct cgraph_varpool_node *vnode;
-
-      if (!cgraph_global_info_ready)
-       {
-         node = cgraph_node_for_identifier (id);
-         if (node)
-           cgraph_mark_needed_node (node);
-       }
-
-      vnode = cgraph_varpool_node_for_identifier (id);
-      if (vnode)
-       cgraph_varpool_mark_needed_node (vnode);
-    }
   TREE_SYMBOL_REFERENCED (id) = 1;
 }
 
+/* Set the symbol_referenced flag for DECL and notify callgraph.  */
+void
+mark_decl_referenced (tree decl)
+{
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    cgraph_mark_needed_node (cgraph_node (decl));
+  else if (TREE_CODE (decl) == VAR_DECL)
+    cgraph_varpool_mark_needed_node (cgraph_varpool_node (decl));
+  /* else do nothing - we can get various sorts of CST nodes here,
+     which do not need to be marked.  */
+}
+
 /* 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
@@ -1685,7 +1722,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)
@@ -1745,6 +1782,8 @@ assemble_static_space (unsigned HOST_WIDE_INT 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 (void)
@@ -1754,6 +1793,9 @@ assemble_trampoline_template (void)
   int align;
   rtx symbol;
 
+  if (initial_trampoline)
+    return initial_trampoline;
+
   /* By default, put trampoline templates in read-only data section.  */
 
 #ifdef TRAMPOLINE_SECTION
@@ -1769,7 +1811,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.  */
@@ -1778,7 +1820,10 @@ assemble_trampoline_template (void)
   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
@@ -1861,7 +1906,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
@@ -2000,7 +2045,7 @@ decode_addr_const (tree exp, struct addr_const *value)
       abort ();
     }
 
-  if (GET_CODE (x) != MEM)
+  if (!MEM_P (x))
     abort ();
   x = XEXP (x, 0);
 
@@ -2008,39 +2053,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(())
 {
@@ -2090,6 +2105,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)));
@@ -2203,9 +2219,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;
 
@@ -2305,13 +2318,14 @@ compare_constant (const tree t1, const tree 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
@@ -2352,9 +2366,9 @@ copy_constant (tree 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:
@@ -2382,7 +2396,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
@@ -2410,6 +2424,10 @@ build_constant_desc (tree 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);
@@ -2431,7 +2449,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;
 
@@ -2449,7 +2467,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)
@@ -2490,9 +2508,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
@@ -2534,7 +2552,7 @@ output_constant_def_contents (rtx symbol)
   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)
     {
@@ -2555,15 +2573,8 @@ output_constant_def_contents (rtx symbol)
 
   /* Output the value of EXP.  */
   output_constant (exp, size, align);
-}
-
-/* A constant which was deferred in its original location has been
-   inserted by the RTL inliner into a different function.  The
-   current function's deferred constant count must be incremented.  */
-void
-notice_rtl_inlining_of_deferred_constant (void)
-{
-  n_deferred_constants++;
+  if (flag_mudflap)
+    mudflap_enqueue_constant (exp);
 }
 
 /* Look up EXP in the table of constant descriptors.  Return the rtl
@@ -2583,314 +2594,189 @@ lookup_constant_def (tree 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(())
-{
-  /* More constant_descriptors with the same hash code.  */
-  struct constant_descriptor_rtx *next;
-
-  /* A MEM for the constant.  */
-  rtx rtl;
-
-  /* The value of the constant.  */
-  struct rtx_const value;
+   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 = ggc_alloc (sizeof (struct varasm_status));
-  f->varasm = p;
-  p->x_const_rtx_hash_table
-    = ggc_alloc_cleared (MAX_RTX_HASH_TABLE
-                        * sizeof (struct constant_descriptor_rtx *));
-  p->x_const_rtx_sym_hash_table
-    = 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)
+       h ^= (hashval_t) hwi;
+       for (i = 1; i < n; ++i)
          {
-           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);
-                 }
-             }
+           hwi >>= shift;
+           h ^= (hashval_t) hwi;
          }
-       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;
 
-    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;
-
-  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;
-}
-
-/* Compare a constant rtl object X with a constant-descriptor DESC.
-   Return 1 if DESC describes a constant with the same value as X.  */
+  struct varasm_status *p;
+  struct rtx_constant_pool *pool;
 
-static int
-compare_constant_rtx (enum machine_mode mode, rtx x,
-                     struct constant_descriptor_rtx *desc)
-{
-  struct rtx_const value;
+  p = ggc_alloc (sizeof (struct varasm_status));
+  f->varasm = p;
 
-  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 = 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
@@ -2899,108 +2785,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 copy_rtx (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 = 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 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.  */
@@ -3008,7 +2887,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
@@ -3017,9 +2896,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.  */
@@ -3027,7 +2908,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.  */
@@ -3035,13 +2916,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.  */
@@ -3049,7 +2930,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.  */
@@ -3057,295 +2938,240 @@ 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)
+         || (NOTE_P (tmp)
+             && NOTE_LINE_NUMBER (tmp) == NOTE_INSN_DELETED))
+       {
          abort ();
+         x = const0_rtx;
        }
+      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);
+    default:
+      break;
+    }
+
+  /* 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);
+       }
     }
-}
 
-/* Look through appropriate parts of X, marking all entries in the
+  return -1;
+} 
+
+/* 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
 /* Determine what kind of relocations EXP may need.  */
@@ -3358,7 +3184,7 @@ compute_reloc_for_constant (tree exp)
 
   /* 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))
     {
@@ -3422,7 +3248,7 @@ output_addressed_constants (tree exp)
 
   /* 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))
     {
@@ -3478,7 +3304,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))
     {
@@ -3565,7 +3391,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)))
@@ -3576,8 +3403,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;
@@ -3705,7 +3534,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;
@@ -3741,7 +3570,7 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align)
     }
 
   /* 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:
@@ -3753,7 +3582,7 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align)
     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;
 
@@ -3790,10 +3619,10 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align)
          unsigned int nalign;
          enum machine_mode inner;
 
-         inner = GET_MODE_INNER (TYPE_MODE (TREE_TYPE (exp)));
+         inner = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
          nalign = MIN (align, GET_MODE_ALIGNMENT (inner));
 
-         elt_size = GET_MODE_UNIT_SIZE (TYPE_MODE (TREE_TYPE (exp)));
+         elt_size = GET_MODE_SIZE (inner);
 
          link = TREE_VECTOR_CST_ELTS (exp);
          output_constant (TREE_VALUE (link), elt_size, align);
@@ -4206,7 +4035,7 @@ 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;
@@ -4348,9 +4177,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
@@ -4363,7 +4195,7 @@ assemble_alias (tree decl, tree target ATTRIBUTE_UNUSED)
 
   /* We must force creation of DECL_RTL for debug info generation, even though
      we don't use it here.  */
-  make_decl_rtl (decl, NULL);
+  make_decl_rtl (decl);
 
   name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
 
@@ -4383,14 +4215,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
@@ -4430,10 +4274,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
@@ -4460,16 +4304,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
@@ -4512,7 +4356,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)
@@ -4532,30 +4376,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.
@@ -4579,6 +4399,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;
 
@@ -4728,7 +4550,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;
 
@@ -4787,15 +4609,19 @@ categorize_decl_for_section (tree decl, int reloc, int 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)
@@ -4837,14 +4663,18 @@ categorize_decl_for_section (tree decl, int reloc, int shlib)
   /* There are no read-only thread-local sections.  */
   if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (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;
@@ -5012,7 +4842,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);
@@ -5077,7 +4907,7 @@ default_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
   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)
@@ -5086,9 +4916,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;
@@ -5130,8 +4960,8 @@ default_binds_local_p_1 (tree exp, int 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))
@@ -5139,6 +4969,9 @@ default_binds_local_p_1 (tree exp, int 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)
@@ -5178,6 +5011,17 @@ 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 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.  */
 
@@ -5206,6 +5050,9 @@ default_file_start (void)
    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)
 {