OSDN Git Service

2008-08-14 Rafael Avila de Espindola <espindola@google.com>
[pf3gnuchains/gcc-fork.git] / gcc / varasm.c
index 5f58bf4..941716f 100644 (file)
@@ -1,13 +1,13 @@
 /* Output variables, constants and external declarations, for GNU compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
 /* 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, 2004, 2005
+   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
    Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
    Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -16,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 
 /* This file handles generation of all the assembler code
 
 
 /* This file handles generation of all the assembler code
@@ -49,10 +48,12 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "tm_p.h"
 #include "debug.h"
 #include "target.h"
 #include "tm_p.h"
 #include "debug.h"
 #include "target.h"
+#include "targhooks.h"
 #include "tree-mudflap.h"
 #include "cgraph.h"
 #include "cfglayout.h"
 #include "basic-block.h"
 #include "tree-mudflap.h"
 #include "cgraph.h"
 #include "cfglayout.h"
 #include "basic-block.h"
+#include "tree-iterator.h"
 
 #ifdef XCOFF_DEBUGGING_INFO
 #include "xcoffout.h"          /* Needed for external data
 
 #ifdef XCOFF_DEBUGGING_INFO
 #include "xcoffout.h"          /* Needed for external data
@@ -70,17 +71,7 @@ struct addr_const;
 struct constant_descriptor_rtx;
 struct rtx_constant_pool;
 
 struct constant_descriptor_rtx;
 struct rtx_constant_pool;
 
-struct varasm_status GTY(())
-{
-  /* 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 n_deferred_constants (cfun->varasm->deferred_constants)
+#define n_deferred_constants (crtl->varasm.deferred_constants)
 
 /* Number for making the label on the next
    constant that is stored in memory.  */
 
 /* Number for making the label on the next
    constant that is stored in memory.  */
@@ -107,7 +98,7 @@ bool first_function_block_is_cold;
 /* We give all constants their own alias set.  Perhaps redundant with
    MEM_READONLY_P, but pre-dates it.  */
 
 /* We give all constants their own alias set.  Perhaps redundant with
    MEM_READONLY_P, but pre-dates it.  */
 
-static HOST_WIDE_INT const_alias_set;
+static alias_set_type const_alias_set;
 
 static const char *strip_reg_name (const char *);
 static int contains_pointers_p (tree);
 
 static const char *strip_reg_name (const char *);
 static int contains_pointers_p (tree);
@@ -126,7 +117,6 @@ static unsigned HOST_WIDE_INT array_size_for_constructor (tree);
 static unsigned min_align (unsigned, unsigned);
 static void output_constructor (tree, unsigned HOST_WIDE_INT, unsigned int);
 static void globalize_decl (tree);
 static unsigned min_align (unsigned, unsigned);
 static void output_constructor (tree, unsigned HOST_WIDE_INT, unsigned int);
 static void globalize_decl (tree);
-static void maybe_assemble_visibility (tree);
 #ifdef BSS_SECTION_ASM_OP
 #ifdef ASM_OUTPUT_BSS
 static void asm_output_bss (FILE *, tree, const char *,
 #ifdef BSS_SECTION_ASM_OP
 #ifdef ASM_OUTPUT_BSS
 static void asm_output_bss (FILE *, tree, const char *,
@@ -138,10 +128,8 @@ static void asm_output_aligned_bss (FILE *, tree, const char *,
      ATTRIBUTE_UNUSED;
 #endif
 #endif /* BSS_SECTION_ASM_OP */
      ATTRIBUTE_UNUSED;
 #endif
 #endif /* BSS_SECTION_ASM_OP */
-static bool asm_emit_uninitialised (tree, const char*,
-                                   unsigned HOST_WIDE_INT,
-                                   unsigned HOST_WIDE_INT);
 static void mark_weak (tree);
 static void mark_weak (tree);
+static void output_constant_pool (const char *, tree);
 \f
 /* Well-known sections, each one associated with some sort of *_ASM_OP.  */
 section *text_section;
 \f
 /* Well-known sections, each one associated with some sort of *_ASM_OP.  */
 section *text_section;
@@ -153,6 +141,15 @@ section *dtors_section;
 section *bss_section;
 section *sbss_section;
 
 section *bss_section;
 section *sbss_section;
 
+/* Various forms of common section.  All are guaranteed to be nonnull.  */
+section *tls_comm_section;
+section *comm_section;
+section *lcomm_section;
+
+/* A SECTION_NOSWITCH section used for declaring global BSS variables.
+   May be null.  */
+section *bss_noswitch_section;
+
 /* The section that holds the main exception table, when known.  The section
    is set either by the target's init_sections hook or by the first call to
    switch_to_exception_section.  */
 /* The section that holds the main exception table, when known.  The section
    is set either by the target's init_sections hook or by the first call to
    switch_to_exception_section.  */
@@ -184,24 +181,335 @@ static GTY(()) section *unnamed_sections;
 /* Hash table of named sections.  */
 static GTY((param_is (section))) htab_t section_htab;
 
 /* Hash table of named sections.  */
 static GTY((param_is (section))) htab_t section_htab;
 
+/* A table of object_blocks, indexed by section.  */
+static GTY((param_is (struct object_block))) htab_t object_block_htab;
+
+/* The next number to use for internal anchor labels.  */
+static GTY(()) int anchor_labelno;
+
+/* A pool of constants that can be shared between functions.  */
+static GTY(()) struct rtx_constant_pool *shared_constant_pool;
+
+/* TLS emulation.  */
+
+static GTY ((if_marked ("tree_map_marked_p"), param_is (struct tree_map)))
+     htab_t emutls_htab;
+static GTY (()) tree emutls_object_type;
+/* Emulated TLS objects have the TLS model TLS_MODEL_EMULATED.  This
+   macro can be used on them to distinguish the control variable from
+   the initialization template.  */
+#define DECL_EMUTLS_VAR_P(D)  (TREE_TYPE (D) == emutls_object_type)
+
+#if !defined (NO_DOT_IN_LABEL)
+# define EMUTLS_SEPARATOR      "."
+#elif !defined (NO_DOLLAR_IN_LABEL)
+# define EMUTLS_SEPARATOR      "$"
+#else
+# define EMUTLS_SEPARATOR      "_"
+#endif
+
+/* Create an IDENTIFIER_NODE by prefixing PREFIX to the
+   IDENTIFIER_NODE NAME's name.  */
+
+static tree
+prefix_name (const char *prefix, tree name)
+{
+  unsigned plen = strlen (prefix);
+  unsigned nlen = strlen (IDENTIFIER_POINTER (name));
+  char *toname = (char *) alloca (plen + nlen + 1);
+  
+  memcpy (toname, prefix, plen);
+  memcpy (toname + plen, IDENTIFIER_POINTER (name), nlen + 1);
+
+  return get_identifier (toname);
+}
+
+/* Create an identifier for the struct __emutls_object, given an identifier
+   of the DECL_ASSEMBLY_NAME of the original object.  */
+
+static tree
+get_emutls_object_name (tree name)
+{
+  const char *prefix = (targetm.emutls.var_prefix
+                       ? targetm.emutls.var_prefix
+                       : "__emutls_v" EMUTLS_SEPARATOR);
+  return prefix_name (prefix, name);
+}
+
+tree
+default_emutls_var_fields (tree type, tree *name ATTRIBUTE_UNUSED)
+{
+  tree word_type_node, field, next_field;
+  
+  field = build_decl (FIELD_DECL, get_identifier ("__templ"), ptr_type_node);
+  DECL_CONTEXT (field) = type;
+  next_field = field;
+    
+  field = build_decl (FIELD_DECL, get_identifier ("__offset"),
+                     ptr_type_node);
+  DECL_CONTEXT (field) = type;
+  TREE_CHAIN (field) = next_field;
+  next_field = field;
+  
+  word_type_node = lang_hooks.types.type_for_mode (word_mode, 1);
+  field = build_decl (FIELD_DECL, get_identifier ("__align"),
+                     word_type_node);
+  DECL_CONTEXT (field) = type;
+  TREE_CHAIN (field) = next_field;
+  next_field = field;
+  
+  field = build_decl (FIELD_DECL, get_identifier ("__size"), word_type_node);
+  DECL_CONTEXT (field) = type;
+  TREE_CHAIN (field) = next_field;
+
+  return field;
+}
+
+/* Create the structure for struct __emutls_object.  This should match the
+   structure at the top of emutls.c, modulo the union there.  */
+
+static tree
+get_emutls_object_type (void)
+{
+  tree type, type_name, field;
+
+  type = emutls_object_type;
+  if (type)
+    return type;
+
+  emutls_object_type = type = lang_hooks.types.make_type (RECORD_TYPE);
+  type_name = NULL;
+  field = targetm.emutls.var_fields (type, &type_name);
+  if (!type_name)
+    type_name = get_identifier ("__emutls_object");
+  type_name = build_decl (TYPE_DECL, type_name, type);
+  TYPE_NAME (type) = type_name;
+  TYPE_FIELDS (type) = field;
+  layout_type (type);
+
+  return type;
+}
+
+/* Create a read-only variable like DECL, with the same DECL_INITIAL.
+   This will be used for initializing the emulated tls data area.  */
+
+static tree
+get_emutls_init_templ_addr (tree decl)
+{
+  tree name, to;
+  
+  if (targetm.emutls.register_common && !DECL_INITIAL (decl)
+      && !DECL_SECTION_NAME (decl))
+    return null_pointer_node;
+
+  name = DECL_ASSEMBLER_NAME (decl);
+  if (!targetm.emutls.tmpl_prefix || targetm.emutls.tmpl_prefix[0])
+    {
+      const char *prefix = (targetm.emutls.tmpl_prefix
+                           ? targetm.emutls.tmpl_prefix
+                           : "__emutls_t" EMUTLS_SEPARATOR);
+      name = prefix_name (prefix, name);
+    }
+
+  to = build_decl (VAR_DECL, name, TREE_TYPE (decl));
+  SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to));
+  DECL_TLS_MODEL (to) = TLS_MODEL_EMULATED;
+  DECL_ARTIFICIAL (to) = 1;
+  TREE_USED (to) = TREE_USED (decl);
+  TREE_READONLY (to) = 1;
+  DECL_IGNORED_P (to) = 1;
+  DECL_CONTEXT (to) = DECL_CONTEXT (decl);
+  DECL_SECTION_NAME (to) = DECL_SECTION_NAME (decl);
+  
+  DECL_WEAK (to) = DECL_WEAK (decl);
+  if (DECL_ONE_ONLY (decl))
+    {
+      make_decl_one_only (to);
+      TREE_STATIC (to) = TREE_STATIC (decl);
+      TREE_PUBLIC (to) = TREE_PUBLIC (decl);
+      DECL_VISIBILITY (to) = DECL_VISIBILITY (decl);
+    }
+  else
+    TREE_STATIC (to) = 1;
+
+  DECL_INITIAL (to) = DECL_INITIAL (decl);
+  DECL_INITIAL (decl) = NULL;
+
+  varpool_finalize_decl (to);
+  return build_fold_addr_expr (to);
+}
+
+/* When emulating tls, we use a control structure for use by the runtime.
+   Create and return this structure.  */
+
+tree
+emutls_decl (tree decl)
+{
+  tree name, to;
+  struct tree_map *h, in;
+  void **loc;
+
+  if (targetm.have_tls || decl == NULL || decl == error_mark_node
+      || TREE_CODE (decl) != VAR_DECL || ! DECL_THREAD_LOCAL_P (decl))
+    return decl;
+
+  /* Look up the object in the hash; return the control structure if
+     it has already been created.  */
+  if (! emutls_htab)
+    emutls_htab = htab_create_ggc (512, tree_map_hash, tree_map_eq, 0);
+
+  name = DECL_ASSEMBLER_NAME (decl);
+
+  /* Note that we use the hash of the decl's name, rather than a hash
+     of the decl's pointer.  In emutls_finish we iterate through the
+     hash table, and we want this traversal to be predictable.  */
+  in.hash = htab_hash_string (IDENTIFIER_POINTER (name));
+  in.base.from = decl;
+  loc = htab_find_slot_with_hash (emutls_htab, &in, in.hash, INSERT);
+  h = (struct tree_map *) *loc;
+  if (h != NULL)
+    to = h->to;
+  else
+    {
+      to = build_decl (VAR_DECL, get_emutls_object_name (name),
+                      get_emutls_object_type ());
+
+      h = GGC_NEW (struct tree_map);
+      h->hash = in.hash;
+      h->base.from = decl;
+      h->to = to;
+      *(struct tree_map **) loc = h;
+
+      DECL_TLS_MODEL (to) = TLS_MODEL_EMULATED;
+      DECL_ARTIFICIAL (to) = 1;
+      DECL_IGNORED_P (to) = 1;
+      TREE_READONLY (to) = 0;
+      SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to));
+      if (DECL_ONE_ONLY (decl))
+       make_decl_one_only (to);
+      DECL_CONTEXT (to) = DECL_CONTEXT (decl);
+      if (targetm.emutls.var_align_fixed)
+       /* If we're not allowed to change the proxy object's
+          alignment, pretend it's been set by the user.  */
+       DECL_USER_ALIGN (to) = 1;
+    }
+
+  /* Note that these fields may need to be updated from time to time from
+     the original decl.  Consider:
+       extern __thread int i;
+       int foo() { return i; }
+       __thread int i = 1;
+     in which I goes from external to locally defined and initialized.  */
+
+  TREE_STATIC (to) = TREE_STATIC (decl);
+  TREE_USED (to) = TREE_USED (decl);
+  TREE_PUBLIC (to) = TREE_PUBLIC (decl);
+  DECL_EXTERNAL (to) = DECL_EXTERNAL (decl);
+  DECL_COMMON (to) = DECL_COMMON (decl);
+  DECL_WEAK (to) = DECL_WEAK (decl);
+  DECL_VISIBILITY (to) = DECL_VISIBILITY (decl);
+
+  return to;
+}
+
+static int
+emutls_common_1 (void **loc, void *xstmts)
+{
+  struct tree_map *h = *(struct tree_map **) loc;
+  tree args, x, *pstmts = (tree *) xstmts;
+  tree word_type_node;
+
+  if (! DECL_COMMON (h->base.from)
+      || (DECL_INITIAL (h->base.from)
+         && DECL_INITIAL (h->base.from) != error_mark_node))
+    return 1;
+
+  word_type_node = lang_hooks.types.type_for_mode (word_mode, 1);
+
+  /* The idea was to call get_emutls_init_templ_addr here, but if we
+     do this and there is an initializer, -fanchor_section loses,
+     because it would be too late to ensure the template is
+     output.  */
+  x = null_pointer_node;
+  args = tree_cons (NULL, x, NULL);
+  x = build_int_cst (word_type_node, DECL_ALIGN_UNIT (h->base.from));
+  args = tree_cons (NULL, x, args);
+  x = fold_convert (word_type_node, DECL_SIZE_UNIT (h->base.from));
+  args = tree_cons (NULL, x, args);
+  x = build_fold_addr_expr (h->to);
+  args = tree_cons (NULL, x, args);
+
+  x = built_in_decls[BUILT_IN_EMUTLS_REGISTER_COMMON];
+  x = build_function_call_expr (x, args);
+
+  append_to_statement_list (x, pstmts);
+  return 1;
+}
+
+void
+emutls_finish (void)
+{
+  if (!targetm.emutls.register_common)
+    {
+      tree body = NULL_TREE;
+
+      if (emutls_htab == NULL)
+       return;
+
+      htab_traverse_noresize (emutls_htab, emutls_common_1, &body);
+      if (body == NULL_TREE)
+       return;
+      
+      cgraph_build_static_cdtor ('I', body, DEFAULT_INIT_PRIORITY);
+    }
+}
+
 /* Helper routines for maintaining section_htab.  */
 
 static int
 section_entry_eq (const void *p1, const void *p2)
 {
 /* Helper routines for maintaining section_htab.  */
 
 static int
 section_entry_eq (const void *p1, const void *p2)
 {
-  const section *old = p1;
-  const char *new = p2;
+  const section *old = (const section *) p1;
+  const char *new_name = (const char *) p2;
 
 
-  return strcmp (old->named.name, new) == 0;
+  return strcmp (old->named.name, new_name) == 0;
 }
 
 static hashval_t
 section_entry_hash (const void *p)
 {
 }
 
 static hashval_t
 section_entry_hash (const void *p)
 {
-  const section *old = p;
+  const section *old = (const section *) p;
   return htab_hash_string (old->named.name);
 }
 
   return htab_hash_string (old->named.name);
 }
 
+/* Return a hash value for section SECT.  */
+
+static hashval_t
+hash_section (section *sect)
+{
+  if (sect->common.flags & SECTION_NAMED)
+    return htab_hash_string (sect->named.name);
+  return sect->common.flags;
+}
+
+/* Helper routines for maintaining object_block_htab.  */
+
+static int
+object_block_entry_eq (const void *p1, const void *p2)
+{
+  const struct object_block *old = (const struct object_block *) p1;
+  const section *new_section = (const section *) p2;
+
+  return old->sect == new_section;
+}
+
+static hashval_t
+object_block_entry_hash (const void *p)
+{
+  const struct object_block *old = (const struct object_block *) p;
+  return hash_section (old->sect);
+}
+
 /* Return a new unnamed section with the given fields.  */
 
 section *
 /* Return a new unnamed section with the given fields.  */
 
 section *
