OSDN Git Service

* cgraph.h (constant_pool_htab): New function.
[pf3gnuchains/gcc-fork.git] / gcc / varasm.c
index b01ad1d..2a8fb11 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,
-   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
    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
@@ -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
-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
@@ -43,16 +42,17 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "output.h"
 #include "toplev.h"
 #include "hashtab.h"
-#include "c-pragma.h"
 #include "ggc.h"
 #include "langhooks.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-iterator.h"
 
 #ifdef XCOFF_DEBUGGING_INFO
 #include "xcoffout.h"          /* Needed for external data
@@ -70,17 +70,7 @@ struct addr_const;
 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.  */
@@ -107,7 +97,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.  */
 
-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);
@@ -124,9 +114,7 @@ static void output_constant_def_contents (rtx);
 static void output_addressed_constants (tree);
 static unsigned HOST_WIDE_INT array_size_for_constructor (tree);
 static unsigned min_align (unsigned, unsigned);
-static void output_constructor (tree, unsigned HOST_WIDE_INT, unsigned int);
 static void globalize_decl (tree);
-static void maybe_assemble_visibility (tree);
 #ifdef BSS_SECTION_ASM_OP
 #ifdef ASM_OUTPUT_BSS
 static void asm_output_bss (FILE *, tree, const char *,
@@ -139,7 +127,7 @@ static void asm_output_aligned_bss (FILE *, tree, const char *,
 #endif
 #endif /* BSS_SECTION_ASM_OP */
 static void mark_weak (tree);
-static void output_constant_pool (void);
+static void output_constant_pool (const char *, tree);
 \f
 /* Well-known sections, each one associated with some sort of *_ASM_OP.  */
 section *text_section;
@@ -200,21 +188,302 @@ 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 (UNKNOWN_LOCATION,
+                     FIELD_DECL, get_identifier ("__templ"), ptr_type_node);
+  DECL_CONTEXT (field) = type;
+  next_field = field;
+    
+  field = build_decl (UNKNOWN_LOCATION,
+                     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 (UNKNOWN_LOCATION,
+                     FIELD_DECL, get_identifier ("__align"),
+                     word_type_node);
+  DECL_CONTEXT (field) = type;
+  TREE_CHAIN (field) = next_field;
+  next_field = field;
+  
+  field = build_decl (UNKNOWN_LOCATION,
+                     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 (UNKNOWN_LOCATION,
+                         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 (DECL_SOURCE_LOCATION (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, DECL_ASSEMBLER_NAME (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 (DECL_SOURCE_LOCATION (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_ASSEMBLER_NAME (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 (UNKNOWN_LOCATION, 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)
 {
-  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)
 {
-  const section *old = p;
+  const section *old = (const section *) p;
   return htab_hash_string (old->named.name);
 }
 
@@ -233,16 +502,16 @@ hash_section (section *sect)
 static int
 object_block_entry_eq (const void *p1, const void *p2)
 {
-  const struct object_block *old = p1;
-  const section *new = p2;
+  const struct object_block *old = (const struct object_block *) p1;
+  const section *new_section = (const section *) p2;
 
-  return old->sect == new;
+  return old->sect == new_section;
 }
 
 static hashval_t
 object_block_entry_hash (const void *p)
 {
-  const struct object_block *old = p;
+  const struct object_block *old = (const struct object_block *) p;
   return hash_section (old->sect);
 }
 
@@ -254,7 +523,7 @@ get_unnamed_section (unsigned int flags, void (*callback) (const void *),
 {
   section *sect;
 
-  sect = ggc_alloc (sizeof (struct unnamed_section));
+  sect = GGC_NEW (section);
   sect->unnamed.common.flags = flags | SECTION_UNNAMED;
   sect->unnamed.callback = callback;
   sect->unnamed.data = data;
@@ -271,7 +540,7 @@ get_noswitch_section (unsigned int flags, noswitch_section_callback callback)
 {
   section *sect;
 
-  sect = ggc_alloc (sizeof (struct unnamed_section));
+  sect = GGC_NEW (section);
   sect->noswitch.common.flags = flags | SECTION_NOSWITCH;
   sect->noswitch.callback = callback;
 
@@ -292,7 +561,7 @@ get_section (const char *name, unsigned int flags, tree decl)
   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;
@@ -362,7 +631,7 @@ create_block_symbol (const char *label, struct object_block *block,
 
   /* Create the extended SYMBOL_REF.  */
   size = RTX_HDR_SIZE + sizeof (struct block_symbol);
-  symbol = ggc_alloc_zone (size, &rtl_zone);
+  symbol = (rtx) ggc_alloc_zone (size, &rtl_zone);
 
   /* Initialize the normal SYMBOL_REF fields.  */
   memset (symbol, 0, size);
@@ -386,22 +655,22 @@ initialize_cold_section_name (void)
   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)
     {
-      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));
-      cfun->unlikely_text_section_name = ggc_strdup (buffer);
+      crtl->subsections.unlikely_text_section_name = ggc_strdup (buffer);
     }
   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.  */
@@ -411,10 +680,10 @@ unlikely_text_section (void)
 {
   if (cfun)
     {
-      if (!cfun->unlikely_text_section_name)
+      if (!crtl->subsections.unlikely_text_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);
@@ -431,7 +700,7 @@ unlikely_text_section_p (section *sect)
   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;
 
@@ -490,7 +759,8 @@ asm_output_bss (FILE *file, tree decl ATTRIBUTE_UNUSED,
                unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
                unsigned HOST_WIDE_INT rounded)
 {
-  targetm.asm_out.globalize_label (file, name);
+  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;
@@ -604,11 +874,18 @@ default_function_rodata_section (tree decl)
 
       if (DECL_ONE_ONLY (decl) && HAVE_COMDAT_GROUP)
         {
-         size_t len = strlen (name) + 3;
-         char* rname = alloca (len);
+         const char *dot;
+         size_t len;
+         char* rname;
+
+         dot = strchr (name + 1, '.');
+         if (!dot)
+           dot = name;
+         len = strlen (dot) + 8;
+         rname = (char *) alloca (len);
 
          strcpy (rname, ".rodata");
-         strcat (rname, name + 5);
+         strcat (rname, dot);
          return get_section (rname, SECTION_LINKONCE, decl);
        }
       /* For .gnu.linkonce.t.foo we want to use .gnu.linkonce.r.foo.  */
@@ -616,7 +893,7 @@ default_function_rodata_section (tree decl)
               && 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';
@@ -627,7 +904,7 @@ default_function_rodata_section (tree decl)
               && 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);
@@ -655,16 +932,20 @@ mergeable_string_section (tree decl 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
-      && 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;
-      int i, j, len, unit;
+      HOST_WIDE_INT i;
+      int j, unit;
       char name[30];
 
       mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (decl)));
@@ -676,7 +957,6 @@ mergeable_string_section (tree decl ATTRIBUTE_UNUSED,
            align = modesize;
 
          str = TREE_STRING_POINTER (decl);
-         len = TREE_STRING_LENGTH (decl);
          unit = GET_MODE_SIZE (mode);
 
          /* Check for embedded NUL characters.  */
@@ -747,7 +1027,7 @@ strip_reg_name (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));
@@ -817,7 +1097,7 @@ decode_reg_name (const char *asmspec)
 /* Return true if DECL's initializer is suitable for a BSS section.  */
 
 static bool
-bss_initializer_p (tree decl)
+bss_initializer_p (const_tree decl)
 {
   return (DECL_INITIAL (decl) == NULL
          || DECL_INITIAL (decl) == error_mark_node
@@ -828,6 +1108,59 @@ bss_initializer_p (tree 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.  */
@@ -843,7 +1176,12 @@ get_variable_section (tree decl, bool prefer_noswitch_p)
     {
       if (DECL_THREAD_LOCAL_P (decl))
        return tls_comm_section;
-      if (TREE_PUBLIC (decl) && bss_initializer_p (decl))
+      /* 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;
     }
 
@@ -899,6 +1237,8 @@ get_block_for_decl (tree decl)
 
   /* 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;
@@ -934,6 +1274,10 @@ use_blocks_for_decl_p (tree decl)
   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;
 }
 
@@ -1115,17 +1459,6 @@ make_decl_rtl (tree 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.  */
@@ -1160,26 +1493,44 @@ default_stabs_asm_out_destructor (rtx symbol ATTRIBUTE_UNUSED,
 #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.  */
+  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)
-    {
-      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
@@ -1187,9 +1538,7 @@ void
 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
 
@@ -1213,23 +1562,15 @@ default_stabs_asm_out_constructor (rtx symbol ATTRIBUTE_UNUSED,
 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)
-    {
-      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
@@ -1237,9 +1578,7 @@ void
 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
@@ -1276,7 +1615,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.  */
-  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)
@@ -1304,27 +1643,27 @@ assemble_start_function (tree decl, const char *fnname)
   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);
-      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);
-      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);
-      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);
-      cfun->cold_section_end_label = ggc_strdup (tmp_label);
+      crtl->subsections.cold_section_end_label = ggc_strdup (tmp_label);
       const_labelno++;
     }
   else
     {
-      cfun->hot_section_label = NULL;
-      cfun->cold_section_label = NULL;
-      cfun->hot_section_end_label = NULL;
-      cfun->cold_section_end_label = NULL;
+      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.  */
@@ -1332,7 +1671,7 @@ assemble_start_function (tree decl, const char *fnname)
   app_disable ();
 
   if (CONSTANT_POOL_BEFORE_FUNCTION)
-    output_constant_pool ();
+    output_constant_pool (fnname, decl);
 
   resolve_unique_section (decl, 0, flag_function_sections);
 
@@ -1344,18 +1683,18 @@ assemble_start_function (tree decl, const char *fnname)
   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.  */
-      if (!current_function_is_thunk
+      if (!cfun->is_thunk
          && 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;
        }
@@ -1369,9 +1708,9 @@ assemble_start_function (tree decl, const char *fnname)
 
       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)),
-                    cfun->unlikely_text_section_name) == 0)
+                    crtl->subsections.unlikely_text_section_name) == 0)
        first_function_block_is_cold = true;
     }
 
@@ -1382,22 +1721,21 @@ assemble_start_function (tree decl, const char *fnname)
   switch_to_section (function_section (decl));
   if (flag_reorder_blocks_and_partition
       && !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.  */
-  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.
-     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.  */
-  if (align_functions_log > align
-      && cfun->function_frequency != FUNCTION_FREQUENCY_UNLIKELY_EXECUTED)
+  if (! DECL_USER_ALIGN (decl)
+      && align_functions_log > align
+      && optimize_function_for_speed_p (cfun))
     {
 #ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
       ASM_OUTPUT_MAX_SKIP_ALIGN (asm_out_file,
@@ -1440,7 +1778,7 @@ assemble_start_function (tree decl, const char *fnname)
    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.  */
@@ -1450,7 +1788,7 @@ assemble_end_function (tree decl, const char *fnname)
 #endif
   if (! CONSTANT_POOL_BEFORE_FUNCTION)
     {
-      output_constant_pool ();
+      output_constant_pool (fnname, decl);
       switch_to_section (function_section (decl)); /* need to switch back */
     }
   /* Output labels for end of hot/cold text sections (to be used by
@@ -1461,12 +1799,12 @@ assemble_end_function (tree decl, const char *fnname)
 
       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));
-      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);
     }
 }
@@ -1668,6 +2006,40 @@ assemble_variable_contents (tree decl, const char *name,
     }
 }
 
+/* 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.
    Not used for automatic variables, and not used for function definitions.
    Should not be called for variables of incomplete structure type.
@@ -1683,12 +2055,37 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
                   int at_end ATTRIBUTE_UNUSED, int dont_output_data)
 {
   const char *name;
-  unsigned int align;
   rtx decl_rtl, symbol;
   section *sect;
 
-  if (lang_hooks.decls.prepare_assemble_variable)
-    lang_hooks.decls.prepare_assemble_variable (decl);
+  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);
+       }
+
+      decl = to;
+    }
 
   last_assemble_variable_decl = 0;
 
@@ -1764,41 +2161,8 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
 
   /* 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);
@@ -1809,7 +2173,6 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
   /* 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);
 
@@ -1818,7 +2181,7 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
     output_addressed_constants (DECL_INITIAL (decl));
 
   /* 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;
 
   /* If the decl is part of an object_block, make sure that the decl
@@ -1834,7 +2197,7 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
   else
     {
       switch_to_section (sect);
-      if (align > BITS_PER_UNIT)
+      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);
     }
@@ -1876,7 +2239,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.  */
@@ -1898,7 +2261,7 @@ incorporeal_function_p (tree decl)
        return true;
 
       name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
-      if (strncmp (name, "__builtin_", strlen ("__builtin_")) == 0)
+      if (is_builtin_name (name))
        return true;
     }
   return false;
@@ -1934,9 +2297,14 @@ process_pending_assemble_externals (void)
 #endif
 }
 
-/* Output something to declare an external symbol to the assembler.
-   (Most assemblers don't need this, so we normally output nothing.)
-   Do nothing if DECL is not external.  */
+/* This TREE_LIST contains any weak symbol declarations waiting
+   to be emitted.  */
+static GTY(()) tree weak_decls;
+
+/* Output something to declare an external symbol to the assembler,
+   and qualifiers such as weakness.  (Most assemblers don't need
+   extern declaration, so we normally output nothing.)  Do nothing if
+   DECL is not external.  */
 
 void
 assemble_external (tree decl ATTRIBUTE_UNUSED)
@@ -1947,15 +2315,26 @@ assemble_external (tree decl ATTRIBUTE_UNUSED)
      open.  If it's not, we should not be calling this function.  */
   gcc_assert (asm_out_file);
 
-#ifdef ASM_OUTPUT_EXTERNAL
   if (!DECL_P (decl) || !DECL_EXTERNAL (decl) || !TREE_PUBLIC (decl))
     return;
 
-  if (flag_unit_at_a_time)
-    pending_assemble_externals = tree_cons (0, decl,
+  /* We want to output annotation for weak and external symbols at
+     very last to check if they are references or not.  */
+
+  if (SUPPORTS_WEAK && DECL_WEAK (decl)
+      /* TREE_STATIC is a weird and abused creature which is not
+        generally the right test for whether an entity has been
+        locally emitted, inlined or otherwise not-really-extern, but
+        for declarations that can be weak, it happens to be
+        match.  */
+      && !TREE_STATIC (decl)
+      && tree_find_value (weak_decls, decl) == NULL_TREE)
+      weak_decls = tree_cons (NULL, decl, weak_decls);
+
+#ifdef ASM_OUTPUT_EXTERNAL
+  if (tree_find_value (pending_assemble_externals, decl) == NULL_TREE)
+    pending_assemble_externals = tree_cons (NULL, decl,
                                            pending_assemble_externals);
-  else
-    assemble_external_real (decl);
 #endif
 }
 
@@ -2005,8 +2384,8 @@ mark_decl_referenced (tree 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;
@@ -2263,11 +2642,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 mode_class mclass;
 
       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)
        {
@@ -2333,8 +2718,7 @@ assemble_real (REAL_VALUE_TYPE d, enum machine_mode mode, unsigned int align)
    Store them both in the structure *VALUE.
    EXP must be reducible.  */
 
-struct addr_const GTY(())
-{
+struct GTY(()) addr_const {
   rtx base;
   HOST_WIDE_INT offset;
 };
@@ -2379,6 +2763,7 @@ decode_addr_const (tree exp, struct addr_const *value)
       break;
 
     case REAL_CST:
+    case FIXED_CST:
     case STRING_CST:
     case COMPLEX_CST:
     case CONSTRUCTOR:
@@ -2397,23 +2782,6 @@ decode_addr_const (tree exp, struct addr_const *value)
   value->offset = offset;
 }
 \f
-/* Uniquize all constants that appear in memory.
-   Each constant in memory thus far output is recorded
-   in `const_desc_table'.  */
-
-struct constant_descriptor_tree GTY(())
-{
-  /* A MEM for the constant.  */
-  rtx rtl;
-
-  /* The value of the constant.  */
-  tree value;
-
-  /* Hash of value.  Computing the hash from value each time
-     hashfn is called can't work properly, as that means recursive
-     use of the hash table during hash table expansion.  */
-  hashval_t hash;
-};
 
 static GTY((param_is (struct constant_descriptor_tree)))
      htab_t const_desc_htab;
@@ -2421,12 +2789,20 @@ static GTY((param_is (struct constant_descriptor_tree)))
 static struct constant_descriptor_tree * build_constant_desc (tree);
 static void maybe_output_constant_def_contents (struct constant_descriptor_tree *, int);
 
+/* Constant pool accessor function.  */
+
+htab_t 
+constant_pool_htab (void)
+{
+  return const_desc_htab;
+}
+
 /* Compute a hash code for a constant expression.  */
 
 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
@@ -2450,6 +2826,9 @@ const_hash_1 (const tree 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);
@@ -2501,13 +2880,12 @@ const_hash_1 (const tree exp)
       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 NOP_EXPR:
-    case CONVERT_EXPR:
-    case NON_LVALUE_EXPR:
+    CASE_CONVERT:
       return const_hash_1 (TREE_OPERAND (exp, 0)) * 7 + 2;
 
     default:
@@ -2527,8 +2905,10 @@ const_hash_1 (const tree exp)
 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);
@@ -2567,6 +2947,13 @@ compare_constant (const tree t1, const tree 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;
@@ -2647,27 +3034,18 @@ compare_constant (const tree t1, const tree t2)
       }
 
     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 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:
-      {
-       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 ();
@@ -2692,6 +3070,7 @@ copy_constant (tree exp)
 
     case INTEGER_CST:
     case REAL_CST:
+    case FIXED_CST:
     case STRING_CST:
       return copy_node (exp);
 
@@ -2701,14 +3080,13 @@ copy_constant (tree exp)
                            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 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)));
@@ -2733,12 +3111,7 @@ copy_constant (tree exp)
       }
 
     default:
-      {
-       tree t = lang_hooks.expand_constant (exp);
-
-       gcc_assert (t == exp);
-       return copy_constant (t);
-      }
+      gcc_unreachable ();
     }
 }
 \f
@@ -2798,7 +3171,7 @@ build_constant_desc (tree exp)
   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.  */
@@ -2827,6 +3200,10 @@ build_constant_desc (tree exp)
   set_mem_alias_set (rtl, 0);
   set_mem_alias_set (rtl, const_alias_set);
 
+  /* We cannot share RTX'es in pool entries.
+     Mark this piece of RTL as required for unsharing.  */
+  RTX_FLAG (rtl, used) = 1;
+
   /* Set flags or add text to the name to record information, such as
      that it is a local symbol.  If the name is changed, the macro
      ASM_OUTPUT_LABELREF will have to know how to strip this
@@ -2866,7 +3243,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);
 
-  desc = *loc;
+  desc = (struct constant_descriptor_tree *) *loc;
   if (desc == 0)
     {
       desc = build_constant_desc (exp);
@@ -2977,7 +3354,8 @@ lookup_constant_def (tree 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);
 }
@@ -2989,8 +3367,7 @@ lookup_constant_def (tree exp)
    can use one per-file pool.  Should add a targetm bit to tell the
    difference.  */
 
-struct rtx_constant_pool GTY(())
-{
+struct GTY(()) rtx_constant_pool {
   /* Pointers to first and last constant in pool, as ordered by offset.  */
   struct constant_descriptor_rtx *first;
   struct constant_descriptor_rtx *last;
@@ -3006,8 +3383,7 @@ struct rtx_constant_pool GTY(())
   HOST_WIDE_INT offset;
 };
 
-struct constant_descriptor_rtx GTY((chain_next ("%h.next")))
-{
+struct GTY((chain_next ("%h.next"))) constant_descriptor_rtx {
   struct constant_descriptor_rtx *next;
   rtx mem;
   rtx sym;
@@ -3025,15 +3401,18 @@ struct constant_descriptor_rtx GTY((chain_next ("%h.next")))
 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)
 {
-  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;
@@ -3062,7 +3441,7 @@ const_rtx_hash_1 (rtx *xp, void *data)
       hwi = INTVAL (x);
     fold_hwi:
       {
-       const int shift = sizeof (hashval_t) * CHAR_BIT;
+       int shift = sizeof (hashval_t) * CHAR_BIT;
        const int n = sizeof (HOST_WIDE_INT) / sizeof (hashval_t);
        int i;
 
@@ -3085,6 +3464,10 @@ const_rtx_hash_1 (rtx *xp, void *data)
        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;
@@ -3110,7 +3493,7 @@ const_rtx_hash_1 (rtx *xp, void *data)
       break;
     }
 
-  hp = data;
+  hp = (hashval_t *) data;
   *hp = *hp * 509 + h;
   return 0;
 }
@@ -3133,7 +3516,7 @@ create_constant_pool (void)
 {
   struct rtx_constant_pool *pool;
 
-  pool = ggc_alloc (sizeof (struct rtx_constant_pool));
+  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->first = NULL;
@@ -3145,15 +3528,10 @@ create_constant_pool (void)
 /* Initialize constant pool hashing for a new function.  */
 
 void
-init_varasm_status (struct function *f)
+init_varasm_status (void)
 {
-  struct varasm_status *p;
-
-  p = ggc_alloc (sizeof (struct varasm_status));
-  f->varasm = p;
-
-  p->pool = create_constant_pool ();
-  p->deferred_constants = 0;
+  crtl->varasm.pool = create_constant_pool ();
+  crtl->varasm.deferred_constants = 0;
 }
 \f
 /* Given a MINUS expression, simplify it if both sides
@@ -3185,26 +3563,26 @@ force_const_mem (enum machine_mode mode, rtx x)
     return NULL_RTX;
 
   /* Record that this function has used a constant pool entry.  */
-  current_function_uses_const_pool = 1;
+  crtl->uses_const_pool = 1;
 
   /* Decide which pool to use.  */
   pool = (targetm.use_blocks_for_constant_p (mode, x)
          ? shared_constant_pool
-         : cfun->varasm->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);
-  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.  */
-  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.  */
@@ -3292,7 +3670,7 @@ get_pool_constant_mark (rtx addr, bool *pmarked)
 /* Similar, return the mode.  */
 
 enum machine_mode
-get_pool_mode (rtx addr)
+get_pool_mode (const_rtx addr)
 {
   return SYMBOL_REF_CONSTANT (addr)->mode;
 }
@@ -3302,7 +3680,7 @@ get_pool_mode (rtx addr)
 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
@@ -3326,11 +3704,19 @@ output_constant_pool_2 (enum machine_mode mode, rtx x, unsigned int align)
 
     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:
+    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);
@@ -3373,20 +3759,20 @@ output_constant_pool_1 (struct constant_descriptor_rtx *desc,
      functioning even with INSN_DELETED_P and friends.  */
 
   tmp = x;
-  switch (GET_CODE (x))
+  switch (GET_CODE (tmp))
     {
     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;
-      tmp = XEXP (XEXP (x, 0), 0);
+      tmp = XEXP (XEXP (tmp, 0), 0);
       /* FALLTHRU  */
 
     case LABEL_REF:
-      tmp = XEXP (x, 0);
+      tmp = XEXP (tmp, 0);
       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:
@@ -3491,13 +3877,13 @@ mark_constant_pool (void)
 {
   rtx insn, link;
 
-  if (!current_function_uses_const_pool && n_deferred_constants == 0)
+  if (!crtl->uses_const_pool && n_deferred_constants == 0)
     return;
 
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
     mark_constants (insn);
 
-  for (link = current_function_epilogue_delay_list;
+  for (link = crtl->epilogue_delay_list;
        link;
        link = XEXP (link, 1))
     mark_constants (XEXP (link, 0));
@@ -3533,9 +3919,10 @@ output_constant_pool_contents (struct rtx_constant_pool *pool)
    out the function's private constant pool.  */
 
 static void
-output_constant_pool (void)
+output_constant_pool (const char *fnname ATTRIBUTE_UNUSED,
+                     tree fndecl ATTRIBUTE_UNUSED)
 {
-  struct rtx_constant_pool *pool = cfun->varasm->pool;
+  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
@@ -3569,10 +3956,6 @@ compute_reloc_for_constant (tree exp)
   int reloc = 0, reloc2;
   tree tem;
 
-  /* Give the front-end a chance to convert VALUE to something that
-     looks more like a constant to the back-end.  */
-  exp = lang_hooks.expand_constant (exp);
-
   switch (TREE_CODE (exp))
     {
     case ADDR_EXPR:
@@ -3591,6 +3974,7 @@ compute_reloc_for_constant (tree exp)
       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;
@@ -3605,9 +3989,7 @@ compute_reloc_for_constant (tree exp)
        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;
@@ -3636,10 +4018,6 @@ output_addressed_constants (tree exp)
 {
   tree tem;
 
-  /* Give the front-end a chance to convert VALUE to something that
-     looks more like a constant to the back-end.  */
-  exp = lang_hooks.expand_constant (exp);
-
   switch (TREE_CODE (exp))
     {
     case ADDR_EXPR:
@@ -3660,13 +4038,12 @@ output_addressed_constants (tree exp)
       break;
 
     case PLUS_EXPR:
+    case POINTER_PLUS_EXPR:
     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;
@@ -3685,11 +4062,98 @@ output_addressed_constants (tree exp)
     }
 }
 \f
-/* 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.
+/* 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.  */
 
-   Return null_pointer_node if the value is absolute;
+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)));
+}
+
+/* A subroutine of initializer_constant_valid_p.  VALUE is a MINUS_EXPR,
+   PLUS_EXPR or POINTER_PLUS_EXPR.  This looks for cases of VALUE
+   which are valid when ENDTYPE is an integer of any size; in
+   particular, this does not accept a pointer minus a constant.  This
+   returns null_pointer_node if the VALUE is an absolute constant
+   which can be used to initialize a static variable.  Otherwise it
+   returns NULL.  */
+
+static tree
+narrowing_initializer_constant_valid_p (tree value, tree endtype)
+{
+  tree op0, op1;
+
+  if (!INTEGRAL_TYPE_P (endtype))
+    return NULL_TREE;
+
+  op0 = TREE_OPERAND (value, 0);
+  op1 = TREE_OPERAND (value, 1);
+
+  /* Like STRIP_NOPS except allow the operand mode to widen.  This
+     works around a feature of fold that simplifies (int)(p1 - p2) to
+     ((int)p1 - (int)p2) under the theory that the narrower operation
+     is cheaper.  */
+
+  while (CONVERT_EXPR_P (op0)
+        || TREE_CODE (op0) == NON_LVALUE_EXPR)
+    {
+      tree inner = TREE_OPERAND (op0, 0);
+      if (inner == error_mark_node
+         || ! INTEGRAL_MODE_P (TYPE_MODE (TREE_TYPE (inner)))
+         || (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0)))
+             > GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (inner)))))
+       break;
+      op0 = inner;
+    }
+
+  while (CONVERT_EXPR_P (op1)
+        || TREE_CODE (op1) == NON_LVALUE_EXPR)
+    {
+      tree inner = TREE_OPERAND (op1, 0);
+      if (inner == error_mark_node
+         || ! INTEGRAL_MODE_P (TYPE_MODE (TREE_TYPE (inner)))
+         || (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op1)))
+             > GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (inner)))))
+       break;
+      op1 = inner;
+    }
+
+  op0 = initializer_constant_valid_p (op0, endtype);
+  op1 = initializer_constant_valid_p (op1, endtype);
+
+  /* Both initializers must be known.  */
+  if (op0 && op1)
+    {
+      if (op0 == op1
+         && (op0 == null_pointer_node
+             || TREE_CODE (value) == MINUS_EXPR))
+       return null_pointer_node;
+
+      /* Support differences between labels.  */
+      if (TREE_CODE (op0) == LABEL_DECL
+         && TREE_CODE (op1) == LABEL_DECL)
+       return null_pointer_node;
+
+      if (TREE_CODE (op0) == STRING_CST
+         && TREE_CODE (op1) == STRING_CST
+         && operand_equal_p (op0, op1, 1))
+       return null_pointer_node;
+    }
+
+  return NULL_TREE;
+}
+
+/* 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 null_pointer_node if the value is absolute;
    if it is relocatable, return the variable that determines the relocation.
    We assume that VALUE has been folded as much as possible;
    therefore, we do not need to check for such things as
@@ -3698,17 +4162,12 @@ output_addressed_constants (tree exp)
 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);
+  tree ret;
 
   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;
@@ -3734,47 +4193,67 @@ initializer_constant_valid_p (tree value, tree endtype)
     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:
-      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 CONVERT_EXPR:
-    case NOP_EXPR:
+    case VIEW_CONVERT_EXPR:
       {
-       tree src;
-       tree src_type;
-       tree dest_type;
+       tree src = TREE_OPERAND (value, 0);
+       tree src_type = TREE_TYPE (src);
+       tree dest_type = TREE_TYPE (value);
+
+       /* Allow view-conversions from aggregate to non-aggregate type only
+          if the bit pattern is fully preserved afterwards; otherwise, the
+          RTL expander won't be able to apply a subsequent transformation
+          to the underlying constructor.  */
+       if (AGGREGATE_TYPE_P (src_type) && !AGGREGATE_TYPE_P (dest_type))
+         {
+           if (TYPE_MODE (endtype) == TYPE_MODE (dest_type))
+             return initializer_constant_valid_p (src, endtype);
+           else
+             return NULL_TREE;
+         }
 
