OSDN Git Service

2004-12-02 H.J. Lu <hongjiu.lu@intel.com>
[pf3gnuchains/gcc-fork.git] / gcc / varasm.c
index 5dbcb22..d900273 100644 (file)
@@ -57,10 +57,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
                                   declarations for e.g. AIX 4.x.  */
 #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;
@@ -104,26 +100,22 @@ tree last_assemble_variable_decl;
    partitions hot and cold basic blocks into separate sections of the .o
    file.  */
 
-bool unlikely_section_label_printed = false;
+static bool unlikely_section_label_printed = false;
 
 /* The following global variable indicates the label name to be put at
    the start of the first cold section within each function, when
    partitioning basic blocks into hot and cold sections.  */
 
-char *unlikely_section_label = NULL;
+static char *unlikely_section_label = NULL;
  
 /* The following global variable indicates the section name to be used
    for the current cold section, when partitioning hot and cold basic
    blocks into separate sections.  */
 
-char *unlikely_text_section_name = NULL;
+static char *unlikely_text_section_name = NULL;
 
-/* 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.  */
+/* 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;
 
@@ -226,18 +218,42 @@ text_section (void)
 void
 unlikely_text_section (void)
 {
-  if ((in_section != in_unlikely_executed_text)
-      &&  (in_section != in_named 
-          || strcmp (in_named_name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) != 0))
+  const char *name;
+  int len;
+
+  if (! unlikely_text_section_name)
     {
-      if (targetm.have_named_sections)
-        named_section (NULL_TREE, UNLIKELY_EXECUTED_TEXT_SECTION_NAME, 0);
+      if (DECL_SECTION_NAME (current_function_decl)
+         && (strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME
+                                          (current_function_decl)),
+                     HOT_TEXT_SECTION_NAME) != 0)
+         && (strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME
+                                          (current_function_decl)),
+                     UNLIKELY_EXECUTED_TEXT_SECTION_NAME) != 0))
+       {
+         name = TREE_STRING_POINTER (DECL_SECTION_NAME 
+                                                  (current_function_decl));
+         len = strlen (name);
+         unlikely_text_section_name = xmalloc ((len + 10) * sizeof (char));
+         strcpy (unlikely_text_section_name, name);
+         strcat (unlikely_text_section_name, "_unlikely");
+       }
       else
        {
-         in_section = in_unlikely_executed_text;
-         fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
+         len = strlen (UNLIKELY_EXECUTED_TEXT_SECTION_NAME);
+         unlikely_text_section_name = xmalloc (len+1 * sizeof (char));
+         strcpy (unlikely_text_section_name, 
+                 UNLIKELY_EXECUTED_TEXT_SECTION_NAME);
        }
-      
+    }
+
+  if ((in_section != in_unlikely_executed_text)
+      &&  (in_section != in_named 
+          || strcmp (in_named_name, unlikely_text_section_name) != 0))
+    {
+      named_section (NULL_TREE, unlikely_text_section_name, 0);
+      in_section = in_unlikely_executed_text;
+
       if (!unlikely_section_label_printed)
        {
          ASM_OUTPUT_LABEL (asm_out_file, unlikely_section_label);
@@ -293,7 +309,14 @@ in_text_section (void)
 int
 in_unlikely_text_section (void)
 {
-  return in_section == in_unlikely_executed_text;
+  bool ret_val;
+
+  ret_val = ((in_section == in_unlikely_executed_text)
+            || (in_section == in_named
+                && unlikely_text_section_name
+                && strcmp (in_named_name, unlikely_text_section_name) == 0));
+
+  return ret_val;
 }
 
 /* Determine if we're in the data section.  */
@@ -327,7 +350,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;
@@ -390,17 +413,19 @@ 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 ();
 
-      targetm.asm_out.named_section (name, flags);
+      targetm.asm_out.named_section (name, flags, decl);
 
       if (flags & SECTION_FORGET)
        in_section = no_section;
@@ -427,6 +452,16 @@ named_section (tree decl, const char *name, int reloc)
   if (name == NULL)
     name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
 
+  if (strcmp (name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0
+      && !unlikely_text_section_name)
+    {
+      unlikely_text_section_name = xmalloc 
+            (strlen (UNLIKELY_EXECUTED_TEXT_SECTION_NAME) + 1 
+             * sizeof (char));
+      strcpy (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
@@ -441,7 +476,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.  */
@@ -528,22 +563,33 @@ 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)
 {
-  if (scan_ahead_for_unlikely_executed_note (get_insns()))
-    unlikely_text_section ();
+  if (decl == NULL_TREE)
+    text_section ();
   else
     {
-      if (decl != NULL_TREE
-         && DECL_SECTION_NAME (decl) != NULL_TREE)
-       named_section (decl, (char *) 0, 0);
+      /* ??? Typical use of this function maybe shouldn't be looking
+        for unlikely blocks at all - in the event that an entire
+        function is going into the unlikely-execute section, that
+        should be reflected in its DECL_SECTION_NAME.  */
+      rtx insns = cfun && cfun->emit ? get_insns () : 0;
+      bool unlikely = insns && scan_ahead_for_unlikely_executed_note (insns);
+
+#ifdef USE_SELECT_SECTION_FOR_FUNCTIONS
+      targetm.asm_out.select_section (decl, unlikely, DECL_ALIGN (decl));
+#else
+      if (unlikely)
+       unlikely_text_section ();
+      else if (DECL_SECTION_NAME (decl))
+       named_section (decl, 0, 0);
       else
-       text_section (); 
+       text_section ();
+#endif
     }
 }
 
@@ -564,7 +610,7 @@ default_function_rodata_section (tree decl)
 
          memcpy (rname, name, len);
          rname[14] = 'r';
-         named_section_flags (rname, SECTION_LINKONCE);
+         named_section_real (rname, SECTION_LINKONCE, decl);
          return;
        }
       /* For .text.foo we want to use .rodata.foo.  */
@@ -855,20 +901,20 @@ make_decl_rtl (tree decl)
 
   name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
 
-  reg_number = decode_reg_name (name);
 
   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
@@ -881,7 +927,8 @@ make_decl_rtl (tree decl)
              error ("global register variable has initial value");
            }
          if (TREE_THIS_VOLATILE (decl))