@@ -210,8 +518,8 @@ get_unnamed_section (unsigned int flags, void (*callback) (const void *),
 {
   section *sect;
 
 {
   section *sect;
 
-  sect = ggc_alloc (sizeof (struct unnamed_section));
-  sect->unnamed.common.flags = flags;
+  sect = GGC_NEW (section);
+  sect->unnamed.common.flags = flags | SECTION_UNNAMED;
   sect->unnamed.callback = callback;
   sect->unnamed.data = data;
   sect->unnamed.next = unnamed_sections;
   sect->unnamed.callback = callback;
   sect->unnamed.data = data;
   sect->unnamed.next = unnamed_sections;
@@ -220,6 +528,20 @@ get_unnamed_section (unsigned int flags, void (*callback) (const void *),
   return sect;
 }
 
   return sect;
 }
 
+/* Return a SECTION_NOSWITCH section with the given fields.  */
+
+static section *
+get_noswitch_section (unsigned int flags, noswitch_section_callback callback)
+{
+  section *sect;
+
+  sect = GGC_NEW (section);
+  sect->noswitch.common.flags = flags | SECTION_NOSWITCH;
+  sect->noswitch.callback = callback;
+
+  return sect;
+}
+
 /* Return the named section structure associated with NAME.  Create
    a new section with the given fields if no such structure exists.  */
 
 /* Return the named section structure associated with NAME.  Create
    a new section with the given fields if no such structure exists.  */
 
@@ -234,7 +556,7 @@ get_section (const char *name, unsigned int flags, tree decl)
   flags |= SECTION_NAMED;
   if (*slot == NULL)
     {
   flags |= SECTION_NAMED;
   if (*slot == NULL)
     {
-      sect = ggc_alloc (sizeof (struct named_section));
+      sect = GGC_NEW (section);
       sect->named.common.flags = flags;
       sect->named.name = ggc_strdup (name);
       sect->named.decl = decl;
       sect->named.common.flags = flags;
       sect->named.name = ggc_strdup (name);
       sect->named.decl = decl;
@@ -256,6 +578,70 @@ get_section (const char *name, unsigned int flags, tree decl)
   return sect;
 }
 
   return sect;
 }
 
+/* Return true if the current compilation mode benefits from having
+   objects grouped into blocks.  */
+
+static bool
+use_object_blocks_p (void)
+{
+  return flag_section_anchors;
+}
+
+/* Return the object_block structure for section SECT.  Create a new
+   structure if we haven't created one already.  Return null if SECT
+   itself is null.  */
+
+static struct object_block *
+get_block_for_section (section *sect)
+{
+  struct object_block *block;
+  void **slot;
+
+  if (sect == NULL)
+    return NULL;
+
+  slot = htab_find_slot_with_hash (object_block_htab, sect,
+                                  hash_section (sect), INSERT);
+  block = (struct object_block *) *slot;
+  if (block == NULL)
+    {
+      block = (struct object_block *)
+       ggc_alloc_cleared (sizeof (struct object_block));
+      block->sect = sect;
+      *slot = block;
+    }
+  return block;
+}
+
+/* Create a symbol with label LABEL and place it at byte offset
+   OFFSET in BLOCK.  OFFSET can be negative if the symbol's offset
+   is not yet known.  LABEL must be a garbage-collected string.  */
+
+static rtx
+create_block_symbol (const char *label, struct object_block *block,
+                    HOST_WIDE_INT offset)
+{
+  rtx symbol;
+  unsigned int size;
+
+  /* Create the extended SYMBOL_REF.  */
+  size = RTX_HDR_SIZE + sizeof (struct block_symbol);
+  symbol = (rtx) ggc_alloc_zone (size, &rtl_zone);
+
+  /* Initialize the normal SYMBOL_REF fields.  */
+  memset (symbol, 0, size);
+  PUT_CODE (symbol, SYMBOL_REF);
+  PUT_MODE (symbol, Pmode);
+  XSTR (symbol, 0) = label;
+  SYMBOL_REF_FLAGS (symbol) = SYMBOL_FLAG_HAS_BLOCK_INFO;
+
+  /* Initialize the block_symbol stuff.  */
+  SYMBOL_REF_BLOCK (symbol) = block;
+  SYMBOL_REF_BLOCK_OFFSET (symbol) = offset;
+
+  return symbol;
+}
+
 static void
 initialize_cold_section_name (void)
 {
 static void
 initialize_cold_section_name (void)
 {
@@ -264,22 +650,22 @@ initialize_cold_section_name (void)
   tree dsn;
 
   gcc_assert (cfun && current_function_decl);
   tree dsn;
 
   gcc_assert (cfun && current_function_decl);
-  if (cfun->unlikely_text_section_name)
+  if (crtl->subsections.unlikely_text_section_name)
     return;
 
   dsn = DECL_SECTION_NAME (current_function_decl);
   if (flag_function_sections && dsn)
     {
     return;
 
   dsn = DECL_SECTION_NAME (current_function_decl);
   if (flag_function_sections && dsn)
     {
-      name = alloca (TREE_STRING_LENGTH (dsn) + 1);
+      name = (char *) alloca (TREE_STRING_LENGTH (dsn) + 1);
       memcpy (name, TREE_STRING_POINTER (dsn), TREE_STRING_LENGTH (dsn) + 1);
 
       stripped_name = targetm.strip_name_encoding (name);
 
       buffer = ACONCAT ((stripped_name, "_unlikely", NULL));
       memcpy (name, TREE_STRING_POINTER (dsn), TREE_STRING_LENGTH (dsn) + 1);
 
       stripped_name = targetm.strip_name_encoding (name);
 
       buffer = ACONCAT ((stripped_name, "_unlikely", NULL));
-      cfun->unlikely_text_section_name = ggc_strdup (buffer);
+      crtl->subsections.unlikely_text_section_name = ggc_strdup (buffer);
     }
   else
     }
   else
-    cfun->unlikely_text_section_name =  UNLIKELY_EXECUTED_TEXT_SECTION_NAME;
+    crtl->subsections.unlikely_text_section_name =  UNLIKELY_EXECUTED_TEXT_SECTION_NAME;
 }
 
 /* Tell assembler to switch to unlikely-to-be-executed text section.  */
 }
 
 /* Tell assembler to switch to unlikely-to-be-executed text section.  */
@@ -289,10 +675,10 @@ unlikely_text_section (void)
 {
   if (cfun)
     {
 {
   if (cfun)
     {
-      if (!cfun->unlikely_text_section_name)
+      if (!crtl->subsections.unlikely_text_section_name)
        initialize_cold_section_name ();
 
        initialize_cold_section_name ();
 
-      return get_named_section (NULL, cfun->unlikely_text_section_name, 0);
+      return get_named_section (NULL, crtl->subsections.unlikely_text_section_name, 0);
     }
   else
     return get_named_section (NULL, UNLIKELY_EXECUTED_TEXT_SECTION_NAME, 0);
     }
   else
     return get_named_section (NULL, UNLIKELY_EXECUTED_TEXT_SECTION_NAME, 0);
@@ -309,13 +695,13 @@ unlikely_text_section_p (section *sect)
   const char *name;
 
   if (cfun)
   const char *name;
 
   if (cfun)
-    name = cfun->unlikely_text_section_name;
+    name = crtl->subsections.unlikely_text_section_name;
   else
     name = UNLIKELY_EXECUTED_TEXT_SECTION_NAME;
 
   return (name
          && sect
   else
     name = UNLIKELY_EXECUTED_TEXT_SECTION_NAME;
 
   return (name
          && sect
-         && (sect->common.flags & SECTION_NAMED) != 0
+         && SECTION_STYLE (sect) == SECTION_NAMED
          && strcmp (name, sect->named.name) == 0);
 }
 
          && strcmp (name, sect->named.name) == 0);
 }
 
@@ -368,7 +754,8 @@ asm_output_bss (FILE *file, tree decl ATTRIBUTE_UNUSED,
                unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
                unsigned HOST_WIDE_INT rounded)
 {
                unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
                unsigned HOST_WIDE_INT rounded)
 {
-  targetm.asm_out.globalize_label (file, name);
+  gcc_assert (strcmp (XSTR (XEXP (DECL_RTL (decl), 0), 0), name) == 0);
+  targetm.asm_out.globalize_decl_name (file, decl);
   switch_to_section (bss_section);
 #ifdef ASM_DECLARE_OBJECT_NAME
   last_assemble_variable_decl = decl;
   switch_to_section (bss_section);
 #ifdef ASM_DECLARE_OBJECT_NAME
   last_assemble_variable_decl = decl;
@@ -435,14 +822,19 @@ section *
 function_section (tree decl)
 {
   int reloc = 0;
 function_section (tree decl)
 {
   int reloc = 0;
-    
+
   if (first_function_block_is_cold)
     reloc = 1;
   if (first_function_block_is_cold)
     reloc = 1;
-  
+
 #ifdef USE_SELECT_SECTION_FOR_FUNCTIONS
 #ifdef USE_SELECT_SECTION_FOR_FUNCTIONS
-  return targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
+  if (decl != NULL_TREE
+      && DECL_SECTION_NAME (decl) != NULL_TREE)
+    return reloc ? unlikely_text_section ()
+                : get_named_section (decl, NULL, 0);
+  else
+    return targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
 #else
 #else
-  return hot_function_section (decl);
+  return reloc ? unlikely_text_section () : hot_function_section (decl);
 #endif
 }
 
 #endif
 }
 
@@ -450,9 +842,15 @@ section *
 current_function_section (void)
 {
 #ifdef USE_SELECT_SECTION_FOR_FUNCTIONS
 current_function_section (void)
 {
 #ifdef USE_SELECT_SECTION_FOR_FUNCTIONS
-  return targetm.asm_out.select_section (current_function_decl,
-                                        in_cold_section_p,
-                                        DECL_ALIGN (current_function_decl));
+  if (current_function_decl != NULL_TREE
+      && DECL_SECTION_NAME (current_function_decl) != NULL_TREE)
+    return in_cold_section_p ? unlikely_text_section ()
+                            : get_named_section (current_function_decl,
+                                                 NULL, 0);
+  else
+    return targetm.asm_out.select_section (current_function_decl,
+                                          in_cold_section_p,
+                                          DECL_ALIGN (current_function_decl));
 #else
   return (in_cold_section_p
          ? unlikely_text_section ()
 #else
   return (in_cold_section_p
          ? unlikely_text_section ()
@@ -472,8 +870,8 @@ default_function_rodata_section (tree decl)
       if (DECL_ONE_ONLY (decl) && HAVE_COMDAT_GROUP)
         {
          size_t len = strlen (name) + 3;
       if (DECL_ONE_ONLY (decl) && HAVE_COMDAT_GROUP)
         {
          size_t len = strlen (name) + 3;
-         char* rname = alloca (len);
-         
+         char* rname = (char *) alloca (len);
+
          strcpy (rname, ".rodata");
          strcat (rname, name + 5);
          return get_section (rname, SECTION_LINKONCE, decl);
          strcpy (rname, ".rodata");
          strcat (rname, name + 5);
          return get_section (rname, SECTION_LINKONCE, decl);
@@ -483,7 +881,7 @@ default_function_rodata_section (tree decl)
               && strncmp (name, ".gnu.linkonce.t.", 16) == 0)
        {
          size_t len = strlen (name) + 1;
               && strncmp (name, ".gnu.linkonce.t.", 16) == 0)
        {
          size_t len = strlen (name) + 1;
-         char *rname = alloca (len);
+         char *rname = (char *) alloca (len);
 
          memcpy (rname, name, len);
          rname[14] = 'r';
 
          memcpy (rname, name, len);
          rname[14] = 'r';
@@ -494,7 +892,7 @@ default_function_rodata_section (tree decl)
               && strncmp (name, ".text.", 6) == 0)
        {
          size_t len = strlen (name) + 1;
               && strncmp (name, ".text.", 6) == 0)
        {
          size_t len = strlen (name) + 1;
-         char *rname = alloca (len + 2);
+         char *rname = (char *) alloca (len + 2);
 
          memcpy (rname, ".rodata", 7);
          memcpy (rname + 7, name + 5, len - 5);
 
          memcpy (rname, ".rodata", 7);
          memcpy (rname + 7, name + 5, len - 5);
@@ -515,19 +913,6 @@ default_no_function_rodata_section (tree decl ATTRIBUTE_UNUSED)
   return readonly_data_section;
 }
 
   return readonly_data_section;
 }
 
-/* Switch to section for variable DECL.  RELOC is the same as the
-   argument to SELECT_SECTION.  */
-
-void
-variable_section (tree decl, int reloc)
-{
-  if (IN_NAMED_SECTION (decl))
-    switch_to_section (get_named_section (decl, NULL, reloc));
-  else
-    switch_to_section (targetm.asm_out.select_section (decl, reloc,
-                                                      DECL_ALIGN (decl)));
-}
-
 /* Return the section to use for string merging.  */
 
 static section *
 /* Return the section to use for string merging.  */
 
 static section *
@@ -535,16 +920,20 @@ mergeable_string_section (tree decl ATTRIBUTE_UNUSED,
                          unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED,
                          unsigned int flags ATTRIBUTE_UNUSED)
 {
                          unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED,
                          unsigned int flags ATTRIBUTE_UNUSED)
 {
+  HOST_WIDE_INT len;
+
   if (HAVE_GAS_SHF_MERGE && flag_merge_constants
       && TREE_CODE (decl) == STRING_CST
       && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
       && align <= 256
   if (HAVE_GAS_SHF_MERGE && flag_merge_constants
       && TREE_CODE (decl) == STRING_CST
       && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
       && align <= 256
-      && TREE_STRING_LENGTH (decl) >= int_size_in_bytes (TREE_TYPE (decl)))
+      && (len = int_size_in_bytes (TREE_TYPE (decl))) > 0
+      && TREE_STRING_LENGTH (decl) >= len)
     {
       enum machine_mode mode;
       unsigned int modesize;
       const char *str;
     {
       enum machine_mode mode;
       unsigned int modesize;
       const char *str;
-      int i, j, len, unit;
+      HOST_WIDE_INT i;
+      int j, unit;
       char name[30];
 
       mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (decl)));
       char name[30];
 
       mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (decl)));
@@ -556,7 +945,6 @@ mergeable_string_section (tree decl ATTRIBUTE_UNUSED,
            align = modesize;
 
          str = TREE_STRING_POINTER (decl);
            align = modesize;
 
          str = TREE_STRING_POINTER (decl);
-         len = TREE_STRING_LENGTH (decl);
          unit = GET_MODE_SIZE (mode);
 
          /* Check for embedded NUL characters.  */
          unit = GET_MODE_SIZE (mode);
 
          /* Check for embedded NUL characters.  */
@@ -627,7 +1015,7 @@ strip_reg_name (const char *name)
 void
 set_user_assembler_name (tree decl, const char *name)
 {
 void
 set_user_assembler_name (tree decl, const char *name)
 {
-  char *starred = alloca (strlen (name) + 2);
+  char *starred = (char *) alloca (strlen (name) + 2);
   starred[0] = '*';
   strcpy (starred + 1, name);
   change_decl_assembler_name (decl, get_identifier (starred));
   starred[0] = '*';
   strcpy (starred + 1, name);
   change_decl_assembler_name (decl, get_identifier (starred));
@@ -694,6 +1082,193 @@ decode_reg_name (const char *asmspec)
   return -1;
 }
 \f
   return -1;
 }
 \f
+/* Return true if DECL's initializer is suitable for a BSS section.  */
+
+static bool
+bss_initializer_p (const_tree decl)
+{
+  return (DECL_INITIAL (decl) == NULL
+         || 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))));
+}
+
+/* Compute the alignment of variable specified by DECL.
+   DONT_OUTPUT_DATA is from assemble_variable.  */
+
+void
+align_variable (tree decl, bool dont_output_data)
+{
+  unsigned int align = DECL_ALIGN (decl);
+
+  /* In the case for initialing an array whose length isn't specified,
+     where we have not yet been able to do the layout,
+     figure out the proper alignment now.  */
+  if (dont_output_data && DECL_SIZE (decl) == 0
+      && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
+    align = MAX (align, TYPE_ALIGN (TREE_TYPE (TREE_TYPE (decl))));
+
+  /* Some object file formats have a maximum alignment which they support.
+     In particular, a.out format supports a maximum alignment of 4.  */
+  if (align > MAX_OFILE_ALIGNMENT)
+    {
+      warning (0, "alignment of %q+D is greater than maximum object "
+               "file alignment.  Using %d", decl,
+              MAX_OFILE_ALIGNMENT/BITS_PER_UNIT);
+      align = MAX_OFILE_ALIGNMENT;
+    }
+
+  /* On some machines, it is good to increase alignment sometimes.  */
+  if (! DECL_USER_ALIGN (decl))
+    {
+#ifdef DATA_ALIGNMENT
+      unsigned int data_align = DATA_ALIGNMENT (TREE_TYPE (decl), align);
+      /* Don't increase alignment too much for TLS variables - TLS space
+        is too precious.  */
+      if (! DECL_THREAD_LOCAL_P (decl) || data_align <= BITS_PER_WORD)
+       align = data_align;
+#endif
+#ifdef CONSTANT_ALIGNMENT
+      if (DECL_INITIAL (decl) != 0 && DECL_INITIAL (decl) != error_mark_node)
+       {
+         unsigned int const_align = CONSTANT_ALIGNMENT (DECL_INITIAL (decl),
+                                                        align);
+         /* Don't increase alignment too much for TLS variables - TLS space
+            is too precious.  */
+         if (! DECL_THREAD_LOCAL_P (decl) || const_align <= BITS_PER_WORD)
+           align = const_align;
+       }
+#endif
+    }
+
+  /* Reset the alignment in case we have made it tighter, so we can benefit
+     from it in get_pointer_alignment.  */
+  DECL_ALIGN (decl) = align;
+}
+
+/* Return the section into which the given VAR_DECL or CONST_DECL
+   should be placed.  PREFER_NOSWITCH_P is true if a noswitch
+   section should be used wherever possible.  */
+
+static section *
+get_variable_section (tree decl, bool prefer_noswitch_p)
+{
+  int reloc;
+
+  /* If the decl has been given an explicit section name, then it
+     isn't common, and shouldn't be handled as such.  */
+  if (DECL_COMMON (decl) && DECL_SECTION_NAME (decl) == NULL)
+    {
+      if (DECL_THREAD_LOCAL_P (decl))
+       return tls_comm_section;
+      /* This cannot be common bss for an emulated TLS object without
+        a register_common hook.  */
+      else if (DECL_TLS_MODEL (decl) == TLS_MODEL_EMULATED
+              && !targetm.emutls.register_common)
+       ;
+      else if (TREE_PUBLIC (decl) && bss_initializer_p (decl))
+       return comm_section;
+    }
+
+  if (DECL_INITIAL (decl) == error_mark_node)
+    reloc = contains_pointers_p (TREE_TYPE (decl)) ? 3 : 0;
+  else if (DECL_INITIAL (decl))
+    reloc = compute_reloc_for_constant (DECL_INITIAL (decl));
+  else
+    reloc = 0;
+
+  resolve_unique_section (decl, reloc, flag_data_sections);
+  if (IN_NAMED_SECTION (decl))
+    return get_named_section (decl, NULL, reloc);
+
+  if (!DECL_THREAD_LOCAL_P (decl)
+      && !(prefer_noswitch_p && targetm.have_switchable_bss_sections)
+      && bss_initializer_p (decl))
+    {
+      if (!TREE_PUBLIC (decl))
+       return lcomm_section;
+      if (bss_noswitch_section)
+       return bss_noswitch_section;
+    }
+
+  return targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
+}
+
+/* Return the block into which object_block DECL should be placed.  */
+
+static struct object_block *
+get_block_for_decl (tree decl)
+{
+  section *sect;
+
+  if (TREE_CODE (decl) == VAR_DECL)
+    {
+      /* The object must be defined in this translation unit.  */
+      if (DECL_EXTERNAL (decl))
+       return NULL;
+
+      /* There's no point using object blocks for something that is
+        isolated by definition.  */
+      if (DECL_ONE_ONLY (decl))
+       return NULL;
+    }
+
+  /* We can only calculate block offsets if the decl has a known
+     constant size.  */
+  if (DECL_SIZE_UNIT (decl) == NULL)
+    return NULL;
+  if (!host_integerp (DECL_SIZE_UNIT (decl), 1))
+    return NULL;
+
+  /* Find out which section should contain DECL.  We cannot put it into
+     an object block if it requires a standalone definition.  */
+  if (TREE_CODE (decl) == VAR_DECL)
+      align_variable (decl, 0);
+  sect = get_variable_section (decl, true);
+  if (SECTION_STYLE (sect) == SECTION_NOSWITCH)
+    return NULL;
+
+  return get_block_for_section (sect);
+}
+
+/* Make sure block symbol SYMBOL is in block BLOCK.  */
+
+static void
+change_symbol_block (rtx symbol, struct object_block *block)
+{
+  if (block != SYMBOL_REF_BLOCK (symbol))
+    {
+      gcc_assert (SYMBOL_REF_BLOCK_OFFSET (symbol) < 0);
+      SYMBOL_REF_BLOCK (symbol) = block;
+    }
+}
+
+/* Return true if it is possible to put DECL in an object_block.  */
+
+static bool
+use_blocks_for_decl_p (tree decl)
+{
+  /* Only data DECLs can be placed into object blocks.  */
+  if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != CONST_DECL)
+    return false;
+
+  /* Detect decls created by dw2_force_const_mem.  Such decls are
+     special because DECL_INITIAL doesn't specify the decl's true value.
+     dw2_output_indirect_constants will instead call assemble_variable
+     with dont_output_data set to 1 and then print the contents itself.  */
+  if (DECL_INITIAL (decl) == decl)
+    return false;
+
+  /* If this decl is an alias, then we don't want to emit a definition.  */
+  if (lookup_attribute ("alias", DECL_ATTRIBUTES (decl)))
+    return false;
+
+  return true;
+}
+
 /* Create the DECL_RTL for a VAR_DECL or FUNCTION_DECL.  DECL should
    have static storage duration.  In other words, it should not be an
    automatic variable, including PARM_DECLs.
 /* Create the DECL_RTL for a VAR_DECL or FUNCTION_DECL.  DECL should
    have static storage duration.  In other words, it should not be an
    automatic variable, including PARM_DECLs.
@@ -720,7 +1295,7 @@ make_decl_rtl (tree decl)
              || TREE_PUBLIC (decl)
              || DECL_EXTERNAL (decl)
              || DECL_REGISTER (decl));
              || TREE_PUBLIC (decl)
              || DECL_EXTERNAL (decl)
              || DECL_REGISTER (decl));
-  
+
   /* And that we were not given a type or a label.  */
   gcc_assert (TREE_CODE (decl) != TYPE_DECL
              && TREE_CODE (decl) != LABEL_DECL);
   /* And that we were not given a type or a label.  */
   gcc_assert (TREE_CODE (decl) != TYPE_DECL
              && TREE_CODE (decl) != LABEL_DECL);
@@ -730,9 +1305,9 @@ make_decl_rtl (tree decl)
   if (DECL_RTL_SET_P (decl))
     {
       /* If the old RTL had the wrong mode, fix the mode.  */
   if (DECL_RTL_SET_P (decl))
     {
       /* If the old RTL had the wrong mode, fix the mode.  */
-      if (GET_MODE (DECL_RTL (decl)) != DECL_MODE (decl))
-       SET_DECL_RTL (decl, adjust_address_nv (DECL_RTL (decl),
-                                              DECL_MODE (decl), 0));
+      x = DECL_RTL (decl);
+      if (GET_MODE (x) != DECL_MODE (decl))
+       SET_DECL_RTL (decl, adjust_address_nv (x, DECL_MODE (decl), 0));
 
       if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
        return;
 
       if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
        return;
@@ -747,6 +1322,13 @@ make_decl_rtl (tree decl)
         decl attribute overrides another.  */
       targetm.encode_section_info (decl, DECL_RTL (decl), false);
 
         decl attribute overrides another.  */
       targetm.encode_section_info (decl, DECL_RTL (decl), false);
 
+      /* If the symbol has a SYMBOL_REF_BLOCK field, update it based
+        on the new decl information.  */
+      if (MEM_P (x)
+         && GET_CODE (XEXP (x, 0)) == SYMBOL_REF
+         && SYMBOL_REF_HAS_BLOCK_INFO_P (XEXP (x, 0)))
+       change_symbol_block (XEXP (x, 0), get_block_for_decl (decl));
+
       /* Make this function static known to the mudflap runtime.  */
       if (flag_mudflap && TREE_CODE (decl) == VAR_DECL)
        mudflap_enqueue_decl (decl);
       /* Make this function static known to the mudflap runtime.  */
       if (flag_mudflap && TREE_CODE (decl) == VAR_DECL)
        mudflap_enqueue_decl (decl);
@@ -755,11 +1337,11 @@ make_decl_rtl (tree decl)
     }
 
   name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
     }
 
   name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
-  
+
   if (name[0] != '*' && TREE_CODE (decl) != FUNCTION_DECL
       && DECL_REGISTER (decl))
     {
   if (name[0] != '*' && TREE_CODE (decl) != FUNCTION_DECL
       && DECL_REGISTER (decl))
     {
-      error ("register name not specified for %q+D", decl);    
+      error ("register name not specified for %q+D", decl);
     }
   else if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
     {
     }
   else if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
     {
@@ -843,9 +1425,12 @@ make_decl_rtl (tree decl)
   if (TREE_CODE (decl) == VAR_DECL && DECL_WEAK (decl))
     DECL_COMMON (decl) = 0;
 
   if (TREE_CODE (decl) == VAR_DECL && DECL_WEAK (decl))
     DECL_COMMON (decl) = 0;
 
-  x = gen_rtx_SYMBOL_REF (Pmode, name);
+  if (use_object_blocks_p () && use_blocks_for_decl_p (decl))
+    x = create_block_symbol (name, get_block_for_decl (decl), -1);
+  else
+    x = gen_rtx_SYMBOL_REF (Pmode, name);
   SYMBOL_REF_WEAK (x) = DECL_WEAK (decl);
   SYMBOL_REF_WEAK (x) = DECL_WEAK (decl);
-  SYMBOL_REF_DECL (x) = decl;
+  SET_SYMBOL_REF_DECL (x, decl);
 
   x = gen_rtx_MEM (DECL_MODE (decl), x);
   if (TREE_CODE (decl) != FUNCTION_DECL)
 
   x = gen_rtx_MEM (DECL_MODE (decl), x);
   if (TREE_CODE (decl) != FUNCTION_DECL)
@@ -862,17 +1447,6 @@ make_decl_rtl (tree decl)
   if (flag_mudflap && TREE_CODE (decl) == VAR_DECL)
     mudflap_enqueue_decl (decl);
 }
   if (flag_mudflap && TREE_CODE (decl) == VAR_DECL)
     mudflap_enqueue_decl (decl);
 }
-
-/* Make the rtl for variable VAR be volatile.
-   Use this only for static variables.  */
-
-void
-make_var_volatile (tree var)
-{
-  gcc_assert (MEM_P (DECL_RTL (var)));
-
-  MEM_VOLATILE_P (DECL_RTL (var)) = 1;
-}
 \f
 /* Output a string of literal assembler code
    for an `asm' keyword used between functions.  */
 \f
 /* Output a string of literal assembler code
    for an `asm' keyword used between functions.  */
@@ -907,26 +1481,44 @@ default_stabs_asm_out_destructor (rtx symbol ATTRIBUTE_UNUSED,
 #endif
 }
 
 #endif
 }
 
-void
-default_named_section_asm_out_destructor (rtx symbol, int priority)
+/* Write the address of the entity given by SYMBOL to SEC.  */
+void 
+assemble_addr_to_section (rtx symbol, section *sec)
+{
+  switch_to_section (sec);
+  assemble_align (POINTER_SIZE);
+  assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
+}
+
+/* Return the numbered .ctors.N (if CONSTRUCTOR_P) or .dtors.N (if
+   not) section for PRIORITY.  */
+section *
+get_cdtor_priority_section (int priority, bool constructor_p)
 {
 {
-  const char *section = ".dtors";
   char buf[16];
 
   /* ??? This only works reliably with the GNU linker.  */
   char buf[16];
 
   /* ??? This only works reliably with the GNU linker.  */
+  sprintf (buf, "%s.%.5u",
+          constructor_p ? ".ctors" : ".dtors",
+          /* Invert the numbering so the linker puts us in the proper
+             order; constructors are run from right to left, and the
+             linker sorts in increasing order.  */
+          MAX_INIT_PRIORITY - priority);
+  return get_section (buf, SECTION_WRITE, NULL);
+}
+
+void
+default_named_section_asm_out_destructor (rtx symbol, int priority)
+{
+  section *sec;
+
   if (priority != DEFAULT_INIT_PRIORITY)
   if (priority != DEFAULT_INIT_PRIORITY)
-    {
-      sprintf (buf, ".dtors.%.5u",
-              /* Invert the numbering so the linker puts us in the proper
-                 order; constructors are run from right to left, and the
-                 linker sorts in increasing order.  */
-              MAX_INIT_PRIORITY - priority);
-      section = buf;
-    }
+    sec = get_cdtor_priority_section (priority, 
+                                     /*constructor_p=*/false);
+  else
+    sec = get_section (".dtors", SECTION_WRITE, NULL);
 
 
-  switch_to_section (get_section (section, SECTION_WRITE, NULL));
-  assemble_align (POINTER_SIZE);
-  assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
+  assemble_addr_to_section (symbol, sec);
 }
 
 #ifdef DTORS_SECTION_ASM_OP
 }
 
 #ifdef DTORS_SECTION_ASM_OP
@@ -934,9 +1526,7 @@ void
 default_dtor_section_asm_out_destructor (rtx symbol,
                                         int priority ATTRIBUTE_UNUSED)
 {
 default_dtor_section_asm_out_destructor (rtx symbol,
                                         int priority ATTRIBUTE_UNUSED)
 {
-  switch_to_section (dtors_section);
-  assemble_align (POINTER_SIZE);
-  assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
+  assemble_addr_to_section (symbol, dtors_section);
 }
 #endif
 
 }
 #endif
 
@@ -960,23 +1550,15 @@ default_stabs_asm_out_constructor (rtx symbol ATTRIBUTE_UNUSED,
 void
 default_named_section_asm_out_constructor (rtx symbol, int priority)
 {
 void
 default_named_section_asm_out_constructor (rtx symbol, int priority)
 {
-  const char *section = ".ctors";
-  char buf[16];
+  section *sec;
 
 
-  /* ??? This only works reliably with the GNU linker.  */
   if (priority != DEFAULT_INIT_PRIORITY)
   if (priority != DEFAULT_INIT_PRIORITY)
-    {
-      sprintf (buf, ".ctors.%.5u",
-              /* Invert the numbering so the linker puts us in the proper
-                 order; constructors are run from right to left, and the
-                 linker sorts in increasing order.  */
-              MAX_INIT_PRIORITY - priority);
-      section = buf;
-    }
+    sec = get_cdtor_priority_section (priority, 
+                                     /*constructor_p=*/true);
+  else
+    sec = get_section (".ctors", SECTION_WRITE, NULL);
 
 
-  switch_to_section (get_section (section, SECTION_WRITE, NULL));
-  assemble_align (POINTER_SIZE);
-  assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
+  assemble_addr_to_section (symbol, sec);
 }
 
 #ifdef CTORS_SECTION_ASM_OP
 }
 
 #ifdef CTORS_SECTION_ASM_OP
@@ -984,9 +1566,7 @@ void
 default_ctor_section_asm_out_constructor (rtx symbol,
                                          int priority ATTRIBUTE_UNUSED)
 {
 default_ctor_section_asm_out_constructor (rtx symbol,
                                          int priority ATTRIBUTE_UNUSED)
 {
-  switch_to_section (ctors_section);
-  assemble_align (POINTER_SIZE);
-  assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
+  assemble_addr_to_section (symbol, ctors_section);
 }
 #endif
 \f
 }
 #endif
 \f
@@ -1010,7 +1590,8 @@ notice_global_symbol (tree decl)
   const char **type = &first_global_object_name;
 
   if (first_global_object_name
   const char **type = &first_global_object_name;
 
   if (first_global_object_name
-      || !TREE_PUBLIC (decl) || DECL_EXTERNAL (decl)
+      || !TREE_PUBLIC (decl)
+      || DECL_EXTERNAL (decl)
       || !DECL_NAME (decl)
       || (TREE_CODE (decl) != FUNCTION_DECL
          && (TREE_CODE (decl) != VAR_DECL
       || !DECL_NAME (decl)
       || (TREE_CODE (decl) != FUNCTION_DECL
          && (TREE_CODE (decl) != VAR_DECL
@@ -1022,7 +1603,7 @@ notice_global_symbol (tree decl)
 
   /* 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.  */
 
   /* 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))
+  if (DECL_WEAK (decl) || DECL_ONE_ONLY (decl) || flag_shlib)
     type = &weak_global_object_name;
 
   if (!*type)
     type = &weak_global_object_name;
 
   if (!*type)
@@ -1050,27 +1631,27 @@ assemble_start_function (tree decl, const char *fnname)
   char tmp_label[100];
   bool hot_label_written = false;
 
   char tmp_label[100];
   bool hot_label_written = false;
 
-  cfun->unlikely_text_section_name = NULL;
+  crtl->subsections.unlikely_text_section_name = NULL;
+
   first_function_block_is_cold = false;
   if (flag_reorder_blocks_and_partition)
     {
       ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LHOTB", const_labelno);
   first_function_block_is_cold = false;
   if (flag_reorder_blocks_and_partition)
     {
       ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LHOTB", const_labelno);
-      cfun->hot_section_label = ggc_strdup (tmp_label);
+      crtl->subsections.hot_section_label = ggc_strdup (tmp_label);
       ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LCOLDB", const_labelno);
       ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LCOLDB", const_labelno);
-      cfun->cold_section_label = ggc_strdup (tmp_label);
+      crtl->subsections.cold_section_label = ggc_strdup (tmp_label);
       ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LHOTE", const_labelno);
       ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LHOTE", const_labelno);
-      cfun->hot_section_end_label = ggc_strdup (tmp_label);
+      crtl->subsections.hot_section_end_label = ggc_strdup (tmp_label);
       ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LCOLDE", const_labelno);
       ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LCOLDE", const_labelno);
-      cfun->cold_section_end_label = ggc_strdup (tmp_label);
+      crtl->subsections.cold_section_end_label = ggc_strdup (tmp_label);
       const_labelno++;
     }
   else
     {
       const_labelno++;
     }
   else
     {
-      cfun->hot_section_label = NULL;
-      cfun->cold_section_label = NULL;
-      cfun->hot_section_end_label = NULL;
-      cfun->cold_section_end_label = NULL;
+      crtl->subsections.hot_section_label = NULL;
+      crtl->subsections.cold_section_label = NULL;
+      crtl->subsections.hot_section_end_label = NULL;
+      crtl->subsections.cold_section_end_label = NULL;
     }
 
   /* The following code does not need preprocessing in the assembler.  */
     }
 
   /* The following code does not need preprocessing in the assembler.  */
@@ -1090,18 +1671,18 @@ assemble_start_function (tree decl, const char *fnname)
   if (flag_reorder_blocks_and_partition)
     {
       switch_to_section (unlikely_text_section ());
   if (flag_reorder_blocks_and_partition)
     {
       switch_to_section (unlikely_text_section ());
-      assemble_align (FUNCTION_BOUNDARY);
-      ASM_OUTPUT_LABEL (asm_out_file, cfun->cold_section_label);
+      assemble_align (DECL_ALIGN (decl));
+      ASM_OUTPUT_LABEL (asm_out_file, crtl->subsections.cold_section_label);
 
       /* When the function starts with a cold section, we need to explicitly
         align the hot section and write out the hot section label.
         But if the current function is a thunk, we do not have a CFG.  */
 
       /* When the function starts with a cold section, we need to explicitly
         align the hot section and write out the hot section label.
         But if the current function is a thunk, we do not have a CFG.  */
-      if (!current_function_is_thunk
+      if (!crtl->is_thunk
          && BB_PARTITION (ENTRY_BLOCK_PTR->next_bb) == BB_COLD_PARTITION)
        {
          switch_to_section (text_section);
          && BB_PARTITION (ENTRY_BLOCK_PTR->next_bb) == BB_COLD_PARTITION)
        {
          switch_to_section (text_section);
-         assemble_align (FUNCTION_BOUNDARY);
-         ASM_OUTPUT_LABEL (asm_out_file, cfun->hot_section_label);
+         assemble_align (DECL_ALIGN (decl));
+         ASM_OUTPUT_LABEL (asm_out_file, crtl->subsections.hot_section_label);
          hot_label_written = true;
          first_function_block_is_cold = true;
        }
          hot_label_written = true;
          first_function_block_is_cold = true;
        }
@@ -1115,9 +1696,9 @@ assemble_start_function (tree decl, const char *fnname)
 
       initialize_cold_section_name ();
 
 
       initialize_cold_section_name ();
 
-      if (cfun->unlikely_text_section_name 
+      if (crtl->subsections.unlikely_text_section_name
          && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
          && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
-                    cfun->unlikely_text_section_name) == 0)
+                    crtl->subsections.unlikely_text_section_name) == 0)
        first_function_block_is_cold = true;
     }
 
        first_function_block_is_cold = true;
     }
 
@@ -1126,23 +1707,22 @@ assemble_start_function (tree decl, const char *fnname)
   /* Switch to the correct text section for the start of the function.  */
 
   switch_to_section (function_section (decl));
   /* Switch to the correct text section for the start of the function.  */
 
   switch_to_section (function_section (decl));
-  if (flag_reorder_blocks_and_partition 
+  if (flag_reorder_blocks_and_partition
       && !hot_label_written)
       && !hot_label_written)
-    ASM_OUTPUT_LABEL (asm_out_file, cfun->hot_section_label);
+    ASM_OUTPUT_LABEL (asm_out_file, crtl->subsections.hot_section_label);
 
   /* Tell assembler to move to target machine's alignment for functions.  */
 
   /* Tell assembler to move to target machine's alignment for functions.  */
-  align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
-  if (align < force_align_functions_log)
-    align = force_align_functions_log;
+  align = floor_log2 (DECL_ALIGN (decl) / BITS_PER_UNIT);
   if (align > 0)
     {
       ASM_OUTPUT_ALIGN (asm_out_file, align);
     }
 
   /* Handle a user-specified function alignment.
   if (align > 0)
     {
       ASM_OUTPUT_ALIGN (asm_out_file, align);
     }
 
   /* Handle a user-specified function alignment.
-     Note that we still need to align to FUNCTION_BOUNDARY, as above,
+     Note that we still need to align to DECL_ALIGN, as above,
      because ASM_OUTPUT_MAX_SKIP_ALIGN might not do any alignment at all.  */
      because ASM_OUTPUT_MAX_SKIP_ALIGN might not do any alignment at all.  */
-  if (align_functions_log > align
+  if (! DECL_USER_ALIGN (decl)
+      && align_functions_log > align
       && cfun->function_frequency != FUNCTION_FREQUENCY_UNLIKELY_EXECUTED)
     {
 #ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
       && cfun->function_frequency != FUNCTION_FREQUENCY_UNLIKELY_EXECUTED)
     {
 #ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
@@ -1186,7 +1766,7 @@ assemble_start_function (tree decl, const char *fnname)
    function.  DECL describes the function.  NAME is the function's name.  */
 
 void
    function.  DECL describes the function.  NAME is the function's name.  */
 
 void
-assemble_end_function (tree decl, const char *fnname)
+assemble_end_function (tree decl, const char *fnname ATTRIBUTE_UNUSED)
 {
 #ifdef ASM_DECLARE_FUNCTION_SIZE
   /* We could have switched section in the middle of the function.  */
 {
 #ifdef ASM_DECLARE_FUNCTION_SIZE
   /* We could have switched section in the middle of the function.  */
@@ -1207,12 +1787,12 @@ assemble_end_function (tree decl, const char *fnname)
 
       save_text_section = in_section;
       switch_to_section (unlikely_text_section ());
 
       save_text_section = in_section;
       switch_to_section (unlikely_text_section ());
-      ASM_OUTPUT_LABEL (asm_out_file, cfun->cold_section_end_label);
+      ASM_OUTPUT_LABEL (asm_out_file, crtl->subsections.cold_section_end_label);
       if (first_function_block_is_cold)
        switch_to_section (text_section);
       else
        switch_to_section (function_section (decl));
       if (first_function_block_is_cold)
        switch_to_section (text_section);
       else
        switch_to_section (function_section (decl));
-      ASM_OUTPUT_LABEL (asm_out_file, cfun->hot_section_end_label);
+      ASM_OUTPUT_LABEL (asm_out_file, crtl->subsections.hot_section_end_label);
       switch_to_section (save_text_section);
     }
 }
       switch_to_section (save_text_section);
     }
 }
@@ -1276,124 +1856,176 @@ assemble_string (const char *p, int size)
 }
 
 \f
 }
 
 \f
-#if defined  ASM_OUTPUT_ALIGNED_DECL_LOCAL
-#define ASM_EMIT_LOCAL(decl, name, size, rounded) \
-  ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, decl, name, size, DECL_ALIGN (decl))
-#else
-#if defined  ASM_OUTPUT_ALIGNED_LOCAL
-#define ASM_EMIT_LOCAL(decl, name, size, rounded) \
-  ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, DECL_ALIGN (decl))
+/* A noswitch_section_callback for lcomm_section.  */
+
+static bool
+emit_local (tree decl ATTRIBUTE_UNUSED,
+           const char *name ATTRIBUTE_UNUSED,
+           unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
+           unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
+{
+#if defined ASM_OUTPUT_ALIGNED_DECL_LOCAL
+  ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, decl, name,
+                                size, DECL_ALIGN (decl));
+  return true;
+#elif defined ASM_OUTPUT_ALIGNED_LOCAL
+  ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, DECL_ALIGN (decl));
+  return true;
 #else
 #else
-#define ASM_EMIT_LOCAL(decl, name, size, rounded) \
-  ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded)
-#endif
+  ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
+  return false;
 #endif
 #endif
+}
 
 
+/* A noswitch_section_callback for bss_noswitch_section.  */
+
+#if defined ASM_OUTPUT_ALIGNED_BSS || defined ASM_OUTPUT_BSS
+static bool
+emit_bss (tree decl ATTRIBUTE_UNUSED,
+         const char *name ATTRIBUTE_UNUSED,
+         unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
+         unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
+{
 #if defined ASM_OUTPUT_ALIGNED_BSS
 #if defined ASM_OUTPUT_ALIGNED_BSS
-#define ASM_EMIT_BSS(decl, name, size, rounded) \
-  ASM_OUTPUT_ALIGNED_BSS (asm_out_file, decl, name, size, DECL_ALIGN (decl))
-#else
-#if defined ASM_OUTPUT_BSS
-#define ASM_EMIT_BSS(decl, name, size, rounded) \
-  ASM_OUTPUT_BSS (asm_out_file, decl, name, size, rounded)
+  ASM_OUTPUT_ALIGNED_BSS (asm_out_file, decl, name, size, DECL_ALIGN (decl));
+  return true;
 #else
 #else
-#undef  ASM_EMIT_BSS
+  ASM_OUTPUT_BSS (asm_out_file, decl, name, size, rounded);
+  return false;
 #endif
 #endif
+}
 #endif
 
 #endif
 
+/* A noswitch_section_callback for comm_section.  */
+
+static bool
+emit_common (tree decl ATTRIBUTE_UNUSED,
+            const char *name ATTRIBUTE_UNUSED,
+            unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
+            unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
+{
 #if defined ASM_OUTPUT_ALIGNED_DECL_COMMON
 #if defined ASM_OUTPUT_ALIGNED_DECL_COMMON
-#define ASM_EMIT_COMMON(decl, name, size, rounded) \
-  ASM_OUTPUT_ALIGNED_DECL_COMMON (asm_out_file, decl, name, size, DECL_ALIGN (decl))
-#else
-#if defined ASM_OUTPUT_ALIGNED_COMMON
-#define ASM_EMIT_COMMON(decl, name, size, rounded) \
-  ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, name, size, DECL_ALIGN (decl))
+  ASM_OUTPUT_ALIGNED_DECL_COMMON (asm_out_file, decl, name,
+                                 size, DECL_ALIGN (decl));
+  return true;
+#elif defined ASM_OUTPUT_ALIGNED_COMMON
+  ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, name, size, DECL_ALIGN (decl));
+  return true;
 #else
 #else
-#define ASM_EMIT_COMMON(decl, name, size, rounded) \
-  ASM_OUTPUT_COMMON (asm_out_file, name, size, rounded)
-#endif
+  ASM_OUTPUT_COMMON (asm_out_file, name, size, rounded);
+  return false;
 #endif
 #endif
+}
+
+/* A noswitch_section_callback for tls_comm_section.  */
 
 static bool
 
 static bool
-asm_emit_uninitialised (tree decl, const char *name,
-                       unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
-                       unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
+emit_tls_common (tree decl ATTRIBUTE_UNUSED,
+                const char *name ATTRIBUTE_UNUSED,
+                unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
+                unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
 {
 {
-  enum
-  {
-    asm_dest_common,
-    asm_dest_bss,
-    asm_dest_local
-  }
-  destination = asm_dest_local;
-
-  /* ??? We should handle .bss via select_section mechanisms rather than
-     via special target hooks.  That would eliminate this special case.  */
-  if (TREE_PUBLIC (decl))
-    {
-      if (!DECL_COMMON (decl))
-#ifdef ASM_EMIT_BSS
-       destination = asm_dest_bss;
+#ifdef ASM_OUTPUT_TLS_COMMON
+  ASM_OUTPUT_TLS_COMMON (asm_out_file, decl, name, size);
+  return true;
 #else
 #else
-       return false;
+  sorry ("thread-local COMMON data not implemented");
+  return true;
 #endif
 #endif
-      else
-       destination = asm_dest_common;
-    }
+}
 
 
-  if (destination != asm_dest_common)
-    {
-      resolve_unique_section (decl, 0, flag_data_sections);
-      /* Custom sections don't belong here.  */
-      if (DECL_SECTION_NAME (decl))
-        return false;
-    }
+/* Assemble DECL given that it belongs in SECTION_NOSWITCH section SECT.
+   NAME is the name of DECL's SYMBOL_REF.  */
 
 
-  if (destination == asm_dest_bss)
-    globalize_decl (decl);
+static void
+assemble_noswitch_variable (tree decl, const char *name, section *sect)
+{
+  unsigned HOST_WIDE_INT size, rounded;
 
 
-  if (flag_shared_data)
-    {
-      switch (destination)
-       {
-#ifdef ASM_OUTPUT_SHARED_BSS
-       case asm_dest_bss:
-         ASM_OUTPUT_SHARED_BSS (asm_out_file, decl, name, size, rounded);
-         return;
-#endif
-#ifdef ASM_OUTPUT_SHARED_COMMON
-       case asm_dest_common:
-         ASM_OUTPUT_SHARED_COMMON (asm_out_file, name, size, rounded);
-         return;
-#endif
-#ifdef ASM_OUTPUT_SHARED_LOCAL
-       case asm_dest_local:
-         ASM_OUTPUT_SHARED_LOCAL (asm_out_file, name, size, rounded);
-         return;
-#endif
-       default:
-         break;
-       }
-    }
+  size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
+  rounded = size;
+
+  /* Don't allocate zero bytes of common,
+     since that means "undefined external" in the linker.  */
+  if (size == 0)
+    rounded = 1;
 
 
-  switch (destination)
+  /* Round size up to multiple of BIGGEST_ALIGNMENT bits
+     so that each uninitialized object starts on such a boundary.  */
+  rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;
+  rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
+            * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
+
+  if (!sect->noswitch.callback (decl, name, size, rounded)
+      && (unsigned HOST_WIDE_INT) DECL_ALIGN_UNIT (decl) > rounded)
+    warning (0, "requested alignment for %q+D is greater than "
+            "implemented alignment of %wu", decl, rounded);
+}
+
+/* A subroutine of assemble_variable.  Output the label and contents of
+   DECL, whose address is a SYMBOL_REF with name NAME.  DONT_OUTPUT_DATA
+   is as for assemble_variable.  */
+
+static void
+assemble_variable_contents (tree decl, const char *name,
+                           bool dont_output_data)
+{
+  /* Do any machine/system dependent processing of the object.  */
+#ifdef ASM_DECLARE_OBJECT_NAME
+  last_assemble_variable_decl = decl;
+  ASM_DECLARE_OBJECT_NAME (asm_out_file, name, decl);
+#else
+  /* Standard thing is just output label for the object.  */
+  ASM_OUTPUT_LABEL (asm_out_file, name);
+#endif /* ASM_DECLARE_OBJECT_NAME */
+
+  if (!dont_output_data)
     {
     {
-#ifdef ASM_EMIT_BSS
-    case asm_dest_bss:
-      ASM_EMIT_BSS (decl, name, size, rounded);
-      break;
-#endif
-    case asm_dest_common:
-      ASM_EMIT_COMMON (decl, name, size, rounded);
-      break;
-    case asm_dest_local:
-      ASM_EMIT_LOCAL (decl, name, size, rounded);
-      break;
-    default:
-      gcc_unreachable ();
+      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),
+                        DECL_ALIGN (decl));
+      else
+       /* Leave space for it.  */
+       assemble_zeros (tree_low_cst (DECL_SIZE_UNIT (decl), 1));
     }
     }
+}
 
 
-  return true;
+/* Initialize emulated tls object TO, which refers to TLS variable
+   DECL and is initialized by PROXY.  */
+
+tree
+default_emutls_var_init (tree to, tree decl, tree proxy)
+{
+  VEC(constructor_elt,gc) *v = VEC_alloc (constructor_elt, gc, 4);
+  constructor_elt *elt;
+  tree type = TREE_TYPE (to);
+  tree field = TYPE_FIELDS (type);
+  
+  elt = VEC_quick_push (constructor_elt, v, NULL);
+  elt->index = field;
+  elt->value = fold_convert (TREE_TYPE (field), DECL_SIZE_UNIT (decl));
+  
+  elt = VEC_quick_push (constructor_elt, v, NULL);
+  field = TREE_CHAIN (field);
+  elt->index = field;
+  elt->value = build_int_cst (TREE_TYPE (field),
+                             DECL_ALIGN_UNIT (decl));
+  
+  elt = VEC_quick_push (constructor_elt, v, NULL);
+  field = TREE_CHAIN (field);
+  elt->index = field;
+  elt->value = null_pointer_node;
+  
+  elt = VEC_quick_push (constructor_elt, v, NULL);
+  field = TREE_CHAIN (field);
+  elt->index = field;
+  elt->value = proxy;
+  
+  return build_constructor (type, v);
 }
 
 /* Assemble everything that is needed for a variable or function declaration.
 }
 
 /* Assemble everything that is needed for a variable or function declaration.
@@ -1411,12 +2043,37 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
                   int at_end ATTRIBUTE_UNUSED, int dont_output_data)
 {
   const char *name;
                   int at_end ATTRIBUTE_UNUSED, int dont_output_data)
 {
   const char *name;
-  unsigned int align;
-  int reloc = 0;
-  rtx decl_rtl;
+  rtx decl_rtl, symbol;
+  section *sect;
+
+  if (! targetm.have_tls
+      && TREE_CODE (decl) == VAR_DECL
+      && DECL_THREAD_LOCAL_P (decl))
+    {
+      tree to = emutls_decl (decl);
+
+      /* If this variable is defined locally, then we need to initialize the
+         control structure with size and alignment information.  We do this
+        at the last moment because tentative definitions can take a locally
+        defined but uninitialized variable and initialize it later, which
+        would result in incorrect contents.  */
+      if (! DECL_EXTERNAL (to)
+         && (! DECL_COMMON (to)
+             || (DECL_INITIAL (decl)
+                 && DECL_INITIAL (decl) != error_mark_node)))
+       {
+         DECL_INITIAL (to) = targetm.emutls.var_init
+           (to, decl, get_emutls_init_templ_addr (decl));
+
+         /* Make sure the template is marked as needed early enough.
+            Without this, if the variable is placed in a
+            section-anchored block, the template will only be marked
+            when it's too late.  */
+         record_references_in_initializer (to);
+       }
 
 
-  if (lang_hooks.decls.prepare_assemble_variable)
-    lang_hooks.decls.prepare_assemble_variable (decl);
+      decl = to;
+    }
 
   last_assemble_variable_decl = 0;
 
 
   last_assemble_variable_decl = 0;
 
@@ -1483,47 +2140,17 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
       return;
     }
 
       return;
     }
 
