OSDN Git Service

Update FSF address.
[pf3gnuchains/gcc-fork.git] / gcc / varasm.c
index a518dd7..e5d3649 100644 (file)
@@ -1,6 +1,7 @@
 /* Output variables, constants and external declarations, for GNU compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -16,8 +17,8 @@ for more details.
 
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 
 /* This file handles generation of all the assembler code
@@ -48,21 +49,16 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "tm_p.h"
 #include "debug.h"
 #include "target.h"
+#include "tree-mudflap.h"
 #include "cgraph.h"
+#include "cfglayout.h"
+#include "basic-block.h"
 
 #ifdef XCOFF_DEBUGGING_INFO
 #include "xcoffout.h"          /* Needed for external data
                                   declarations for e.g. AIX 4.x.  */
 #endif
 
-#ifndef TRAMPOLINE_ALIGNMENT
-#define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY
-#endif
-
-#ifndef ASM_STABS_OP
-#define ASM_STABS_OP "\t.stabs\t"
-#endif
-
 /* The (assembler) name of the first globally-visible object output.  */
 const char *first_global_object_name;
 const char *weak_global_object_name;
@@ -100,12 +96,13 @@ int size_directive_output;
 
 tree last_assemble_variable_decl;
 
-/* RTX_UNCHANGING_P in a MEM can mean it is stored into, for initialization.
-   So giving constant the alias set for the type will allow such
-   initializations to appear to conflict with the load of the constant.  We
-   avoid this by giving all constants an alias set for just constants.
-   Since there will be no stores to that alias set, nothing will ever
-   conflict with them.  */
+/* The following global variable indicates if the first basic block
+   in a function belongs to the cold partition or not.  */
+
+bool first_function_block_is_cold;
+
+/* We give all constants their own alias set.  Perhaps redundant with
+   MEM_READONLY_P, but pre-dates it.  */
 
 static HOST_WIDE_INT const_alias_set;
 
@@ -129,11 +126,12 @@ static void globalize_decl (tree);
 static void maybe_assemble_visibility (tree);
 static int in_named_entry_eq (const void *, const void *);
 static hashval_t in_named_entry_hash (const void *);
+static void initialize_cold_section_name (void);
+#ifdef BSS_SECTION_ASM_OP
 #ifdef ASM_OUTPUT_BSS
 static void asm_output_bss (FILE *, tree, const char *,
                            unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT);
 #endif
-#ifdef BSS_SECTION_ASM_OP
 #ifdef ASM_OUTPUT_ALIGNED_BSS
 static void asm_output_aligned_bss (FILE *, tree, const char *,
                                    unsigned HOST_WIDE_INT, int)
@@ -145,24 +143,8 @@ static bool asm_emit_uninitialised (tree, const char*,
                                    unsigned HOST_WIDE_INT);
 static void mark_weak (tree);
 \f
-enum in_section { no_section, in_text, in_data, in_named
-#ifdef BSS_SECTION_ASM_OP
-  , in_bss
-#endif
-#ifdef CTORS_SECTION_ASM_OP
-  , in_ctors
-#endif
-#ifdef DTORS_SECTION_ASM_OP
-  , in_dtors
-#endif
-#ifdef READONLY_DATA_SECTION_ASM_OP
-  , in_readonly_data
-#endif
-#ifdef EXTRA_SECTIONS
-  , EXTRA_SECTIONS
-#endif
-};
 static GTY(()) enum in_section in_section = no_section;
+enum in_section last_text_section;
 
 /* Return a nonzero value if DECL has a section attribute.  */
 #ifndef IN_NAMED_SECTION
@@ -173,6 +155,7 @@ static GTY(()) enum in_section in_section = no_section;
 
 /* Text of section name when in_section == in_named.  */
 static GTY(()) const char *in_named_name;
+const char *last_text_section_name;
 
 /* Hash table of flags that have been used for a particular named section.  */
 
@@ -190,6 +173,32 @@ static GTY((param_is (struct in_named_entry))) htab_t in_named_htab;
 EXTRA_SECTION_FUNCTIONS
 #endif
 
+static void
+initialize_cold_section_name (void)
+{
+  const char *stripped_name;
+  char *name, *buffer;
+  tree dsn;
+
+  gcc_assert (cfun && current_function_decl);
+  if (cfun->unlikely_text_section_name)
+    return;
+
+  dsn = DECL_SECTION_NAME (current_function_decl);
+  if (flag_function_sections && dsn)
+    {
+      name = alloca (TREE_STRING_LENGTH (dsn) + 1);
+      memcpy (name, TREE_STRING_POINTER (dsn), TREE_STRING_LENGTH (dsn) + 1);
+
+      stripped_name = targetm.strip_name_encoding (name);
+
+      buffer = ACONCAT ((stripped_name, "_unlikely", NULL));
+      cfun->unlikely_text_section_name = ggc_strdup (buffer);
+    }
+  else
+    cfun->unlikely_text_section_name =  UNLIKELY_EXECUTED_TEXT_SECTION_NAME;
+}
+
 /* Tell assembler to switch to text section.  */
 
 void
@@ -198,10 +207,40 @@ text_section (void)
   if (in_section != in_text)
     {
       in_section = in_text;
+      last_text_section = in_text;
       fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
     }
 }
 
+/* Tell assembler to switch to unlikely-to-be-executed text section.  */
+
+void
+unlikely_text_section (void)
+{
+  if (cfun)
+    {
+      if (!cfun->unlikely_text_section_name)
+       initialize_cold_section_name ();
+
+      if (flag_function_sections
+         || ((in_section != in_unlikely_executed_text)
+             &&  (in_section != in_named 
+                  || (strcmp (in_named_name, cfun->unlikely_text_section_name) 
+                      != 0))))
+       {
+         named_section (NULL_TREE, cfun->unlikely_text_section_name, 0);
+         in_section = in_unlikely_executed_text;
+         last_text_section = in_unlikely_executed_text;
+       }
+    }
+  else
+    {
+      named_section (NULL_TREE, UNLIKELY_EXECUTED_TEXT_SECTION_NAME, 0);
+      in_section = in_unlikely_executed_text;
+      last_text_section = in_unlikely_executed_text;
+    }
+}
+
 /* Tell assembler to switch to data section.  */
 
 void
@@ -244,6 +283,32 @@ in_text_section (void)
   return in_section == in_text;
 }
 
+/* Determine if we're in the unlikely-to-be-executed text section.  */
+
+int
+in_unlikely_text_section (void)
+{
+  bool ret_val;
+
+  if (cfun)
+    {
+      ret_val = ((in_section == in_unlikely_executed_text)
+                || (in_section == in_named
+                    && cfun->unlikely_text_section_name
+                    && strcmp (in_named_name, 
+                               cfun->unlikely_text_section_name) == 0));
+    }
+  else
+    {
+      ret_val = ((in_section == in_unlikely_executed_text)
+                || (in_section == in_named
+                    && strcmp (in_named_name,
+                               UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0));
+    }
+
+  return ret_val;
+}
+
 /* Determine if we're in the data section.  */
 
 int
@@ -275,7 +340,7 @@ in_named_entry_hash (const void *p)
    set of flags for a section to have, so 0 does not mean that the section
    has not been seen.  */
 
-unsigned int
+static unsigned int
 get_named_section_flags (const char *section)
 {
   struct in_named_entry **slot;
@@ -338,17 +403,20 @@ set_named_section_flags (const char *section, unsigned int flags)
   return true;
 }
 
-/* Tell assembler to change to section NAME with attributes FLAGS.  */
+/* Tell assembler to change to section NAME with attributes FLAGS.  If
+   DECL is non-NULL, it is the VAR_DECL or FUNCTION_DECL with which
+   this section is associated.  */
 
 void
-named_section_flags (const char *name, unsigned int flags)
+named_section_real (const char *name, unsigned int flags, tree decl)
 {
   if (in_section != in_named || strcmp (name, in_named_name) != 0)
     {
-      if (! set_named_section_flags (name, flags))
-       abort ();
+      bool unchanged = set_named_section_flags (name, flags);
 
-      targetm.asm_out.named_section (name, flags);
+      gcc_assert (unchanged);
+
+      targetm.asm_out.named_section (name, flags, decl);
 
       if (flags & SECTION_FORGET)
        in_section = no_section;
@@ -358,6 +426,12 @@ named_section_flags (const char *name, unsigned int flags)
          in_section = in_named;
        }
     }
+
+  if (in_text_section () || in_unlikely_text_section ())
+    {
+      last_text_section = in_section;
+      last_text_section_name = name;
+    }
 }
 
 /* Tell assembler to change to section NAME for DECL.
@@ -370,15 +444,19 @@ named_section (tree decl, const char *name, int reloc)
 {
   unsigned int flags;
 
-  if (decl != NULL_TREE && !DECL_P (decl))
-    abort ();
+  gcc_assert (!decl || DECL_P (decl));
   if (name == NULL)
     name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
 
+  if (strcmp (name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0
+      && cfun
+      && ! cfun->unlikely_text_section_name)
+    cfun->unlikely_text_section_name = UNLIKELY_EXECUTED_TEXT_SECTION_NAME;
+
   flags = targetm.section_type_flags (decl, name, reloc);
 
   /* Sanity check user variables for flag changes.  Non-user
-     section flag changes will abort in named_section_flags.
+     section flag changes will die in named_section_flags.
      However, don't complain if SECTION_OVERRIDE is set.
      We trust that the setter knows that it is safe to ignore
      the default flags for this decl.  */
@@ -389,7 +467,7 @@ named_section (tree decl, const char *name, int reloc)
        error ("%J%D causes a section type conflict", decl, decl);
     }
 
-  named_section_flags (name, flags);
+  named_section_real (name, flags, decl);
 }
 
 /* If required, set DECL_SECTION_NAME to a unique name.  */
@@ -476,18 +554,109 @@ asm_output_aligned_bss (FILE *file, tree decl ATTRIBUTE_UNUSED,
 
 /* Switch to the section for function DECL.
 
-   If DECL is NULL_TREE, switch to the text section.
-   ??? It's not clear that we will ever be passed NULL_TREE, but it's
-   safer to handle it.  */
+   If DECL is NULL_TREE, switch to the text section.  We can be passed
+   NULL_TREE under some circumstances by dbxout.c at least.  */
 
 void
 function_section (tree decl)
 {
+  int reloc = 0;
+    
+  if (first_function_block_is_cold)
+    reloc = 1;
+  
+#ifdef USE_SELECT_SECTION_FOR_FUNCTIONS
+  targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
+#else
   if (decl != NULL_TREE
-      && DECL_SECTION_NAME (decl) != NULL_TREE)
+      && DECL_SECTION_NAME (decl) != NULL_TREE
+      && targetm.have_named_sections)
     named_section (decl, (char *) 0, 0);
   else
     text_section ();
+#endif
+}
+
+void
+current_function_section (tree decl)
+{
+#ifdef USE_SELECT_SECTION_FOR_FUNCTIONS
+  int reloc = 0; 
+
+  if (in_unlikely_text_section () 
+      || last_text_section == in_unlikely_executed_text)
+    reloc = 1;
+  targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
+#else
+  if (last_text_section == in_unlikely_executed_text)
+    unlikely_text_section ();
+  else if (last_text_section == in_text)
+    text_section ();
+  else if (last_text_section == in_named
+          && targetm.have_named_sections)
+    named_section (NULL_TREE, last_text_section_name, 0);
+  else
+    function_section (decl);
+#endif
+}
+
+/* Switch to read-only data section associated with function DECL.  */
+
+void
+default_function_rodata_section (tree decl)
+{
+  if (decl != NULL_TREE && DECL_SECTION_NAME (decl))
+    {
+      const char *name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
+
+      if (DECL_ONE_ONLY (decl) && HAVE_COMDAT_GROUP)
+        {
+         size_t len = strlen (name) + 3;
+         char* rname = alloca (len);
+         
+         strcpy (rname, ".rodata");
+         strcat (rname, name + 5); 
+          named_section_real (rname, SECTION_LINKONCE, decl);
+         return;
+       }
+      /* For .gnu.linkonce.t.foo we want to use .gnu.linkonce.r.foo.  */
+      else if (DECL_ONE_ONLY (decl)
+              && strncmp (name, ".gnu.linkonce.t.", 16) == 0)
+       {
+         size_t len = strlen (name) + 1;
+         char *rname = alloca (len);
+
+         memcpy (rname, name, len);
+         rname[14] = 'r';
+         named_section_real (rname, SECTION_LINKONCE, decl);
+         return;
+       }
+      /* For .text.foo we want to use .rodata.foo.  */
+      else if (flag_function_sections && flag_data_sections
+              && strncmp (name, ".text.", 6) == 0)
+       {
+         size_t len = strlen (name) + 1;
+         char *rname = alloca (len + 2);
+
+         memcpy (rname, ".rodata", 7);
+         memcpy (rname + 7, name + 5, len - 5);
+         named_section_flags (rname, 0);
+         return;
+       }
+    }
+
+  readonly_data_section ();
+}
+
+/* Switch to read-only data section associated with function DECL
+   for targets where that section should be always the single
+   readonly data section.  */
+
+void
+default_no_function_rodata_section (tree decl ATTRIBUTE_UNUSED)
+{
+  readonly_data_section ();
 }
 
 /* Switch to section for variable DECL.  RELOC is the same as the
@@ -617,6 +786,19 @@ strip_reg_name (const char *name)
   return name;
 }
 \f
+/* The user has asked for a DECL to have a particular name.  Set (or
+   change) it in such a way that we don't prefix an underscore to
+   it.  */
+void
+set_user_assembler_name (tree decl, const char *name)
+{
+  char *starred = alloca (strlen (name) + 2);
+  starred[0] = '*';
+  strcpy (starred + 1, name);
+  change_decl_assembler_name (decl, get_identifier (starred));
+  SET_DECL_RTL (decl, NULL_RTX);
+}
+\f
 /* Decode an `asm' spec for a declaration as a register name.
    Return the register number, or -1 if nothing specified,
    or -2 if the ASMSPEC is not `cc' or `memory' and is not recognized,
@@ -683,32 +865,29 @@ decode_reg_name (const char *asmspec)
    There is, however, one exception: this function handles variables
    explicitly placed in a particular register by the user.
 
-   ASMSPEC, if not 0, is the string which the user specified as the
-   assembler symbol name.
-
    This is never called for PARM_DECL nodes.  */
 
 void