-           warning ("volatile register variables don't work as you might wish");
+           warning ("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
@@ -908,12 +955,19 @@ make_decl_rtl (tree decl)
          return;
        }
     }
-
   /* Now handle ordinary static variables and functions (in memory).
      Also handle vars declared register invalidly.  */
-
-  if (name[0] == '*' && (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.  */
@@ -978,14 +1032,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
@@ -1035,14 +1093,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
@@ -1153,11 +1215,9 @@ assemble_start_function (tree decl, const char *fnname)
   unlikely_section_label_printed = false;
   unlikely_text_section_name = NULL;
   
-  if (unlikely_section_label)
-    free (unlikely_section_label);
-  unlikely_section_label = xmalloc ((strlen (fnname) + 18) * sizeof (char));
-  sprintf (unlikely_section_label, "%s_unlikely_section", fnname);
-
+  unlikely_section_label = reconcat (unlikely_section_label, 
+                                    fnname, ".unlikely_section", NULL);
+  
   /* The following code does not need preprocessing in the assembler.  */
 
   app_disable ();
@@ -1485,7 +1545,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;
     }
@@ -1513,7 +1573,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;
     }
 
@@ -1534,12 +1594,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 ("%Jalignment of %qD is greater than maximum object "
                "file alignment.  Using %d", decl, decl,
               MAX_OFILE_ALIGNMENT/BITS_PER_UNIT);
       align = MAX_OFILE_ALIGNMENT;
@@ -1612,8 +1669,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 ("%Jrequested alignment for %qD is greater than "
                  "implemented alignment of %d", decl, decl, rounded);
 #endif
 
@@ -1640,10 +1697,7 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
 
   /* 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
@@ -1979,6 +2033,10 @@ 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);
 }
 
@@ -2437,7 +2495,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
@@ -2628,7 +2686,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
@@ -2948,9 +3006,8 @@ force_const_mem (enum machine_mode mode, rtx x)
   *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;
 
   /* If we're dropping a label to the constant pool, make sure we
      don't delete it.  */
@@ -3008,20 +3065,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
@@ -3350,8 +3393,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;
 
@@ -3433,7 +3479,14 @@ 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;
+      return value;
 
     case VIEW_CONVERT_EXPR:
     case NON_LVALUE_EXPR:
@@ -3535,16 +3588,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);
 
@@ -3579,11 +3633,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;
 
@@ -3962,7 +4030,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
        {
@@ -4149,7 +4217,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
@@ -4157,7 +4225,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 ("%Jweak declaration of %qD after first use results "
                  "in unspecified behavior", newdecl, newdecl);
 
       if (SUPPORTS_WEAK)
@@ -4191,16 +4259,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 ("%Jweak declaration of %qD not supported", decl, decl);
 
   mark_weak (decl);
 }
@@ -4420,7 +4488,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;
@@ -4488,7 +4556,8 @@ default_section_type_flags_1 (tree decl, const char *name, int reloc,
     flags = SECTION_CODE;
   else if (decl && decl_readonly_section_1 (decl, reloc, shlib))
     flags = 0;
-  else if (strcmp (name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0)
+  else if (unlikely_text_section_name
+          && strcmp (name, unlikely_text_section_name) == 0)
     flags = SECTION_CODE;
   else
     flags = SECTION_WRITE;
@@ -4534,7 +4603,8 @@ 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.  */
@@ -4542,11 +4612,17 @@ default_no_named_section (const char *name ATTRIBUTE_UNUSED,
 }
 
 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_GAS_COMDAT_GROUP && (flags & SECTION_LINKONCE))
+      && ! named_section_first_declaration (name))
     {
       fprintf (asm_out_file, "\t.section\t%s\n", name);
       return;
@@ -4566,6 +4642,8 @@ default_elf_asm_named_section (const char *name, unsigned int flags)
     *f++ = 'S';
   if (flags & SECTION_TLS)
     *f++ = 'T';
+  if (HAVE_GAS_COMDAT_GROUP && (flags & SECTION_LINKONCE))
+    *f++ = 'G';
   *f = '\0';
 
   fprintf (asm_out_file, "\t.section\t%s,\"%s\"", name, flagchars);
@@ -4573,23 +4651,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_GAS_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;
 
@@ -4603,9 +4693,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)
     {
@@ -4813,6 +4904,7 @@ 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:
@@ -4820,56 +4912,61 @@ default_elf_select_section_1 (tree decl, int reloc,
       abort ();
     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 ();
     }
+
+  if (!DECL_P (decl))
+    decl = NULL_TREE;
+  named_section (decl, sname, reloc);
 }
 
 /* Construct a unique section name based on the decl name and the
@@ -5007,10 +5104,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.  */