-  name = XSTR (XEXP (decl_rtl, 0), 0);
+  gcc_assert (MEM_P (decl_rtl));
+  gcc_assert (GET_CODE (XEXP (decl_rtl, 0)) == SYMBOL_REF);
+  symbol = XEXP (decl_rtl, 0);
+  name = XSTR (symbol, 0);
   if (TREE_PUBLIC (decl) && DECL_NAME (decl))
     notice_global_symbol (decl);
 
   /* Compute the alignment of this data.  */
 
   if (TREE_PUBLIC (decl) && DECL_NAME (decl))
     notice_global_symbol (decl);
 
   /* Compute the alignment of this data.  */
 
-  align = DECL_ALIGN (decl);
-
-  /* In the case for initialing an array whose length isn't specified,
-     where we have not yet been able to do the layout,
-     figure out the proper alignment now.  */
-  if (dont_output_data && DECL_SIZE (decl) == 0
-      && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
-    align = MAX (align, TYPE_ALIGN (TREE_TYPE (TREE_TYPE (decl))));
-
-  /* Some object file formats have a maximum alignment which they support.
-     In particular, a.out format supports a maximum alignment of 4.  */
-  if (align > MAX_OFILE_ALIGNMENT)
-    {
-      warning (0, "alignment of %q+D is greater than maximum object "
-               "file alignment.  Using %d", decl,
-              MAX_OFILE_ALIGNMENT/BITS_PER_UNIT);
-      align = MAX_OFILE_ALIGNMENT;
-    }
-
-  /* On some machines, it is good to increase alignment sometimes.  */
-  if (! DECL_USER_ALIGN (decl))
-    {
-#ifdef DATA_ALIGNMENT
-      align = DATA_ALIGNMENT (TREE_TYPE (decl), align);
-#endif
-#ifdef CONSTANT_ALIGNMENT
-      if (DECL_INITIAL (decl) != 0 && DECL_INITIAL (decl) != error_mark_node)
-       align = CONSTANT_ALIGNMENT (DECL_INITIAL (decl), align);
-#endif
-    }
-
-  /* Reset the alignment in case we have made it tighter, so we can benefit
-     from it in get_pointer_alignment.  */
-  DECL_ALIGN (decl) = align;
-  set_mem_align (decl_rtl, align);
+  align_variable (decl, dont_output_data);
+  set_mem_align (decl_rtl, DECL_ALIGN (decl));
 
   if (TREE_PUBLIC (decl))
     maybe_assemble_visibility (decl);
 
   if (TREE_PUBLIC (decl))
     maybe_assemble_visibility (decl);
@@ -1531,110 +2158,37 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
   if (DECL_PRESERVE_P (decl))
     targetm.asm_out.mark_decl_preserved (name);
 
   if (DECL_PRESERVE_P (decl))
     targetm.asm_out.mark_decl_preserved (name);
 
-  /* Handle uninitialized definitions.  */
-
-  /* If the decl has been given an explicit section name, then it
-     isn't common, and shouldn't be handled as such.  */
-  if (DECL_SECTION_NAME (decl) || dont_output_data)
-    ;
-  else if (DECL_THREAD_LOCAL_P (decl))
-    {
-      if (DECL_COMMON (decl))
-       {
-#ifdef ASM_OUTPUT_TLS_COMMON
-         unsigned HOST_WIDE_INT size;
-
-         size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
-         ASM_OUTPUT_TLS_COMMON (asm_out_file, decl, name, size);
-         return;
-#else
-         sorry ("thread-local COMMON data not implemented");
-#endif
-       }
-    }
-  else if (DECL_INITIAL (decl) == 0
-          || 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))))
-    {
-      unsigned HOST_WIDE_INT size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
-      unsigned HOST_WIDE_INT rounded = size;
-
-      /* Don't allocate zero bytes of common,
-        since that means "undefined external" in the linker.  */
-      if (size == 0)
-       rounded = 1;
-
-      /* Round size up to multiple of BIGGEST_ALIGNMENT bits
-        so that each uninitialized object starts on such a boundary.  */
-      rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;
-      rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
-                * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
-
-#if !defined(ASM_OUTPUT_ALIGNED_COMMON) && !defined(ASM_OUTPUT_ALIGNED_DECL_COMMON) && !defined(ASM_OUTPUT_ALIGNED_BSS)
-      if ((unsigned HOST_WIDE_INT) DECL_ALIGN_UNIT (decl) > rounded)
-       warning (0, "requested alignment for %q+D is greater than "
-                 "implemented alignment of %wu", decl, rounded);
-#endif
-
-      /* If the target cannot output uninitialized but not common global data
-        in .bss, then we have to use .data, so fall through.  */
-      if (asm_emit_uninitialised (decl, name, size, rounded))
-       return;
-    }
-
-  /* Handle initialized definitions.
-     Also handle uninitialized global definitions if -fno-common and the
-     target doesn't support ASM_OUTPUT_BSS.  */
-
-  /* First make the assembler name(s) global if appropriate.  */
-  if (TREE_PUBLIC (decl) && DECL_NAME (decl))
-    globalize_decl (decl);
-
-  /* Output any data that we will need to use the address of.  */
-  if (DECL_INITIAL (decl) == error_mark_node)
-    reloc = contains_pointers_p (TREE_TYPE (decl)) ? 3 : 0;
-  else if (DECL_INITIAL (decl))
-    {
-      reloc = compute_reloc_for_constant (DECL_INITIAL (decl));
-      output_addressed_constants (DECL_INITIAL (decl));
-    }
-
-  /* Switch to the appropriate section.  */
-  resolve_unique_section (decl, reloc, flag_data_sections);
-  variable_section (decl, reloc);
+  /* First make the assembler name(s) global if appropriate.  */
+  sect = get_variable_section (decl, false);
+  if (TREE_PUBLIC (decl)
+      && DECL_NAME (decl)
+      && (sect->common.flags & SECTION_COMMON) == 0)
+    globalize_decl (decl);
+
+  /* Output any data that we will need to use the address of.  */
+  if (DECL_INITIAL (decl) && DECL_INITIAL (decl) != error_mark_node)
+    output_addressed_constants (DECL_INITIAL (decl));
 
   /* dbxout.c needs to know this.  */
 
   /* dbxout.c needs to know this.  */