-make_decl_rtl (tree decl, const char *asmspec)
+make_decl_rtl (tree decl)
 {
   const char *name = 0;
   int reg_number;
   rtx x;
 
   /* Check that we are not being given an automatic variable.  */
+  gcc_assert (TREE_CODE (decl) != PARM_DECL
+             && TREE_CODE (decl) != RESULT_DECL);
+
   /* A weak alias has TREE_PUBLIC set but not the other bits.  */
-  if (TREE_CODE (decl) == PARM_DECL
-      || TREE_CODE (decl) == RESULT_DECL
-      || (TREE_CODE (decl) == VAR_DECL
-         && !TREE_STATIC (decl)
-         && !TREE_PUBLIC (decl)
-         && !DECL_EXTERNAL (decl)
-         && !DECL_REGISTER (decl)))
-    abort ();
+  gcc_assert (TREE_CODE (decl) != VAR_DECL
+             || TREE_STATIC (decl)
+             || TREE_PUBLIC (decl)
+             || DECL_EXTERNAL (decl)
+             || DECL_REGISTER (decl));
+  
   /* And that we were not given a type or a label.  */
-  else if (TREE_CODE (decl) == TYPE_DECL
-          || TREE_CODE (decl) == LABEL_DECL)
-    abort ();
+  gcc_assert (TREE_CODE (decl) != TYPE_DECL
+             && TREE_CODE (decl) != LABEL_DECL);
 
   /* For a duplicate declaration, we can be called twice on the
      same DECL node.  Don't discard the RTL already made.  */
@@ -719,6 +898,9 @@ make_decl_rtl (tree decl, const char *asmspec)
        SET_DECL_RTL (decl, adjust_address_nv (DECL_RTL (decl),
                                               DECL_MODE (decl), 0));
 
+      if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
+       return;
+
       /* ??? Another way to do this would be to maintain a hashed
         table of such critters.  Instead of adding stuff to a DECL
         to give certain attributes to it, we could use an external
@@ -728,34 +910,29 @@ make_decl_rtl (tree decl, const char *asmspec)
         This is necessary, for example, when one machine specific
         decl attribute overrides another.  */
       targetm.encode_section_info (decl, DECL_RTL (decl), false);
-      return;
-    }
 
-  reg_number = decode_reg_name (asmspec);
-  if (reg_number == -2)
-    {
-      /* ASMSPEC is given, and not the name of a register.  Mark the
-        name with a star so assemble_name won't munge it.  */
-      char *starred = alloca (strlen (asmspec) + 2);
-      starred[0] = '*';
-      strcpy (starred + 1, asmspec);
-      change_decl_assembler_name (decl, get_identifier (starred));
+      /* Make this function static known to the mudflap runtime.  */
+      if (flag_mudflap && TREE_CODE (decl) == VAR_DECL)
+       mudflap_enqueue_decl (decl);
+
+      return;
     }
 
   name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
 
   if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
     {
+      reg_number = decode_reg_name (name);
       /* First detect errors in declaring global registers.  */
       if (reg_number == -1)
-       error ("%Jregister name not specified for '%D'", decl, decl);
+       error ("%Jregister name not specified for %qD", decl, decl);
       else if (reg_number < 0)
-       error ("%Jinvalid register name for '%D'", decl, decl);
+       error ("%Jinvalid register name for %qD", decl, decl);
       else if (TYPE_MODE (TREE_TYPE (decl)) == BLKmode)
-       error ("%Jdata type of '%D' isn't suitable for a register",
+       error ("%Jdata type of %qD isn%'t suitable for a register",
               decl, decl);
       else if (! HARD_REGNO_MODE_OK (reg_number, TYPE_MODE (TREE_TYPE (decl))))
-       error ("%Jregister specified for '%D' isn't suitable for data type",
+       error ("%Jregister specified for %qD isn%'t suitable for data type",
                decl, decl);
       /* Now handle properly declared static register variables.  */
       else
@@ -768,7 +945,8 @@ make_decl_rtl (tree decl, const char *asmspec)
              error ("global register variable has initial value");
            }
          if (TREE_THIS_VOLATILE (decl))
-           warning ("volatile register variables don't work as you might wish");
+           warning (0, "volatile register variables don%'t "
+                    "work as you might wish");
 
          /* If the user specified one of the eliminables registers here,
             e.g., FRAME_POINTER_REGNUM, we don't want to get this variable
@@ -784,6 +962,7 @@ make_decl_rtl (tree decl, const char *asmspec)
              /* Make this register global, so not usable for anything
                 else.  */
 #ifdef ASM_DECLARE_REGISTER_GLOBAL
+             name = IDENTIFIER_POINTER (DECL_NAME (decl));
              ASM_DECLARE_REGISTER_GLOBAL (asm_out_file, decl, reg_number, name);
 #endif
              nregs = hard_regno_nregs[reg_number][DECL_MODE (decl)];
@@ -795,12 +974,19 @@ make_decl_rtl (tree decl, const char *asmspec)
          return;
        }
     }
-
   /* Now handle ordinary static variables and functions (in memory).
      Also handle vars declared register invalidly.  */
-
-  if (reg_number >= 0 || reg_number == -3)
-    error ("%Jregister name given for non-register variable '%D'", decl, decl);
+  else if (name[0] == '*')
+  {
+#ifdef REGISTER_PREFIX
+    if (strlen (REGISTER_PREFIX) != 0)
+      {
+       reg_number = decode_reg_name (name);
+       if (reg_number >= 0 || reg_number == -3)
+         error ("%Jregister name given for non-register variable %qD", decl, decl);
+      }
+#endif
+  }
 
   /* Specifying a section attribute on a variable forces it into a
      non-.bss section, and thus it cannot be common.  */
@@ -828,6 +1014,10 @@ make_decl_rtl (tree decl, const char *asmspec)
      If the name is changed, the macro ASM_OUTPUT_LABELREF
      will have to know how to strip this information.  */
   targetm.encode_section_info (decl, DECL_RTL (decl), true);
+
+  /* Make this function static known to the mudflap runtime.  */
+  if (flag_mudflap && TREE_CODE (decl) == VAR_DECL)
+    mudflap_enqueue_decl (decl);
 }
 
 /* Make the rtl for variable VAR be volatile.
@@ -836,8 +1026,7 @@ make_decl_rtl (tree decl, const char *asmspec)
 void
 make_var_volatile (tree var)
 {
-  if (GET_CODE (DECL_RTL (var)) != MEM)
-    abort ();
+  gcc_assert (MEM_P (DECL_RTL (var)));
 
   MEM_VOLATILE_P (DECL_RTL (var)) = 1;
 }
@@ -861,14 +1050,18 @@ assemble_asm (tree string)
    between 0 and MAX_INIT_PRIORITY.  */
 
 void
-default_stabs_asm_out_destructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
+default_stabs_asm_out_destructor (rtx symbol ATTRIBUTE_UNUSED,
+                                 int priority ATTRIBUTE_UNUSED)
 {
+#if defined DBX_DEBUGGING_INFO || defined XCOFF_DEBUGGING_INFO
   /* Tell GNU LD that this is part of the static destructor set.
      This will work for any system that uses stabs, most usefully
      aout systems.  */
-  fprintf (asm_out_file, "%s\"___DTOR_LIST__\",22,0,0,", ASM_STABS_OP);
-  assemble_name (asm_out_file, XSTR (symbol, 0));
-  fputc ('\n', asm_out_file);
+  dbxout_begin_simple_stabs ("___DTOR_LIST__", 22 /* N_SETT */);
+  dbxout_stab_value_label (XSTR (symbol, 0));
+#else
+  sorry ("global destructors not supported on this target");
+#endif
 }
 
 void
@@ -918,14 +1111,18 @@ default_dtor_section_asm_out_destructor (rtx symbol,
 /* Likewise for global constructors.  */
 
 void
-default_stabs_asm_out_constructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
+default_stabs_asm_out_constructor (rtx symbol ATTRIBUTE_UNUSED,
+                                  int priority ATTRIBUTE_UNUSED)
 {
+#if defined DBX_DEBUGGING_INFO || defined XCOFF_DEBUGGING_INFO
   /* Tell GNU LD that this is part of the static destructor set.
      This will work for any system that uses stabs, most usefully
      aout systems.  */
-  fprintf (asm_out_file, "%s\"___CTOR_LIST__\",22,0,0,", ASM_STABS_OP);
-  assemble_name (asm_out_file, XSTR (symbol, 0));
-  fputc ('\n', asm_out_file);
+  dbxout_begin_simple_stabs ("___CTOR_LIST__", 22 /* N_SETT */);
+  dbxout_stab_value_label (XSTR (symbol, 0));
+#else
+  sorry ("global constructors not supported on this target");
+#endif
 }
 
 void
@@ -999,7 +1196,7 @@ notice_global_symbol (tree decl)
              || (DECL_COMMON (decl)
                  && (DECL_INITIAL (decl) == 0
                      || DECL_INITIAL (decl) == error_mark_node))))
-      || GET_CODE (DECL_RTL (decl)) != MEM)
+      || !MEM_P (DECL_RTL (decl)))
     return;
 
   /* We win when global object is found, but it is useful to know about weak
@@ -1029,6 +1226,31 @@ void
 assemble_start_function (tree decl, const char *fnname)
 {
   int align;
+  char tmp_label[100];
+  bool hot_label_written = false;
+
+  cfun->unlikely_text_section_name = NULL;
+  first_function_block_is_cold = false;
+  if (flag_reorder_blocks_and_partition)
+    {
+      ASM_GENERATE_INTERNAL_LABEL (tmp_label, "HOTB", const_labelno);
+      cfun->hot_section_label = ggc_strdup (tmp_label);
+      ASM_GENERATE_INTERNAL_LABEL (tmp_label, "COLDB", const_labelno);
+      cfun->cold_section_label = ggc_strdup (tmp_label);
+      ASM_GENERATE_INTERNAL_LABEL (tmp_label, "HOTE", const_labelno);
+      cfun->hot_section_end_label = ggc_strdup (tmp_label);
+      ASM_GENERATE_INTERNAL_LABEL (tmp_label, "COLDE", const_labelno);
+      cfun->cold_section_end_label = ggc_strdup (tmp_label);
+      const_labelno++;
+    }
+  else
+    {
+      cfun->hot_section_label = NULL;
+      cfun->cold_section_label = NULL;
+      cfun->hot_section_end_label = NULL;
+      cfun->cold_section_end_label = NULL;
+    }
 
   /* The following code does not need preprocessing in the assembler.  */
 
@@ -1038,7 +1260,52 @@ assemble_start_function (tree decl, const char *fnname)
     output_constant_pool (fnname, decl);
 
   resolve_unique_section (decl, 0, flag_function_sections);
+
+  /* Make sure the not and cold text (code) sections are properly
+     aligned.  This is necessary here in the case where the function
+     has both hot and cold sections, because we don't want to re-set
+     the alignment when the section switch happens mid-function.  */
+
+  if (flag_reorder_blocks_and_partition)
+    {
+      unlikely_text_section ();
+      assemble_align (FUNCTION_BOUNDARY);
+      ASM_OUTPUT_LABEL (asm_out_file, cfun->cold_section_label);
+      if (BB_PARTITION (ENTRY_BLOCK_PTR->next_bb) == BB_COLD_PARTITION)
+       {
+         /* Since the function starts with a cold section, we need to
+            explicitly align the hot section and write out the hot
+            section label.  */
+         text_section ();
+         assemble_align (FUNCTION_BOUNDARY);
+         ASM_OUTPUT_LABEL (asm_out_file, cfun->hot_section_label);
+         hot_label_written = true;
+         first_function_block_is_cold = true;
+       }
+    }
+  else if (DECL_SECTION_NAME (decl))
+    {
+      /* Calls to function_section rely on first_function_block_is_cold
+        being accurate.  The first block may be cold even if we aren't
+        doing partitioning, if the entire function was decided by
+        choose_function_section (predict.c) to be cold.  */
+
+      initialize_cold_section_name ();
+
+      if (cfun->unlikely_text_section_name 
+         && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
+                    cfun->unlikely_text_section_name) == 0)
+       first_function_block_is_cold = true;
+    }
+
+  last_text_section = no_section;
+
+  /* Switch to the correct text section for the start of the function.  */
+
   function_section (decl);
+  if (flag_reorder_blocks_and_partition 
+      && !hot_label_written)
+    ASM_OUTPUT_LABEL (asm_out_file, cfun->hot_section_label);
 
   /* Tell assembler to move to target machine's alignment for functions.  */
   align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
@@ -1080,6 +1347,9 @@ assemble_start_function (tree decl, const char *fnname)
       maybe_assemble_visibility (decl);
     }
 