-       src = TREE_OPERAND (value, 0);
-       src_type = TREE_TYPE (src);
-       dest_type = TREE_TYPE (value);
+       /* Allow all other kinds of view-conversion.  */
+       return initializer_constant_valid_p (src, endtype);
+      }
+
+    CASE_CONVERT:
+      {
+       tree src = TREE_OPERAND (value, 0);
+       tree src_type = TREE_TYPE (src);
+       tree dest_type = TREE_TYPE (value);
 
        /* Allow conversions between pointer types, floating-point
           types, and offset types.  */
@@ -3827,6 +4306,7 @@ initializer_constant_valid_p (tree value, tree endtype)
       }
       break;
 
+    case POINTER_PLUS_EXPR:
     case PLUS_EXPR:
       if (! INTEGRAL_TYPE_P (endtype)
          || TYPE_PRECISION (endtype) >= POINTER_SIZE)
@@ -3835,12 +4315,18 @@ initializer_constant_valid_p (tree value, tree 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)
            return valid0;
        }
+
+      /* Support narrowing pointer differences.  */
+      ret = narrowing_initializer_constant_valid_p (value, endtype);
+      if (ret != NULL_TREE)
+       return ret;
+
       break;
 
     case MINUS_EXPR:
@@ -3869,73 +4355,68 @@ initializer_constant_valid_p (tree value, tree endtype)
        }
 
       /* Support narrowing differences.  */