-  if (in_section && (in_section->common.flags & SECTION_CODE) != 0)
+  if (sect && (sect->common.flags & SECTION_CODE) != 0)
     DECL_IN_TEXT_SECTION (decl) = 1;
 
     DECL_IN_TEXT_SECTION (decl) = 1;
 
-  /* Output the alignment of this data.  */
-  if (align > BITS_PER_UNIT)
-    ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DECL_ALIGN_UNIT (decl)));
-
-  /* Do any machine/system dependent processing of the object.  */
-#ifdef ASM_DECLARE_OBJECT_NAME
-  last_assemble_variable_decl = decl;
-  ASM_DECLARE_OBJECT_NAME (asm_out_file, name, decl);
-#else
-  /* Standard thing is just output label for the object.  */
-  ASM_OUTPUT_LABEL (asm_out_file, name);
-#endif /* ASM_DECLARE_OBJECT_NAME */
-
-  if (!dont_output_data)
+  /* If the decl is part of an object_block, make sure that the decl
+     has been positioned within its block, but do not write out its
+     definition yet.  output_object_blocks will do that later.  */
+  if (SYMBOL_REF_HAS_BLOCK_INFO_P (symbol) && SYMBOL_REF_BLOCK (symbol))
     {
     {
-      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),
-                        align);
-      else
-       /* Leave space for it.  */
-       assemble_zeros (tree_low_cst (DECL_SIZE_UNIT (decl), 1));
+      gcc_assert (!dont_output_data);
+      place_block_symbol (symbol);
+    }
+  else if (SECTION_STYLE (sect) == SECTION_NOSWITCH)
+    assemble_noswitch_variable (decl, name, sect);
+  else
+    {
+      switch_to_section (sect);
+      if (DECL_ALIGN (decl) > BITS_PER_UNIT)
+       ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DECL_ALIGN_UNIT (decl)));
+      assemble_variable_contents (decl, name, dont_output_data);
     }
 }
 
     }
 }
 
@@ -1674,7 +2228,7 @@ contains_pointers_p (tree type)
     }
 }
 
     }
 }
 
-/* In unit-at-a-time mode, we delay assemble_external processing until
+/* We delay assemble_external processing until
    the compilation unit is finalized.  This is the best we can do for
    right now (i.e. stage 3 of GCC 4.0) - the right thing is to delay
    it all the way to final.  See PR 17982 for further discussion.  */
    the compilation unit is finalized.  This is the best we can do for
    right now (i.e. stage 3 of GCC 4.0) - the right thing is to delay
    it all the way to final.  See PR 17982 for further discussion.  */
@@ -1749,11 +2303,10 @@ assemble_external (tree decl ATTRIBUTE_UNUSED)
   if (!DECL_P (decl) || !DECL_EXTERNAL (decl) || !TREE_PUBLIC (decl))
     return;
 
   if (!DECL_P (decl) || !DECL_EXTERNAL (decl) || !TREE_PUBLIC (decl))
     return;
 
-  if (flag_unit_at_a_time)
-    pending_assemble_externals = tree_cons (0, decl,
-                                           pending_assemble_externals);
-  else
-    assemble_external_real (decl);
+  /* We want to output external symbols at very last to check if they
+     are references or not.  */
+  pending_assemble_externals = tree_cons (0, decl,
+                                         pending_assemble_externals);
 #endif
 }
 
 #endif
 }
 
@@ -1803,8 +2356,8 @@ mark_decl_referenced (tree decl)
     }
   else if (TREE_CODE (decl) == VAR_DECL)
     {
     }
   else if (TREE_CODE (decl) == VAR_DECL)
     {
-      struct cgraph_varpool_node *node = cgraph_varpool_node (decl);
-      cgraph_varpool_mark_needed_node (node);
+      struct varpool_node *node = varpool_node (decl);
+      varpool_mark_needed_node (node);
       /* C++ frontend use mark_decl_references to force COMDAT variables
          to be output that might appear dead otherwise.  */
       node->force_output = true;
       /* C++ frontend use mark_decl_references to force COMDAT variables
          to be output that might appear dead otherwise.  */
       node->force_output = true;
@@ -1890,11 +2443,6 @@ assemble_static_space (unsigned HOST_WIDE_INT size)
   const char *namestring;
   rtx x;
 
   const char *namestring;
   rtx x;
 
-#if 0
-  if (flag_shared_data)
-    switch_to_section (data_section);
-#endif
-
   ASM_GENERATE_INTERNAL_LABEL (name, "LF", const_labelno);
   ++const_labelno;
   namestring = ggc_strdup (name);
   ASM_GENERATE_INTERNAL_LABEL (name, "LF", const_labelno);
   ++const_labelno;
   namestring = ggc_strdup (name);
@@ -2066,11 +2614,17 @@ assemble_integer (rtx x, unsigned int size, unsigned int align, int force)
       enum machine_mode omode, imode;
       unsigned int subalign;
       unsigned int subsize, i;
       enum machine_mode omode, imode;
       unsigned int subalign;
       unsigned int subsize, i;
+      unsigned char mclass;
 
       subsize = size > UNITS_PER_WORD? UNITS_PER_WORD : 1;
       subalign = MIN (align, subsize * BITS_PER_UNIT);
 
       subsize = size > UNITS_PER_WORD? UNITS_PER_WORD : 1;
       subalign = MIN (align, subsize * BITS_PER_UNIT);
-      omode = mode_for_size (subsize * BITS_PER_UNIT, MODE_INT, 0);
-      imode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
+      if (GET_CODE (x) == CONST_FIXED)
+       mclass = GET_MODE_CLASS (GET_MODE (x));
+      else
+       mclass = MODE_INT;
+
+      omode = mode_for_size (subsize * BITS_PER_UNIT, mclass, 0);
+      imode = mode_for_size (size * BITS_PER_UNIT, mclass, 0);
 
       for (i = 0; i < size; i += subsize)
        {
 
       for (i = 0; i < size; i += subsize)
        {
@@ -2087,14 +2641,14 @@ assemble_integer (rtx x, unsigned int size, unsigned int align, int force)
     }
 
   gcc_assert (!force);
     }
 
   gcc_assert (!force);
-  
+
   return false;
 }
 \f
 void
 assemble_real (REAL_VALUE_TYPE d, enum machine_mode mode, unsigned int align)
 {
   return false;
 }
 \f
 void
 assemble_real (REAL_VALUE_TYPE d, enum machine_mode mode, unsigned int align)
 {
-  long data[4];
+  long data[4] = {0, 0, 0, 0};
   int i;
   int bitsize, nelts, nunits, units_per;
 
   int i;
   int bitsize, nelts, nunits, units_per;
 
@@ -2182,6 +2736,7 @@ decode_addr_const (tree exp, struct addr_const *value)
       break;
 
     case REAL_CST:
       break;
 
     case REAL_CST:
+    case FIXED_CST:
     case STRING_CST:
     case COMPLEX_CST:
     case CONSTRUCTOR:
     case STRING_CST:
     case COMPLEX_CST:
     case CONSTRUCTOR:
@@ -2229,7 +2784,7 @@ static void maybe_output_constant_def_contents (struct constant_descriptor_tree
 static hashval_t
 const_desc_hash (const void *ptr)
 {
 static hashval_t
 const_desc_hash (const void *ptr)
 {
-  return ((struct constant_descriptor_tree *)ptr)->hash;
+  return ((const struct constant_descriptor_tree *)ptr)->hash;
 }
 
 static hashval_t
 }
 
 static hashval_t
@@ -2253,6 +2808,9 @@ const_hash_1 (const tree exp)
     case REAL_CST:
       return real_hash (TREE_REAL_CST_PTR (exp));
 
     case REAL_CST:
       return real_hash (TREE_REAL_CST_PTR (exp));
 
+    case FIXED_CST:
+      return fixed_hash (TREE_FIXED_CST_PTR (exp));
+
     case STRING_CST:
       p = TREE_STRING_POINTER (exp);
       len = TREE_STRING_LENGTH (exp);
     case STRING_CST:
       p = TREE_STRING_POINTER (exp);
       len = TREE_STRING_LENGTH (exp);
@@ -2266,13 +2824,13 @@ const_hash_1 (const tree exp)
       {
        unsigned HOST_WIDE_INT idx;
        tree value;
       {
        unsigned HOST_WIDE_INT idx;
        tree value;
-       
+
        hi = 5 + int_size_in_bytes (TREE_TYPE (exp));
        hi = 5 + int_size_in_bytes (TREE_TYPE (exp));
-       
+
        FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, value)
          if (value)
            hi = hi * 603 + const_hash_1 (value);
        FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, value)
          if (value)
            hi = hi * 603 + const_hash_1 (value);
-       
+
        return hi;
       }
 
        return hi;
       }
 
@@ -2304,13 +2862,12 @@ const_hash_1 (const tree exp)
       return hi;
 
     case PLUS_EXPR:
       return hi;
 
     case PLUS_EXPR:
+    case POINTER_PLUS_EXPR:
     case MINUS_EXPR:
       return (const_hash_1 (TREE_OPERAND (exp, 0)) * 9
              + const_hash_1 (TREE_OPERAND (exp, 1)));
 
     case MINUS_EXPR:
       return (const_hash_1 (TREE_OPERAND (exp, 0)) * 9
              + const_hash_1 (TREE_OPERAND (exp, 1)));
 
-    case NOP_EXPR:
-    case CONVERT_EXPR:
-    case NON_LVALUE_EXPR:
+    CASE_CONVERT:
       return const_hash_1 (TREE_OPERAND (exp, 0)) * 7 + 2;
 
     default:
       return const_hash_1 (TREE_OPERAND (exp, 0)) * 7 + 2;
 
     default:
@@ -2330,8 +2887,10 @@ const_hash_1 (const tree exp)
 static int
 const_desc_eq (const void *p1, const void *p2)
 {
 static int
 const_desc_eq (const void *p1, const void *p2)
 {
-  const struct constant_descriptor_tree *c1 = p1;
-  const struct constant_descriptor_tree *c2 = p2;
+  const struct constant_descriptor_tree *const c1
+    = (const struct constant_descriptor_tree *) p1;
+  const struct constant_descriptor_tree *const c2
+    = (const struct constant_descriptor_tree *) p2;
   if (c1->hash != c2->hash)
     return 0;
   return compare_constant (c1->value, c2->value);
   if (c1->hash != c2->hash)
     return 0;
   return compare_constant (c1->value, c2->value);
@@ -2359,6 +2918,8 @@ compare_constant (const tree t1, const tree t2)
       /* Integer constants are the same only if the same width of type.  */
       if (TYPE_PRECISION (TREE_TYPE (t1)) != TYPE_PRECISION (TREE_TYPE (t2)))
        return 0;
       /* Integer constants are the same only if the same width of type.  */
       if (TYPE_PRECISION (TREE_TYPE (t1)) != TYPE_PRECISION (TREE_TYPE (t2)))
        return 0;
+      if (TYPE_MODE (TREE_TYPE (t1)) != TYPE_MODE (TREE_TYPE (t2)))
+       return 0;
       return tree_int_cst_equal (t1, t2);
 
     case REAL_CST:
       return tree_int_cst_equal (t1, t2);
 
     case REAL_CST:
@@ -2368,6 +2929,13 @@ compare_constant (const tree t1, const tree t2)
 
       return REAL_VALUES_IDENTICAL (TREE_REAL_CST (t1), TREE_REAL_CST (t2));
 
 
       return REAL_VALUES_IDENTICAL (TREE_REAL_CST (t1), TREE_REAL_CST (t2));
 
+    case FIXED_CST:
+      /* Fixed constants are the same only if the same width of type.  */
+      if (TYPE_PRECISION (TREE_TYPE (t1)) != TYPE_PRECISION (TREE_TYPE (t2)))
+       return 0;
+
+      return FIXED_VALUES_IDENTICAL (TREE_FIXED_CST (t1), TREE_FIXED_CST (t2));
+
     case STRING_CST:
       if (TYPE_MODE (TREE_TYPE (t1)) != TYPE_MODE (TREE_TYPE (t2)))
        return 0;
     case STRING_CST:
       if (TYPE_MODE (TREE_TYPE (t1)) != TYPE_MODE (TREE_TYPE (t2)))
        return 0;
@@ -2384,7 +2952,7 @@ compare_constant (const tree t1, const tree t2)
       {
        VEC(constructor_elt, gc) *v1, *v2;
        unsigned HOST_WIDE_INT idx;
       {
        VEC(constructor_elt, gc) *v1, *v2;
        unsigned HOST_WIDE_INT idx;
-       
+
        typecode = TREE_CODE (TREE_TYPE (t1));
        if (typecode != TREE_CODE (TREE_TYPE (t2)))
          return 0;
        typecode = TREE_CODE (TREE_TYPE (t1));
        if (typecode != TREE_CODE (TREE_TYPE (t2)))
          return 0;
@@ -2432,7 +3000,7 @@ compare_constant (const tree t1, const tree t2)
                  return 0;
              }
          }
                  return 0;
              }
          }
-       
+
        return 1;
       }
 
        return 1;
       }
 
@@ -2448,27 +3016,18 @@ compare_constant (const tree t1, const tree t2)
       }
 
     case PLUS_EXPR:
       }
 
     case PLUS_EXPR:
+    case POINTER_PLUS_EXPR:
     case MINUS_EXPR:
     case RANGE_EXPR:
       return (compare_constant (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0))
              && compare_constant(TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1)));
 
     case MINUS_EXPR:
     case RANGE_EXPR:
       return (compare_constant (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0))
              && compare_constant(TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1)));
 
-    case NOP_EXPR:
-    case CONVERT_EXPR:
-    case NON_LVALUE_EXPR:
+    CASE_CONVERT:
     case VIEW_CONVERT_EXPR:
       return compare_constant (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
 
     default:
     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);
-       if (nt1 != t1 || nt2 != t2)
-         return compare_constant (nt1, nt2);
-       else
-         return 0;
-      }
+      return 0;
     }
 
   gcc_unreachable ();
     }
 
   gcc_unreachable ();
@@ -2493,6 +3052,7 @@ copy_constant (tree exp)
 
     case INTEGER_CST:
     case REAL_CST:
 
     case INTEGER_CST:
     case REAL_CST:
+    case FIXED_CST:
     case STRING_CST:
       return copy_node (exp);
 
     case STRING_CST:
       return copy_node (exp);
 
@@ -2502,14 +3062,13 @@ copy_constant (tree exp)
                            copy_constant (TREE_IMAGPART (exp)));
 
     case PLUS_EXPR:
                            copy_constant (TREE_IMAGPART (exp)));
 
     case PLUS_EXPR:
+    case POINTER_PLUS_EXPR:
     case MINUS_EXPR:
       return build2 (TREE_CODE (exp), TREE_TYPE (exp),
                     copy_constant (TREE_OPERAND (exp, 0)),
                     copy_constant (TREE_OPERAND (exp, 1)));
 
     case MINUS_EXPR:
       return build2 (TREE_CODE (exp), TREE_TYPE (exp),
                     copy_constant (TREE_OPERAND (exp, 0)),
                     copy_constant (TREE_OPERAND (exp, 1)));
 
-    case NOP_EXPR:
-    case CONVERT_EXPR:
-    case NON_LVALUE_EXPR:
+    CASE_CONVERT:
     case VIEW_CONVERT_EXPR:
       return build1 (TREE_CODE (exp), TREE_TYPE (exp),
                     copy_constant (TREE_OPERAND (exp, 0)));
     case VIEW_CONVERT_EXPR:
       return build1 (TREE_CODE (exp), TREE_TYPE (exp),
                     copy_constant (TREE_OPERAND (exp, 0)));
@@ -2520,7 +3079,7 @@ copy_constant (tree exp)
        VEC(constructor_elt, gc) *v;
        unsigned HOST_WIDE_INT idx;
        tree purpose, value;
        VEC(constructor_elt, gc) *v;
        unsigned HOST_WIDE_INT idx;
        tree purpose, value;
-       
+
        v = VEC_alloc(constructor_elt, gc, VEC_length(constructor_elt,
                                                      CONSTRUCTOR_ELTS (exp)));
        FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (exp), idx, purpose, value)
        v = VEC_alloc(constructor_elt, gc, VEC_length(constructor_elt,
                                                      CONSTRUCTOR_ELTS (exp)));
        FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (exp), idx, purpose, value)
@@ -2534,15 +3093,50 @@ copy_constant (tree exp)
       }
 
     default:
       }
 
     default:
-      {
-       tree t = lang_hooks.expand_constant (exp);
-       
-       gcc_assert (t == exp);
-       return copy_constant (t);
-      }
+      gcc_unreachable ();
     }
 }
 \f
     }
 }
 \f
+/* Return the alignment of constant EXP in bits.  */
+
+static unsigned int
+get_constant_alignment (tree exp)
+{
+  unsigned int align;
+
+  align = TYPE_ALIGN (TREE_TYPE (exp));
+#ifdef CONSTANT_ALIGNMENT
+  align = CONSTANT_ALIGNMENT (exp, align);
+#endif
+  return align;
+}
+
+/* Return the section into which constant EXP should be placed.  */
+
+static section *
+get_constant_section (tree exp)
+{
+  if (IN_NAMED_SECTION (exp))
+    return get_named_section (exp, NULL, compute_reloc_for_constant (exp));
+  else
+    return targetm.asm_out.select_section (exp,
+                                          compute_reloc_for_constant (exp),
+                                          get_constant_alignment (exp));
+}
+
+/* Return the size of constant EXP in bytes.  */
+
+static HOST_WIDE_INT
+get_constant_size (tree exp)
+{
+  HOST_WIDE_INT size;
+
+  size = int_size_in_bytes (TREE_TYPE (exp));
+  if (TREE_CODE (exp) == STRING_CST)
+    size = MAX (TREE_STRING_LENGTH (exp), size);
+  return size;
+}
+
 /* Subroutine of output_constant_def:
    No constant equal to EXP is known to have been output.
    Make a constant descriptor to enter EXP in the hash table.
 /* Subroutine of output_constant_def:
    No constant equal to EXP is known to have been output.
    Make a constant descriptor to enter EXP in the hash table.
@@ -2559,7 +3153,7 @@ build_constant_desc (tree exp)
   int labelno;
   struct constant_descriptor_tree *desc;
 
   int labelno;
   struct constant_descriptor_tree *desc;
 
-  desc = ggc_alloc (sizeof (*desc));
+  desc = GGC_NEW (struct constant_descriptor_tree);
   desc->value = copy_constant (exp);
 
   /* Propagate marked-ness to copied constant.  */
   desc->value = copy_constant (exp);
 
   /* Propagate marked-ness to copied constant.  */
@@ -2571,9 +3165,16 @@ build_constant_desc (tree exp)
   ASM_GENERATE_INTERNAL_LABEL (label, "LC", labelno);
 
   /* We have a symbol name; construct the SYMBOL_REF and the MEM.  */
   ASM_GENERATE_INTERNAL_LABEL (label, "LC", labelno);
 
   /* We have a symbol name; construct the SYMBOL_REF and the MEM.  */
-  symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label));
-  SYMBOL_REF_FLAGS (symbol) = SYMBOL_FLAG_LOCAL;
-  SYMBOL_REF_DECL (symbol) = desc->value;
+  if (use_object_blocks_p ())
+    {
+      section *sect = get_constant_section (exp);
+      symbol = create_block_symbol (ggc_strdup (label),
+                                   get_block_for_section (sect), -1);
+    }
+  else
+    symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label));
+  SYMBOL_REF_FLAGS (symbol) |= SYMBOL_FLAG_LOCAL;
+  SET_SYMBOL_REF_DECL (symbol, desc->value);
   TREE_CONSTANT_POOL_ADDRESS_P (symbol) = 1;
 
   rtl = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)), symbol);
   TREE_CONSTANT_POOL_ADDRESS_P (symbol) = 1;
 
   rtl = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)), symbol);