+  if (DECL_PRESERVE_P (decl))
+    targetm.asm_out.mark_decl_preserved (fnname);
+
   /* Do any machine/system dependent processing of the function name.  */
 #ifdef ASM_DECLARE_FUNCTION_NAME
   ASM_DECLARE_FUNCTION_NAME (asm_out_file, fnname, current_function_decl);
@@ -1087,6 +1357,8 @@ assemble_start_function (tree decl, const char *fnname)
   /* Standard thing is just output label for the function.  */
   ASM_OUTPUT_LABEL (asm_out_file, fnname);
 #endif /* ASM_DECLARE_FUNCTION_NAME */
+
+  insert_section_boundary_note ();
 }
 
 /* Output assembler code associated with defining the size of the
@@ -1103,6 +1375,23 @@ assemble_end_function (tree decl, const char *fnname)
       output_constant_pool (fnname, decl);
       function_section (decl); /* need to switch back */
     }
+  /* Output labels for end of hot/cold text sections (to be used by
+     debug info.)  */
+  if (flag_reorder_blocks_and_partition)
+    {
+      enum in_section save_text_section;
+
+      save_text_section = in_section;
+      unlikely_text_section ();
+      ASM_OUTPUT_LABEL (asm_out_file, cfun->cold_section_end_label);
+      if (first_function_block_is_cold)
+       text_section ();
+      else
+       function_section (decl);
+      ASM_OUTPUT_LABEL (asm_out_file, cfun->hot_section_end_label);
+      if (save_text_section == in_unlikely_executed_text)
+       unlikely_text_section ();
+    }
 }
 \f
 /* Assemble code to leave SIZE bytes of zeros.  */
@@ -1117,7 +1406,8 @@ assemble_zeros (unsigned HOST_WIDE_INT size)
 #ifdef ASM_NO_SKIP_IN_TEXT
   /* The `space' pseudo in the text section outputs nop insns rather than 0s,
      so we must output 0s explicitly in the text section.  */
-  if (ASM_NO_SKIP_IN_TEXT && in_text_section ())
+  if ((ASM_NO_SKIP_IN_TEXT && in_text_section ())
+      || (ASM_NO_SKIP_IN_TEXT && in_unlikely_text_section ()))
     {
       unsigned HOST_WIDE_INT i;
       for (i = 0; i < size; i++)
@@ -1229,9 +1519,16 @@ asm_emit_uninitialised (tree decl, const char *name,
        destination = asm_dest_common;
     }
 
+  if (destination != asm_dest_common)
+    {
+      resolve_unique_section (decl, 0, flag_data_sections);
+      /* Custom sections don't belong here.  */
+      if (DECL_SECTION_NAME (decl))
+        return false;
+    }
+
   if (destination == asm_dest_bss)
     globalize_decl (decl);
-  resolve_unique_section (decl, 0, flag_data_sections);
 
   if (flag_shared_data)
     {
@@ -1271,7 +1568,7 @@ asm_emit_uninitialised (tree decl, const char *name,
       ASM_EMIT_LOCAL (decl, name, size, rounded);
       break;
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
   return true;
@@ -1315,7 +1612,7 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
     return;
 
   /* Do nothing for global register variables.  */
-  if (DECL_RTL_SET_P (decl) && GET_CODE (DECL_RTL (decl)) == REG)
+  if (DECL_RTL_SET_P (decl) && REG_P (DECL_RTL (decl)))
     {
       TREE_ASM_WRITTEN (decl) = 1;
       return;
@@ -1332,7 +1629,7 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
 
   if (!dont_output_data && DECL_SIZE (decl) == 0)
     {
-      error ("%Jstorage size of `%D' isn't known", decl, decl);
+      error ("%Jstorage size of %qD isn%'t known", decl, decl);
       TREE_ASM_WRITTEN (decl) = 1;
       return;
     }
@@ -1360,7 +1657,7 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
   if (! dont_output_data
       && ! host_integerp (DECL_SIZE_UNIT (decl), 1))
     {
-      error ("%Jsize of variable '%D' is too large", decl, decl);
+      error ("%Jsize of variable %qD is too large", decl, decl);
       return;
     }
 
@@ -1381,12 +1678,9 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
 
   /* Some object file formats have a maximum alignment which they support.
      In particular, a.out format supports a maximum alignment of 4.  */
-#ifndef MAX_OFILE_ALIGNMENT
-#define MAX_OFILE_ALIGNMENT BIGGEST_ALIGNMENT
-#endif
   if (align > MAX_OFILE_ALIGNMENT)
     {
-      warning ("%Jalignment of '%D' is greater than maximum object "
+      warning (0, "%Jalignment of %qD is greater than maximum object "
                "file alignment.  Using %d", decl, decl,
               MAX_OFILE_ALIGNMENT/BITS_PER_UNIT);
       align = MAX_OFILE_ALIGNMENT;
@@ -1412,15 +1706,8 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
   if (TREE_PUBLIC (decl))
     maybe_assemble_visibility (decl);
 
-  /* Output any data that we will need to use the address of.  */
-  if (DECL_INITIAL (decl) == error_mark_node)
-    reloc = contains_pointers_p (TREE_TYPE (decl)) ? 3 : 0;
-  else if (DECL_INITIAL (decl))
-    {
-      reloc = compute_reloc_for_constant (DECL_INITIAL (decl));
-      output_addressed_constants (DECL_INITIAL (decl));
-    }
-  resolve_unique_section (decl, reloc, flag_data_sections);
+  if (DECL_PRESERVE_P (decl))
+    targetm.asm_out.mark_decl_preserved (name);
 
   /* Handle uninitialized definitions.  */
 
@@ -1456,8 +1743,8 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
                 * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
 
 #if !defined(ASM_OUTPUT_ALIGNED_COMMON) && !defined(ASM_OUTPUT_ALIGNED_DECL_COMMON) && !defined(ASM_OUTPUT_ALIGNED_BSS)
-      if ((unsigned HOST_WIDE_INT) DECL_ALIGN (decl) / BITS_PER_UNIT > rounded)
-       warning ("%Jrequested alignment for '%D' is greater than "
+      if ((unsigned HOST_WIDE_INT) DECL_ALIGN_UNIT (decl) > rounded)
+       warning (0, "%Jrequested alignment for %qD is greater than "
                  "implemented alignment of %d", decl, decl, rounded);
 #endif
 
@@ -1475,19 +1762,26 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
   if (TREE_PUBLIC (decl) && DECL_NAME (decl))
     globalize_decl (decl);
 
+  /* Output any data that we will need to use the address of.  */
+  if (DECL_INITIAL (decl) == error_mark_node)
+    reloc = contains_pointers_p (TREE_TYPE (decl)) ? 3 : 0;
+  else if (DECL_INITIAL (decl))
+    {
+      reloc = compute_reloc_for_constant (DECL_INITIAL (decl));
+      output_addressed_constants (DECL_INITIAL (decl));
+    }
+
   /* Switch to the appropriate section.  */
+  resolve_unique_section (decl, reloc, flag_data_sections);
   variable_section (decl, reloc);
 
   /* dbxout.c needs to know this.  */
-  if (in_text_section ())
+  if (in_text_section () || in_unlikely_text_section ())
     DECL_IN_TEXT_SECTION (decl) = 1;
 
   /* Output the alignment of this data.  */
   if (align > BITS_PER_UNIT)
-    {
-      ASM_OUTPUT_ALIGN (asm_out_file,
-                       floor_log2 (DECL_ALIGN (decl) / BITS_PER_UNIT));
-    }
+    ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DECL_ALIGN_UNIT (decl)));
 
   /* Do any machine/system dependent processing of the object.  */
 #ifdef ASM_DECLARE_OBJECT_NAME
@@ -1500,7 +1794,9 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
 
   if (!dont_output_data)
     {
-      if (DECL_INITIAL (decl) && DECL_INITIAL (decl) != error_mark_node)
+      if (DECL_INITIAL (decl)
+         && DECL_INITIAL (decl) != error_mark_node
+         && !initializer_zerop (DECL_INITIAL (decl)))
        /* Output the actual data.  */
        output_constant (DECL_INITIAL (decl),
                         tree_low_cst (DECL_SIZE_UNIT (decl), 1),
@@ -1547,6 +1843,12 @@ contains_pointers_p (tree type)
     }
 }
 
+/* In unit-at-a-time mode, we delay assemble_external processing until
+   the compilation unit is finalized.  This is the best we can do for
+   right now (i.e. stage 3 of GCC 4.0) - the right thing is to delay
+   it all the way to final.  See PR 17982 for further discussion.  */
+static GTY(()) tree pending_assemble_externals;
+
 #ifdef ASM_OUTPUT_EXTERNAL
 /* True if DECL is a function decl for which no out-of-line copy exists.
    It is assumed that DECL's assembler name has been set.  */
@@ -1568,8 +1870,37 @@ incorporeal_function_p (tree decl)
     }
   return false;
 }
+
+/* Actually do the tests to determine if this is necessary, and invoke
+   ASM_OUTPUT_EXTERNAL.  */
+static void
+assemble_external_real (tree decl)
+{
+  rtx rtl = DECL_RTL (decl);
+
+  if (MEM_P (rtl) && GET_CODE (XEXP (rtl, 0)) == SYMBOL_REF
+      && !SYMBOL_REF_USED (XEXP (rtl, 0))
+      && !incorporeal_function_p (decl))
+    {
+      /* Some systems do require some output.  */
+      SYMBOL_REF_USED (XEXP (rtl, 0)) = 1;
+      ASM_OUTPUT_EXTERNAL (asm_out_file, decl, XSTR (XEXP (rtl, 0), 0));
+    }
+}
 #endif
 
+void
+process_pending_assemble_externals (void)
+{
+#ifdef ASM_OUTPUT_EXTERNAL
+  tree list;
+  for (list = pending_assemble_externals; list; list = TREE_CHAIN (list))
+    assemble_external_real (TREE_VALUE (list));
+
+  pending_assemble_externals = 0;
+#endif
+}
+
 /* Output something to declare an external symbol to the assembler.
    (Most assemblers don't need this, so we normally output nothing.)
    Do nothing if DECL is not external.  */
@@ -1581,23 +1912,17 @@ assemble_external (tree decl ATTRIBUTE_UNUSED)
      main body of this code is only rarely exercised.  To provide some
      testing, on all platforms, we make sure that the ASM_OUT_FILE is
      open.  If it's not, we should not be calling this function.  */
-  if (!asm_out_file)
-    abort ();
+  gcc_assert (asm_out_file);
 
 #ifdef ASM_OUTPUT_EXTERNAL
-  if (DECL_P (decl) && DECL_EXTERNAL (decl) && TREE_PUBLIC (decl))
-    {
-      rtx rtl = DECL_RTL (decl);
+  if (!DECL_P (decl) || !DECL_EXTERNAL (decl) || !TREE_PUBLIC (decl))
+    return;
 
-      if (GET_CODE (rtl) == MEM && GET_CODE (XEXP (rtl, 0)) == SYMBOL_REF
-         && !SYMBOL_REF_USED (XEXP (rtl, 0))
-         && !incorporeal_function_p (decl))
-       {
-         /* Some systems do require some output.  */
-         SYMBOL_REF_USED (XEXP (rtl, 0)) = 1;
-         ASM_OUTPUT_EXTERNAL (asm_out_file, decl, XSTR (XEXP (rtl, 0), 0));
-       }
-    }
+  if (flag_unit_at_a_time)
+    pending_assemble_externals = tree_cons (0, decl,
+                                           pending_assemble_externals);
+  else
+    assemble_external_real (decl);
 #endif
 }
 
@@ -1622,34 +1947,59 @@ assemble_label (const char *name)
   ASM_OUTPUT_LABEL (asm_out_file, name);
 }
 
-/* Set the symbol_referenced flag for ID and notify callgraph code.  */
+/* Set the symbol_referenced flag for ID.  */
 void
 mark_referenced (tree id)
 {
-  if (!TREE_SYMBOL_REFERENCED (id))
+  TREE_SYMBOL_REFERENCED (id) = 1;
+}
+
+/* Set the symbol_referenced flag for DECL and notify callgraph.  */
+void
+mark_decl_referenced (tree decl)
+{
+  if (TREE_CODE (decl) == FUNCTION_DECL)
     {
-      struct cgraph_node *node;
-      struct cgraph_varpool_node *vnode;
+      /* Extern inline functions don't become needed when referenced.
+        If we know a method will be emitted in other TU and no new
+        functions can be marked reachable, just use the external
+        definition.  */
+      struct cgraph_node *node = cgraph_node (decl);
+      if (!DECL_EXTERNAL (decl)
+         && (!node->local.vtable_method || !cgraph_global_info_ready
+             || !node->local.finalized))
+       cgraph_mark_needed_node (node);
+    }
+  else if (TREE_CODE (decl) == VAR_DECL)
+    {
+      struct cgraph_varpool_node *node = cgraph_varpool_node (decl);
+      cgraph_varpool_mark_needed_node (node);
+      /* C++ frontend use mark_decl_references to force COMDAT variables
+         to be output that might appear dead otherwise.  */
+      node->force_output = true;
+    }
+  /* else do nothing - we can get various sorts of CST nodes here,
+     which do not need to be marked.  */
+}
 
-      if (!cgraph_global_info_ready)
-       {
-         node = cgraph_node_for_identifier (id);
-         if (node)
-           cgraph_mark_needed_node (node);
-       }
+/* Output to FILE (an assembly file) a reference to NAME.  If NAME
+   starts with a *, the rest of NAME is output verbatim.  Otherwise
+   NAME is transformed in a target-specific way (usually by the
+   addition of an underscore).  */
 
-      vnode = cgraph_varpool_node_for_identifier (id);
-      if (vnode)
-       cgraph_varpool_mark_needed_node (vnode);
-    }
-  TREE_SYMBOL_REFERENCED (id) = 1;
+void
+assemble_name_raw (FILE *file, const char *name)
+{
+  if (name[0] == '*')
+    fputs (&name[1], file);
+  else
+    ASM_OUTPUT_LABELREF (file, name);
 }
 