-      if (INTEGRAL_TYPE_P (endtype))
-       {
-         tree op0, op1;
+      ret = narrowing_initializer_constant_valid_p (value, endtype);
+      if (ret != NULL_TREE)
+       return ret;
 
-         op0 = TREE_OPERAND (value, 0);
-         op1 = TREE_OPERAND (value, 1);
+      break;
 
-         /* Like STRIP_NOPS except allow the operand mode to widen.
-            This works around a feature of fold that simplifies
-            (int)(p1 - p2) to ((int)p1 - (int)p2) under the theory
-            that the narrower operation is cheaper.  */
+    default:
+      break;
+    }
 
-         while (TREE_CODE (op0) == NOP_EXPR
-                || TREE_CODE (op0) == CONVERT_EXPR
-                || TREE_CODE (op0) == NON_LVALUE_EXPR)
-           {
-             tree inner = TREE_OPERAND (op0, 0);
-             if (inner == error_mark_node
-                 || ! INTEGRAL_MODE_P (TYPE_MODE (TREE_TYPE (inner)))
-                 || (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0)))
-                     > GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (inner)))))
-               break;
-             op0 = inner;
-           }
+  return 0;
+}
+\f
+/* Return true if VALUE is a valid constant-valued expression
+   for use in initializing a static bit-field; one that can be
+   an element of a "constant" initializer.  */
 