@@ -2620,7 +3221,7 @@ output_constant_def (tree exp, int defer)
   key.hash = const_hash_1 (exp);
   loc = htab_find_slot_with_hash (const_desc_htab, &key, key.hash, INSERT);
 
   key.hash = const_hash_1 (exp);
   loc = htab_find_slot_with_hash (const_desc_htab, &key, key.hash, INSERT);
 
-  desc = *loc;
+  desc = (struct constant_descriptor_tree *) *loc;
   if (desc == 0)
     {
       desc = build_constant_desc (exp);
   if (desc == 0)
     {
       desc = build_constant_desc (exp);
@@ -2665,54 +3266,57 @@ maybe_output_constant_def_contents (struct constant_descriptor_tree *desc,
   output_constant_def_contents (symbol);
 }
 
   output_constant_def_contents (symbol);
 }
 
+/* Subroutine of output_constant_def_contents.  Output the definition
+   of constant EXP, which is pointed to by label LABEL.  ALIGN is the
+   constant's alignment in bits.  */
+
+static void
+assemble_constant_contents (tree exp, const char *label, unsigned int align)
+{
+  HOST_WIDE_INT size;
+
+  size = get_constant_size (exp);
+
+  /* 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, size, align);
+}
+
 /* We must output the constant data referred to by SYMBOL; do so.  */
 
 static void
 output_constant_def_contents (rtx symbol)
 {
   tree exp = SYMBOL_REF_DECL (symbol);
 /* We must output the constant data referred to by SYMBOL; do so.  */
 
 static void
 output_constant_def_contents (rtx symbol)
 {
   tree exp = SYMBOL_REF_DECL (symbol);
-  const char *label = XSTR (symbol, 0);
-  HOST_WIDE_INT size;
+  unsigned int align;
 
   /* Make sure any other constants whose addresses appear in EXP
      are assigned label numbers.  */
 
   /* Make sure any other constants whose addresses appear in EXP
      are assigned label numbers.  */
-  int reloc = compute_reloc_for_constant (exp);
-
-  /* Align the location counter as required by EXP's data type.  */
-  unsigned int align = TYPE_ALIGN (TREE_TYPE (exp));
-#ifdef CONSTANT_ALIGNMENT
-  align = CONSTANT_ALIGNMENT (exp, align);
-#endif
-
   output_addressed_constants (exp);
 
   /* We are no longer deferring this constant.  */
   TREE_ASM_WRITTEN (exp) = 1;
 
   output_addressed_constants (exp);
 
   /* We are no longer deferring this constant.  */
   TREE_ASM_WRITTEN (exp) = 1;
 
-  if (IN_NAMED_SECTION (exp))
-    switch_to_section (get_named_section (exp, NULL, reloc));
+  /* If the constant is part of an object block, make sure that the
+     decl has been positioned within its block, but do not write out
+     its definition yet.  output_object_blocks will do that later.  */
+  if (SYMBOL_REF_HAS_BLOCK_INFO_P (symbol) && SYMBOL_REF_BLOCK (symbol))
+    place_block_symbol (symbol);
   else
   else
-    switch_to_section (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));
+      switch_to_section (get_constant_section (exp));
+      align = get_constant_alignment (exp);
+      if (align > BITS_PER_UNIT)
+       ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
+      assemble_constant_contents (exp, XSTR (symbol, 0), align);
     }
     }
-
-  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, size, align);
   if (flag_mudflap)
     mudflap_enqueue_constant (exp);
 }
   if (flag_mudflap)
     mudflap_enqueue_constant (exp);
 }
@@ -2728,7 +3332,8 @@ lookup_constant_def (tree exp)
 
   key.value = exp;
   key.hash = const_hash_1 (exp);
 
   key.value = exp;
   key.hash = const_hash_1 (exp);
-  desc = htab_find_with_hash (const_desc_htab, &key, key.hash);
+  desc = (struct constant_descriptor_tree *)
+    htab_find_with_hash (const_desc_htab, &key, key.hash);
 
   return (desc ? desc->rtl : NULL_RTX);
 }
 
   return (desc ? desc->rtl : NULL_RTX);
 }
@@ -2751,7 +3356,6 @@ struct rtx_constant_pool GTY(())
      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;
      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).  */
 
   /* Current offset in constant pool (does not include any
      machine-specific header).  */
@@ -2777,38 +3381,24 @@ struct constant_descriptor_rtx GTY((chain_next ("%h.next")))
 static hashval_t
 const_desc_rtx_hash (const void *ptr)
 {
 static hashval_t
 const_desc_rtx_hash (const void *ptr)
 {
-  const struct constant_descriptor_rtx *desc = ptr;
+  const struct constant_descriptor_rtx *const desc
+    = (const struct constant_descriptor_rtx *) ptr;
   return desc->hash;
 }
 
 static int
 const_desc_rtx_eq (const void *a, const void *b)
 {
   return desc->hash;
 }
 
 static int
 const_desc_rtx_eq (const void *a, const void *b)
 {
-  const struct constant_descriptor_rtx *x = a;
-  const struct constant_descriptor_rtx *y = b;
+  const struct constant_descriptor_rtx *const x
+    = (const struct constant_descriptor_rtx *) a;
+  const struct constant_descriptor_rtx *const y
+    = (const struct constant_descriptor_rtx *) b;
 
   if (x->mode != y->mode)
     return 0;
   return rtx_equal_p (x->constant, y->constant);
 }
 
 
   if (x->mode != y->mode)
     return 0;
   return rtx_equal_p (x->constant, y->constant);
 }
 
-/* Hash and compare functions for const_rtx_sym_htab.  */
-
-static hashval_t
-const_desc_rtx_sym_hash (const void *ptr)
-{
-  const struct constant_descriptor_rtx *desc = ptr;
-  return htab_hash_string (XSTR (desc->sym, 0));
-}
-
-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);
-}
-
 /* This is the worker function for const_rtx_hash, called via for_each_rtx.  */
 
 static int
 /* This is the worker function for const_rtx_hash, called via for_each_rtx.  */
 
 static int
@@ -2854,6 +3444,10 @@ const_rtx_hash_1 (rtx *xp, void *data)
        h ^= real_hash (CONST_DOUBLE_REAL_VALUE (x));
       break;
 
        h ^= real_hash (CONST_DOUBLE_REAL_VALUE (x));
       break;
 
+    case CONST_FIXED:
+      h ^= fixed_hash (CONST_FIXED_VALUE (x));
+      break;
+
     case CONST_VECTOR:
       {
        int i;
     case CONST_VECTOR:
       {
        int i;
@@ -2879,7 +3473,7 @@ const_rtx_hash_1 (rtx *xp, void *data)
       break;
     }
 
       break;
     }
 
-  hp = data;
+  hp = (hashval_t *) data;
   *hp = *hp * 509 + h;
   return 0;
 }
   *hp = *hp * 509 + h;
   return 0;
 }
@@ -2895,27 +3489,29 @@ const_rtx_hash (rtx x)
 }
 
 \f
 }
 
 \f
-/* Initialize constant pool hashing for a new function.  */
+/* Create and return a new rtx constant pool.  */
 
 
-void
-init_varasm_status (struct function *f)
+static struct rtx_constant_pool *
+create_constant_pool (void)
 {
 {
-  struct varasm_status *p;
   struct rtx_constant_pool *pool;
 
   struct rtx_constant_pool *pool;
 
-  p = ggc_alloc (sizeof (struct varasm_status));
-  f->varasm = p;
-
-  pool = ggc_alloc (sizeof (struct rtx_constant_pool));
-  p->pool = pool;
-  p->deferred_constants = 0;
-
+  pool = GGC_NEW (struct rtx_constant_pool);
   pool->const_rtx_htab = htab_create_ggc (31, const_desc_rtx_hash,
                                          const_desc_rtx_eq, NULL);
   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->first = NULL;
+  pool->last = NULL;
   pool->offset = 0;
   pool->offset = 0;
+  return pool;
+}
+
+/* Initialize constant pool hashing for a new function.  */
+
+void
+init_varasm_status (void)
+{
+  crtl->varasm.pool = create_constant_pool ();
+  crtl->varasm.deferred_constants = 0;
 }
 \f
 /* Given a MINUS expression, simplify it if both sides
 }
 \f
 /* Given a MINUS expression, simplify it if both sides
@@ -2935,7 +3531,7 @@ rtx
 force_const_mem (enum machine_mode mode, rtx x)
 {
   struct constant_descriptor_rtx *desc, tmp;
 force_const_mem (enum machine_mode mode, rtx x)
 {
   struct constant_descriptor_rtx *desc, tmp;
-  struct rtx_constant_pool *pool = cfun->varasm->pool;
+  struct rtx_constant_pool *pool;
   char label[256];
   rtx def, symbol;
   hashval_t hash;
   char label[256];
   rtx def, symbol;
   hashval_t hash;
@@ -2946,19 +3542,27 @@ force_const_mem (enum machine_mode mode, rtx x)
   if (targetm.cannot_force_const_mem (x))
     return NULL_RTX;
 
   if (targetm.cannot_force_const_mem (x))
     return NULL_RTX;
 
+  /* Record that this function has used a constant pool entry.  */
+  crtl->uses_const_pool = 1;
+
+  /* Decide which pool to use.  */
+  pool = (targetm.use_blocks_for_constant_p (mode, x)
+         ? shared_constant_pool
+         : crtl->varasm.pool);
+
   /* 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);
   /* 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;
-  
+  desc = (struct constant_descriptor_rtx *) *slot;
+
   /* If the constant was already present, return its memory.  */
   if (desc)
     return copy_rtx (desc->mem);
 
   /* Otherwise, create a new descriptor.  */
   /* 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));
+  desc = GGC_NEW (struct constant_descriptor_rtx);
   *slot = desc;
 
   /* Align the location counter as required by EXP's data type.  */
   *slot = desc;
 
   /* Align the location counter as required by EXP's data type.  */
@@ -2996,15 +3600,18 @@ force_const_mem (enum machine_mode mode, rtx x)
 
   /* Construct the SYMBOL_REF.  Make sure to mark it as belonging to
      the constants pool.  */
 
   /* 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;
+  if (use_object_blocks_p () && targetm.use_blocks_for_constant_p (mode, x))
+    {
+      section *sect = targetm.asm_out.select_rtx_section (mode, x, align);
+      symbol = create_block_symbol (ggc_strdup (label),
+                                   get_block_for_section (sect), -1);
+    }
+  else
+    symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label));
+  desc->sym = symbol;
+  SYMBOL_REF_FLAGS (symbol) |= SYMBOL_FLAG_LOCAL;
   CONSTANT_POOL_ADDRESS_P (symbol) = 1;
   CONSTANT_POOL_ADDRESS_P (symbol) = 1;
-  current_function_uses_const_pool = 1;
-
-  /* Insert the descriptor into the symbol cross-reference table too.  */
-  slot = htab_find_slot (pool->const_rtx_sym_htab, desc, INSERT);
-  gcc_assert (!*slot);
-  *slot = desc;
+  SET_SYMBOL_REF_CONSTANT (symbol, desc);
 
   /* Construct the MEM.  */
   desc->mem = def = gen_const_mem (mode, symbol);
 
   /* Construct the MEM.  */
   desc->mem = def = gen_const_mem (mode, symbol);
@@ -3019,23 +3626,12 @@ force_const_mem (enum machine_mode mode, rtx x)
   return copy_rtx (def);
 }
 \f
   return copy_rtx (def);
 }
 \f
-/* Given a SYMBOL_REF with CONSTANT_POOL_ADDRESS_P true, return a pointer to
-   the corresponding constant_descriptor_rtx structure.  */
-
-static struct constant_descriptor_rtx *
-find_pool_constant (struct rtx_constant_pool *pool, rtx sym)
-{
-  struct constant_descriptor_rtx tmp;
-  tmp.sym = sym;
-  return htab_find (pool->const_rtx_sym_htab, &tmp);
-}
-
 /* Given a constant pool SYMBOL_REF, return the corresponding constant.  */
 
 rtx
 get_pool_constant (rtx addr)
 {
 /* Given a constant pool SYMBOL_REF, return the corresponding constant.  */
 
 rtx
 get_pool_constant (rtx addr)
 {
-  return find_pool_constant (cfun->varasm->pool, addr)->constant;
+  return SYMBOL_REF_CONSTANT (addr)->constant;
 }
 
 /* Given a constant pool SYMBOL_REF, return the corresponding constant
 }
 
 /* Given a constant pool SYMBOL_REF, return the corresponding constant
@@ -3046,25 +3642,17 @@ get_pool_constant_mark (rtx addr, bool *pmarked)
 {
   struct constant_descriptor_rtx *desc;
 
 {
   struct constant_descriptor_rtx *desc;
 
-  desc = find_pool_constant (cfun->varasm->pool, addr);
+  desc = SYMBOL_REF_CONSTANT (addr);
   *pmarked = (desc->mark != 0);
   return desc->constant;
 }
 
   *pmarked = (desc->mark != 0);
   return desc->constant;
 }
 
-/* Likewise, but for the constant pool of a specific function.  */
-
-rtx
-get_pool_constant_for_function (struct function *f, rtx addr)
-{
-  return find_pool_constant (f->varasm->pool, addr)->constant;
-}
-
 /* Similar, return the mode.  */
 
 enum machine_mode
 /* Similar, return the mode.  */
 
 enum machine_mode
-get_pool_mode (rtx addr)
+get_pool_mode (const_rtx addr)
 {
 {
-  return find_pool_constant (cfun->varasm->pool, addr)->mode;
+  return SYMBOL_REF_CONSTANT (addr)->mode;
 }
 
 /* Return the size of the constant pool.  */
 }
 
 /* Return the size of the constant pool.  */
@@ -3072,7 +3660,7 @@ get_pool_mode (rtx addr)
 int
 get_pool_size (void)
 {
 int
 get_pool_size (void)
 {
-  return cfun->varasm->pool->offset;
+  return crtl->varasm.pool->offset;
 }
 \f
 /* Worker function for output_constant_pool_1.  Emit assembly for X
 }
 \f
 /* Worker function for output_constant_pool_1.  Emit assembly for X
@@ -3087,20 +3675,28 @@ output_constant_pool_2 (enum machine_mode mode, rtx x, unsigned int align)
     case MODE_DECIMAL_FLOAT:
       {
        REAL_VALUE_TYPE r;
     case MODE_DECIMAL_FLOAT:
       {
        REAL_VALUE_TYPE r;
-       
+
        gcc_assert (GET_CODE (x) == CONST_DOUBLE);
        REAL_VALUE_FROM_CONST_DOUBLE (r, x);
        assemble_real (r, mode, align);
        break;
       }
        gcc_assert (GET_CODE (x) == CONST_DOUBLE);
        REAL_VALUE_FROM_CONST_DOUBLE (r, x);
        assemble_real (r, mode, align);
        break;
       }
-      
+
     case MODE_INT:
     case MODE_PARTIAL_INT:
     case MODE_INT:
     case MODE_PARTIAL_INT:
+    case MODE_FRACT:
+    case MODE_UFRACT:
+    case MODE_ACCUM:
+    case MODE_UACCUM:
       assemble_integer (x, GET_MODE_SIZE (mode), align, 1);
       break;
 
     case MODE_VECTOR_FLOAT:
     case MODE_VECTOR_INT:
       assemble_integer (x, GET_MODE_SIZE (mode), align, 1);
       break;
 
     case MODE_VECTOR_FLOAT:
     case MODE_VECTOR_INT:
+    case MODE_VECTOR_FRACT:
+    case MODE_VECTOR_UFRACT:
+    case MODE_VECTOR_ACCUM:
+    case MODE_VECTOR_UACCUM:
       {
        int i, units;
         enum machine_mode submode = GET_MODE_INNER (mode);
       {
        int i, units;
         enum machine_mode submode = GET_MODE_INNER (mode);
@@ -3122,15 +3718,15 @@ output_constant_pool_2 (enum machine_mode mode, rtx x, unsigned int align)
     }
 }
 
     }
 }
 
-/* Worker function for output_constant_pool.  Emit POOL.  */
+/* Worker function for output_constant_pool.  Emit constant DESC,
+   giving it ALIGN bits of alignment.  */
 
 static void
 
 static void
-output_constant_pool_1 (struct constant_descriptor_rtx *desc)
+output_constant_pool_1 (struct constant_descriptor_rtx *desc,
+                       unsigned int align)
 {
   rtx x, tmp;
 
 {
   rtx x, tmp;
 
-  if (!desc->mark)
-    return;
   x = desc->constant;
 
   /* See if X is a LABEL_REF (or a CONST referring to a LABEL_REF)
   x = desc->constant;
 
   /* See if X is a LABEL_REF (or a CONST referring to a LABEL_REF)
@@ -3143,49 +3739,45 @@ output_constant_pool_1 (struct constant_descriptor_rtx *desc)
      functioning even with INSN_DELETED_P and friends.  */
 
   tmp = x;
      functioning even with INSN_DELETED_P and friends.  */
 
   tmp = x;
-  switch (GET_CODE (x))
+  switch (GET_CODE (tmp))
     {
     case CONST:
     {
     case CONST:
-      if (GET_CODE (XEXP (x, 0)) != PLUS
-         || GET_CODE (XEXP (XEXP (x, 0), 0)) != LABEL_REF)
+      if (GET_CODE (XEXP (tmp, 0)) != PLUS
+         || GET_CODE (XEXP (XEXP (tmp, 0), 0)) != LABEL_REF)
        break;
        break;
-      tmp = XEXP (XEXP (x, 0), 0);
+      tmp = XEXP (XEXP (tmp, 0), 0);
       /* FALLTHRU  */
 
     case LABEL_REF:
       /* FALLTHRU  */
 
     case LABEL_REF:
-      tmp = XEXP (x, 0);
+      tmp = XEXP (tmp, 0);
       gcc_assert (!INSN_DELETED_P (tmp));
       gcc_assert (!NOTE_P (tmp)
       gcc_assert (!INSN_DELETED_P (tmp));
       gcc_assert (!NOTE_P (tmp)
-                 || NOTE_LINE_NUMBER (tmp) != NOTE_INSN_DELETED);
+                 || NOTE_KIND (tmp) != NOTE_INSN_DELETED);
       break;
 
     default:
       break;
     }
 
       break;
 
     default:
       break;
     }
 
-  /* First switch to correct section.  */
-  switch_to_section (targetm.asm_out.select_rtx_section (desc->mode, x,
-                                                        desc->align));
-
 #ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
   ASM_OUTPUT_SPECIAL_POOL_ENTRY (asm_out_file, x, desc->mode,
 #ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
   ASM_OUTPUT_SPECIAL_POOL_ENTRY (asm_out_file, x, desc->mode,
-                                desc->align, desc->labelno, done);
+                                align, desc->labelno, done);
 #endif
 
 #endif
 
-  assemble_align (desc->align);
+  assemble_align (align);
 
   /* Output the label.  */
   targetm.asm_out.internal_label (asm_out_file, "LC", desc->labelno);
 
   /* Output the data.  */
 
   /* Output the label.  */
   targetm.asm_out.internal_label (asm_out_file, "LC", desc->labelno);
 
   /* Output the data.  */
-  output_constant_pool_2 (desc->mode, x, desc->align);
+  output_constant_pool_2 (desc->mode, x, align);
 
   /* Make sure all constants in SECTION_MERGE and not SECTION_STRINGS
      sections have proper size.  */
 
   /* Make sure all constants in SECTION_MERGE and not SECTION_STRINGS
      sections have proper size.  */
-  if (desc->align > GET_MODE_BITSIZE (desc->mode)
+  if (align > GET_MODE_BITSIZE (desc->mode)
       && in_section
       && (in_section->common.flags & SECTION_MERGE))
       && in_section
       && (in_section->common.flags & SECTION_MERGE))
-    assemble_align (desc->align);
+    assemble_align (align);
 
 #ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
  done:
 
 #ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
  done:
@@ -3198,9 +3790,8 @@ output_constant_pool_1 (struct constant_descriptor_rtx *desc)
    be used with for_each_rtx to mark all SYMBOL_REFs in an rtx.  */
 
 static int
    be used with for_each_rtx to mark all SYMBOL_REFs in an rtx.  */
 
 static int
-mark_constant (rtx *current_rtx, void *data)
+mark_constant (rtx *current_rtx, void *data ATTRIBUTE_UNUSED)
 {
 {
-  struct rtx_constant_pool *pool = data;
   rtx x = *current_rtx;
 
   if (x == NULL_RTX || GET_CODE (x) != SYMBOL_REF)
   rtx x = *current_rtx;
 
   if (x == NULL_RTX || GET_CODE (x) != SYMBOL_REF)
@@ -3208,11 +3799,11 @@ mark_constant (rtx *current_rtx, void *data)
 
   if (CONSTANT_POOL_ADDRESS_P (x))
     {
 
   if (CONSTANT_POOL_ADDRESS_P (x))
     {
-      struct constant_descriptor_rtx *desc = find_pool_constant (pool, x);
+      struct constant_descriptor_rtx *desc = SYMBOL_REF_CONSTANT (x);
       if (desc->mark == 0)
        {
          desc->mark = 1;
       if (desc->mark == 0)
        {
          desc->mark = 1;
-         for_each_rtx (&desc->constant, mark_constant, pool);
+         for_each_rtx (&desc->constant, mark_constant, NULL);
        }
     }
   else if (TREE_CONSTANT_POOL_ADDRESS_P (x))
        }
     }
   else if (TREE_CONSTANT_POOL_ADDRESS_P (x))
@@ -3226,7 +3817,7 @@ mark_constant (rtx *current_rtx, void *data)
     }
 
   return -1;
     }
 
   return -1;
-} 
+}
 
 /* Look through appropriate parts of INSN, marking all entries in the
    constant pool which are actually being used.  Entries that are only
 
 /* Look through appropriate parts of INSN, marking all entries in the
    constant pool which are actually being used.  Entries that are only
@@ -3234,7 +3825,7 @@ mark_constant (rtx *current_rtx, void *data)
    deferred strings that are used.  */
 
 static void
    deferred strings that are used.  */
 
 static void
-mark_constants (struct rtx_constant_pool *pool, rtx insn)
+mark_constants (rtx insn)
 {
   if (!INSN_P (insn))
     return;
 {
   if (!INSN_P (insn))
     return;
@@ -3250,11 +3841,11 @@ mark_constants (struct rtx_constant_pool *pool, rtx insn)
        {
          rtx subinsn = XVECEXP (seq, 0, i);
          if (INSN_P (subinsn))
        {
          rtx subinsn = XVECEXP (seq, 0, i);
          if (INSN_P (subinsn))
-           for_each_rtx (&PATTERN (subinsn), mark_constant, pool);
+           for_each_rtx (&PATTERN (subinsn), mark_constant, NULL);
        }
     }
   else
        }
     }
   else
-    for_each_rtx (&PATTERN (insn), mark_constant, pool);
+    for_each_rtx (&PATTERN (insn), mark_constant, NULL);
 }
 
 /* Look through the instructions for this function, and mark all the
 }
 
 /* Look through the instructions for this function, and mark all the
@@ -3262,48 +3853,81 @@ mark_constants (struct rtx_constant_pool *pool, rtx insn)
    which have indeed been used.  */
 
 static void
    which have indeed been used.  */
 
 static void
-mark_constant_pool (struct rtx_constant_pool *pool)
+mark_constant_pool (void)
 {
   rtx insn, link;
 
 {
   rtx insn, link;
 
-  if (pool->first == 0 && n_deferred_constants == 0)
+  if (!crtl->uses_const_pool && n_deferred_constants == 0)
     return;
 
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
     return;
 
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
-    mark_constants (pool, insn);
+    mark_constants (insn);
 
 
-  for (link = current_function_epilogue_delay_list;
+  for (link = crtl->epilogue_delay_list;
        link;
        link = XEXP (link, 1))
        link;
        link = XEXP (link, 1))
-    mark_constants (pool, XEXP (link, 0));
+    mark_constants (XEXP (link, 0));
 }
 
 }
 
-/* Write all the constants in the constant pool.  */
+/* Write all the constants in POOL.  */
 
 
-void
+static void
+output_constant_pool_contents (struct rtx_constant_pool *pool)
+{
+  struct constant_descriptor_rtx *desc;
+
+  for (desc = pool->first; desc ; desc = desc->next)
+    if (desc->mark)
+      {
+       /* If the constant is part of an object_block, make sure that
+          the constant has been positioned within its block, but do not
+          write out its definition yet.  output_object_blocks will do
+          that later.  */
+       if (SYMBOL_REF_HAS_BLOCK_INFO_P (desc->sym)
+           && SYMBOL_REF_BLOCK (desc->sym))
+         place_block_symbol (desc->sym);
+       else
+         {
+           switch_to_section (targetm.asm_out.select_rtx_section
+                              (desc->mode, desc->constant, desc->align));
+           output_constant_pool_1 (desc, desc->align);
+         }
+      }
+}
+
+/* Mark all constants that are used in the current function, then write
+   out the function's private constant pool.  */
+
+static void
 output_constant_pool (const char *fnname ATTRIBUTE_UNUSED,
                      tree fndecl ATTRIBUTE_UNUSED)
 {
 output_constant_pool (const char *fnname ATTRIBUTE_UNUSED,
                      tree fndecl ATTRIBUTE_UNUSED)
 {
-  struct rtx_constant_pool *pool = cfun->varasm->pool;
-  struct constant_descriptor_rtx *desc;
+  struct rtx_constant_pool *pool = crtl->varasm.pool;
 
   /* 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.  */
 
   /* 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);
+  mark_constant_pool ();
 
 #ifdef ASM_OUTPUT_POOL_PROLOGUE
   ASM_OUTPUT_POOL_PROLOGUE (asm_out_file, fnname, fndecl, pool->offset);
 #endif
 
 
 #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);
+  output_constant_pool_contents (pool);
 
 #ifdef ASM_OUTPUT_POOL_EPILOGUE
   ASM_OUTPUT_POOL_EPILOGUE (asm_out_file, fnname, fndecl, pool->offset);
 #endif
 }
 \f
 
 #ifdef ASM_OUTPUT_POOL_EPILOGUE
   ASM_OUTPUT_POOL_EPILOGUE (asm_out_file, fnname, fndecl, pool->offset);
 #endif
 }
 \f
+/* Write the contents of the shared constant pool.  */
+
+void
+output_shared_constant_pool (void)
+{
+  output_constant_pool_contents (shared_constant_pool);
+}
+\f
 /* Determine what kind of relocations EXP may need.  */
 
 int
 /* Determine what kind of relocations EXP may need.  */
 
 int
@@ -3312,10 +3936,6 @@ compute_reloc_for_constant (tree exp)
   int reloc = 0, reloc2;
   tree tem;
 
   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);
-
   switch (TREE_CODE (exp))
     {
     case ADDR_EXPR:
   switch (TREE_CODE (exp))
     {
     case ADDR_EXPR:
@@ -3334,6 +3954,7 @@ compute_reloc_for_constant (tree exp)
       break;
 
     case PLUS_EXPR:
       break;
 
     case PLUS_EXPR:
+    case POINTER_PLUS_EXPR:
       reloc = compute_reloc_for_constant (TREE_OPERAND (exp, 0));
       reloc |= compute_reloc_for_constant (TREE_OPERAND (exp, 1));
       break;
       reloc = compute_reloc_for_constant (TREE_OPERAND (exp, 0));
       reloc |= compute_reloc_for_constant (TREE_OPERAND (exp, 1));
       break;
@@ -3348,9 +3969,7 @@ compute_reloc_for_constant (tree exp)
        reloc |= reloc2;
       break;
 
        reloc |= reloc2;
       break;
 
-    case NOP_EXPR:
-    case CONVERT_EXPR:
-    case NON_LVALUE_EXPR:
+    CASE_CONVERT:
     case VIEW_CONVERT_EXPR:
       reloc = compute_reloc_for_constant (TREE_OPERAND (exp, 0));
       break;
     case VIEW_CONVERT_EXPR:
       reloc = compute_reloc_for_constant (TREE_OPERAND (exp, 0));
       break;
@@ -3379,10 +3998,6 @@ output_addressed_constants (tree exp)
 {
   tree tem;
 
 {
   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:
   switch (TREE_CODE (exp))
     {
     case ADDR_EXPR:
@@ -3403,13 +4018,12 @@ output_addressed_constants (tree exp)
       break;
 
     case PLUS_EXPR:
       break;
 
     case PLUS_EXPR:
+    case POINTER_PLUS_EXPR:
     case MINUS_EXPR:
       output_addressed_constants (TREE_OPERAND (exp, 1));
       /* Fall through.  */
 
     case MINUS_EXPR:
       output_addressed_constants (TREE_OPERAND (exp, 1));
       /* Fall through.  */
 
-    case NOP_EXPR:
-    case CONVERT_EXPR:
-    case NON_LVALUE_EXPR:
+    CASE_CONVERT:
     case VIEW_CONVERT_EXPR:
       output_addressed_constants (TREE_OPERAND (exp, 0));
       break;
     case VIEW_CONVERT_EXPR:
       output_addressed_constants (TREE_OPERAND (exp, 0));
       break;
@@ -3428,6 +4042,20 @@ output_addressed_constants (tree exp)
     }
 }
 \f
     }
 }
 \f
+/* Whether a constructor CTOR is a valid static constant initializer if all
+   its elements are.  This used to be internal to initializer_constant_valid_p
+   and has been exposed to let other functions like categorize_ctor_elements
+   evaluate the property while walking a constructor for other purposes.  */
+
+bool
+constructor_static_from_elts_p (const_tree ctor)
+{
+  return (TREE_CONSTANT (ctor)
+         && (TREE_CODE (TREE_TYPE (ctor)) == UNION_TYPE
+             || TREE_CODE (TREE_TYPE (ctor)) == RECORD_TYPE)
+         && !VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (ctor)));
+}
+
 /* Return nonzero if VALUE is a valid constant-valued expression
    for use in initializing a static variable; one that can be an
    element of a "constant" initializer.
 /* Return nonzero if VALUE is a valid constant-valued expression
    for use in initializing a static variable; one that can be an
    element of a "constant" initializer.
@@ -3441,17 +4069,10 @@ output_addressed_constants (tree exp)
 tree
 initializer_constant_valid_p (tree value, tree endtype)
 {
 tree
 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);
-
   switch (TREE_CODE (value))
     {
     case CONSTRUCTOR:
   switch (TREE_CODE (value))
     {
     case CONSTRUCTOR:
-      if ((TREE_CODE (TREE_TYPE (value)) == UNION_TYPE
-          || TREE_CODE (TREE_TYPE (value)) == RECORD_TYPE)
-         && TREE_CONSTANT (value)
-         && !VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (value)))
+      if (constructor_static_from_elts_p (value))
        {
          unsigned HOST_WIDE_INT idx;
          tree elt;
        {
          unsigned HOST_WIDE_INT idx;
          tree elt;
@@ -3477,39 +4098,42 @@ initializer_constant_valid_p (tree value, tree endtype)
     case INTEGER_CST:
     case VECTOR_CST:
     case REAL_CST:
     case INTEGER_CST:
     case VECTOR_CST:
     case REAL_CST:
+    case FIXED_CST:
     case STRING_CST:
     case COMPLEX_CST:
       return null_pointer_node;
 
     case ADDR_EXPR:
     case FDESC_EXPR:
     case STRING_CST:
     case COMPLEX_CST:
       return null_pointer_node;
 
     case ADDR_EXPR:
     case FDESC_EXPR:
-      value = staticp (TREE_OPERAND (value, 0));
-      if (value)
-       {
-         /* "&(*a).f" is like unto pointer arithmetic.  If "a" turns out to
-            be a constant, this is old-skool offsetof-like nonsense.  */
-         if (TREE_CODE (value) == INDIRECT_REF
-             && TREE_CONSTANT (TREE_OPERAND (value, 0)))
-           return null_pointer_node;
-         /* Taking the address of a nested function involves a trampoline.  */
-         if (TREE_CODE (value) == FUNCTION_DECL
-             && ((decl_function_context (value) 
-                  && !DECL_NO_STATIC_CHAIN (value))
-                 || DECL_DLLIMPORT_P (value)))
-           return NULL_TREE;
-         /* "&{...}" requires a temporary to hold the constructed
-            object.  */
-         if (TREE_CODE (value) == CONSTRUCTOR)
-           return NULL_TREE;
-       }
-      return value;
+      {
+       tree op0 = staticp (TREE_OPERAND (value, 0));
+       if (op0)
+         {
+           /* "&(*a).f" is like unto pointer arithmetic.  If "a" turns out
+              to be a constant, this is old-skool offsetof-like nonsense.  */
+           if (TREE_CODE (op0) == INDIRECT_REF
+               && TREE_CONSTANT (TREE_OPERAND (op0, 0)))
+             return null_pointer_node;
+           /* Taking the address of a nested function involves a trampoline,
+              unless we don't need or want one.  */
+           if (TREE_CODE (op0) == FUNCTION_DECL
+               && decl_function_context (op0)
+               && !DECL_NO_STATIC_CHAIN (op0)
+               && !TREE_NO_TRAMPOLINE (value))
+             return NULL_TREE;
+           /* "&{...}" requires a temporary to hold the constructed
+              object.  */
+           if (TREE_CODE (op0) == CONSTRUCTOR)
+             return NULL_TREE;
+         }
+       return op0;
+      }
 
     case VIEW_CONVERT_EXPR:
     case NON_LVALUE_EXPR:
       return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
 
 
     case VIEW_CONVERT_EXPR:
     case NON_LVALUE_EXPR:
       return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
 
-    case CONVERT_EXPR:
-    case NOP_EXPR:
+    CASE_CONVERT:
       {
        tree src;
        tree src_type;
       {
        tree src;
        tree src_type;
@@ -3553,6 +4177,9 @@ initializer_constant_valid_p (tree value, tree endtype)
             || TREE_CODE (dest_type) == OFFSET_TYPE)
            && INTEGRAL_TYPE_P (src_type))
          {
             || TREE_CODE (dest_type) == OFFSET_TYPE)
            && INTEGRAL_TYPE_P (src_type))
          {
+           if (TREE_CODE (src) == INTEGER_CST
+               && TYPE_PRECISION (dest_type) >= TYPE_PRECISION (src_type))
+             return null_pointer_node;
            if (integer_zerop (src))
              return null_pointer_node;
            else if (TYPE_PRECISION (dest_type) <= TYPE_PRECISION (src_type))
            if (integer_zerop (src))
              return null_pointer_node;
            else if (TYPE_PRECISION (dest_type) <= TYPE_PRECISION (src_type))
@@ -3567,6 +4194,7 @@ initializer_constant_valid_p (tree value, tree endtype)
       }
       break;
 
       }
       break;
 