-/* Output to FILE a reference to the assembler name of a C-level name NAME.
-   If NAME starts with a *, the rest of NAME is output verbatim.
-   Otherwise NAME is transformed in an implementation-defined way
-   (usually by the addition of an underscore).
-   Many macros in the tm file are defined to call this function.  */
+/* Like assemble_name_raw, but should be used when NAME might refer to
+   an entity that is also represented as a tree (like a function or
+   variable).  If NAME does refer to such an entity, that entity will
+   be marked as referenced.  */
 
 void
 assemble_name (FILE *file, const char *name)
@@ -1663,10 +2013,7 @@ assemble_name (FILE *file, const char *name)
   if (id)
     mark_referenced (id);
 
-  if (name[0] == '*')
-    fputs (&name[1], file);
-  else
-    ASM_OUTPUT_LABELREF (file, name);
+  assemble_name_raw (file, name);
 }
 
 /* Allocate SIZE bytes writable static space with a gensym name
@@ -1717,6 +2064,8 @@ assemble_static_space (unsigned HOST_WIDE_INT size)
    This is done at most once per compilation.
    Returns an RTX for the address of the template.  */
 
+static GTY(()) rtx initial_trampoline;
+
 #ifdef TRAMPOLINE_TEMPLATE
 rtx
 assemble_trampoline_template (void)
@@ -1726,6 +2075,9 @@ assemble_trampoline_template (void)
   int align;
   rtx symbol;
 
+  if (initial_trampoline)
+    return initial_trampoline;
+
   /* By default, put trampoline templates in read-only data section.  */
 
 #ifdef TRAMPOLINE_SECTION
@@ -1750,7 +2102,10 @@ assemble_trampoline_template (void)
   symbol = gen_rtx_SYMBOL_REF (Pmode, name);
   SYMBOL_REF_FLAGS (symbol) = SYMBOL_FLAG_LOCAL;
 
-  return symbol;
+  initial_trampoline = gen_rtx_MEM (BLKmode, symbol);
+  set_mem_align (initial_trampoline, TRAMPOLINE_ALIGNMENT);
+
+  return initial_trampoline;
 }
 #endif
 \f
@@ -1817,13 +2172,17 @@ default_assemble_integer (rtx x ATTRIBUTE_UNUSED,
                          int aligned_p ATTRIBUTE_UNUSED)
 {
   const char *op = integer_asm_op (size, aligned_p);
+  /* Avoid GAS bugs for large values.  Specifically negative values whose
+     absolute value fits in a bfd_vma, but not in a bfd_signed_vma.  */
+  if (size > UNITS_PER_WORD && size > POINTER_SIZE / BITS_PER_UNIT)
+    return false;
   return op && (assemble_integer_with_op (op, x), true);
 }
 
 /* Assemble the integer constant X into an object of SIZE bytes.  ALIGN is
    the alignment of the integer in bits.  Return 1 if we were able to output
-   the constant, otherwise 0.  If FORCE is nonzero, abort if we can't output
-   the constant.  */
+   the constant, otherwise 0.  We must be able to output the constant,
+   if FORCE is nonzero.  */
 
 bool
 assemble_integer (rtx x, unsigned int size, unsigned int align, int force)
@@ -1860,13 +2219,11 @@ assemble_integer (rtx x, unsigned int size, unsigned int align, int force)
 
       /* If we've printed some of it, but not all of it, there's no going
         back now.  */
-      if (i > 0)
-       abort ();
+      gcc_assert (!i);
     }
 
-  if (force)
-    abort ();
-
+  gcc_assert (!force);
+  
   return false;
 }
 \f
@@ -1913,7 +2270,7 @@ assemble_real (REAL_VALUE_TYPE d, enum machine_mode mode, unsigned int align)
 /* Given an expression EXP with a constant value,
    reduce it to the sum of an assembler symbol and an integer.
    Store them both in the structure *VALUE.
-   Abort if EXP does not reduce.  */
+   EXP must be reducible.  */
 
 struct addr_const GTY(())
 {
@@ -1957,7 +2314,7 @@ decode_addr_const (tree exp, struct addr_const *value)
 
     case LABEL_DECL:
       x = gen_rtx_MEM (FUNCTION_MODE,
-                      gen_rtx_LABEL_REF (VOIDmode, force_label_rtx (target)));
+                      gen_rtx_LABEL_REF (Pmode, force_label_rtx (target)));
       break;
 
     case REAL_CST:
@@ -1969,11 +2326,10 @@ decode_addr_const (tree exp, struct addr_const *value)
       break;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
-  if (GET_CODE (x) != MEM)
-    abort ();
+  gcc_assert (MEM_P (x));
   x = XEXP (x, 0);
 
   value->base = x;
@@ -1991,6 +2347,11 @@ struct constant_descriptor_tree GTY(())
 
   /* 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)))
@@ -2004,7 +2365,7 @@ static void maybe_output_constant_def_contents (struct constant_descriptor_tree
 static hashval_t
 const_desc_hash (const void *ptr)
 {
-  return const_hash_1 (((struct constant_descriptor_tree *)ptr)->value);
+  return ((struct constant_descriptor_tree *)ptr)->hash;
 }
 
 static hashval_t
@@ -2038,28 +2399,17 @@ const_hash_1 (const tree exp)
              + const_hash_1 (TREE_IMAGPART (exp)));
 
     case CONSTRUCTOR:
-      if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
-       {
-         char *tmp;
-
-         len = int_size_in_bytes (TREE_TYPE (exp));
-         tmp = alloca (len);
-         get_set_constructor_bytes (exp, (unsigned char *) tmp, len);
-         p = tmp;
-         break;
-       }
-      else
-       {
-         tree link;
-
-         hi = 5 + int_size_in_bytes (TREE_TYPE (exp));
-
-         for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
-           if (TREE_VALUE (link))
-             hi = hi * 603 + const_hash_1 (TREE_VALUE (link));
-
-         return hi;
-       }
+      {
+       tree link;
+       
+       hi = 5 + int_size_in_bytes (TREE_TYPE (exp));
+       
+       for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
+         if (TREE_VALUE (link))
+           hi = hi * 603 + const_hash_1 (TREE_VALUE (link));
+       
+       return hi;
+      }
 
     case ADDR_EXPR:
     case FDESC_EXPR:
@@ -2067,19 +2417,24 @@ const_hash_1 (const tree exp)
        struct addr_const value;
 
        decode_addr_const (exp, &value);
-       if (GET_CODE (value.base) == SYMBOL_REF)
+       switch (GET_CODE (value.base))
          {
+         case SYMBOL_REF:
            /* Don't hash the address of the SYMBOL_REF;
               only use the offset and the symbol name.  */
            hi = value.offset;
            p = XSTR (value.base, 0);
            for (i = 0; p[i] != 0; i++)
              hi = ((hi * 613) + (unsigned) (p[i]));
+           break;
+
+         case LABEL_REF:
+           hi = value.offset + CODE_LABEL_NUMBER (XEXP (value.base, 0)) * 13;
+           break;
+
+         default:
+           gcc_unreachable ();
          }
-       else if (GET_CODE (value.base) == LABEL_REF)
-         hi = value.offset + CODE_LABEL_NUMBER (XEXP (value.base, 0)) * 13;
-       else
-         abort ();
       }
       return hi;
 
@@ -2110,8 +2465,11 @@ const_hash_1 (const tree exp)
 static int
 const_desc_eq (const void *p1, const void *p2)
 {
-  return compare_constant (((struct constant_descriptor_tree *)p1)->value,
-                          ((struct constant_descriptor_tree *)p2)->value);
+  const struct constant_descriptor_tree *c1 = p1;
+  const struct constant_descriptor_tree *c2 = p2;
+  if (c1->hash != c2->hash)
+    return 0;
+  return compare_constant (c1->value, c2->value);
 }
 
 /* Compare t1 and t2, and return 1 only if they are known to result in
@@ -2158,72 +2516,53 @@ compare_constant (const tree t1, const tree t2)
              && compare_constant (TREE_IMAGPART (t1), TREE_IMAGPART (t2)));
 
     case CONSTRUCTOR:
-      typecode = TREE_CODE (TREE_TYPE (t1));
-      if (typecode != TREE_CODE (TREE_TYPE (t2)))
-       return 0;
-
-      if (typecode == SET_TYPE)
-       {
-         int len = int_size_in_bytes (TREE_TYPE (t2));
-         unsigned char *tmp1, *tmp2;
-
-         if (int_size_in_bytes (TREE_TYPE (t1)) != len)
-           return 0;
-
-         tmp1 = alloca (len);
-         tmp2 = alloca (len);
-
-         if (get_set_constructor_bytes (t1, tmp1, len) != NULL_TREE)
-           return 0;
-         if (get_set_constructor_bytes (t2, tmp2, len) != NULL_TREE)
-           return 0;
-
-         return memcmp (tmp1, tmp2, len) == 0;
-       }
-      else
-       {
-         tree l1, l2;
-
-         if (typecode == ARRAY_TYPE)
-           {
-             HOST_WIDE_INT size_1 = int_size_in_bytes (TREE_TYPE (t1));
-             /* For arrays, check that the sizes all match.  */
-             if (TYPE_MODE (TREE_TYPE (t1)) != TYPE_MODE (TREE_TYPE (t2))
-                 || size_1 == -1
-                 || size_1 != int_size_in_bytes (TREE_TYPE (t2)))
-               return 0;
-           }
-         else
-           {
-             /* For record and union constructors, require exact type
-                 equality.  */
-             if (TREE_TYPE (t1) != TREE_TYPE (t2))
-               return 0;
-           }
+      {
+       tree l1, l2;
+       
+       typecode = TREE_CODE (TREE_TYPE (t1));
+       if (typecode != TREE_CODE (TREE_TYPE (t2)))
+         return 0;
 
-         for (l1 = CONSTRUCTOR_ELTS (t1), l2 = CONSTRUCTOR_ELTS (t2);
-              l1 && l2;
-              l1 = TREE_CHAIN (l1), l2 = TREE_CHAIN (l2))
-           {
-             /* Check that each value is the same...  */
-             if (! compare_constant (TREE_VALUE (l1), TREE_VALUE (l2)))
-               return 0;
-             /* ... and that they apply to the same fields!  */
-             if (typecode == ARRAY_TYPE)
-               {
-                 if (! compare_constant (TREE_PURPOSE (l1),
-                                         TREE_PURPOSE (l2)))
-                   return 0;
-               }
-             else
-               {
-                 if (TREE_PURPOSE (l1) != TREE_PURPOSE (l2))
-                   return 0;
-               }
-           }
+       if (typecode == ARRAY_TYPE)
+         {
+           HOST_WIDE_INT size_1 = int_size_in_bytes (TREE_TYPE (t1));
+           /* For arrays, check that the sizes all match.  */
+           if (TYPE_MODE (TREE_TYPE (t1)) != TYPE_MODE (TREE_TYPE (t2))
+               || size_1 == -1
+               || size_1 != int_size_in_bytes (TREE_TYPE (t2)))
+             return 0;
+         }
+       else
+         {
+           /* For record and union constructors, require exact type
+               equality.  */
+           if (TREE_TYPE (t1) != TREE_TYPE (t2))
+             return 0;
+         }
 
-         return l1 == NULL_TREE && l2 == NULL_TREE;
-       }
+       for (l1 = CONSTRUCTOR_ELTS (t1), l2 = CONSTRUCTOR_ELTS (t2);
+            l1 && l2;
+            l1 = TREE_CHAIN (l1), l2 = TREE_CHAIN (l2))
+         {
+           /* Check that each value is the same...  */
+           if (! compare_constant (TREE_VALUE (l1), TREE_VALUE (l2)))
+             return 0;
+           /* ... and that they apply to the same fields!  */
+           if (typecode == ARRAY_TYPE)
+             {
+               if (! compare_constant (TREE_PURPOSE (l1),
+                                       TREE_PURPOSE (l2)))
+                 return 0;
+             }
+           else
+             {
+               if (TREE_PURPOSE (l1) != TREE_PURPOSE (l2))
+                 return 0;
+             }
+         }
+       
+       return l1 == NULL_TREE && l2 == NULL_TREE;
+      }
 
     case ADDR_EXPR:
     case FDESC_EXPR:
@@ -2245,6 +2584,7 @@ compare_constant (const tree t1, const tree t2)
     case NOP_EXPR:
     case CONVERT_EXPR:
     case NON_LVALUE_EXPR:
+    case VIEW_CONVERT_EXPR:
       return compare_constant (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
 
     default:
@@ -2259,8 +2599,7 @@ compare_constant (const tree t1, const tree t2)
       }
     }
 
-  /* Should not get here.  */
-  abort ();
+  gcc_unreachable ();
 }
 \f
 /* Make a copy of the whole tree structure for a constant.  This
@@ -2274,7 +2613,7 @@ copy_constant (tree exp)
     case ADDR_EXPR:
       /* For ADDR_EXPR, we do not want to copy the decl whose address
         is requested.  We do want to copy constants though.  */