-         while (TREE_CODE (op1) == NOP_EXPR
-                || TREE_CODE (op1) == CONVERT_EXPR
-                || TREE_CODE (op1) == NON_LVALUE_EXPR)
-           {
-             tree inner = TREE_OPERAND (op1, 0);
-             if (inner == error_mark_node
-                 || ! INTEGRAL_MODE_P (TYPE_MODE (TREE_TYPE (inner)))
-                 || (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op1)))
-                     > GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (inner)))))
-               break;
-             op1 = inner;
-           }
+bool
+initializer_constant_valid_for_bitfield_p (tree value)
+{
+  /* For bitfields we support integer constants or possibly nested aggregates
+     of such.  */
+  switch (TREE_CODE (value))
+    {
+    case CONSTRUCTOR:
+      {
+       unsigned HOST_WIDE_INT idx;
+       tree elt;
 
-         op0 = initializer_constant_valid_p (op0, endtype);
-         op1 = initializer_constant_valid_p (op1, endtype);
+       FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (value), idx, elt)
+         if (!initializer_constant_valid_for_bitfield_p (elt))
+           return false;
+       return true;
+      }
 
-         /* Both initializers must be known.  */
-         if (op0 && op1)
-           {
-             if (op0 == op1)
-               return null_pointer_node;
-
-             /* Support differences between labels.  */
-             if (TREE_CODE (op0) == LABEL_DECL
-                 && TREE_CODE (op1) == LABEL_DECL)
-               return null_pointer_node;
-
-             if (TREE_CODE (op0) == STRING_CST
-                 && TREE_CODE (op1) == STRING_CST
-                 && operand_equal_p (op0, op1, 1))
-               return null_pointer_node;
-           }
-       }
-      break;
+    case INTEGER_CST:
+      return true;
+
+    case VIEW_CONVERT_EXPR:
+    case NON_LVALUE_EXPR:
+      return
+       initializer_constant_valid_for_bitfield_p (TREE_OPERAND (value, 0));
 
     default:
       break;
     }
 
-  return 0;
+  return false;
 }
-\f
+
+/* output_constructor outer state of relevance in recursive calls, typically
+   for nested aggregate bitfields.  */
+
+typedef struct {
+  unsigned int bit_offset;  /* current position in ...  */
+  int byte;                 /* ... the outer byte buffer.  */
+} oc_outer_state;
+
+static unsigned HOST_WIDE_INT
+  output_constructor (tree, unsigned HOST_WIDE_INT, unsigned int,
+                     oc_outer_state *);
+
 /* Output assembler code for constant EXP to FILE, with no label.
    This includes the pseudo-op such as ".int" or ".byte", and a newline.
    Assumes output_addressed_constants has been done on EXP already.
@@ -3962,11 +4443,6 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align)
   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;
 
@@ -4001,7 +4477,7 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align)
 
   /* 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)
     {
@@ -4014,10 +4490,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)
-       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));
@@ -4054,10 +4530,11 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align)
     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))
-       error ("initializer for integer value is too complicated");
+       error ("initializer for integer/fixed-point value is too complicated");
       break;
 
     case REAL_TYPE:
@@ -4078,7 +4555,7 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align)
       switch (TREE_CODE (exp))
        {
        case CONSTRUCTOR:
-         output_constructor (exp, size, align);
+           output_constructor (exp, size, align, NULL);
          return;
        case STRING_CST:
          thissize = MIN ((unsigned HOST_WIDE_INT)TREE_STRING_LENGTH (exp),
@@ -4100,8 +4577,12 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align)
 
            link = TREE_VECTOR_CST_ELTS (exp);
            output_constant (TREE_VALUE (link), elt_size, align);
+           thissize = elt_size;
            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:
@@ -4112,7 +4593,7 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align)
     case RECORD_TYPE:
     case UNION_TYPE:
       gcc_assert (TREE_CODE (exp) == CONSTRUCTOR);
-      output_constructor (exp, size, align);
+      output_constructor (exp, size, align, NULL);
       return;
 
     case ERROR_MARK:
@@ -4136,7 +4617,7 @@ array_size_for_constructor (tree val)
 {
   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
@@ -4157,9 +4638,9 @@ array_size_for_constructor (tree val)
     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.  */
@@ -4168,321 +4649,463 @@ array_size_for_constructor (tree val)
   return tree_low_cst (i, 1);
 }
 
-/* Subroutine of output_constant, used for CONSTRUCTORs (aggregate constants).
-   Generate at least SIZE bytes, padding if necessary.  */
+/* Other datastructures + helpers for output_constructor.  */
 
-static void
-output_constructor (tree exp, unsigned HOST_WIDE_INT size,
-                   unsigned int align)
-{
-  tree type = TREE_TYPE (exp);
-  tree field = 0;
-  tree min_index = 0;
-  /* Number of bytes output or skipped so far.
-     In other words, current position within the constructor.  */
-  HOST_WIDE_INT total_bytes = 0;
-  /* Nonzero means BYTE contains part of a byte, to be output.  */
-  int byte_buffer_in_use = 0;
-  int byte = 0;
-  unsigned HOST_WIDE_INT cnt;
-  constructor_elt *ce;
+/* output_constructor local state to support interaction with helpers.  */
 
-  gcc_assert (HOST_BITS_PER_WIDE_INT >= BITS_PER_UNIT);
+typedef struct {
 
-  if (TREE_CODE (type) == RECORD_TYPE)
-    field = TYPE_FIELDS (type);
+  /* Received arguments.  */
+  tree exp;                     /* Constructor expression.  */
+  unsigned HOST_WIDE_INT size;  /* # bytes to output - pad if necessary.  */
+  unsigned int align;           /* Known initial alignment.  */
 
-  if (TREE_CODE (type) == ARRAY_TYPE
-      && TYPE_DOMAIN (type) != 0)
-    min_index = TYPE_MIN_VALUE (TYPE_DOMAIN (type));
+  /* Constructor expression data.  */
+  tree type;       /* Expression type.  */
+  tree field;      /* Current field decl in a record.  */
+  tree min_index;  /* Lower bound if specified for an array.  */
 
-  /* As LINK goes through the elements of the constant,
-     FIELD goes through the structure fields, if the constant is a structure.
-     if the constant is a union, then we override this,
-     by getting the field from the TREE_LIST element.
-     But the constant could also be an array.  Then FIELD is zero.
+  /* Output processing state.  */
+  HOST_WIDE_INT total_bytes;  /* # bytes output so far / current position.  */
+  bool byte_buffer_in_use;    /* Whether byte ...  */
+  int byte;                   /* ... contains part of a bitfield byte yet to
+                                be output.  */
 
-     There is always a maximum of one element in the chain LINK for unions
-     (even if the initializer in a source program incorrectly contains
-     more one).  */
-  for (cnt = 0;
-       VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (exp), cnt, ce);
-       cnt++, field = field ? TREE_CHAIN (field) : 0)
+  int last_relative_index;    /* Implicit or explicit index of the last
+                                array element output within a bitfield.  */
+  /* Current element.  */
+  tree val;    /* Current element value.  */
+  tree index;  /* Current element index.  */
+
+} oc_local_state;
+
+/* Helper for output_constructor.  From the current LOCAL state, output a
+   RANGE_EXPR element.  */
+
+static void
+output_constructor_array_range (oc_local_state *local)
+{
+  unsigned HOST_WIDE_INT fieldsize
+    = int_size_in_bytes (TREE_TYPE (local->type));
+
+  HOST_WIDE_INT lo_index
+    = tree_low_cst (TREE_OPERAND (local->index, 0), 0);
+  HOST_WIDE_INT hi_index
+    = tree_low_cst (TREE_OPERAND (local->index, 1), 0);
+  HOST_WIDE_INT index;
+
+  unsigned int align2
+    = min_align (local->align, fieldsize * BITS_PER_UNIT);
+  
+  for (index = lo_index; index <= hi_index; index++)
     {
-      tree val = ce->value;
-      tree index = 0;
+      /* Output the element's initial value.  */
+      if (local->val == NULL_TREE)
+       assemble_zeros (fieldsize);
+      else
+       output_constant (local->val, fieldsize, align2);
+      
+      /* Count its size.  */
+      local->total_bytes += fieldsize;
+    }
+}
 