+    case POINTER_PLUS_EXPR:
     case PLUS_EXPR:
       if (! INTEGRAL_TYPE_P (endtype)
          || TYPE_PRECISION (endtype) >= POINTER_SIZE)
     case PLUS_EXPR:
       if (! INTEGRAL_TYPE_P (endtype)
          || TYPE_PRECISION (endtype) >= POINTER_SIZE)
@@ -3575,7 +4203,7 @@ initializer_constant_valid_p (tree value, tree endtype)
                                                      endtype);
          tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1),
                                                      endtype);
                                                      endtype);
          tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1),
                                                      endtype);
-         /* If either term is absolute, use the other terms relocation.  */
+         /* If either term is absolute, use the other term's relocation.  */
          if (valid0 == null_pointer_node)
            return valid1;
          if (valid1 == null_pointer_node)
          if (valid0 == null_pointer_node)
            return valid1;
          if (valid1 == null_pointer_node)
@@ -3621,8 +4249,7 @@ initializer_constant_valid_p (tree value, tree endtype)
             (int)(p1 - p2) to ((int)p1 - (int)p2) under the theory
             that the narrower operation is cheaper.  */
 
             (int)(p1 - p2) to ((int)p1 - (int)p2) under the theory
             that the narrower operation is cheaper.  */
 
-         while (TREE_CODE (op0) == NOP_EXPR
-                || TREE_CODE (op0) == CONVERT_EXPR
+         while (CONVERT_EXPR_P (op0)
                 || TREE_CODE (op0) == NON_LVALUE_EXPR)
            {
              tree inner = TREE_OPERAND (op0, 0);
                 || TREE_CODE (op0) == NON_LVALUE_EXPR)
            {
              tree inner = TREE_OPERAND (op0, 0);
@@ -3634,8 +4261,7 @@ initializer_constant_valid_p (tree value, tree endtype)
              op0 = inner;
            }
 
              op0 = inner;
            }
 
-         while (TREE_CODE (op1) == NOP_EXPR
-                || TREE_CODE (op1) == CONVERT_EXPR
+         while (CONVERT_EXPR_P (op1)
                 || TREE_CODE (op1) == NON_LVALUE_EXPR)
            {
              tree inner = TREE_OPERAND (op1, 0);
                 || TREE_CODE (op1) == NON_LVALUE_EXPR)
            {
              tree inner = TREE_OPERAND (op1, 0);
@@ -3702,11 +4328,6 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align)
   enum tree_code code;
   unsigned HOST_WIDE_INT thissize;
 
   enum tree_code code;
   unsigned HOST_WIDE_INT thissize;
 
-  /* Some front-ends use constants other than the standard language-independent
-     varieties, but which may still be output directly.  Give the front-end a
-     chance to convert EXP to a language-independent representation.  */
-  exp = lang_hooks.expand_constant (exp);
-
   if (size == 0 || flag_syntax_only)
     return;
 
   if (size == 0 || flag_syntax_only)
     return;
 
@@ -3732,11 +4353,16 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align)
         way.  */
       if (TREE_CODE (exp) == ADDR_EXPR)
        exp = build1 (ADDR_EXPR, saved_type, TREE_OPERAND (exp, 0));
         way.  */
       if (TREE_CODE (exp) == ADDR_EXPR)
        exp = build1 (ADDR_EXPR, saved_type, TREE_OPERAND (exp, 0));
+      /* Likewise for constant ints.  */
+      else if (TREE_CODE (exp) == INTEGER_CST)
+       exp = build_int_cst_wide (saved_type, TREE_INT_CST_LOW (exp),
+                                 TREE_INT_CST_HIGH (exp));
+      
     }
 
   /* Eliminate any conversions since we'll be outputting the underlying
      constant.  */
     }
 
   /* Eliminate any conversions since we'll be outputting the underlying
      constant.  */
-  while (TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR
+  while (CONVERT_EXPR_P (exp)
         || TREE_CODE (exp) == NON_LVALUE_EXPR
         || TREE_CODE (exp) == VIEW_CONVERT_EXPR)
     {
         || TREE_CODE (exp) == NON_LVALUE_EXPR
         || TREE_CODE (exp) == VIEW_CONVERT_EXPR)
     {
@@ -3749,10 +4375,10 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align)
       if (type_size > op_size
          && TREE_CODE (exp) != VIEW_CONVERT_EXPR
          && TREE_CODE (TREE_TYPE (exp)) != UNION_TYPE)
       if (type_size > op_size
          && TREE_CODE (exp) != VIEW_CONVERT_EXPR
          && TREE_CODE (TREE_TYPE (exp)) != UNION_TYPE)
-       internal_error ("no-op convert from %wd to %wd bytes in initializer",
-                       op_size, type_size);
-
-      exp = TREE_OPERAND (exp, 0);
+       /* Keep the conversion. */
+       break;
+      else
+       exp = TREE_OPERAND (exp, 0);
     }
 
   code = TREE_CODE (TREE_TYPE (exp));
     }
 
   code = TREE_CODE (TREE_TYPE (exp));
@@ -3783,17 +4409,17 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align)
      Otherwise, break and ensure SIZE is the size written.  */
   switch (code)
     {
      Otherwise, break and ensure SIZE is the size written.  */
   switch (code)
     {
-    case CHAR_TYPE:
     case BOOLEAN_TYPE:
     case INTEGER_TYPE:
     case ENUMERAL_TYPE:
     case POINTER_TYPE:
     case REFERENCE_TYPE:
     case OFFSET_TYPE:
     case BOOLEAN_TYPE:
     case INTEGER_TYPE:
     case ENUMERAL_TYPE:
     case POINTER_TYPE:
     case REFERENCE_TYPE:
     case OFFSET_TYPE:
+    case FIXED_POINT_TYPE:
       if (! assemble_integer (expand_expr (exp, NULL_RTX, VOIDmode,
                                           EXPAND_INITIALIZER),
                              MIN (size, thissize), align, 0))
       if (! assemble_integer (expand_expr (exp, NULL_RTX, VOIDmode,
                                           EXPAND_INITIALIZER),
                              MIN (size, thissize), align, 0))
-       error ("initializer for integer value is too complicated");
+       error ("initializer for integer/fixed-point value is too complicated");
       break;
 
     case REAL_TYPE:
       break;
 
     case REAL_TYPE:
@@ -3828,16 +4454,20 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align)
            tree link;
            unsigned int nalign;
            enum machine_mode inner;
            tree link;
            unsigned int nalign;
            enum machine_mode inner;
-           
+
            inner = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
            nalign = MIN (align, GET_MODE_ALIGNMENT (inner));
            inner = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
            nalign = MIN (align, GET_MODE_ALIGNMENT (inner));
-           
+
            elt_size = GET_MODE_SIZE (inner);
            elt_size = GET_MODE_SIZE (inner);
-           
+
            link = TREE_VECTOR_CST_ELTS (exp);
            output_constant (TREE_VALUE (link), elt_size, align);
            link = TREE_VECTOR_CST_ELTS (exp);
            output_constant (TREE_VALUE (link), elt_size, align);
+           thissize = elt_size;
            while ((link = TREE_CHAIN (link)) != NULL)
            while ((link = TREE_CHAIN (link)) != NULL)
-             output_constant (TREE_VALUE (link), elt_size, nalign);
+             {
+               output_constant (TREE_VALUE (link), elt_size, nalign);
+               thissize += elt_size;
+             }
            break;
          }
        default:
            break;
          }
        default:
@@ -3872,7 +4502,7 @@ array_size_for_constructor (tree val)
 {
   tree max_index, i;
   unsigned HOST_WIDE_INT cnt;
 {
   tree max_index, i;
   unsigned HOST_WIDE_INT cnt;
-  tree index, value;
+  tree index, value, tmp;
 
   /* This code used to attempt to handle string constants that are not
      arrays of single-bytes, but nothing else does, so there's no point in
 
   /* This code used to attempt to handle string constants that are not
      arrays of single-bytes, but nothing else does, so there's no point in
@@ -3893,9 +4523,9 @@ array_size_for_constructor (tree val)
     return 0;
 
   /* Compute the total number of array elements.  */
     return 0;
 
   /* Compute the total number of array elements.  */
-  i = size_binop (MINUS_EXPR, convert (sizetype, max_index),
-                 convert (sizetype,
-                          TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (val)))));
+  tmp = TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (val)));
+  i = size_binop (MINUS_EXPR, fold_convert (sizetype, max_index),
+                 fold_convert (sizetype, tmp));
   i = size_binop (PLUS_EXPR, i, build_int_cst (sizetype, 1));
 
   /* Multiply by the array element unit size to find number of bytes.  */
   i = size_binop (PLUS_EXPR, i, build_int_cst (sizetype, 1));
 
   /* Multiply by the array element unit size to find number of bytes.  */