-      if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == 'c')
+      if (CONSTANT_CLASS_P (TREE_OPERAND (exp, 0)))
        return build1 (TREE_CODE (exp), TREE_TYPE (exp),
                       copy_constant (TREE_OPERAND (exp, 0)));
       else
@@ -2292,9 +2631,9 @@ copy_constant (tree exp)
 
     case PLUS_EXPR:
     case MINUS_EXPR:
-      return build (TREE_CODE (exp), TREE_TYPE (exp),
-                   copy_constant (TREE_OPERAND (exp, 0)),
-                   copy_constant (TREE_OPERAND (exp, 1)));
+      return build2 (TREE_CODE (exp), TREE_TYPE (exp),
+                    copy_constant (TREE_OPERAND (exp, 0)),
+                    copy_constant (TREE_OPERAND (exp, 1)));
 
     case NOP_EXPR:
     case CONVERT_EXPR:
@@ -2312,21 +2651,16 @@ copy_constant (tree exp)
        CONSTRUCTOR_ELTS (copy) = list;
        for (tail = list; tail; tail = TREE_CHAIN (tail))
          TREE_VALUE (tail) = copy_constant (TREE_VALUE (tail));
-       if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
-         for (tail = list; tail; tail = TREE_CHAIN (tail))
-           TREE_PURPOSE (tail) = copy_constant (TREE_PURPOSE (tail));
 
        return copy;
       }
 
     default:
       {
-       tree t;
-       t = lang_hooks.expand_constant (exp);
-       if (t != exp)
-         return copy_constant (t);
-       else
-         abort ();
+       tree t = lang_hooks.expand_constant (exp);
+       
+       gcc_assert (t == exp);
+       return copy_constant (t);
       }
     }
 }
@@ -2350,6 +2684,10 @@ build_constant_desc (tree exp)
   desc = ggc_alloc (sizeof (*desc));
   desc->value = copy_constant (exp);
 
+  /* Propagate marked-ness to copied constant.  */
+  if (flag_mudflap && mf_marked_p (exp))
+    mf_mark (desc->value);
+
   /* Create a string containing the label name, in LABEL.  */
   labelno = const_labelno++;
   ASM_GENERATE_INTERNAL_LABEL (label, "LC", labelno);
@@ -2401,12 +2739,14 @@ output_constant_def (tree exp, int defer)
   /* Look up EXP in the table of constant descriptors.  If we didn't find
      it, create a new one.  */
   key.value = exp;
-  loc = htab_find_slot (const_desc_htab, &key, INSERT);
+  key.hash = const_hash_1 (exp);
+  loc = htab_find_slot_with_hash (const_desc_htab, &key, key.hash, INSERT);
 
   desc = *loc;
   if (desc == 0)
     {
       desc = build_constant_desc (exp);
+      desc->hash = key.hash;
       *loc = desc;
     }
 
@@ -2461,7 +2801,7 @@ output_constant_def_contents (rtx symbol)
   int reloc = compute_reloc_for_constant (exp);
 
   /* Align the location counter as required by EXP's data type.  */
-  int align = TYPE_ALIGN (TREE_TYPE (exp));
+  unsigned int align = TYPE_ALIGN (TREE_TYPE (exp));
 #ifdef CONSTANT_ALIGNMENT
   align = CONSTANT_ALIGNMENT (exp, align);
 #endif
@@ -2495,15 +2835,8 @@ output_constant_def_contents (rtx symbol)
 
   /* Output the value of EXP.  */
   output_constant (exp, size, align);
-}
-
-/* A constant which was deferred in its original location has been
-   inserted by the RTL inliner into a different function.  The
-   current function's deferred constant count must be incremented.  */
-void
-notice_rtl_inlining_of_deferred_constant (void)
-{
-  n_deferred_constants++;
+  if (flag_mudflap)
+    mudflap_enqueue_constant (exp);
 }
 
 /* Look up EXP in the table of constant descriptors.  Return the rtl
@@ -2516,7 +2849,8 @@ lookup_constant_def (tree exp)
   struct constant_descriptor_tree key;
 
   key.value = exp;
-  desc = htab_find (const_desc_htab, &key);
+  key.hash = const_hash_1 (exp);
+  desc = htab_find_with_hash (const_desc_htab, &key, key.hash);
 
   return (desc ? desc->rtl : NULL_RTX);
 }
@@ -2642,6 +2976,14 @@ const_rtx_hash_1 (rtx *xp, void *data)
        h ^= real_hash (CONST_DOUBLE_REAL_VALUE (x));
       break;
 
+    case CONST_VECTOR:
+      {
+       int i;
+       for (i = XVECLEN (x, 0); i-- > 0; )
+         h = h * 251 + const_rtx_hash_1 (&XVECEXP (x, 0, i), data);
+      }
+      break;
+
     case SYMBOL_REF:
       h ^= htab_hash_string (XSTR (x, 0));
       break;
@@ -2783,14 +3125,13 @@ force_const_mem (enum machine_mode mode, rtx x)
 
   /* Insert the descriptor into the symbol cross-reference table too.  */
   slot = htab_find_slot (pool->const_rtx_sym_htab, desc, INSERT);
-  if (*slot)
-    abort ();
+  gcc_assert (!*slot);
   *slot = desc;
 
   /* Construct the MEM.  */
-  desc->mem = def = gen_rtx_MEM (mode, symbol);
+  desc->mem = def = gen_const_mem (mode, symbol);
   set_mem_attributes (def, lang_hooks.types.type_for_mode (mode, 0), 1);
-  RTX_UNCHANGING_P (def) = 1;
+  set_mem_align (def, align);
 
   /* If we're dropping a label to the constant pool, make sure we
      don't delete it.  */
@@ -2848,20 +3189,6 @@ get_pool_mode (rtx addr)
   return find_pool_constant (cfun->varasm->pool, addr)->mode;
 }
 
-enum machine_mode
-get_pool_mode_for_function (struct function *f, rtx addr)
-{
-  return find_pool_constant (f->varasm->pool, addr)->mode;
-}
-
-/* Similar, return the offset in the constant pool.  */
-
-int
-get_pool_offset (rtx addr)
-{
-  return find_pool_constant (cfun->varasm->pool, addr)->offset;
-}
-
 /* Return the size of the constant pool.  */
 
 int
@@ -2879,16 +3206,15 @@ output_constant_pool_2 (enum machine_mode mode, rtx x, unsigned int align)
   switch (GET_MODE_CLASS (mode))
     {
     case MODE_FLOAT:
-      if (GET_CODE (x) != CONST_DOUBLE)
-       abort ();
-      else
-       {
-         REAL_VALUE_TYPE r;
-         REAL_VALUE_FROM_CONST_DOUBLE (r, x);
-         assemble_real (r, mode, align);
-       }
-      break;
-
+      {
+       REAL_VALUE_TYPE r;
+       
+       gcc_assert (GET_CODE (x) == CONST_DOUBLE);
+       REAL_VALUE_FROM_CONST_DOUBLE (r, x);
+       assemble_real (r, mode, align);
+       break;
+      }
+      
     case MODE_INT:
     case MODE_PARTIAL_INT:
       assemble_integer (x, GET_MODE_SIZE (mode), align, 1);
@@ -2901,8 +3227,7 @@ output_constant_pool_2 (enum machine_mode mode, rtx x, unsigned int align)
         enum machine_mode submode = GET_MODE_INNER (mode);
        unsigned int subalign = MIN (align, GET_MODE_BITSIZE (submode));
 
-       if (GET_CODE (x) != CONST_VECTOR)
-         abort ();
+       gcc_assert (GET_CODE (x) == CONST_VECTOR);
        units = CONST_VECTOR_NUNITS (x);
 
        for (i = 0; i < units; i++)
@@ -2914,7 +3239,7 @@ output_constant_pool_2 (enum machine_mode mode, rtx x, unsigned int align)
       break;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }
 
@@ -2950,13 +3275,9 @@ output_constant_pool_1 (struct constant_descriptor_rtx *desc)
 
     case LABEL_REF:
       tmp = XEXP (x, 0);
-      if (INSN_DELETED_P (tmp)
-         || (GET_CODE (tmp) == NOTE
-             && NOTE_LINE_NUMBER (tmp) == NOTE_INSN_DELETED))
-       {
-         abort ();
-         x = const0_rtx;
-       }
+      gcc_assert (!INSN_DELETED_P (tmp));
+      gcc_assert (!NOTE_P (tmp)
+                 || NOTE_LINE_NUMBER (tmp) != NOTE_INSN_DELETED);
       break;
 
     default:
@@ -3150,6 +3471,7 @@ compute_reloc_for_constant (tree exp)
     case NOP_EXPR:
     case CONVERT_EXPR:
     case NON_LVALUE_EXPR:
+    case VIEW_CONVERT_EXPR:
       reloc = compute_reloc_for_constant (TREE_OPERAND (exp, 0));
       break;
 
@@ -3190,8 +3512,11 @@ output_addressed_constants (tree exp)
           tem = TREE_OPERAND (tem, 0))
        ;
 
-      if (TREE_CODE_CLASS (TREE_CODE (tem)) == 'c'
-         || TREE_CODE (tem) == CONSTRUCTOR)
+      /* If we have an initialized CONST_DECL, retrieve the initializer.  */
+      if (TREE_CODE (tem) == CONST_DECL && DECL_INITIAL (tem))
+       tem = DECL_INITIAL (tem);
+
+      if (CONSTANT_CLASS_P (tem) || TREE_CODE (tem) == CONSTRUCTOR)
        output_constant_def (tem, 0);
       break;
 
@@ -3203,6 +3528,7 @@ output_addressed_constants (tree exp)
     case NOP_EXPR:
     case CONVERT_EXPR:
     case NON_LVALUE_EXPR:
+    case VIEW_CONVERT_EXPR:
       output_addressed_constants (TREE_OPERAND (exp, 0));
       break;
 
@@ -3273,7 +3599,20 @@ initializer_constant_valid_p (tree value, tree endtype)
 
     case ADDR_EXPR:
     case FDESC_EXPR:
-      return staticp (TREE_OPERAND (value, 0)) ? TREE_OPERAND (value, 0) : 0;
+      value = staticp (TREE_OPERAND (value, 0));
+      /* "&(*a).f" is like unto pointer arithmetic.  If "a" turns out to
+        be a constant, this is old-skool offsetof-like nonsense.  */
+      if (value
+         && TREE_CODE (value) == INDIRECT_REF
+         && TREE_CONSTANT (TREE_OPERAND (value, 0)))
+       return null_pointer_node;
+      /* Taking the address of a nested function involves a trampoline.  */
+      if (value
+         && TREE_CODE (value) == FUNCTION_DECL
+         && ((decl_function_context (value) && !DECL_NO_STATIC_CHAIN (value))
+             || DECL_NON_ADDR_CONST_P (value)))
+       return NULL_TREE;
+      return value;
 
     case VIEW_CONVERT_EXPR:
     case NON_LVALUE_EXPR:
@@ -3281,61 +3620,61 @@ initializer_constant_valid_p (tree value, tree endtype)
 
     case CONVERT_EXPR:
     case NOP_EXPR:
-      /* Allow conversions between pointer types.  */
-      if (POINTER_TYPE_P (TREE_TYPE (value))
-         && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
-       return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
-
-      /* Allow conversions between real types.  */
-      if (FLOAT_TYPE_P (TREE_TYPE (value))
-         && FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
-       return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
-
-      /* Allow length-preserving conversions between integer types.  */
-      if (INTEGRAL_TYPE_P (TREE_TYPE (value))
-         && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0)))
-         && (TYPE_PRECISION (TREE_TYPE (value))
-             == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
-       return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
-
-      /* Allow conversions between other integer types only if
-        explicit value.  */
-      if (INTEGRAL_TYPE_P (TREE_TYPE (value))
-         && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
-       {
-         tree inner = initializer_constant_valid_p (TREE_OPERAND (value, 0),
-                                                    endtype);
-         if (inner == null_pointer_node)
-           return null_pointer_node;
-         break;
-       }
+      {
+       tree src;
+       tree src_type;
+       tree dest_type;
+
+       src = TREE_OPERAND (value, 0);
+       src_type = TREE_TYPE (src);
+       dest_type = TREE_TYPE (value);
+
+       /* Allow conversions between pointer types, floating-point
+          types, and offset types.  */
+       if ((POINTER_TYPE_P (dest_type) && POINTER_TYPE_P (src_type))
+           || (FLOAT_TYPE_P (dest_type) && FLOAT_TYPE_P (src_type))
+           || (TREE_CODE (dest_type) == OFFSET_TYPE
+               && TREE_CODE (src_type) == OFFSET_TYPE))
+         return initializer_constant_valid_p (src, endtype);
+
+       /* Allow length-preserving conversions between integer types.  */
+       if (INTEGRAL_TYPE_P (dest_type) && INTEGRAL_TYPE_P (src_type)
+           && (TYPE_PRECISION (dest_type) == TYPE_PRECISION (src_type)))
+         return initializer_constant_valid_p (src, endtype);
+
+       /* Allow conversions between other integer types only if
+          explicit value.  */
+       if (INTEGRAL_TYPE_P (dest_type) && INTEGRAL_TYPE_P (src_type))
+         {
+           tree inner = initializer_constant_valid_p (src, endtype);
+           if (inner == null_pointer_node)
+             return null_pointer_node;
+           break;
+         }
 
-      /* Allow (int) &foo provided int is as wide as a pointer.  */
-      if (INTEGRAL_TYPE_P (TREE_TYPE (value))
-         && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0)))
-         && (TYPE_PRECISION (TREE_TYPE (value))
-             >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
-       return initializer_constant_valid_p (TREE_OPERAND (value, 0),
-                                            endtype);
-
-      /* Likewise conversions from int to pointers, but also allow
-        conversions from 0.  */
-      if ((POINTER_TYPE_P (TREE_TYPE (value))
-          || TREE_CODE (TREE_TYPE (value)) == OFFSET_TYPE)
-         && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
-       {
-         if (integer_zerop (TREE_OPERAND (value, 0)))
-           return null_pointer_node;
-         else if (TYPE_PRECISION (TREE_TYPE (value))
-                  <= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0))))
-           return initializer_constant_valid_p (TREE_OPERAND (value, 0),
-                                                endtype);
-       }
+       /* Allow (int) &foo provided int is as wide as a pointer.  */
+       if (INTEGRAL_TYPE_P (dest_type) && POINTER_TYPE_P (src_type)
+           && (TYPE_PRECISION (dest_type) >= TYPE_PRECISION (src_type)))
+         return initializer_constant_valid_p (src, endtype);
 