-      /* The element in a union constructor specifies the proper field
-        or index.  */
-      if ((TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE
-          || TREE_CODE (type) == QUAL_UNION_TYPE)
-         && ce->index != 0)
-       field = ce->index;
+/* Helper for output_constructor.  From the current LOCAL state, output a
+   field element that is not true bitfield or part of an outer one.  */
 
-      else if (TREE_CODE (type) == ARRAY_TYPE)
-       index = ce->index;
+static void
+output_constructor_regular_field (oc_local_state *local)
+{
+  /* Field size and position.  Since this structure is static, we know the
+     positions are constant.  */
+  unsigned HOST_WIDE_INT fieldsize;
+  HOST_WIDE_INT fieldpos;
 
-#ifdef ASM_COMMENT_START
-      if (field && flag_verbose_asm)
-       fprintf (asm_out_file, "%s %s:\n",
-                ASM_COMMENT_START,
-                DECL_NAME (field)
-                ? IDENTIFIER_POINTER (DECL_NAME (field))
-                : "<anonymous>");
-#endif
+  unsigned int align2;
 
-      /* Eliminate the marker that makes a cast not be an lvalue.  */
-      if (val != 0)
-       STRIP_NOPS (val);
+  if (local->index != NULL_TREE)
+    fieldpos = (tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (local->val)), 1)
+               * ((tree_low_cst (local->index, 0) 
+                   - tree_low_cst (local->min_index, 0))));
+  else if (local->field != NULL_TREE) 
+    fieldpos = int_byte_position (local->field);
+  else
+    fieldpos = 0; 
 
-      if (index && TREE_CODE (index) == RANGE_EXPR)
+  /* Output any buffered-up bit-fields preceding this element.  */
+  if (local->byte_buffer_in_use)
+    {
+      assemble_integer (GEN_INT (local->byte), 1, BITS_PER_UNIT, 1);
+      local->total_bytes++;
+      local->byte_buffer_in_use = false;
+    }
+  
+  /* Advance to offset of this element.
+     Note no alignment needed in an array, since that is guaranteed
+     if each element has the proper size.  */
+  if ((local->field != NULL_TREE || local->index != NULL_TREE)
+      && fieldpos != local->total_bytes)
+    {
+      gcc_assert (fieldpos >= local->total_bytes);
+      assemble_zeros (fieldpos - local->total_bytes);
+      local->total_bytes = fieldpos;
+    }
+  
+  /* Find the alignment of this element.  */
+  align2 = min_align (local->align, BITS_PER_UNIT * fieldpos);
+
+  /* Determine size this element should occupy.  */
+  if (local->field)
+    {
+      fieldsize = 0;
+      
+      /* If this is an array with an unspecified upper bound,
+        the initializer determines the size.  */
+      /* ??? This ought to only checked if DECL_SIZE_UNIT is NULL,
+        but we cannot do this until the deprecated support for
+        initializing zero-length array members is removed.  */
+      if (TREE_CODE (TREE_TYPE (local->field)) == ARRAY_TYPE
+         && TYPE_DOMAIN (TREE_TYPE (local->field))
+         && ! TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (local->field))))
        {
-         unsigned HOST_WIDE_INT fieldsize
-           = int_size_in_bytes (TREE_TYPE (type));
-         HOST_WIDE_INT lo_index = tree_low_cst (TREE_OPERAND (index, 0), 0);
-         HOST_WIDE_INT hi_index = tree_low_cst (TREE_OPERAND (index, 1), 0);
-         HOST_WIDE_INT index;
-         unsigned int align2 = min_align (align, fieldsize * BITS_PER_UNIT);
-
-         for (index = lo_index; index <= hi_index; index++)
-           {
-             /* Output the element's initial value.  */
-             if (val == 0)
-               assemble_zeros (fieldsize);
-             else
-               output_constant (val, fieldsize, align2);
-
-             /* Count its size.  */
-             total_bytes += fieldsize;
-           }
+         fieldsize = array_size_for_constructor (local->val);
+         /* Given a non-empty initialization, this field had
+            better be last.  */
+         gcc_assert (!fieldsize || !TREE_CHAIN (local->field));
        }
-      else if (field == 0 || !DECL_BIT_FIELD (field))
+      else if (DECL_SIZE_UNIT (local->field))
        {
-         /* An element that is not a bit-field.  */
-
-         unsigned HOST_WIDE_INT fieldsize;
-         /* Since this structure is static,
-            we know the positions are constant.  */
-         HOST_WIDE_INT pos = field ? int_byte_position (field) : 0;
-         unsigned int align2;
+         /* ??? This can't be right.  If the decl size overflows
+            a host integer we will silently emit no data.  */
+         if (host_integerp (DECL_SIZE_UNIT (local->field), 1))
+           fieldsize = tree_low_cst (DECL_SIZE_UNIT (local->field), 1);
+       }
+    }
+  else
+    fieldsize = int_size_in_bytes (TREE_TYPE (local->type));
+  
+  /* Output the element's initial value.  */
+  if (local->val == NULL_TREE)
+    assemble_zeros (fieldsize);
+  else
+    output_constant (local->val, fieldsize, align2);
 
-         if (index != 0)
-           pos = (tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (val)), 1)
-                  * (tree_low_cst (index, 0) - tree_low_cst (min_index, 0)));
+  /* Count its size.  */
+  local->total_bytes += fieldsize;
+}
 
-         /* Output any buffered-up bit-fields preceding this element.  */
-         if (byte_buffer_in_use)
-           {
-             assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
-             total_bytes++;
-             byte_buffer_in_use = 0;
-           }
+/* Helper for output_constructor.  From the current LOCAL and OUTER states,
+   output an element that is a true bitfield or part of an outer one.  */
 