@@ -3961,8 +4591,8 @@ output_constructor (tree exp, unsigned HOST_WIDE_INT size,
 #ifdef ASM_COMMENT_START
       if (field && flag_verbose_asm)
        fprintf (asm_out_file, "%s %s:\n",
 #ifdef ASM_COMMENT_START
       if (field && flag_verbose_asm)
        fprintf (asm_out_file, "%s %s:\n",
-                ASM_COMMENT_START, 
-                DECL_NAME (field) 
+                ASM_COMMENT_START,
+                DECL_NAME (field)
                 ? IDENTIFIER_POINTER (DECL_NAME (field))
                 : "<anonymous>");
 #endif
                 ? IDENTIFIER_POINTER (DECL_NAME (field))
                 : "<anonymous>");
 #endif
@@ -4263,7 +4893,7 @@ merge_weak (tree newdecl, tree olddecl)
       /* NEWDECL is weak, but OLDDECL is not.  */
 
       /* If we already output the OLDDECL, we're in trouble; we can't
       /* NEWDECL is weak, but OLDDECL is not.  */
 
       /* If we already output the OLDDECL, we're in trouble; we can't
-        go back and make it weak.  This error cannot caught in
+        go back and make it weak.  This error cannot be caught in
         declare_weak because the NEWDECL and OLDDECL was not yet
         been merged; therefore, TREE_ASM_WRITTEN was not set.  */
       if (TREE_ASM_WRITTEN (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))
@@ -4381,7 +5011,7 @@ weak_finish (void)
       else if (! TREE_SYMBOL_REFERENCED (target))
        {
          /* Use ASM_WEAKEN_LABEL only if ASM_WEAKEN_DECL is not
       else if (! TREE_SYMBOL_REFERENCED (target))
        {
          /* Use ASM_WEAKEN_LABEL only if ASM_WEAKEN_DECL is not
-            defined, otherwise we and weak_finish_1 would use a
+            defined, otherwise we and weak_finish_1 would use
             different macros.  */
 # if defined ASM_WEAKEN_LABEL && ! defined ASM_WEAKEN_DECL
          ASM_WEAKEN_LABEL (asm_out_file, IDENTIFIER_POINTER (target));
             different macros.  */
 # if defined ASM_WEAKEN_LABEL && ! defined ASM_WEAKEN_DECL
          ASM_WEAKEN_LABEL (asm_out_file, IDENTIFIER_POINTER (target));
@@ -4445,11 +5075,11 @@ weak_finish (void)
 static void
 globalize_decl (tree decl)
 {
 static void
 globalize_decl (tree decl)
 {
-  const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
 
 #if defined (ASM_WEAKEN_LABEL) || defined (ASM_WEAKEN_DECL)
   if (DECL_WEAK (decl))
     {
 
 #if defined (ASM_WEAKEN_LABEL) || defined (ASM_WEAKEN_DECL)
   if (DECL_WEAK (decl))
     {
+      const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
       tree *p, t;
 
 #ifdef ASM_WEAKEN_DECL
       tree *p, t;
 
 #ifdef ASM_WEAKEN_DECL
@@ -4468,25 +5098,22 @@ globalize_decl (tree decl)
            p = &TREE_CHAIN (t);
        }
 
            p = &TREE_CHAIN (t);
        }
 
-       /* Remove weakrefs to the same target from the pending weakref
-          list, for the same reason.  */
-       for (p = &weakref_targets; (t = *p) ; )
-         {
-           if (DECL_ASSEMBLER_NAME (decl)
-               == ultimate_transparent_alias_target (&TREE_VALUE (t)))
-             *p = TREE_CHAIN (t);
-           else
-             p = &TREE_CHAIN (t);
-         }
+      /* Remove weakrefs to the same target from the pending weakref
+        list, for the same reason.  */
+      for (p = &weakref_targets; (t = *p) ; )
+       {
+         if (DECL_ASSEMBLER_NAME (decl)
+             == ultimate_transparent_alias_target (&TREE_VALUE (t)))
+           *p = TREE_CHAIN (t);
+         else
+           p = &TREE_CHAIN (t);
+       }
 
       return;
     }
 
       return;
     }
-#elif defined(ASM_MAKE_LABEL_LINKONCE)
-  if (DECL_ONE_ONLY (decl))
-    ASM_MAKE_LABEL_LINKONCE (asm_out_file, name);
 #endif
 
 #endif
 
-  targetm.asm_out.globalize_label (asm_out_file, name);
+  targetm.asm_out.globalize_decl_name (asm_out_file, decl);
 }
 
 /* We have to be able to tell cgraph about the needed-ness of the target
 }
 
 /* We have to be able to tell cgraph about the needed-ness of the target
@@ -4512,17 +5139,17 @@ static tree
 find_decl_and_mark_needed (tree decl, tree target)
 {
   struct cgraph_node *fnode = NULL;
 find_decl_and_mark_needed (tree decl, tree target)
 {
   struct cgraph_node *fnode = NULL;
-  struct cgraph_varpool_node *vnode = NULL;
+  struct varpool_node *vnode = NULL;
 
   if (TREE_CODE (decl) == FUNCTION_DECL)
     {
       fnode = cgraph_node_for_asm (target);
       if (fnode == NULL)
 
   if (TREE_CODE (decl) == FUNCTION_DECL)
     {
       fnode = cgraph_node_for_asm (target);
       if (fnode == NULL)
-       vnode = cgraph_varpool_node_for_asm (target);
+       vnode = varpool_node_for_asm (target);
     }
   else
     {
     }
   else
     {
-      vnode = cgraph_varpool_node_for_asm (target);
+      vnode = varpool_node_for_asm (target);
       if (vnode == NULL)
        fnode = cgraph_node_for_asm (target);
     }
       if (vnode == NULL)
        fnode = cgraph_node_for_asm (target);
     }
@@ -4540,10 +5167,10 @@ find_decl_and_mark_needed (tree decl, tree target)
     }
   else if (vnode)
     {
     }
   else if (vnode)
     {
-      cgraph_varpool_mark_needed_node (vnode);
+      varpool_mark_needed_node (vnode);
       return vnode->decl;
     }
       return vnode->decl;
     }
-  else 
+  else
     return NULL_TREE;
 }
 
     return NULL_TREE;
 }
 
@@ -4564,6 +5191,14 @@ do_assemble_alias (tree decl, tree target)
     {
       ultimate_transparent_alias_target (&target);
 
     {
       ultimate_transparent_alias_target (&target);
 
+      if (!targetm.have_tls
+         && TREE_CODE (decl) == VAR_DECL
+         && DECL_THREAD_LOCAL_P (decl))
+       {
+         decl = emutls_decl (decl);
+         target = get_emutls_object_name (target);
+       }
+
       if (!TREE_SYMBOL_REFERENCED (target))
        weakref_targets = tree_cons (decl, target, weakref_targets);
 
       if (!TREE_SYMBOL_REFERENCED (target))
        weakref_targets = tree_cons (decl, target, weakref_targets);
 
@@ -4581,6 +5216,14 @@ do_assemble_alias (tree decl, tree target)
       return;
     }
 
       return;
     }
 
+  if (!targetm.have_tls
+      && TREE_CODE (decl) == VAR_DECL
+      && DECL_THREAD_LOCAL_P (decl))
+    {
+      decl = emutls_decl (decl);
+      target = get_emutls_object_name (target);
+    }
+
 #ifdef ASM_OUTPUT_DEF
   /* Make name accessible from other files, if appropriate.  */
 
 #ifdef ASM_OUTPUT_DEF
   /* Make name accessible from other files, if appropriate.  */
 
@@ -4733,11 +5376,14 @@ assemble_alias (tree decl, tree target)
   if (TREE_CODE (decl) == FUNCTION_DECL)
     cgraph_node (decl)->alias = true;
   else
   if (TREE_CODE (decl) == FUNCTION_DECL)
     cgraph_node (decl)->alias = true;
   else
-    cgraph_varpool_node (decl)->alias = true;
+    varpool_node (decl)->alias = true;
 
   /* If the target has already been emitted, we don't have to queue the
 
   /* If the target has already been emitted, we don't have to queue the
-     alias.  This saves a tad o memory.  */
-  target_decl = find_decl_and_mark_needed (decl, target);
+     alias.  This saves a tad of memory.  */
+  if (cgraph_global_info_ready)
+    target_decl = find_decl_and_mark_needed (decl, target);
+  else
+    target_decl= NULL;
   if (target_decl && TREE_ASM_WRITTEN (target_decl))
     do_assemble_alias (decl, target);
   else
   if (target_decl && TREE_ASM_WRITTEN (target_decl))
     do_assemble_alias (decl, target);
   else
@@ -4755,7 +5401,7 @@ void
 default_assemble_visibility (tree decl, int vis)
 {
   static const char * const visibility_types[] = {
 default_assemble_visibility (tree decl, int vis)
 {
   static const char * const visibility_types[] = {
-    NULL, "internal", "hidden", "protected"
+    NULL, "protected", "hidden", "internal"
   };
 
   const char *name, *type;
   };
 
   const char *name, *type;
@@ -4775,13 +5421,18 @@ default_assemble_visibility (tree decl, int vis)
 
 /* A helper function to call assemble_visibility when needed for a decl.  */
 
 
 /* A helper function to call assemble_visibility when needed for a decl.  */
 
-static void
+int
 maybe_assemble_visibility (tree decl)
 {
   enum symbol_visibility vis = DECL_VISIBILITY (decl);
 
   if (vis != VISIBILITY_DEFAULT)
 maybe_assemble_visibility (tree decl)
 {
   enum symbol_visibility vis = DECL_VISIBILITY (decl);
 
   if (vis != VISIBILITY_DEFAULT)
-    targetm.asm_out.visibility (decl, vis);
+    {
+      targetm.asm_out.visibility (decl, vis);
+      return 1;
+    }
+  else
+    return 0;
 }
 
 /* Returns 1 if the target configuration supports defining public symbols
 }
 
 /* Returns 1 if the target configuration supports defining public symbols
@@ -4830,10 +5481,13 @@ init_varasm_once (void)
 {
   section_htab = htab_create_ggc (31, section_entry_hash,
                                  section_entry_eq, NULL);
 {
   section_htab = htab_create_ggc (31, section_entry_hash,
                                  section_entry_eq, NULL);
+  object_block_htab = htab_create_ggc (31, object_block_entry_hash,
+                                      object_block_entry_eq, NULL);
   const_desc_htab = htab_create_ggc (1009, const_desc_hash,
                                     const_desc_eq, NULL);
 
   const_alias_set = new_alias_set ();
   const_desc_htab = htab_create_ggc (1009, const_desc_hash,
                                     const_desc_eq, NULL);
 
   const_alias_set = new_alias_set ();
+  shared_constant_pool = create_constant_pool ();
 
 #ifdef TEXT_SECTION_ASM_OP
   text_section = get_unnamed_section (SECTION_CODE, output_section_asm_op,
 
 #ifdef TEXT_SECTION_ASM_OP
   text_section = get_unnamed_section (SECTION_CODE, output_section_asm_op,
@@ -4877,6 +5531,18 @@ init_varasm_once (void)
                                      SBSS_SECTION_ASM_OP);
 #endif
 
                                      SBSS_SECTION_ASM_OP);
 #endif
 
+  tls_comm_section = get_noswitch_section (SECTION_WRITE | SECTION_BSS
+                                          | SECTION_COMMON, emit_tls_common);
+  lcomm_section = get_noswitch_section (SECTION_WRITE | SECTION_BSS
+                                       | SECTION_COMMON, emit_local);
+  comm_section = get_noswitch_section (SECTION_WRITE | SECTION_BSS
+                                      | SECTION_COMMON, emit_common);
+
+#if defined ASM_OUTPUT_ALIGNED_BSS || defined ASM_OUTPUT_BSS
+  bss_noswitch_section = get_noswitch_section (SECTION_WRITE | SECTION_BSS,
+                                              emit_bss);
+#endif
+
   targetm.asm_out.init_sections ();
 
   if (readonly_data_section == NULL)
   targetm.asm_out.init_sections ();
 
   if (readonly_data_section == NULL)
@@ -4884,7 +5550,7 @@ init_varasm_once (void)
 }
 
 enum tls_model
 }
 
 enum tls_model
-decl_default_tls_model (tree decl)
+decl_default_tls_model (const_tree decl)
 {
   enum tls_model kind;
   bool is_local;
 {
   enum tls_model kind;
   bool is_local;
@@ -4920,28 +5586,21 @@ decl_default_tls_model (tree decl)
 unsigned int
 default_section_type_flags (tree decl, const char *name, int reloc)
 {
 unsigned int
 default_section_type_flags (tree decl, const char *name, int reloc)
 {
-  return default_section_type_flags_1 (decl, name, reloc, flag_pic);
-}
-
-unsigned int
-default_section_type_flags_1 (tree decl, const char *name, int reloc,
-                             int shlib)
-{
   unsigned int flags;
 
   if (decl && TREE_CODE (decl) == FUNCTION_DECL)
     flags = SECTION_CODE;
   unsigned int flags;
 
   if (decl && TREE_CODE (decl) == FUNCTION_DECL)
     flags = SECTION_CODE;
-  else if (decl && decl_readonly_section_1 (decl, reloc, shlib))
+  else if (decl && decl_readonly_section (decl, reloc))
     flags = 0;
   else if (current_function_decl
           && cfun
     flags = 0;
   else if (current_function_decl
           && cfun
-          && cfun->unlikely_text_section_name
-          && strcmp (name, cfun->unlikely_text_section_name) == 0)
+          && crtl->subsections.unlikely_text_section_name
+          && strcmp (name, crtl->subsections.unlikely_text_section_name) == 0)
     flags = SECTION_CODE;
     flags = SECTION_CODE;
-  else if (!decl 
+  else if (!decl
           && (!current_function_decl || !cfun)
           && strcmp (name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0)
           && (!current_function_decl || !cfun)
           && strcmp (name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0)
-    flags = SECTION_CODE; 
+    flags = SECTION_CODE;
   else
     flags = SECTION_WRITE;
 
   else
     flags = SECTION_WRITE;
 
@@ -4983,6 +5642,16 @@ default_section_type_flags_1 (tree decl, const char *name, int reloc,
   return flags;
 }
 
   return flags;
 }
 
+/* Return true if the target supports some form of global BSS,
+   either through bss_noswitch_section, or by selecting a BSS
+   section in TARGET_ASM_SELECT_SECTION.  */
+
+bool
+have_global_bss_p (void)
+{
+  return bss_noswitch_section || targetm.have_switchable_bss_sections;
+}
+
 /* Output assembly to switch to section NAME with attribute FLAGS.
    Four variants for common object file formats.  */
 
 /* Output assembly to switch to section NAME with attribute FLAGS.
    Four variants for common object file formats.  */
 
@@ -5055,7 +5724,7 @@ default_elf_asm_named_section (const char *name, unsigned int flags,
       if (flags & SECTION_ENTSIZE)
        fprintf (asm_out_file, ",%d", flags & SECTION_ENTSIZE);
       if (HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))
       if (flags & SECTION_ENTSIZE)
        fprintf (asm_out_file, ",%d", flags & SECTION_ENTSIZE);
       if (HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))
-       fprintf (asm_out_file, ",%s,comdat", 
+       fprintf (asm_out_file, ",%s,comdat",
                 lang_hooks.decls.comdat_group (decl));
     }
 
                 lang_hooks.decls.comdat_group (decl));
     }
 
@@ -5063,7 +5732,7 @@ default_elf_asm_named_section (const char *name, unsigned int flags,
 }
 
 void
 }
 
 void
-default_coff_asm_named_section (const char *name, unsigned int flags, 
+default_coff_asm_named_section (const char *name, unsigned int flags,
                                tree decl ATTRIBUTE_UNUSED)
 {
   char flagchars[8], *f = flagchars;
                                tree decl ATTRIBUTE_UNUSED)
 {
   char flagchars[8], *f = flagchars;
@@ -5121,7 +5790,7 @@ default_select_section (tree decl, int reloc,
 }
 
 enum section_category
 }
 
 enum section_category
-categorize_decl_for_section (tree decl, int reloc, int shlib)
+categorize_decl_for_section (const_tree decl, int reloc)
 {
   enum section_category ret;
 
 {
   enum section_category ret;
 
@@ -5136,28 +5805,23 @@ categorize_decl_for_section (tree decl, int reloc, int shlib)
     }
   else if (TREE_CODE (decl) == VAR_DECL)
     {
     }
   else if (TREE_CODE (decl) == VAR_DECL)
     {
-      if (DECL_INITIAL (decl) == NULL
-         || 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))))
+      if (bss_initializer_p (decl))
        ret = SECCAT_BSS;
       else if (! TREE_READONLY (decl)
               || TREE_SIDE_EFFECTS (decl)
               || ! TREE_CONSTANT (DECL_INITIAL (decl)))
        {
        ret = SECCAT_BSS;
       else if (! TREE_READONLY (decl)
               || TREE_SIDE_EFFECTS (decl)
               || ! TREE_CONSTANT (DECL_INITIAL (decl)))
        {
-         if (shlib && (reloc & 2))
-           ret = SECCAT_DATA_REL;
-         else if (shlib && reloc)
-           ret = SECCAT_DATA_REL_LOCAL;
+         /* Here the reloc_rw_mask is not testing whether the section should
+            be read-only or not, but whether the dynamic link will have to
+            do something.  If so, we wish to segregate the data in order to
+            minimize cache misses inside the dynamic linker.  */
+         if (reloc & targetm.asm_out.reloc_rw_mask ())
+           ret = reloc == 1 ? SECCAT_DATA_REL_LOCAL : SECCAT_DATA_REL;
          else
            ret = SECCAT_DATA;
        }
          else
            ret = SECCAT_DATA;
        }
-      else if (shlib && (reloc & 2))
-       ret = SECCAT_DATA_REL_RO;
-      else if (shlib && reloc)
-       ret = SECCAT_DATA_REL_RO_LOCAL;
+      else if (reloc & targetm.asm_out.reloc_rw_mask ())
+       ret = reloc == 1 ? SECCAT_DATA_REL_RO_LOCAL : SECCAT_DATA_REL_RO;
       else if (reloc || flag_merge_constants < 2)
        /* C and C++ don't allow different variables to share the same
           location.  -fmerge-all-constants allows even that (at the
       else if (reloc || flag_merge_constants < 2)
        /* C and C++ don't allow different variables to share the same
           location.  -fmerge-all-constants allows even that (at the
@@ -5170,7 +5834,7 @@ categorize_decl_for_section (tree decl, int reloc, int shlib)
     }
   else if (TREE_CODE (decl) == CONSTRUCTOR)
     {
     }
   else if (TREE_CODE (decl) == CONSTRUCTOR)
     {
-      if ((shlib && reloc)
+      if ((reloc & targetm.asm_out.reloc_rw_mask ())
          || TREE_SIDE_EFFECTS (decl)
          || ! TREE_CONSTANT (decl))
        ret = SECCAT_DATA;
          || TREE_SIDE_EFFECTS (decl)
          || ! TREE_CONSTANT (decl))
        ret = SECCAT_DATA;
@@ -5181,13 +5845,26 @@ categorize_decl_for_section (tree decl, int reloc, int shlib)
     ret = SECCAT_RODATA;
 
   /* There are no read-only thread-local sections.  */
     ret = SECCAT_RODATA;
 
   /* There are no read-only thread-local sections.  */
-  if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl))
+  if (TREE_CODE (decl) == VAR_DECL && DECL_TLS_MODEL (decl))
     {
     {
+      if (DECL_TLS_MODEL (decl) == TLS_MODEL_EMULATED)
+       {
+         if (DECL_EMUTLS_VAR_P (decl))
+           {
+             if (targetm.emutls.var_section)
+               ret = SECCAT_EMUTLS_VAR;
+           }
+         else
+           {
+             if (targetm.emutls.tmpl_prefix)
+               ret = SECCAT_EMUTLS_TMPL;
+           }
+       }
       /* Note that this would be *just* SECCAT_BSS, except that there's
         no concept of a read-only thread-local-data section.  */
       /* 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))))
+      else if (ret == SECCAT_BSS
+              || (flag_zero_initialized_in_bss
+                  && initializer_zerop (DECL_INITIAL (decl))))
        ret = SECCAT_TBSS;
       else
        ret = SECCAT_TDATA;
        ret = SECCAT_TBSS;
       else
        ret = SECCAT_TDATA;
@@ -5208,15 +5885,9 @@ categorize_decl_for_section (tree decl, int reloc, int shlib)
 }
 
 bool
 }
 
 bool
-decl_readonly_section (tree decl, int reloc)
-{
-  return decl_readonly_section_1 (decl, reloc, flag_pic);
-}
-
-bool
-decl_readonly_section_1 (tree decl, int reloc, int shlib)
+decl_readonly_section (const_tree decl, int reloc)
 {
 {
-  switch (categorize_decl_for_section (decl, reloc, shlib))
+  switch (categorize_decl_for_section (decl, reloc))
     {
     case SECCAT_RODATA:
     case SECCAT_RODATA_MERGE_STR:
     {
     case SECCAT_RODATA:
     case SECCAT_RODATA_MERGE_STR:
@@ -5237,15 +5908,8 @@ section *
 default_elf_select_section (tree decl, int reloc,
                            unsigned HOST_WIDE_INT align)
 {
 default_elf_select_section (tree decl, int reloc,
                            unsigned HOST_WIDE_INT align)
 {
-  return default_elf_select_section_1 (decl, reloc, align, flag_pic);
-}
-
-section *
-default_elf_select_section_1 (tree decl, int reloc,
-                             unsigned HOST_WIDE_INT align, int shlib)
-{
   const char *sname;
   const char *sname;
-  switch (categorize_decl_for_section (decl, reloc, shlib))
+  switch (categorize_decl_for_section (decl, reloc))
     {
     case SECCAT_TEXT:
       /* We're not supposed to be called on FUNCTION_DECLs.  */
     {
     case SECCAT_TEXT:
       /* We're not supposed to be called on FUNCTION_DECLs.  */
@@ -5292,6 +5956,12 @@ default_elf_select_section_1 (tree decl, int reloc,
     case SECCAT_TBSS:
       sname = ".tbss";
       break;
     case SECCAT_TBSS:
       sname = ".tbss";
       break;
+    case SECCAT_EMUTLS_VAR:
+      sname = targetm.emutls.var_section;
+      break;
+    case SECCAT_EMUTLS_TMPL:
+      sname = targetm.emutls.tmpl_section;
+      break;
     default:
       gcc_unreachable ();
     }
     default:
       gcc_unreachable ();
     }
@@ -5307,77 +5977,119 @@ default_elf_select_section_1 (tree decl, int reloc,
 void
 default_unique_section (tree decl, int reloc)
 {
 void
 default_unique_section (tree decl, int reloc)
 {
-  default_unique_section_1 (decl, reloc, flag_pic);
-}
-
-void
-default_unique_section_1 (tree decl, int reloc, int shlib)
-{
   /* We only need to use .gnu.linkonce if we don't have COMDAT groups.  */
   bool one_only = DECL_ONE_ONLY (decl) && !HAVE_COMDAT_GROUP;
   /* We only need to use .gnu.linkonce if we don't have COMDAT groups.  */
   bool one_only = DECL_ONE_ONLY (decl) && !HAVE_COMDAT_GROUP;
-  const char *prefix, *name;
-  size_t nlen, plen;
+  const char *prefix, *name, *linkonce;
   char *string;
 
   char *string;
 
-  switch (categorize_decl_for_section (decl, reloc, shlib))
+  switch (categorize_decl_for_section (decl, reloc))
     {
     case SECCAT_TEXT:
     {
     case SECCAT_TEXT:
-      prefix = one_only ? ".gnu.linkonce.t." : ".text.";
+      prefix = one_only ? ".t" : ".text";
       break;
     case SECCAT_RODATA:
     case SECCAT_RODATA_MERGE_STR:
     case SECCAT_RODATA_MERGE_STR_INIT:
     case SECCAT_RODATA_MERGE_CONST:
       break;
     case SECCAT_RODATA:
     case SECCAT_RODATA_MERGE_STR:
     case SECCAT_RODATA_MERGE_STR_INIT:
     case SECCAT_RODATA_MERGE_CONST:
-      prefix = one_only ? ".gnu.linkonce.r." : ".rodata.";
+      prefix = one_only ? ".r" : ".rodata";
       break;
     case SECCAT_SRODATA:
       break;
     case SECCAT_SRODATA:
-      prefix = one_only ? ".gnu.linkonce.s2." : ".sdata2.";
+      prefix = one_only ? ".s2" : ".sdata2";
       break;
     case SECCAT_DATA:
       break;
     case SECCAT_DATA:
-      prefix = one_only ? ".gnu.linkonce.d." : ".data.";
+      prefix = one_only ? ".d" : ".data";
       break;
     case SECCAT_DATA_REL:
       break;
     case SECCAT_DATA_REL:
-      prefix = one_only ? ".gnu.linkonce.d.rel." : ".data.rel.";
+      prefix = one_only ? ".d.rel" : ".data.rel";
       break;
     case SECCAT_DATA_REL_LOCAL:
       break;
     case SECCAT_DATA_REL_LOCAL:
-      prefix = one_only ? ".gnu.linkonce.d.rel.local." : ".data.rel.local.";
+      prefix = one_only ? ".d.rel.local" : ".data.rel.local";
       break;
     case SECCAT_DATA_REL_RO:
       break;
     case SECCAT_DATA_REL_RO:
-      prefix = one_only ? ".gnu.linkonce.d.rel.ro." : ".data.rel.ro.";
+      prefix = one_only ? ".d.rel.ro" : ".data.rel.ro";
       break;
     case SECCAT_DATA_REL_RO_LOCAL:
       break;
     case SECCAT_DATA_REL_RO_LOCAL:
-      prefix = one_only ? ".gnu.linkonce.d.rel.ro.local."
-              : ".data.rel.ro.local.";
+      prefix = one_only ? ".d.rel.ro.local" : ".data.rel.ro.local";
       break;
     case SECCAT_SDATA:
       break;
     case SECCAT_SDATA:
-      prefix = one_only ? ".gnu.linkonce.s." : ".sdata.";
+      prefix = one_only ? ".s" : ".sdata";
       break;
     case SECCAT_BSS:
       break;
     case SECCAT_BSS:
-      prefix = one_only ? ".gnu.linkonce.b." : ".bss.";
+      prefix = one_only ? ".b" : ".bss";
       break;
     case SECCAT_SBSS:
       break;
     case SECCAT_SBSS:
-      prefix = one_only ? ".gnu.linkonce.sb." : ".sbss.";
+      prefix = one_only ? ".sb" : ".sbss";
       break;
     case SECCAT_TDATA:
       break;
     case SECCAT_TDATA:
-      prefix = one_only ? ".gnu.linkonce.td." : ".tdata.";
+      prefix = one_only ? ".td" : ".tdata";
       break;
     case SECCAT_TBSS:
       break;
     case SECCAT_TBSS:
-      prefix = one_only ? ".gnu.linkonce.tb." : ".tbss.";
+      prefix = one_only ? ".tb" : ".tbss";
+      break;
+    case SECCAT_EMUTLS_VAR:
+      prefix = targetm.emutls.var_section;
+      break;
+    case SECCAT_EMUTLS_TMPL:
+      prefix = targetm.emutls.tmpl_section;
       break;
     default:
       gcc_unreachable ();
     }
       break;
     default:
       gcc_unreachable ();
     }
-  plen = strlen (prefix);
 
   name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
   name = targetm.strip_name_encoding (name);
 
   name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
   name = targetm.strip_name_encoding (name);
-  nlen = strlen (name);
 
 
-  string = alloca (nlen + plen + 1);
-  memcpy (string, prefix, plen);
-  memcpy (string + plen, name, nlen + 1);
+  /* If we're using one_only, then there needs to be a .gnu.linkonce
+     prefix to the section name.  */
+  linkonce = one_only ? ".gnu.linkonce" : "";
+  
+  string = ACONCAT ((linkonce, prefix, ".", name, NULL));
+
+  DECL_SECTION_NAME (decl) = build_string (strlen (string), string);
+}
+
+/* Like compute_reloc_for_constant, except for an RTX.  The return value
+   is a mask for which bit 1 indicates a global relocation, and bit 0
+   indicates a local relocation.  */
+
+static int
+compute_reloc_for_rtx_1 (rtx *xp, void *data)
+{
+  int *preloc = (int *) data;
+  rtx x = *xp;
+
+  switch (GET_CODE (x))
+    {
+    case SYMBOL_REF:
+      *preloc |= SYMBOL_REF_LOCAL_P (x) ? 1 : 2;
+      break;
+    case LABEL_REF:
+      *preloc |= 1;
+      break;
+    default:
+      break;
+    }
+
+  return 0;
+}
+
+static int
+compute_reloc_for_rtx (rtx x)
+{
+  int reloc;
+
+  switch (GET_CODE (x))
+    {
+    case CONST:
+    case SYMBOL_REF:
+    case LABEL_REF:
+      reloc = 0;
+      for_each_rtx (&x, compute_reloc_for_rtx_1, &reloc);
+      return reloc;
 
 
-  DECL_SECTION_NAME (decl) = build_string (nlen + plen, string);
+    default:
+      return 0;
+    }
 }
 
 section *
 }
 
 section *
@@ -5385,40 +6097,27 @@ default_select_rtx_section (enum machine_mode mode ATTRIBUTE_UNUSED,
                            rtx x,
                            unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
 {
                            rtx x,
                            unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
 {
-  if (flag_pic)
-    switch (GET_CODE (x))
-      {
-      case CONST:
-      case SYMBOL_REF:
-      case LABEL_REF:
-       return data_section;
-
-      default:
-       break;
-      }
-
-  return readonly_data_section;
+  if (compute_reloc_for_rtx (x) & targetm.asm_out.reloc_rw_mask ())
+    return data_section;
+  else
+    return readonly_data_section;
 }
 
 section *
 default_elf_select_rtx_section (enum machine_mode mode, rtx x,
                                unsigned HOST_WIDE_INT align)
 {
 }
 
 section *
 default_elf_select_rtx_section (enum machine_mode mode, rtx x,
                                unsigned HOST_WIDE_INT align)
 {
-  /* ??? Handle small data here somehow.  */
+  int reloc = compute_reloc_for_rtx (x);
 
 
-  if (flag_pic)
-    switch (GET_CODE (x))
-      {
-      case CONST:
-      case SYMBOL_REF:
-       return get_named_section (NULL, ".data.rel.ro", 3);
+  /* ??? Handle small data here somehow.  */
 
 
-      case LABEL_REF:
+  if (reloc & targetm.asm_out.reloc_rw_mask ())
+    {
+      if (reloc == 1)
        return get_named_section (NULL, ".data.rel.ro.local", 1);
        return get_named_section (NULL, ".data.rel.ro.local", 1);
-
-      default:
-       break;
-      }
+      else
+       return get_named_section (NULL, ".data.rel.ro", 3);
+    }
 
   return mergeable_constant_section (mode, align, 0);
 }
 
   return mergeable_constant_section (mode, align, 0);
 }
@@ -5438,12 +6137,13 @@ default_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
   if (GET_CODE (symbol) != SYMBOL_REF)
     return;
 
   if (GET_CODE (symbol) != SYMBOL_REF)
     return;
 
-  flags = 0;
+  flags = SYMBOL_REF_FLAGS (symbol) & SYMBOL_FLAG_HAS_BLOCK_INFO;
   if (TREE_CODE (decl) == FUNCTION_DECL)
     flags |= SYMBOL_FLAG_FUNCTION;
   if (targetm.binds_local_p (decl))
     flags |= SYMBOL_FLAG_LOCAL;
   if (TREE_CODE (decl) == FUNCTION_DECL)
     flags |= SYMBOL_FLAG_FUNCTION;
   if (targetm.binds_local_p (decl))
     flags |= SYMBOL_FLAG_LOCAL;
-  if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl))
+  if (targetm.have_tls && TREE_CODE (decl) == VAR_DECL
+      && DECL_THREAD_LOCAL_P (decl))
     flags |= DECL_TLS_MODEL (decl) << SYMBOL_FLAG_TLS_SHIFT;
   else if (targetm.in_small_data_p (decl))
     flags |= SYMBOL_FLAG_SMALL;
     flags |= DECL_TLS_MODEL (decl) << SYMBOL_FLAG_TLS_SHIFT;
   else if (targetm.in_small_data_p (decl))
     flags |= SYMBOL_FLAG_SMALL;
@@ -5465,17 +6165,70 @@ default_strip_name_encoding (const char *str)
   return str + (*str == '*');
 }
 
   return str + (*str == '*');
 }
 