-      /* Allow conversions to union types if the value inside is okay.  */
-      if (TREE_CODE (TREE_TYPE (value)) == UNION_TYPE)
-       return initializer_constant_valid_p (TREE_OPERAND (value, 0),
-                                            endtype);
+       /* Likewise conversions from int to pointers, but also allow
+          conversions from 0.  */
+       if ((POINTER_TYPE_P (dest_type)
+            || TREE_CODE (dest_type) == OFFSET_TYPE)
+           && INTEGRAL_TYPE_P (src_type))
+         {
+           if (integer_zerop (src))
+             return null_pointer_node;
+           else if (TYPE_PRECISION (dest_type) <= TYPE_PRECISION (src_type))
+             return initializer_constant_valid_p (src, endtype);
+         }
+
+       /* Allow conversions to struct or union types if the value
+          inside is okay.  */
+       if (TREE_CODE (dest_type) == RECORD_TYPE
+           || TREE_CODE (dest_type) == UNION_TYPE)
+         return initializer_constant_valid_p (src, endtype);
+      }
       break;
 
     case PLUS_EXPR:
@@ -3373,16 +3712,17 @@ initializer_constant_valid_p (tree value, tree endtype)
          /* Since GCC guarantees that string constants are unique in the
             generated code, a subtraction between two copies of the same
             constant string is absolute.  */
-         if (valid0 && TREE_CODE (valid0) == STRING_CST &&
-             valid1 && TREE_CODE (valid1) == STRING_CST &&
-             TREE_STRING_POINTER (valid0) == TREE_STRING_POINTER (valid1))
+         if (valid0 && TREE_CODE (valid0) == STRING_CST
+             && valid1 && TREE_CODE (valid1) == STRING_CST
+             && operand_equal_p (valid0, valid1, 1))
            return null_pointer_node;
        }
 
-      /* Support differences between labels.  */
+      /* Support narrowing differences.  */
       if (INTEGRAL_TYPE_P (endtype))
        {
          tree op0, op1;
+
          op0 = TREE_OPERAND (value, 0);
          op1 = TREE_OPERAND (value, 1);
 
@@ -3417,11 +3757,25 @@ initializer_constant_valid_p (tree value, tree endtype)
              op1 = inner;
            }
 
-         if (TREE_CODE (op0) == ADDR_EXPR
-             && TREE_CODE (TREE_OPERAND (op0, 0)) == LABEL_DECL
-             && TREE_CODE (op1) == ADDR_EXPR
-             && TREE_CODE (TREE_OPERAND (op1, 0)) == LABEL_DECL)
-           return null_pointer_node;
+         op0 = initializer_constant_valid_p (op0, endtype);
+         op1 = initializer_constant_valid_p (op1, endtype);
+
+         /* Both initializers must be known.  */
+         if (op0 && op1)
+           {
+             if (op0 == op1)
+               return null_pointer_node;
+
+             /* Support differences between labels.  */
+             if (TREE_CODE (op0) == LABEL_DECL
+                 && TREE_CODE (op1) == LABEL_DECL)
+               return null_pointer_node;
+
+             if (TREE_CODE (op0) == STRING_CST
+                 && TREE_CODE (op1) == STRING_CST
+                 && operand_equal_p (op0, op1, 1))
+               return null_pointer_node;
+           }
        }
       break;
 
@@ -3491,13 +3845,13 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align)
       tree decl = TREE_OPERAND (exp, 0);
       ASM_OUTPUT_FDESC (asm_out_file, decl, part);
 #else
-      abort ();
+      gcc_unreachable ();
 #endif
       return;
     }
 
   /* Now output the underlying data.  If we've handling the padding, return.
-     Otherwise, break and ensure THISSIZE is the size written.  */
+     Otherwise, break and ensure SIZE is the size written.  */
   switch (code)
     {
     case CHAR_TYPE:
@@ -3509,7 +3863,7 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align)
     case OFFSET_TYPE:
       if (! assemble_integer (expand_expr (exp, NULL_RTX, VOIDmode,
                                           EXPAND_INITIALIZER),
-                             size, align, 0))
+                             MIN (size, thissize), align, 0))
        error ("initializer for integer value is too complicated");
       break;
 
@@ -3528,67 +3882,51 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align)
 
     case ARRAY_TYPE:
     case VECTOR_TYPE:
-      if (TREE_CODE (exp) == CONSTRUCTOR)
+      switch (TREE_CODE (exp))
        {
+       case CONSTRUCTOR:
          output_constructor (exp, size, align);
          return;
-       }
-      else if (TREE_CODE (exp) == STRING_CST)
-       {
+       case STRING_CST:
          thissize = MIN ((unsigned HOST_WIDE_INT)TREE_STRING_LENGTH (exp),
                          size);
          assemble_string (TREE_STRING_POINTER (exp), thissize);
-       }
-      else if (TREE_CODE (exp) == VECTOR_CST)
-       {
-         int elt_size;
-         tree link;
-         unsigned int nalign;
-         enum machine_mode inner;
-
-         inner = GET_MODE_INNER (TYPE_MODE (TREE_TYPE (exp)));
-         nalign = MIN (align, GET_MODE_ALIGNMENT (inner));
-
-         elt_size = GET_MODE_UNIT_SIZE (TYPE_MODE (TREE_TYPE (exp)));
+         break;
 
-         link = TREE_VECTOR_CST_ELTS (exp);
-         output_constant (TREE_VALUE (link), elt_size, align);
-         while ((link = TREE_CHAIN (link)) != NULL)
-           output_constant (TREE_VALUE (link), elt_size, nalign);
+       case VECTOR_CST:
+         {
+           int elt_size;
+           tree link;
+           unsigned int nalign;
+           enum machine_mode inner;
+           
+           inner = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
+           nalign = MIN (align, GET_MODE_ALIGNMENT (inner));
+           
+           elt_size = GET_MODE_SIZE (inner);
+           
+           link = TREE_VECTOR_CST_ELTS (exp);
+           output_constant (TREE_VALUE (link), elt_size, align);
+           while ((link = TREE_CHAIN (link)) != NULL)
+             output_constant (TREE_VALUE (link), elt_size, nalign);
+           break;
+         }
+       default:
+         gcc_unreachable ();
        }
-      else
-       abort ();
       break;
 
     case RECORD_TYPE:
     case UNION_TYPE:
-      if (TREE_CODE (exp) == CONSTRUCTOR)
-       output_constructor (exp, size, align);
-      else
-       abort ();
-      return;
-
-    case SET_TYPE:
-      if (TREE_CODE (exp) == INTEGER_CST)
-       assemble_integer (expand_expr (exp, NULL_RTX,
-                                      VOIDmode, EXPAND_INITIALIZER),
-                         thissize, align, 1);
-      else if (TREE_CODE (exp) == CONSTRUCTOR)
-       {
-         unsigned char *buffer = alloca (thissize);
-         if (get_set_constructor_bytes (exp, buffer, thissize))
-           abort ();
-         assemble_string ((char *) buffer, thissize);
-       }
-      else
-       error ("unknown set constructor type");
+      gcc_assert (TREE_CODE (exp) == CONSTRUCTOR);
+      output_constructor (exp, size, align);
       return;
 
     case ERROR_MARK:
       return;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
   if (size > thissize)