-         /* Advance to offset of this element.
-            Note no alignment needed in an array, since that is guaranteed
-            if each element has the proper size.  */
-         if ((field != 0 || index != 0) && pos != total_bytes)
-           {
-             gcc_assert (pos >= total_bytes);
-             assemble_zeros (pos - total_bytes);
-             total_bytes = pos;
-           }
+static void
+output_constructor_bitfield (oc_local_state *local, oc_outer_state *outer)
+{
+  /* Bit size of this element.  */
+  HOST_WIDE_INT ebitsize
+    = (local->field
+       ? tree_low_cst (DECL_SIZE (local->field), 1)
+       : tree_low_cst (TYPE_SIZE (TREE_TYPE (local->type)), 1));
+
+  /* Relative index of this element if this is an array component.  */
+  HOST_WIDE_INT relative_index
+    = (!local->field
+       ? (local->index
+         ? (tree_low_cst (local->index, 0) 
+            - tree_low_cst (local->min_index, 0))
+         : local->last_relative_index + 1)
+       : 0);
+  
+  /* Bit position of this element from the start of the containing
+     constructor.  */
+  HOST_WIDE_INT constructor_relative_ebitpos
+      = (local->field
+        ? int_bit_position (local->field) 
+        : ebitsize * relative_index);
+  
+  /* Bit position of this element from the start of a possibly ongoing
+     outer byte buffer.  */
+  HOST_WIDE_INT byte_relative_ebitpos
+      = ((outer ? outer->bit_offset : 0) + constructor_relative_ebitpos);
+
+  /* From the start of a possibly ongoing outer byte buffer, offsets to 
+     the first bit of this element and to the first bit past the end of
+     this element.  */
+  HOST_WIDE_INT next_offset = byte_relative_ebitpos;
+  HOST_WIDE_INT end_offset = byte_relative_ebitpos + ebitsize;
+  
+  local->last_relative_index = relative_index;
+  
+  if (local->val == NULL_TREE)
+    local->val = integer_zero_node;
+  
+  while (TREE_CODE (local->val) == VIEW_CONVERT_EXPR
+        || TREE_CODE (local->val) == NON_LVALUE_EXPR)
+    local->val = TREE_OPERAND (local->val, 0);
+    
+  if (TREE_CODE (local->val) != INTEGER_CST
+      && TREE_CODE (local->val) != CONSTRUCTOR)
+    {
+      error ("invalid initial value for member %qE", DECL_NAME (local->field));
+      return;
+    }
 
-         /* Find the alignment of this element.  */
-         align2 = min_align (align, BITS_PER_UNIT * pos);
+  /* If this field does not start in this (or, next) byte,
+     skip some bytes.  */
+  if (next_offset / BITS_PER_UNIT != local->total_bytes)
+    {
+      /* Output remnant of any bit field in previous bytes.  */
+      if (local->byte_buffer_in_use)
+       {
+         assemble_integer (GEN_INT (local->byte), 1, BITS_PER_UNIT, 1);
+         local->total_bytes++;
+         local->byte_buffer_in_use = false;
+       }
+      
+      /* If still not at proper byte, advance to there.  */
+      if (next_offset / BITS_PER_UNIT != local->total_bytes)
+       {
+         gcc_assert (next_offset / BITS_PER_UNIT >= local->total_bytes);
+         assemble_zeros (next_offset / BITS_PER_UNIT - local->total_bytes);
+         local->total_bytes = next_offset / BITS_PER_UNIT;
+       }
+    }
+  
+  /* Set up the buffer if necessary.  */
+  if (!local->byte_buffer_in_use)
+    {
+      local->byte = 0;
+      if (ebitsize > 0)
+       local->byte_buffer_in_use = true;
+    }
+  
+  /* If this is nested constructor, recurse passing the bit offset and the
+     pending data, then retrieve the new pending data afterwards.  */
+  if (TREE_CODE (local->val) == CONSTRUCTOR)
+    {
+      oc_outer_state output_state;
 
-         /* Determine size this element should occupy.  */
-         if (field)
+      output_state.bit_offset = next_offset % BITS_PER_UNIT;
+      output_state.byte = local->byte;
+      local->total_bytes
+         += output_constructor (local->val, 0, 0, &output_state);
+      local->byte = output_state.byte;
+      return;
+    }
+  
+  /* Otherwise, we must split the element into pieces that fall within
+     separate bytes, and combine each byte with previous or following
+     bit-fields.  */  
+  while (next_offset < end_offset)
+    {
+      int this_time;
+      int shift;
+      HOST_WIDE_INT value;
+      HOST_WIDE_INT next_byte = next_offset / BITS_PER_UNIT;
+      HOST_WIDE_INT next_bit = next_offset % BITS_PER_UNIT;
+      
+      /* Advance from byte to byte
+        within this element when necessary.  */
+      while (next_byte != local->total_bytes)
+       {
+         assemble_integer (GEN_INT (local->byte), 1, BITS_PER_UNIT, 1);
+         local->total_bytes++;
+         local->byte = 0;
+       }
+      
+      /* Number of bits we can process at once
+        (all part of the same byte).  */
+      this_time = MIN (end_offset - next_offset,
+                      BITS_PER_UNIT - next_bit);
+      if (BYTES_BIG_ENDIAN)
+       {
+         /* On big-endian machine, take the most significant bits
+            first (of the bits that are significant)
+            and put them into bytes from the most significant end.  */
+         shift = end_offset - next_offset - this_time;
+         
+         /* Don't try to take a bunch of bits that cross
+            the word boundary in the INTEGER_CST. We can
+            only select bits from the LOW or HIGH part
+            not from both.  */
+         if (shift < HOST_BITS_PER_WIDE_INT
+             && shift + this_time > HOST_BITS_PER_WIDE_INT)
            {
-             fieldsize = 0;
-
-             /* If this is an array with an unspecified upper bound,
-                the initializer determines the size.  */
-             /* ??? This ought to only checked if DECL_SIZE_UNIT is NULL,
-                but we cannot do this until the deprecated support for
-                initializing zero-length array members is removed.  */
-             if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
-                 && TYPE_DOMAIN (TREE_TYPE (field))
-                 && ! TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (field))))
-               {
-                 fieldsize = array_size_for_constructor (val);
-                 /* Given a non-empty initialization, this field had
-                    better be last.  */
-                 gcc_assert (!fieldsize || !TREE_CHAIN (field));
-               }
-             else if (DECL_SIZE_UNIT (field))
-               {
-                 /* ??? This can't be right.  If the decl size overflows
-                    a host integer we will silently emit no data.  */
-                 if (host_integerp (DECL_SIZE_UNIT (field), 1))
-                   fieldsize = tree_low_cst (DECL_SIZE_UNIT (field), 1);
-               }
+             this_time = shift + this_time - HOST_BITS_PER_WIDE_INT;
+             shift = HOST_BITS_PER_WIDE_INT;
            }
+         
+         /* Now get the bits from the appropriate constant word.  */
+         if (shift < HOST_BITS_PER_WIDE_INT)
+           value = TREE_INT_CST_LOW (local->val);
          else
-           fieldsize = int_size_in_bytes (TREE_TYPE (type));
-
-         /* Output the element's initial value.  */
-         if (val == 0)
-           assemble_zeros (fieldsize);
-         else
-           output_constant (val, fieldsize, align2);
-
-         /* Count its size.  */
-         total_bytes += fieldsize;
+           {
+             gcc_assert (shift < 2 * HOST_BITS_PER_WIDE_INT);
+             value = TREE_INT_CST_HIGH (local->val);
+             shift -= HOST_BITS_PER_WIDE_INT;
+           }
+         
+         /* Get the result. This works only when:
+            1 <= this_time <= HOST_BITS_PER_WIDE_INT.  */
+         local->byte |= (((value >> shift)
+                          & (((HOST_WIDE_INT) 2 << (this_time - 1)) - 1))
+                         << (BITS_PER_UNIT - this_time - next_bit));
        }
-      else if (val != 0 && TREE_CODE (val) != INTEGER_CST)
-       error ("invalid initial value for member %qs",
-              IDENTIFIER_POINTER (DECL_NAME (field)));
       else
        {
-         /* Element that is a bit-field.  */
+         /* On little-endian machines,
+            take first the least significant bits of the value
+            and pack them starting at the least significant
+            bits of the bytes.  */
+         shift = next_offset - byte_relative_ebitpos;
+         
+         /* Don't try to take a bunch of bits that cross
+            the word boundary in the INTEGER_CST. We can
+            only select bits from the LOW or HIGH part
+            not from both.  */
+         if (shift < HOST_BITS_PER_WIDE_INT
+             && shift + this_time > HOST_BITS_PER_WIDE_INT)
+           this_time = (HOST_BITS_PER_WIDE_INT - shift);
+         
+         /* Now get the bits from the appropriate constant word.  */
+         if (shift < HOST_BITS_PER_WIDE_INT)
+           value = TREE_INT_CST_LOW (local->val);
+         else
+           {
+             gcc_assert (shift < 2 * HOST_BITS_PER_WIDE_INT);
+             value = TREE_INT_CST_HIGH (local->val);
+             shift -= HOST_BITS_PER_WIDE_INT;
+           }
+         
+         /* Get the result. This works only when:
+            1 <= this_time <= HOST_BITS_PER_WIDE_INT.  */
+         local->byte |= (((value >> shift)
+                          & (((HOST_WIDE_INT) 2 << (this_time - 1)) - 1))
+                         << next_bit);
+       }
+      
+      next_offset += this_time;
+      local->byte_buffer_in_use = true;
+    }
+}
 
-         HOST_WIDE_INT next_offset = int_bit_position (field);
-         HOST_WIDE_INT end_offset
-           = (next_offset + tree_low_cst (DECL_SIZE (field), 1));
+/* Subroutine of output_constant, used for CONSTRUCTORs (aggregate constants).
+   Generate at least SIZE bytes, padding if necessary.  OUTER designates the
+   caller output state of relevance in recursive invocations.  */
 