+#ifdef ASM_OUTPUT_DEF
+/* The default implementation of TARGET_ASM_OUTPUT_ANCHOR.  Define the
+   anchor relative to ".", the current section position.  */
+
+void
+default_asm_output_anchor (rtx symbol)
+{
+  char buffer[100];
+
+  sprintf (buffer, "*. + " HOST_WIDE_INT_PRINT_DEC,
+          SYMBOL_REF_BLOCK_OFFSET (symbol));
+  ASM_OUTPUT_DEF (asm_out_file, XSTR (symbol, 0), buffer);
+}
+#endif
+
+/* The default implementation of TARGET_USE_ANCHORS_FOR_SYMBOL_P.  */
+
+bool
+default_use_anchors_for_symbol_p (const_rtx symbol)
+{
+  section *sect;
+  tree decl;
+
+  /* Don't use anchors for mergeable sections.  The linker might move
+     the objects around.  */
+  sect = SYMBOL_REF_BLOCK (symbol)->sect;
+  if (sect->common.flags & SECTION_MERGE)
+    return false;
+
+  /* Don't use anchors for small data sections.  The small data register
+     acts as an anchor for such sections.  */
+  if (sect->common.flags & SECTION_SMALL)
+    return false;
+
+  decl = SYMBOL_REF_DECL (symbol);
+  if (decl && DECL_P (decl))
+    {
+      /* Don't use section anchors for decls that might be defined by
+        other modules.  */
+      if (!targetm.binds_local_p (decl))
+       return false;
+
+      /* Don't use section anchors for decls that will be placed in a
+        small data section.  */
+      /* ??? Ideally, this check would be redundant with the SECTION_SMALL
+        one above.  The problem is that we only use SECTION_SMALL for
+        sections that should be marked as small in the section directive.  */
+      if (targetm.in_small_data_p (decl))
+       return false;
+    }
+  return true;
+}
+
 /* Assume ELF-ish defaults, since that's pretty much the most liberal
    wrt cross-module name binding.  */
 
 bool
 /* Assume ELF-ish defaults, since that's pretty much the most liberal
    wrt cross-module name binding.  */
 
 bool
-default_binds_local_p (tree exp)
+default_binds_local_p (const_tree exp)
 {
   return default_binds_local_p_1 (exp, flag_shlib);
 }
 
 bool
 {
   return default_binds_local_p_1 (exp, flag_shlib);
 }
 
 bool
-default_binds_local_p_1 (tree exp, int shlib)
+default_binds_local_p_1 (const_tree exp, int shlib)
 {
   bool local_p;
 
 {
   bool local_p;
 
@@ -5491,7 +6244,7 @@ default_binds_local_p_1 (tree exp, int shlib)
     local_p = true;
   /* A variable is local if the user has said explicitly that it will
      be.  */
     local_p = true;
   /* A variable is local if the user has said explicitly that it will
      be.  */
-  else if (DECL_VISIBILITY_SPECIFIED (exp) 
+  else if (DECL_VISIBILITY_SPECIFIED (exp)
           && DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
     local_p = true;
   /* Variables defined outside this object might not be local.  */
           && DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
     local_p = true;
   /* Variables defined outside this object might not be local.  */
@@ -5506,9 +6259,10 @@ default_binds_local_p_1 (tree exp, int shlib)
   else if (DECL_WEAK (exp))
     local_p = false;
   /* If PIC, then assume that any global name can be overridden by
   else if (DECL_WEAK (exp))
     local_p = false;
   /* If PIC, then assume that any global name can be overridden by
-     symbols resolved from other modules.  */
+     symbols resolved from other modules, unless we are compiling with
+     -fwhole-program, which assumes that names are local.  */
   else if (shlib)
   else if (shlib)
-    local_p = false;
+    local_p = flag_whole_program;
   /* Uninitialized COMMON variable may be unified with symbols
      resolved from other modules.  */
   else if (DECL_COMMON (exp)
   /* Uninitialized COMMON variable may be unified with symbols
      resolved from other modules.  */
   else if (DECL_COMMON (exp)
@@ -5544,6 +6298,14 @@ default_globalize_label (FILE * stream, const char *name)
 }
 #endif /* GLOBAL_ASM_OP */
 
 }
 #endif /* GLOBAL_ASM_OP */
 
+/* Default function to output code that will globalize a declaration.  */
+void
+default_globalize_decl_name (FILE * stream, tree decl)
+{
+  const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
+  targetm.asm_out.globalize_label (stream, name);
+}
+
 /* 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.  */
 /* 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.  */
@@ -5552,7 +6314,15 @@ default_emit_unwind_label (FILE * stream ATTRIBUTE_UNUSED,
                           tree decl ATTRIBUTE_UNUSED,
                           int for_eh ATTRIBUTE_UNUSED,
                           int empty ATTRIBUTE_UNUSED)
                           tree decl ATTRIBUTE_UNUSED,
                           int for_eh ATTRIBUTE_UNUSED,
                           int empty ATTRIBUTE_UNUSED)
-{ 
+{
+}
+
+/* Default function to output a label to divide up the exception table.
+   The default is to do nothing.  A target that needs/wants to divide
+   up the table must provide it's own function to do this.  */
+void
+default_emit_except_table_label (FILE * stream ATTRIBUTE_UNUSED)
+{
 }
 
 /* This is how to output an internal numbered label where PREFIX is
 }
 
 /* This is how to output an internal numbered label where PREFIX is
@@ -5562,7 +6332,7 @@ void
 default_internal_label (FILE *stream, const char *prefix,
                        unsigned long labelno)
 {
 default_internal_label (FILE *stream, const char *prefix,
                        unsigned long labelno)
 {
-  char *const buf = alloca (40 + strlen (prefix));
+  char *const buf = (char *) alloca (40 + strlen (prefix));
   ASM_GENERATE_INTERNAL_LABEL (buf, prefix, labelno);
   ASM_OUTPUT_INTERNAL_LABEL (stream, buf);
 }
   ASM_GENERATE_INTERNAL_LABEL (buf, prefix, labelno);
   ASM_OUTPUT_INTERNAL_LABEL (stream, buf);
 }
@@ -5619,22 +6389,350 @@ switch_to_section (section *new_section)
   else
     in_section = new_section;
 
   else
     in_section = new_section;
 
-  if (new_section->common.flags & SECTION_NAMED)
+  switch (SECTION_STYLE (new_section))
     {
     {
+    case SECTION_NAMED:
       if (cfun
       if (cfun
-         && !cfun->unlikely_text_section_name
+         && !crtl->subsections.unlikely_text_section_name
          && strcmp (new_section->named.name,
                     UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0)
          && strcmp (new_section->named.name,
                     UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0)
-       cfun->unlikely_text_section_name = UNLIKELY_EXECUTED_TEXT_SECTION_NAME;
+       crtl->subsections.unlikely_text_section_name = UNLIKELY_EXECUTED_TEXT_SECTION_NAME;
 
       targetm.asm_out.named_section (new_section->named.name,
                                     new_section->named.common.flags,
                                     new_section->named.decl);
 
       targetm.asm_out.named_section (new_section->named.name,
                                     new_section->named.common.flags,
                                     new_section->named.decl);
+      break;
+
+    case SECTION_UNNAMED:
+      new_section->unnamed.callback (new_section->unnamed.data);
+      break;
+
+    case SECTION_NOSWITCH:
+      gcc_unreachable ();
+      break;
     }
     }
-  else
-    new_section->unnamed.callback (new_section->unnamed.data);
 
   new_section->common.flags |= SECTION_DECLARED;
 }
 
 
   new_section->common.flags |= SECTION_DECLARED;
 }
 
+/* If block symbol SYMBOL has not yet been assigned an offset, place
+   it at the end of its block.  */
+
+void
+place_block_symbol (rtx symbol)
+{
+  unsigned HOST_WIDE_INT size, mask, offset;
+  struct constant_descriptor_rtx *desc;
+  unsigned int alignment;
+  struct object_block *block;
+  tree decl;
+
+  gcc_assert (SYMBOL_REF_BLOCK (symbol));
+  if (SYMBOL_REF_BLOCK_OFFSET (symbol) >= 0)
+    return;
+
+  /* Work out the symbol's size and alignment.  */
+  if (CONSTANT_POOL_ADDRESS_P (symbol))
+    {
+      desc = SYMBOL_REF_CONSTANT (symbol);
+      alignment = desc->align;
+      size = GET_MODE_SIZE (desc->mode);
+    }
+  else if (TREE_CONSTANT_POOL_ADDRESS_P (symbol))
+    {
+      decl = SYMBOL_REF_DECL (symbol);
+      alignment = get_constant_alignment (decl);
+      size = get_constant_size (decl);
+    }
+  else
+    {
+      decl = SYMBOL_REF_DECL (symbol);
+      alignment = DECL_ALIGN (decl);
+      size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
+    }
+
+  /* Calculate the object's offset from the start of the block.  */
+  block = SYMBOL_REF_BLOCK (symbol);
+  mask = alignment / BITS_PER_UNIT - 1;
+  offset = (block->size + mask) & ~mask;
+  SYMBOL_REF_BLOCK_OFFSET (symbol) = offset;
+
+  /* Record the block's new alignment and size.  */
+  block->alignment = MAX (block->alignment, alignment);
+  block->size = offset + size;
+
+  VEC_safe_push (rtx, gc, block->objects, symbol);
+}
+
+/* Return the anchor that should be used to address byte offset OFFSET
+   from the first object in BLOCK.  MODEL is the TLS model used
+   to access it.  */
+
+rtx
+get_section_anchor (struct object_block *block, HOST_WIDE_INT offset,
+                   enum tls_model model)
+{
+  char label[100];
+  unsigned int begin, middle, end;
+  unsigned HOST_WIDE_INT min_offset, max_offset, range, bias, delta;
+  rtx anchor;
+
+  /* Work out the anchor's offset.  Use an offset of 0 for the first
+     anchor so that we don't pessimize the case where we take the address
+     of a variable at the beginning of the block.  This is particularly
+     useful when a block has only one variable assigned to it.
+
+     We try to place anchors RANGE bytes apart, so there can then be
+     anchors at +/-RANGE, +/-2 * RANGE, and so on, up to the limits of
+     a ptr_mode offset.  With some target settings, the lowest such
+     anchor might be out of range for the lowest ptr_mode offset;
+     likewise the highest anchor for the highest offset.  Use anchors
+     at the extreme ends of the ptr_mode range in such cases.
+
+     All arithmetic uses unsigned integers in order to avoid
+     signed overflow.  */
+  max_offset = (unsigned HOST_WIDE_INT) targetm.max_anchor_offset;
+  min_offset = (unsigned HOST_WIDE_INT) targetm.min_anchor_offset;
+  range = max_offset - min_offset + 1;
+  if (range == 0)
+    offset = 0;
+  else
+    {
+      bias = 1 << (GET_MODE_BITSIZE (ptr_mode) - 1);
+      if (offset < 0)
+       {
+         delta = -(unsigned HOST_WIDE_INT) offset + max_offset;
+         delta -= delta % range;
+         if (delta > bias)
+           delta = bias;
+         offset = (HOST_WIDE_INT) (-delta);
+       }
+      else
+       {
+         delta = (unsigned HOST_WIDE_INT) offset - min_offset;
+         delta -= delta % range;
+         if (delta > bias - 1)
+           delta = bias - 1;
+         offset = (HOST_WIDE_INT) delta;
+       }
+    }
+
+  /* Do a binary search to see if there's already an anchor we can use.
+     Set BEGIN to the new anchor's index if not.  */
+  begin = 0;
+  end = VEC_length (rtx, block->anchors);
+  while (begin != end)
+    {
+      middle = (end + begin) / 2;
+      anchor = VEC_index (rtx, block->anchors, middle);
+      if (SYMBOL_REF_BLOCK_OFFSET (anchor) > offset)
+       end = middle;
+      else if (SYMBOL_REF_BLOCK_OFFSET (anchor) < offset)
+       begin = middle + 1;
+      else if (SYMBOL_REF_TLS_MODEL (anchor) > model)
+       end = middle;
+      else if (SYMBOL_REF_TLS_MODEL (anchor) < model)
+       begin = middle + 1;
+      else
+       return anchor;
+    }
+
+  /* Create a new anchor with a unique label.  */
+  ASM_GENERATE_INTERNAL_LABEL (label, "LANCHOR", anchor_labelno++);
+  anchor = create_block_symbol (ggc_strdup (label), block, offset);
+  SYMBOL_REF_FLAGS (anchor) |= SYMBOL_FLAG_LOCAL | SYMBOL_FLAG_ANCHOR;
+  SYMBOL_REF_FLAGS (anchor) |= model << SYMBOL_FLAG_TLS_SHIFT;
+
+  /* Insert it at index BEGIN.  */
+  VEC_safe_insert (rtx, gc, block->anchors, begin, anchor);
+  return anchor;
+}
+
+/* Output the objects in BLOCK.  */
+
+static void
+output_object_block (struct object_block *block)
+{
+  struct constant_descriptor_rtx *desc;
+  unsigned int i;
+  HOST_WIDE_INT offset;
+  tree decl;
+  rtx symbol;
+
+  if (block->objects == NULL)
+    return;
+
+  /* Switch to the section and make sure that the first byte is
+     suitably aligned.  */
+  switch_to_section (block->sect);
+  assemble_align (block->alignment);
+
+  /* Define the values of all anchors relative to the current section
+     position.  */
+  for (i = 0; VEC_iterate (rtx, block->anchors, i, symbol); i++)
+    targetm.asm_out.output_anchor (symbol);
+
+  /* Output the objects themselves.  */
+  offset = 0;
+  for (i = 0; VEC_iterate (rtx, block->objects, i, symbol); i++)
+    {
+      /* Move to the object's offset, padding with zeros if necessary.  */
+      assemble_zeros (SYMBOL_REF_BLOCK_OFFSET (symbol) - offset);
+      offset = SYMBOL_REF_BLOCK_OFFSET (symbol);
+      if (CONSTANT_POOL_ADDRESS_P (symbol))
+       {
+         desc = SYMBOL_REF_CONSTANT (symbol);
+         output_constant_pool_1 (desc, 1);
+         offset += GET_MODE_SIZE (desc->mode);
+       }
+      else if (TREE_CONSTANT_POOL_ADDRESS_P (symbol))
+       {
+         decl = SYMBOL_REF_DECL (symbol);
+         assemble_constant_contents (decl, XSTR (symbol, 0),
+                                     get_constant_alignment (decl));
+         offset += get_constant_size (decl);
+       }
+      else
+       {
+         decl = SYMBOL_REF_DECL (symbol);
+         assemble_variable_contents (decl, XSTR (symbol, 0), false);
+         offset += tree_low_cst (DECL_SIZE_UNIT (decl), 1);
+       }
+    }
+}
+
+/* A htab_traverse callback used to call output_object_block for
+   each member of object_block_htab.  */
+
+static int
+output_object_block_htab (void **slot, void *data ATTRIBUTE_UNUSED)
+{
+  output_object_block ((struct object_block *) (*slot));
+  return 1;
+}
+
+/* Output the definitions of all object_blocks.  */
+
+void
+output_object_blocks (void)
+{
+  htab_traverse (object_block_htab, output_object_block_htab, NULL);
+}
+
+/* This function provides a possible implementation of the
+   TARGET_ASM_RECORD_GCC_SWITCHES target hook for ELF targets.  When triggered
+   by -frecord-gcc-switches it creates a new mergeable, string section in the
+   assembler output file called TARGET_ASM_RECORD_GCC_SWITCHES_SECTION which
+   contains the switches in ASCII format.
+
+   FIXME: This code does not correctly handle double quote characters
+   that appear inside strings, (it strips them rather than preserving them).
+   FIXME: ASM_OUTPUT_ASCII, as defined in config/elfos.h will not emit NUL
+   characters - instead it treats them as sub-string separators.  Since
+   we want to emit NUL strings terminators into the object file we have to use
+   ASM_OUTPUT_SKIP.  */
+
+int
+elf_record_gcc_switches (print_switch_type type, const char * name)
+{
+  static char buffer[1024];
+
+  /* This variable is used as part of a simplistic heuristic to detect
+     command line switches which take an argument:
+
+       "If a command line option does not start with a dash then
+        it is an argument for the previous command line option."
+
+     This fails in the case of the command line option which is the name
+     of the file to compile, but otherwise it is pretty reasonable.  */
+  static bool previous_name_held_back = FALSE;
+
+  switch (type)
+    {
+    case SWITCH_TYPE_PASSED:
+      if (* name != '-')
+       {
+         if (previous_name_held_back)
+           {
+             unsigned int len = strlen (buffer);
+
+             snprintf (buffer + len, sizeof buffer - len, " %s", name);
+             ASM_OUTPUT_ASCII (asm_out_file, buffer, strlen (buffer));
+             ASM_OUTPUT_SKIP (asm_out_file, (unsigned HOST_WIDE_INT) 1);
+             previous_name_held_back = FALSE;
+           }
+         else
+           {
+             strncpy (buffer, name, sizeof buffer);
+             ASM_OUTPUT_ASCII (asm_out_file, buffer, strlen (buffer));
+             ASM_OUTPUT_SKIP (asm_out_file, (unsigned HOST_WIDE_INT) 1);
+           }
+       }
+      else
+       {
+         if (previous_name_held_back)
+           {
+             ASM_OUTPUT_ASCII (asm_out_file, buffer, strlen (buffer));
+             ASM_OUTPUT_SKIP (asm_out_file, (unsigned HOST_WIDE_INT) 1);
+           }
+
+         strncpy (buffer, name, sizeof buffer);
+         previous_name_held_back = TRUE;
+       }
+      break;
+
+    case SWITCH_TYPE_DESCRIPTIVE:
+      if (name == NULL)
+       {
+         /* Distinguish between invocations where name is NULL.  */
+         static bool started = false;
+
+         if (started)
+           {
+             if (previous_name_held_back)
+               {
+                 ASM_OUTPUT_ASCII (asm_out_file, buffer, strlen (buffer));
+                 ASM_OUTPUT_SKIP (asm_out_file, (unsigned HOST_WIDE_INT) 1);
+               }
+           }
+         else
+           {
+             section * sec;
+
+             sec = get_section (targetm.asm_out.record_gcc_switches_section,
+                                SECTION_DEBUG
+                                | SECTION_MERGE
+                                | SECTION_STRINGS
+                                | (SECTION_ENTSIZE & 1),
+                                NULL);
+             switch_to_section (sec);
+             started = true;
+           }
+       }
+
+    default:
+      break;
+    }
+
+  /* The return value is currently ignored by the caller, but must be 0.
+     For -fverbose-asm the return value would be the number of characters
+     emitted into the assembler file.  */
+  return 0;
+}
+
+/* Emit text to declare externally defined symbols. It is needed to
+   properly support non-default visibility.  */
+void
+default_elf_asm_output_external (FILE *file ATTRIBUTE_UNUSED,
+                                tree decl,
+                                const char *name ATTRIBUTE_UNUSED)
+{
+  /* We output the name if and only if TREE_SYMBOL_REFERENCED is
+     set in order to avoid putting out names that are never really
+     used. */
+  if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))
+      && targetm.binds_local_p (decl))
+    maybe_assemble_visibility (decl);
+}
+
 #include "gt-varasm.h"
 #include "gt-varasm.h"