@@ -3654,8 +3992,7 @@ output_constructor (tree exp, unsigned HOST_WIDE_INT size,
   int byte_buffer_in_use = 0;
   int byte = 0;
 
-  if (HOST_BITS_PER_WIDE_INT < BITS_PER_UNIT)
-    abort ();
+  gcc_assert (HOST_BITS_PER_WIDE_INT >= BITS_PER_UNIT);
 
   if (TREE_CODE (type) == RECORD_TYPE)
     field = TYPE_FIELDS (type);
@@ -3776,8 +4113,7 @@ output_constructor (tree exp, unsigned HOST_WIDE_INT size,
                  fieldsize = array_size_for_constructor (val);
                  /* Given a non-empty initialization, this field had
                     better be last.  */
-                 if (fieldsize != 0 && TREE_CHAIN (field) != NULL_TREE)
-                   abort ();
+                 gcc_assert (!fieldsize || !TREE_CHAIN (field));
                }
              else if (DECL_SIZE_UNIT (field))
                {
@@ -3800,7 +4136,7 @@ output_constructor (tree exp, unsigned HOST_WIDE_INT size,
          total_bytes += fieldsize;
        }
       else if (val != 0 && TREE_CODE (val) != INTEGER_CST)
-       error ("invalid initial value for member `%s'",
+       error ("invalid initial value for member %qs",
               IDENTIFIER_POINTER (DECL_NAME (field)));
       else
        {
@@ -3886,13 +4222,12 @@ output_constructor (tree exp, unsigned HOST_WIDE_INT size,
                  /* Now get the bits from the appropriate constant word.  */
                  if (shift < HOST_BITS_PER_WIDE_INT)
                    value = TREE_INT_CST_LOW (val);
-                 else if (shift < 2 * HOST_BITS_PER_WIDE_INT)
+                 else
                    {
+                     gcc_assert (shift < 2 * HOST_BITS_PER_WIDE_INT);
                      value = TREE_INT_CST_HIGH (val);
                      shift -= HOST_BITS_PER_WIDE_INT;
                    }
-                 else
-                   abort ();
 
                  /* Get the result. This works only when:
                     1 <= this_time <= HOST_BITS_PER_WIDE_INT.  */
@@ -3919,13 +4254,12 @@ output_constructor (tree exp, unsigned HOST_WIDE_INT size,
                  /* Now get the bits from the appropriate constant word.  */
                  if (shift < HOST_BITS_PER_WIDE_INT)
                    value = TREE_INT_CST_LOW (val);
-                 else if (shift < 2 * HOST_BITS_PER_WIDE_INT)
+                 else
                    {
+                     gcc_assert (shift < 2 * HOST_BITS_PER_WIDE_INT);
                      value = TREE_INT_CST_HIGH (val);
                      shift -= HOST_BITS_PER_WIDE_INT;
                    }
-                 else
-                   abort ();
 
                  /* Get the result. This works only when:
                     1 <= this_time <= HOST_BITS_PER_WIDE_INT.  */
@@ -3962,7 +4296,7 @@ mark_weak (tree decl)
   DECL_WEAK (decl) = 1;
 
   if (DECL_RTL_SET_P (decl)
-      && GET_CODE (DECL_RTL (decl)) == MEM
+      && MEM_P (DECL_RTL (decl))
       && XEXP (DECL_RTL (decl), 0)
       && GET_CODE (XEXP (DECL_RTL (decl), 0)) == SYMBOL_REF)
     SYMBOL_REF_WEAK (XEXP (DECL_RTL (decl), 0)) = 1;
@@ -3974,7 +4308,21 @@ void
 merge_weak (tree newdecl, tree olddecl)
 {
   if (DECL_WEAK (newdecl) == DECL_WEAK (olddecl))
-    return;
+    {
+      if (DECL_WEAK (newdecl) && SUPPORTS_WEAK)
+        {
+          tree *pwd;
+          /* We put the NEWDECL on the weak_decls list at some point
+             and OLDDECL as well.  Keep just OLDDECL on the list.  */
+         for (pwd = &weak_decls; *pwd; pwd = &TREE_CHAIN (*pwd))
+           if (TREE_VALUE (*pwd) == newdecl)
+             {
+               *pwd = TREE_CHAIN (*pwd);
+               break;
+             }
+        }
+      return;
+    }
 
   if (DECL_WEAK (newdecl))
     {
@@ -3987,7 +4335,7 @@ merge_weak (tree newdecl, tree olddecl)
         declare_weak because the NEWDECL and OLDDECL was not yet
         been merged; therefore, TREE_ASM_WRITTEN was not set.  */
       if (TREE_ASM_WRITTEN (olddecl))
-       error ("%Jweak declaration of '%D' must precede definition",
+       error ("%Jweak declaration of %qD must precede definition",
               newdecl, newdecl);
 
       /* If we've already generated rtl referencing OLDDECL, we may
@@ -3995,7 +4343,7 @@ merge_weak (tree newdecl, tree olddecl)
         a weak symbol.  */
       else if (TREE_USED (olddecl)
               && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (olddecl)))
-       warning ("%Jweak declaration of '%D' after first use results "
+       warning (0, "%Jweak declaration of %qD after first use results "
                  "in unspecified behavior", newdecl, newdecl);
 
       if (SUPPORTS_WEAK)
@@ -4029,16 +4377,16 @@ void
 declare_weak (tree decl)
 {
   if (! TREE_PUBLIC (decl))
-    error ("%Jweak declaration of '%D' must be public", decl, decl);
+    error ("%Jweak declaration of %qD must be public", decl, decl);
   else if (TREE_CODE (decl) == FUNCTION_DECL && TREE_ASM_WRITTEN (decl))
-    error ("%Jweak declaration of '%D' must precede definition", decl, decl);
+    error ("%Jweak declaration of %qD must precede definition", decl, decl);
   else if (SUPPORTS_WEAK)
     {
       if (! DECL_WEAK (decl))
        weak_decls = tree_cons (NULL, decl, weak_decls);
     }
   else
-    warning ("%Jweak declaration of '%D' not supported", decl, decl);
+    warning (0, "%Jweak declaration of %qD not supported", decl, decl);
 
   mark_weak (decl);
 }
@@ -4067,7 +4415,7 @@ weak_finish (void)
       ASM_WEAKEN_LABEL (asm_out_file, name);
 #else
 #ifdef ASM_OUTPUT_WEAK_ALIAS
-      warning ("only weak aliases are supported in this configuration");
+      warning (0, "only weak aliases are supported in this configuration");
       return;
 #endif
 #endif
@@ -4112,19 +4460,75 @@ globalize_decl (tree decl)
   targetm.asm_out.globalize_label (asm_out_file, name);
 }
 
-/* Emit an assembler directive to make the symbol for DECL an alias to
-   the symbol for TARGET.  */
+/* We have to be able to tell cgraph about the needed-ness of the target
+   of an alias.  This requires that the decl have been defined.  Aliases
+   that precede their definition have to be queued for later processing.  */
 
-void
-assemble_alias (tree decl, tree target ATTRIBUTE_UNUSED)
+typedef struct alias_pair GTY(())
 {
-  const char *name;
+  tree decl;
+  tree target;
+} alias_pair;
 
-  /* We must force creation of DECL_RTL for debug info generation, even though
-     we don't use it here.  */
-  make_decl_rtl (decl, NULL);
+/* Define gc'd vector type.  */
+DEF_VEC_O(alias_pair);
+DEF_VEC_ALLOC_O(alias_pair,gc);
 
-  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+static GTY(()) VEC(alias_pair,gc) *alias_pairs;
+
+/* Given an assembly name, find the decl it is associated with.  At the
+   same time, mark it needed for cgraph.  */
+
+static tree
+find_decl_and_mark_needed (tree decl, tree target)
+{
+  struct cgraph_node *fnode = NULL;
+  struct cgraph_varpool_node *vnode = NULL;
+
+  /* C++ thunk emitting code produces aliases late in the game.
+     Avoid confusing cgraph code in that case.  */
+  if (!cgraph_global_info_ready)
+    {
+      if (TREE_CODE (decl) == FUNCTION_DECL)
+       {
+         fnode = cgraph_node_for_asm (target);
+         if (fnode == NULL)
+           vnode = cgraph_varpool_node_for_asm (target);
+       }
+      else
+       {
+         vnode = cgraph_varpool_node_for_asm (target);
+         if (vnode == NULL)
+           fnode = cgraph_node_for_asm (target);
+       }
+    }
+
+  if (fnode)
+    {
+      cgraph_mark_needed_node (fnode);
+      return fnode->decl;
+    }
+  else if (vnode)
+    {
+      cgraph_varpool_mark_needed_node (vnode);
+      return vnode->decl;
+    }
+  else 
+    return NULL_TREE;
+}
+
+/* Output the assembler code for a define (equate) using ASM_OUTPUT_DEF
+   or ASM_OUTPUT_DEF_FROM_DECLS.  The function defines the symbol whose
+   tree node is DECL to have the value of the tree node TARGET.  */
+
+static void
+do_assemble_alias (tree decl, tree target ATTRIBUTE_UNUSED)
+{
+  if (TREE_ASM_WRITTEN (decl))
+    return;
+
+  TREE_ASM_WRITTEN (decl) = 1;
+  TREE_ASM_WRITTEN (DECL_ASSEMBLER_NAME (decl)) = 1;
 
 #ifdef ASM_OUTPUT_DEF
   /* Make name accessible from other files, if appropriate.  */
@@ -4135,41 +4539,122 @@ assemble_alias (tree decl, tree target ATTRIBUTE_UNUSED)
       maybe_assemble_visibility (decl);
     }
 
-#ifdef ASM_OUTPUT_DEF_FROM_DECLS
+# ifdef ASM_OUTPUT_DEF_FROM_DECLS
   ASM_OUTPUT_DEF_FROM_DECLS (asm_out_file, decl, target);
-#else
-  ASM_OUTPUT_DEF (asm_out_file, name, IDENTIFIER_POINTER (target));
+# else
+  ASM_OUTPUT_DEF (asm_out_file,
+                 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
+                 IDENTIFIER_POINTER (target));
+# endif
+#elif defined (ASM_OUTPUT_WEAK_ALIAS) || defined (ASM_WEAKEN_DECL)
+  {
+    const char *name;
+    tree *p, t;
+
+    name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+# ifdef ASM_WEAKEN_DECL
+    ASM_WEAKEN_DECL (asm_out_file, decl, name, IDENTIFIER_POINTER (target));
+# else
+    ASM_OUTPUT_WEAK_ALIAS (asm_out_file, name, IDENTIFIER_POINTER (target));
+# endif
+    /* Remove this function from the pending weak list so that
+       we do not emit multiple .weak directives for it.  */
+    for (p = &weak_decls; (t = *p) ; )
+      if (DECL_ASSEMBLER_NAME (decl) == DECL_ASSEMBLER_NAME (TREE_VALUE (t)))
+       *p = TREE_CHAIN (t);
+      else
+       p = &TREE_CHAIN (t);
+  }
 #endif
-#else /* !ASM_OUTPUT_DEF */
-#if defined (ASM_OUTPUT_WEAK_ALIAS) || defined (ASM_WEAKEN_DECL)
-  if (DECL_WEAK (decl))
+}
+
+/* First pass of completing pending aliases.  Make sure that cgraph knows
+   which symbols will be required.  */
+
+void
+finish_aliases_1 (void)
+{
+  unsigned i;
+  alias_pair *p;
+
+  for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); i++)
     {
-      tree *p, t;
-#ifdef ASM_WEAKEN_DECL
-      ASM_WEAKEN_DECL (asm_out_file, decl, name, IDENTIFIER_POINTER (target));
-#else
-      ASM_OUTPUT_WEAK_ALIAS (asm_out_file, name, IDENTIFIER_POINTER (target));
-#endif
-      /* Remove this function from the pending weak list so that
-        we do not emit multiple .weak directives for it.  */
-      for (p = &weak_decls; (t = *p) ; )
-       if (DECL_ASSEMBLER_NAME (decl)
-           == DECL_ASSEMBLER_NAME (TREE_VALUE (t)))
-         *p = TREE_CHAIN (t);
-       else
-         p = &TREE_CHAIN (t);
+      tree target_decl;
+
+      target_decl = find_decl_and_mark_needed (p->decl, p->target);
+      if (target_decl == NULL)
+       error ("%J%qD aliased to undefined symbol %qE",
+              p->decl, p->decl, p->target);
+      else if (DECL_EXTERNAL (target_decl))
+       error ("%J%qD aliased to external symbol %qE",
+              p->decl, p->decl, p->target);
     }
-  else
-    warning ("only weak aliases are supported in this configuration");
+}
 
-#else
-  warning ("alias definitions not supported in this configuration; ignored");
-#endif
+/* Second pass of completing pending aliases.  Emit the actual assembly.
+   This happens at the end of compilation and thus it is assured that the
+   target symbol has been emitted.  */
+
+void
+finish_aliases_2 (void)
+{
+  unsigned i;
+  alias_pair *p;
+
+  for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); i++)
+    do_assemble_alias (p->decl, p->target);
+
+  VEC_truncate (alias_pair, alias_pairs, 0);
+}
+
+/* Emit an assembler directive to make the symbol for DECL an alias to
+   the symbol for TARGET.  */
+
+void
+assemble_alias (tree decl, tree target)
+{
+  tree target_decl;
+
+#if !defined (ASM_OUTPUT_DEF)
+# if !defined(ASM_OUTPUT_WEAK_ALIAS) && !defined (ASM_WEAKEN_DECL)
+  error ("%Jalias definitions not supported in this configuration", decl);
+  return;
+# else
+  if (!DECL_WEAK (decl))
+    {
+      error ("%Jonly weak aliases are supported in this configuration", decl);
+      return;
+    }
+# endif
 #endif
 
+  /* We must force creation of DECL_RTL for debug info generation, even though
+     we don't use it here.  */
+  make_decl_rtl (decl);
   TREE_USED (decl) = 1;
-  TREE_ASM_WRITTEN (decl) = 1;
-  TREE_ASM_WRITTEN (DECL_ASSEMBLER_NAME (decl)) = 1;
+
+  /* A quirk of the initial implementation of aliases required that the user
+     add "extern" to all of them.  Which is silly, but now historical.  Do
+     note that the symbol is in fact locally defined.  */
+  DECL_EXTERNAL (decl) = 0;
+
+  /* Allow aliases to aliases.  */
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    cgraph_node (decl)->alias = true;
+  else
+    cgraph_varpool_node (decl)->alias = true;
+
+  /* If the target has already been emitted, we don't have to queue the
+     alias.  This saves a tad o memory.  */
+  target_decl = find_decl_and_mark_needed (decl, target);
+  if (target_decl && TREE_ASM_WRITTEN (target_decl))
+    do_assemble_alias (decl, target);
+  else
+    {
+      alias_pair *p = VEC_safe_push (alias_pair, gc, alias_pairs, NULL);
+      p->decl = decl;
+      p->target = target;
+    }
 }
 
 /* Emit an assembler directive to set symbol for DECL visibility to
@@ -4184,7 +4669,7 @@ default_assemble_visibility (tree decl, int vis)
 
   const char *name, *type;
 
-  name = (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
+  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
   type = visibility_types[vis];
 
 #ifdef HAVE_GAS_HIDDEN
@@ -4192,7 +4677,8 @@ default_assemble_visibility (tree decl, int vis)
   assemble_name (asm_out_file, name);
   fprintf (asm_out_file, "\n");
 #else
-  warning ("visibility attribute not supported in this configuration; ignored");
+  warning (OPT_Wattributes, "visibility attribute not supported "
+          "in this configuration; ignored");
 #endif
 }
 
@@ -4226,8 +4712,8 @@ supports_one_only (void)
 void
 make_decl_one_only (tree decl)
 {
-  if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL)
-    abort ();
+  gcc_assert (TREE_CODE (decl) == VAR_DECL
+             || TREE_CODE (decl) == FUNCTION_DECL);
 
   TREE_PUBLIC (decl) = 1;
 
@@ -4241,10 +4727,11 @@ make_decl_one_only (tree decl)
   else if (TREE_CODE (decl) == VAR_DECL
       && (DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node))
     DECL_COMMON (decl) = 1;
-  else if (SUPPORTS_WEAK)
-    DECL_WEAK (decl) = 1;
   else
-    abort ();
+    {
+      gcc_assert (SUPPORTS_WEAK);
+      DECL_WEAK (decl) = 1;
+    }
 }
 
 void
@@ -4258,7 +4745,7 @@ init_varasm_once (void)
   const_alias_set = new_alias_set ();
 }
 
-enum tls_model
+static enum tls_model
 decl_tls_model (tree decl)
 {
   enum tls_model kind;
@@ -4268,8 +4755,8 @@ decl_tls_model (tree decl)
   if (attr)
     {
       attr = TREE_VALUE (TREE_VALUE (attr));
-      if (TREE_CODE (attr) != STRING_CST)
-       abort ();
+      gcc_assert (TREE_CODE (attr) == STRING_CST);
+      
       if (!strcmp (TREE_STRING_POINTER (attr), "local-exec"))
        kind = TLS_MODEL_LOCAL_EXEC;
       else if (!strcmp (TREE_STRING_POINTER (attr), "initial-exec"))
@@ -4279,12 +4766,12 @@ decl_tls_model (tree decl)
       else if (!strcmp (TREE_STRING_POINTER (attr), "global-dynamic"))
        kind = TLS_MODEL_GLOBAL_DYNAMIC;
       else
-       abort ();
+       gcc_unreachable ();
       return kind;
     }
 
   is_local = targetm.binds_local_p (decl);
-  if (!flag_pic)
+  if (!flag_shlib)
     {
       if (is_local)
        kind = TLS_MODEL_LOCAL_EXEC;
@@ -4326,6 +4813,15 @@ default_section_type_flags_1 (tree decl, const char *name, int reloc,
     flags = SECTION_CODE;
   else if (decl && decl_readonly_section_1 (decl, reloc, shlib))
     flags = 0;
+  else if (current_function_decl
+          && cfun
+          && cfun->unlikely_text_section_name
+          && strcmp (name, cfun->unlikely_text_section_name) == 0)
+    flags = SECTION_CODE;
+  else if (!decl 
+          && (!current_function_decl || !cfun)
+          && strcmp (name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0)
+    flags = SECTION_CODE; 
   else
     flags = SECTION_WRITE;
 
@@ -4340,17 +4836,19 @@ default_section_type_flags_1 (tree decl, const char *name, int reloc,
       || strncmp (name, ".gnu.linkonce.b.", 16) == 0
       || strcmp (name, ".sbss") == 0
       || strncmp (name, ".sbss.", 6) == 0
-      || strncmp (name, ".gnu.linkonce.sb.", 17) == 0
-      || strcmp (name, ".tbss") == 0
-      || strncmp (name, ".gnu.linkonce.tb.", 17) == 0)
+      || strncmp (name, ".gnu.linkonce.sb.", 17) == 0)
     flags |= SECTION_BSS;
 
   if (strcmp (name, ".tdata") == 0
-      || strcmp (name, ".tbss") == 0
-      || strncmp (name, ".gnu.linkonce.td.", 17) == 0
-      || strncmp (name, ".gnu.linkonce.tb.", 17) == 0)
+      || strncmp (name, ".tdata.", 7) == 0
+      || strncmp (name, ".gnu.linkonce.td.", 17) == 0)
     flags |= SECTION_TLS;
 
+  if (strcmp (name, ".tbss") == 0
+      || strncmp (name, ".tbss.", 6) == 0
+      || strncmp (name, ".gnu.linkonce.tb.", 17) == 0)
+    flags |= SECTION_TLS | SECTION_BSS;
+
   /* These three sections have special ELF types.  They are neither
      SHT_PROGBITS nor SHT_NOBITS, so when changing sections we don't
      want to print a section type (@progbits or @nobits).  If someone
@@ -4370,19 +4868,26 @@ default_section_type_flags_1 (tree decl, const char *name, int reloc,
 
 void
 default_no_named_section (const char *name ATTRIBUTE_UNUSED,
-                         unsigned int flags ATTRIBUTE_UNUSED)
+                         unsigned int flags ATTRIBUTE_UNUSED,
+                         tree decl ATTRIBUTE_UNUSED)
 {
   /* Some object formats don't support named sections at all.  The
      front-end should already have flagged this as an error.  */
-  abort ();
+  gcc_unreachable ();
 }
 
 void
-default_elf_asm_named_section (const char *name, unsigned int flags)
+default_elf_asm_named_section (const char *name, unsigned int flags,
+                              tree decl ATTRIBUTE_UNUSED)
 {
   char flagchars[10], *f = flagchars;
 
-  if (! named_section_first_declaration (name))
+  /* If we have already declared this section, we can use an
+     abbreviated form to switch back to it -- unless this section is
+     part of a COMDAT groups, in which case GAS requires the full
+     declaration every time.  */
+  if (!(HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))
+      && ! named_section_first_declaration (name))
     {
       fprintf (asm_out_file, "\t.section\t%s\n", name);
       return;
@@ -4402,6 +4907,8 @@ default_elf_asm_named_section (const char *name, unsigned int flags)
     *f++ = 'S';
   if (flags & SECTION_TLS)
     *f++ = 'T';
+  if (HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))
+    *f++ = 'G';
   *f = '\0';
 
   fprintf (asm_out_file, "\t.section\t%s,\"%s\"", name, flagchars);
@@ -4409,23 +4916,35 @@ default_elf_asm_named_section (const char *name, unsigned int flags)
   if (!(flags & SECTION_NOTYPE))
     {
       const char *type;
+      const char *format;
 
       if (flags & SECTION_BSS)
        type = "nobits";
       else
        type = "progbits";
 
-      fprintf (asm_out_file, ",@%s", type);
+      format = ",@%s";
+#ifdef ASM_COMMENT_START
+      /* On platforms that use "@" as the assembly comment character,
+        use "%" instead.  */
+      if (strcmp (ASM_COMMENT_START, "@") == 0)
+       format = ",%%%s";
+#endif
+      fprintf (asm_out_file, format, type);
 
       if (flags & SECTION_ENTSIZE)
        fprintf (asm_out_file, ",%d", flags & SECTION_ENTSIZE);
+      if (HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))
+       fprintf (asm_out_file, ",%s,comdat", 
+                lang_hooks.decls.comdat_group (decl));
     }
 
   putc ('\n', asm_out_file);
 }
 
 void