-         if (val == 0)
-           val = integer_zero_node;
+static unsigned HOST_WIDE_INT
+output_constructor (tree exp, unsigned HOST_WIDE_INT size,
+                   unsigned int align, oc_outer_state * outer)
+{
+  unsigned HOST_WIDE_INT cnt;
+  constructor_elt *ce;
 
-         /* If this field does not start in this (or, next) byte,
-            skip some bytes.  */
-         if (next_offset / BITS_PER_UNIT != total_bytes)
-           {
-             /* Output remnant of any bit field in previous bytes.  */
-             if (byte_buffer_in_use)
-               {
-                 assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
-                 total_bytes++;
-                 byte_buffer_in_use = 0;
-               }
+  oc_local_state local;
 
-             /* If still not at proper byte, advance to there.  */
-             if (next_offset / BITS_PER_UNIT != total_bytes)
-               {
-                 gcc_assert (next_offset / BITS_PER_UNIT >= total_bytes);
-                 assemble_zeros (next_offset / BITS_PER_UNIT - total_bytes);
-                 total_bytes = next_offset / BITS_PER_UNIT;
-               }
-           }
+  /* Setup our local state to communicate with helpers.  */
+  local.exp = exp;
+  local.size = size;
+  local.align = align;
 
-         if (! byte_buffer_in_use)
-           byte = 0;
+  local.total_bytes = 0;
+  local.byte_buffer_in_use = outer != NULL;
+  local.byte = outer ? outer->byte : 0;
 
-         /* We must split the element into pieces that fall within
-            separate bytes, and combine each byte with previous or
-            following bit-fields.  */
+  local.type = TREE_TYPE (exp);
 
-         /* next_offset is the offset n fbits from the beginning of
-            the structure to the next bit of this element to be processed.
-            end_offset is the offset of the first bit past the end of
-            this element.  */
-         while (next_offset < end_offset)
-           {
-             int this_time;
-             int shift;
-             HOST_WIDE_INT value;
-             HOST_WIDE_INT next_byte = next_offset / BITS_PER_UNIT;
-             HOST_WIDE_INT next_bit = next_offset % BITS_PER_UNIT;
-
-             /* Advance from byte to byte
-                within this element when necessary.  */
-             while (next_byte != total_bytes)
-               {
-                 assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
-                 total_bytes++;
-                 byte = 0;
-               }
+  local.last_relative_index = -1;
 
-             /* Number of bits we can process at once
-                (all part of the same byte).  */
-             this_time = MIN (end_offset - next_offset,
-                              BITS_PER_UNIT - next_bit);
-             if (BYTES_BIG_ENDIAN)
-               {
-                 /* On big-endian machine, take the most significant bits
-                    first (of the bits that are significant)
-                    and put them into bytes from the most significant end.  */
-                 shift = end_offset - next_offset - this_time;
-
-                 /* Don't try to take a bunch of bits that cross
-                    the word boundary in the INTEGER_CST. We can
-                    only select bits from the LOW or HIGH part
-                    not from both.  */
-                 if (shift < HOST_BITS_PER_WIDE_INT
-                     && shift + this_time > HOST_BITS_PER_WIDE_INT)
-                   {
-                     this_time = shift + this_time - HOST_BITS_PER_WIDE_INT;
-                     shift = HOST_BITS_PER_WIDE_INT;
-                   }
-
-                 /* Now get the bits from the appropriate constant word.  */
-                 if (shift < HOST_BITS_PER_WIDE_INT)
-                   value = TREE_INT_CST_LOW (val);
-                 else
-                   {
-                     gcc_assert (shift < 2 * HOST_BITS_PER_WIDE_INT);
-                     value = TREE_INT_CST_HIGH (val);
-                     shift -= HOST_BITS_PER_WIDE_INT;
-                   }
-
-                 /* Get the result. This works only when:
-                    1 <= this_time <= HOST_BITS_PER_WIDE_INT.  */
-                 byte |= (((value >> shift)
-                           & (((HOST_WIDE_INT) 2 << (this_time - 1)) - 1))
-                          << (BITS_PER_UNIT - this_time - next_bit));
-               }
-             else
-               {
-                 /* On little-endian machines,
-                    take first the least significant bits of the value
-                    and pack them starting at the least significant
-                    bits of the bytes.  */
-                 shift = next_offset - int_bit_position (field);
-
-                 /* Don't try to take a bunch of bits that cross
-                    the word boundary in the INTEGER_CST. We can
-                    only select bits from the LOW or HIGH part
-                    not from both.  */
-                 if (shift < HOST_BITS_PER_WIDE_INT
-                     && shift + this_time > HOST_BITS_PER_WIDE_INT)
-                   this_time = (HOST_BITS_PER_WIDE_INT - shift);
-
-                 /* Now get the bits from the appropriate constant word.  */
-                 if (shift < HOST_BITS_PER_WIDE_INT)
-                   value = TREE_INT_CST_LOW (val);
-                 else
-                   {
-                     gcc_assert (shift < 2 * HOST_BITS_PER_WIDE_INT);
-                     value = TREE_INT_CST_HIGH (val);
-                     shift -= HOST_BITS_PER_WIDE_INT;
-                   }
-
-                 /* Get the result. This works only when:
-                    1 <= this_time <= HOST_BITS_PER_WIDE_INT.  */
-                 byte |= (((value >> shift)
-                           & (((HOST_WIDE_INT) 2 << (this_time - 1)) - 1))
-                          << next_bit);
-               }
+  local.min_index = NULL_TREE;
+  if (TREE_CODE (local.type) == ARRAY_TYPE
+      && TYPE_DOMAIN (local.type) != NULL_TREE)
+    local.min_index = TYPE_MIN_VALUE (TYPE_DOMAIN (local.type));
+  
+  gcc_assert (HOST_BITS_PER_WIDE_INT >= BITS_PER_UNIT);
 
-             next_offset += this_time;
-             byte_buffer_in_use = 1;
-           }
-       }
-    }
+  /* As CE goes through the elements of the constant, FIELD goes through the
+     structure fields if the constant is a structure.  If the constant is a
+     union, we override this by getting the field from the TREE_LIST element.
+     But the constant could also be an array.  Then FIELD is zero.
+
+     There is always a maximum of one element in the chain LINK for unions
+     (even if the initializer in a source program incorrectly contains
+     more one).  */
 
-  if (byte_buffer_in_use)
+  local.field = NULL_TREE;
+  if (TREE_CODE (local.type) == RECORD_TYPE)
+    local.field = TYPE_FIELDS (local.type);
+
+  for (cnt = 0;
+       VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (exp), cnt, ce);
+       cnt++, local.field = local.field ? TREE_CHAIN (local.field) : 0)
     {
-      assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
-      total_bytes++;
+      local.val = ce->value;
+      local.index = NULL_TREE;
+
+      /* The element in a union constructor specifies the proper field
+        or index.  */
+      if ((TREE_CODE (local.type) == RECORD_TYPE
+          || TREE_CODE (local.type) == UNION_TYPE
+          || TREE_CODE (local.type) == QUAL_UNION_TYPE)
+         && ce->index != NULL_TREE)
+       local.field = ce->index;
+
+      else if (TREE_CODE (local.type) == ARRAY_TYPE)
+       local.index = ce->index;
+
+#ifdef ASM_COMMENT_START
+      if (local.field && flag_verbose_asm)
+       fprintf (asm_out_file, "%s %s:\n",
+                ASM_COMMENT_START,
+                DECL_NAME (local.field)
+                ? IDENTIFIER_POINTER (DECL_NAME (local.field))
+                : "<anonymous>");
+#endif
+
+      /* Eliminate the marker that makes a cast not be an lvalue.  */
+      if (local.val != NULL_TREE)
+       STRIP_NOPS (local.val);
+
+      /* Output the current element, using the appropriate helper ...  */
+
+      /* For an array slice not part of an outer bitfield.  */
+      if (!outer
+         && local.index != NULL_TREE
+         && TREE_CODE (local.index) == RANGE_EXPR)
+       output_constructor_array_range (&local);
+
+      /* For a field that is neither a true bitfield nor part of an outer one,
+        known to be at least byte aligned and multiple-of-bytes long.  */
+      else if (!outer
+              && (local.field == NULL_TREE
+                  || !CONSTRUCTOR_BITFIELD_P (local.field)))
+       output_constructor_regular_field (&local);
+      
+      /* For a true bitfield or part of an outer one.  */
+      else
+       output_constructor_bitfield (&local, outer);
     }
 
-  if ((unsigned HOST_WIDE_INT)total_bytes < size)
-    assemble_zeros (size - total_bytes);
-}
+  /* If we are not at toplevel, save the pending data for our caller.
+     Otherwise output the pending data and padding zeros as needed. */
+  if (outer)
+    outer->byte = local.byte;
+  else
+    {
+      if (local.byte_buffer_in_use)
+       {
+         assemble_integer (GEN_INT (local.byte), 1, BITS_PER_UNIT, 1);
+         local.total_bytes++;
+       }
 
-/* This TREE_LIST contains any weak symbol declarations waiting
-   to be emitted.  */
-static GTY(()) tree weak_decls;
+      if ((unsigned HOST_WIDE_INT)local.total_bytes < local.size)
+       {
+         assemble_zeros (local.size - local.total_bytes);
+         local.total_bytes = local.size;
+       }
+    }
+      
+  return local.total_bytes;
+}
 
 /* Mark DECL as weak.  */
 
@@ -4527,7 +5150,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
-        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))
@@ -4576,12 +5199,7 @@ declare_weak (tree decl)
     error ("weak declaration of %q+D must be public", decl);
   else if (TREE_CODE (decl) == FUNCTION_DECL && TREE_ASM_WRITTEN (decl))
     error ("weak declaration of %q+D must precede definition", decl);
-  else if (SUPPORTS_WEAK)
-    {
-      if (! DECL_WEAK (decl))
-       weak_decls = tree_cons (NULL, decl, weak_decls);
-    }
-  else
+  else if (!SUPPORTS_WEAK)
     warning (0, "weak declaration of %q+D not supported", decl);
 
   mark_weak (decl);
@@ -4645,7 +5263,7 @@ weak_finish (void)
       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));
@@ -4654,7 +5272,8 @@ weak_finish (void)
 
          if (! decl)
            {
-             decl = build_decl (TREE_CODE (alias_decl), target,
+             decl = build_decl (DECL_SOURCE_LOCATION (alias_decl),
+                                TREE_CODE (alias_decl), target,
                                 TREE_TYPE (alias_decl));
 
              DECL_EXTERNAL (decl) = 1;
@@ -4709,11 +5328,11 @@ weak_finish (void)
 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))
     {
+      const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
       tree *p, t;
 
 #ifdef ASM_WEAKEN_DECL
@@ -4732,33 +5351,29 @@ globalize_decl (tree decl)
            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;
     }
-#elif defined(ASM_MAKE_LABEL_LINKONCE)
-  if (DECL_ONE_ONLY (decl))
-    ASM_MAKE_LABEL_LINKONCE (asm_out_file, name);
 #endif
 
-  targetm.asm_out.globalize_label (asm_out_file, name);
+  targetm.asm_out.globalize_decl_name (asm_out_file, decl);
 }
 
 /* We have to be able to tell cgraph about the needed-ness of the target
    of an alias.  This requires that the decl have been defined.  Aliases
    that precede their definition have to be queued for later processing.  */
 
-typedef struct alias_pair GTY(())
-{
+typedef struct GTY(()) alias_pair {
   tree decl;
   tree target;
 } alias_pair;
@@ -4776,17 +5391,17 @@ static tree
 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)
-       vnode = cgraph_varpool_node_for_asm (target);
+       vnode = varpool_node_for_asm (target);
     }
   else
     {
-      vnode = cgraph_varpool_node_for_asm (target);
+      vnode = varpool_node_for_asm (target);
       if (vnode == NULL)
        fnode = cgraph_node_for_asm (target);
     }
@@ -4804,7 +5419,7 @@ find_decl_and_mark_needed (tree decl, tree target)
     }
   else if (vnode)
     {
-      cgraph_varpool_mark_needed_node (vnode);
+      varpool_mark_needed_node (vnode);
       return vnode->decl;
     }
   else
@@ -4828,6 +5443,14 @@ do_assemble_alias (tree decl, tree 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);
 
@@ -4838,13 +5461,22 @@ do_assemble_alias (tree decl, tree target)
 #else
       if (!SUPPORTS_WEAK)
        {
-         error ("%Jweakref is not supported in this configuration", decl);
+         error_at (DECL_SOURCE_LOCATION (decl),
+                   "weakref is not supported in this configuration");
          return;
        }
 #endif
       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.  */
 
@@ -4911,13 +5543,13 @@ finish_aliases_1 (void)
       if (target_decl == NULL)
        {
          if (! lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl)))
-           error ("%q+D aliased to undefined symbol %qs",
-                  p->decl, IDENTIFIER_POINTER (p->target));
+           error ("%q+D aliased to undefined symbol %qE",
+                  p->decl, p->target);
        }
       else if (DECL_EXTERNAL (target_decl)
               && ! lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl)))
-       error ("%q+D aliased to external symbol %qs",
-              p->decl, IDENTIFIER_POINTER (p->target));
+       error ("%q+D aliased to external symbol %qE",
+              p->decl, p->target);
     }
 }
 
@@ -4970,12 +5602,14 @@ assemble_alias (tree decl, tree target)
     {
 #if !defined (ASM_OUTPUT_DEF)
 # if !defined(ASM_OUTPUT_WEAK_ALIAS) && !defined (ASM_WEAKEN_DECL)
-      error ("%Jalias definitions not supported in this configuration", decl);
+      error_at (DECL_SOURCE_LOCATION (decl),
+               "alias definitions not supported in this configuration");
       return;
 # else
       if (!DECL_WEAK (decl))
        {
-         error ("%Jonly weak aliases are supported in this configuration", decl);
+         error_at (DECL_SOURCE_LOCATION (decl),
+                   "only weak aliases are supported in this configuration");
          return;
        }
 # endif
@@ -4997,11 +5631,14 @@ assemble_alias (tree decl, tree target)
   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
-     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
@@ -5019,7 +5656,7 @@ void
 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;
@@ -5039,13 +5676,18 @@ default_assemble_visibility (tree decl, int vis)
 
 /* 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)
-    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
@@ -5065,7 +5707,7 @@ supports_one_only (void)
    translation units without generating a linker error.  */
 
 void
-make_decl_one_only (tree decl)
+make_decl_one_only (tree decl, tree comdat_group)
 {
   gcc_assert (TREE_CODE (decl) == VAR_DECL
              || TREE_CODE (decl) == FUNCTION_DECL);
@@ -5077,7 +5719,7 @@ make_decl_one_only (tree decl)
 #ifdef MAKE_DECL_ONE_ONLY
       MAKE_DECL_ONE_ONLY (decl);
 #endif
-      DECL_ONE_ONLY (decl) = 1;
+      DECL_COMDAT_GROUP (decl) = comdat_group;
     }
   else if (TREE_CODE (decl) == VAR_DECL
       && (DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node))
@@ -5163,7 +5805,7 @@ init_varasm_once (void)
 }
 
 enum tls_model
-decl_default_tls_model (tree decl)
+decl_default_tls_model (const_tree decl)
 {
   enum tls_model kind;
   bool is_local;
@@ -5199,23 +5841,16 @@ decl_default_tls_model (tree decl)
 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;
-  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
-          && 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;
   else if (!decl
           && (!current_function_decl || !cfun)
@@ -5345,7 +5980,7 @@ default_elf_asm_named_section (const char *name, unsigned int flags,
        fprintf (asm_out_file, ",%d", flags & SECTION_ENTSIZE);
       if (HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))
        fprintf (asm_out_file, ",%s,comdat",
-                lang_hooks.decls.comdat_group (decl));
+                IDENTIFIER_POINTER (DECL_COMDAT_GROUP (decl)));
     }
 
   putc ('\n', asm_out_file);
@@ -5410,7 +6045,7 @@ default_select_section (tree decl, int reloc,
 }
 
 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;
 
@@ -5431,17 +6066,17 @@ categorize_decl_for_section (tree decl, int reloc, int shlib)
               || 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 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
@@ -5454,7 +6089,7 @@ categorize_decl_for_section (tree decl, int reloc, int shlib)
     }
   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;
@@ -5465,13 +6100,26 @@ categorize_decl_for_section (tree decl, int reloc, int shlib)
     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.  */
-      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;
@@ -5492,15 +6140,9 @@ categorize_decl_for_section (tree decl, int reloc, int shlib)
 }
 
 bool
-decl_readonly_section (tree decl, int reloc)
+decl_readonly_section (const_tree decl, int reloc)
 {
-  return decl_readonly_section_1 (decl, reloc, flag_pic);
-}
-
-bool
-decl_readonly_section_1 (tree decl, int reloc, int shlib)
-{
-  switch (categorize_decl_for_section (decl, reloc, shlib))
+  switch (categorize_decl_for_section (decl, reloc))
     {
     case SECCAT_RODATA:
     case SECCAT_RODATA_MERGE_STR:
@@ -5521,15 +6163,8 @@ section *
 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;
-  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.  */
@@ -5576,6 +6211,12 @@ default_elf_select_section_1 (tree decl, int reloc,
     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 ();
     }
@@ -5591,77 +6232,119 @@ default_elf_select_section_1 (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;
-  const char *prefix, *name;
-  size_t nlen, plen;
+  const char *prefix, *name, *linkonce;
   char *string;
 
-  switch (categorize_decl_for_section (decl, reloc, shlib))
+  switch (categorize_decl_for_section (decl, reloc))
     {
     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:
-      prefix = one_only ? ".gnu.linkonce.r." : ".rodata.";
+      prefix = one_only ? ".r" : ".rodata";
       break;
     case SECCAT_SRODATA:
-      prefix = one_only ? ".gnu.linkonce.s2." : ".sdata2.";
+      prefix = one_only ? ".s2" : ".sdata2";
       break;
     case SECCAT_DATA:
-      prefix = one_only ? ".gnu.linkonce.d." : ".data.";
+      prefix = one_only ? ".d" : ".data";
       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:
-      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:
-      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:
-      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:
-      prefix = one_only ? ".gnu.linkonce.s." : ".sdata.";
+      prefix = one_only ? ".s" : ".sdata";
       break;
     case SECCAT_BSS:
-      prefix = one_only ? ".gnu.linkonce.b." : ".bss.";
+      prefix = one_only ? ".b" : ".bss";
       break;
     case SECCAT_SBSS:
-      prefix = one_only ? ".gnu.linkonce.sb." : ".sbss.";
+      prefix = one_only ? ".sb" : ".sbss";
       break;
     case SECCAT_TDATA:
-      prefix = one_only ? ".gnu.linkonce.td." : ".tdata.";
+      prefix = one_only ? ".td" : ".tdata";
       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 ();
     }
-  plen = strlen (prefix);
 
   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 (nlen + plen, string);
+  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;
+
+    default:
+      return 0;
+    }
 }
 
 section *
@@ -5669,40 +6352,27 @@ default_select_rtx_section (enum machine_mode mode ATTRIBUTE_UNUSED,
                            rtx x,
                            unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
 {
-  if (flag_pic)
-    switch (GET_CODE (x))
-      {
-      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)
 {
-  /* ??? 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);
-
-      default:
-       break;
-      }
+      else
+       return get_named_section (NULL, ".data.rel.ro", 3);
+    }
 
   return mergeable_constant_section (mode, align, 0);
 }
@@ -5727,7 +6397,8 @@ default_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
     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;
@@ -5758,7 +6429,7 @@ default_asm_output_anchor (rtx symbol)
 {
   char buffer[100];
 
-  sprintf (buffer, ". + " HOST_WIDE_INT_PRINT_DEC,
+  sprintf (buffer, "*. + " HOST_WIDE_INT_PRINT_DEC,
           SYMBOL_REF_BLOCK_OFFSET (symbol));
   ASM_OUTPUT_DEF (asm_out_file, XSTR (symbol, 0), buffer);
 }
@@ -5767,7 +6438,7 @@ default_asm_output_anchor (rtx symbol)
 /* The default implementation of TARGET_USE_ANCHORS_FOR_SYMBOL_P.  */
 
 bool
-default_use_anchors_for_symbol_p (rtx symbol)
+default_use_anchors_for_symbol_p (const_rtx symbol)
 {
   section *sect;
   tree decl;
@@ -5806,13 +6477,13 @@ default_use_anchors_for_symbol_p (rtx symbol)
    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
-default_binds_local_p_1 (tree exp, int shlib)
+default_binds_local_p_1 (const_tree exp, int shlib)
 {
   bool local_p;
 
@@ -5843,9 +6514,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
-     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)
-    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)
@@ -5881,6 +6553,14 @@ default_globalize_label (FILE * stream, const char *name)
 }
 #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.  */
@@ -5907,7 +6587,7 @@ void
 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);
 }
@@ -5917,7 +6597,8 @@ default_internal_label (FILE *stream, const char *prefix,
 void
 default_file_start (void)
 {
-  if (targetm.file_start_app_off && !flag_verbose_asm)
+  if (targetm.file_start_app_off
+      && !(flag_verbose_asm || flag_debug_asm || flag_dump_rtl_in_asm))
     fputs (ASM_APP_OFF, asm_out_file);
 
   if (targetm.file_start_file_directive)
@@ -5968,10 +6649,10 @@ switch_to_section (section *new_section)
     {
     case SECTION_NAMED:
       if (cfun
-         && !cfun->unlikely_text_section_name
+         && !crtl->subsections.unlikely_text_section_name
          && 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,
@@ -6194,4 +6875,120 @@ 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"