-default_coff_asm_named_section (const char *name, unsigned int flags)
+default_coff_asm_named_section (const char *name, unsigned int flags, 
+                               tree decl ATTRIBUTE_UNUSED)
 {
   char flagchars[8], *f = flagchars;
 
@@ -4439,9 +4958,10 @@ default_coff_asm_named_section (const char *name, unsigned int flags)
 }
 
 void
-default_pe_asm_named_section (const char *name, unsigned int flags)
+default_pe_asm_named_section (const char *name, unsigned int flags,
+                             tree decl)
 {
-  default_coff_asm_named_section (name, flags);
+  default_coff_asm_named_section (name, flags, decl);
 
   if (flags & SECTION_LINKONCE)
     {
@@ -4533,11 +5053,20 @@ categorize_decl_for_section (tree decl, int reloc, int shlib)
   if (TREE_CODE (decl) == FUNCTION_DECL)
     return SECCAT_TEXT;
   else if (TREE_CODE (decl) == STRING_CST)
-    return SECCAT_RODATA_MERGE_STR;
+    {
+      if (flag_mudflap) /* or !flag_merge_constants */
+        return SECCAT_RODATA;
+      else
+       return SECCAT_RODATA_MERGE_STR;
+    }
   else if (TREE_CODE (decl) == VAR_DECL)
     {
       if (DECL_INITIAL (decl) == NULL
-         || DECL_INITIAL (decl) == error_mark_node)
+         || DECL_INITIAL (decl) == error_mark_node
+         || (flag_zero_initialized_in_bss
+             /* Leave constant zeroes in .rodata so they can be shared.  */
+             && !TREE_READONLY (decl)
+             && initializer_zerop (DECL_INITIAL (decl))))
        ret = SECCAT_BSS;
       else if (! TREE_READONLY (decl)
               || TREE_SIDE_EFFECTS (decl)
@@ -4579,7 +5108,11 @@ categorize_decl_for_section (tree decl, int reloc, int shlib)
   /* There are no read-only thread-local sections.  */
   if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
     {
-      if (ret == SECCAT_BSS)
+      /* Note that this would be *just* SECCAT_BSS, except that there's
+        no concept of a read-only thread-local-data section.  */
+      if (ret == SECCAT_BSS
+         || (flag_zero_initialized_in_bss
+             && initializer_zerop (DECL_INITIAL (decl))))
        ret = SECCAT_TBSS;
       else
        ret = SECCAT_TDATA;
@@ -4636,63 +5169,69 @@ void
 default_elf_select_section_1 (tree decl, int reloc,
                              unsigned HOST_WIDE_INT align, int shlib)
 {
+  const char *sname;
   switch (categorize_decl_for_section (decl, reloc, shlib))
     {
     case SECCAT_TEXT:
       /* We're not supposed to be called on FUNCTION_DECLs.  */
-      abort ();
+      gcc_unreachable ();
     case SECCAT_RODATA:
       readonly_data_section ();
-      break;
+      return;
     case SECCAT_RODATA_MERGE_STR:
       mergeable_string_section (decl, align, 0);
-      break;
+      return;
     case SECCAT_RODATA_MERGE_STR_INIT:
       mergeable_string_section (DECL_INITIAL (decl), align, 0);
-      break;
+      return;
     case SECCAT_RODATA_MERGE_CONST:
       mergeable_constant_section (DECL_MODE (decl), align, 0);
-      break;
+      return;
     case SECCAT_SRODATA:
-      named_section (NULL_TREE, ".sdata2", reloc);
+      sname = ".sdata2";
       break;
     case SECCAT_DATA:
       data_section ();
-      break;
+      return;
     case SECCAT_DATA_REL:
-      named_section (NULL_TREE, ".data.rel", reloc);
+      sname = ".data.rel";
       break;
     case SECCAT_DATA_REL_LOCAL:
-      named_section (NULL_TREE, ".data.rel.local", reloc);
+      sname = ".data.rel.local";
       break;
     case SECCAT_DATA_REL_RO:
-      named_section (NULL_TREE, ".data.rel.ro", reloc);
+      sname = ".data.rel.ro";
       break;
     case SECCAT_DATA_REL_RO_LOCAL:
-      named_section (NULL_TREE, ".data.rel.ro.local", reloc);
+      sname = ".data.rel.ro.local";
       break;
     case SECCAT_SDATA:
-      named_section (NULL_TREE, ".sdata", reloc);
+      sname = ".sdata";
       break;
     case SECCAT_TDATA:
-      named_section (NULL_TREE, ".tdata", reloc);
+      sname = ".tdata";
       break;
     case SECCAT_BSS:
 #ifdef BSS_SECTION_ASM_OP
       bss_section ();
+      return;
 #else
-      named_section (NULL_TREE, ".bss", reloc);
-#endif
+      sname = ".bss";
       break;
+#endif
     case SECCAT_SBSS:
-      named_section (NULL_TREE, ".sbss", reloc);
+      sname = ".sbss";
       break;
     case SECCAT_TBSS:
-      named_section (NULL_TREE, ".tbss", reloc);
+      sname = ".tbss";
       break;
     default:
-      abort ();
+      gcc_unreachable ();
     }
+
+  if (!DECL_P (decl))
+    decl = NULL_TREE;
+  named_section (decl, sname, reloc);
 }
 
 /* Construct a unique section name based on the decl name and the
@@ -4707,7 +5246,8 @@ default_unique_section (tree decl, int reloc)
 void
 default_unique_section_1 (tree decl, int reloc, int shlib)
 {
-  bool one_only = DECL_ONE_ONLY (decl);
+  /* We only need to use .gnu.linkonce if we don't have COMDAT groups.  */
+  bool one_only = DECL_ONE_ONLY (decl) && !HAVE_COMDAT_GROUP;
   const char *prefix, *name;
   size_t nlen, plen;
   char *string;
@@ -4749,7 +5289,7 @@ default_unique_section_1 (tree decl, int reloc, int shlib)
       prefix = one_only ? ".gnu.linkonce.tb." : ".tbss.";
       break;
     default:
-      abort ();
+      gcc_unreachable ();
     }
   plen = strlen (prefix);
 
@@ -4819,7 +5359,7 @@ default_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
   int flags;
 
   /* Careful not to prod global register variables.  */
-  if (GET_CODE (rtl) != MEM)
+  if (!MEM_P (rtl))
     return;
   symbol = XEXP (rtl, 0);
   if (GET_CODE (symbol) != SYMBOL_REF)
@@ -4830,10 +5370,10 @@ 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 (targetm.in_small_data_p (decl))
-    flags |= SYMBOL_FLAG_SMALL;
   if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
     flags |= decl_tls_model (decl) << SYMBOL_FLAG_TLS_SHIFT;
+  else if (targetm.in_small_data_p (decl))
+    flags |= SYMBOL_FLAG_SMALL;
   /* ??? Why is DECL_EXTERNAL ever set for non-PUBLIC names?  Without
      being PUBLIC, the thing *must* be defined in this translation unit.
      Prevent this buglet from being propagated into rtl code as well.  */
@@ -4872,8 +5412,8 @@ default_binds_local_p_1 (tree exp, int shlib)
   /* Static variables are always local.  */
   else if (! TREE_PUBLIC (exp))
     local_p = true;
-  /* A variable is local if the user tells us so.  */
-  else if (DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
+  /* A variable is local if the user explicitly tells us so.  */
+  else if (DECL_VISIBILITY_SPECIFIED (exp) && DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
     local_p = true;
   /* Otherwise, variables defined outside this object may not be local.  */
   else if (DECL_EXTERNAL (exp))
@@ -4881,6 +5421,9 @@ default_binds_local_p_1 (tree exp, int shlib)
   /* Linkonce and weak data are never local.  */
   else if (DECL_ONE_ONLY (exp) || DECL_WEAK (exp))
     local_p = false;
+  /* If none of the above and visibility is not default, make local.  */
+  else if (DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
+    local_p = true;
   /* If PIC, then assume that any global name can be overridden by
      symbols resolved from other modules.  */
   else if (shlib)
@@ -4908,7 +5451,7 @@ default_valid_pointer_mode (enum machine_mode mode)
 }
 
 /* Default function to output code that will globalize a label.  A
-   target must define GLOBAL_ASM_OP or provide it's own function to
+   target must define GLOBAL_ASM_OP or provide its own function to
    globalize a label.  */
 #ifdef GLOBAL_ASM_OP
 void
@@ -4922,10 +5465,11 @@ default_globalize_label (FILE * stream, const char *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. */
+   unwind information must provide its own function to do this.  */
 void
 default_emit_unwind_label (FILE * stream ATTRIBUTE_UNUSED,
                           tree decl ATTRIBUTE_UNUSED,
+                          int for_eh ATTRIBUTE_UNUSED,
                           int empty ATTRIBUTE_UNUSED)
 { 
 }
@@ -4939,7 +5483,7 @@ default_internal_label (FILE *stream, const char *prefix,
 {
   char *const buf = alloca (40 + strlen (prefix));
   ASM_GENERATE_INTERNAL_LABEL (buf, prefix, labelno);
-  ASM_OUTPUT_LABEL (stream, buf);
+  ASM_OUTPUT_INTERNAL_LABEL (stream, buf);
 }
 
 /* This is the default behavior at the beginning of a file.  It's
@@ -4958,6 +5502,9 @@ default_file_start (void)
    which emits a special section directive used to indicate whether or
    not this object file needs an executable stack.  This is primarily
    a GNU extension to ELF but could be used on other targets.  */
+
+int trampolines_created;
+
 void
 file_end_indicate_exec_stack (void)
 {