OSDN Git Service

* doc/tm.texi (TARGET_HAVE_SWITCHABLE_BSS_SECTIONS): Document.
authorrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 2 Mar 2006 19:32:52 +0000 (19:32 +0000)
committerrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 2 Mar 2006 19:32:52 +0000 (19:32 +0000)
(ASM_OUTPUT_BSS): Describe the two ways of handling global BSS,
and say that only one is needed.
* doc/rtl.texi (SYMBOL_REF_BLOCK): Say that the block can be null.
* target.h (have_switchable_bss_sections): New hook.
* explow.c (use_anchored_address): Check that the symbol is in a block.
* varasm.c (tls_comm_section, comm_section, lcomm_section)
(bss_noswitch_section): New variables.
(get_unnamed_section): Add SECTION_UNNAMED to the flags.
(get_noswitch_section): New function.
(get_block_for_section): Allow SECT to be null.
(unlikely_text_section_p): Use SECTION_STYLE.
(bss_initializer_p): New function.
(get_variable_section): Move earlier in file.  Take a new argument,
prefer_noswitch_p.  Move bss checks from assemble_variable to here.
Return one of the new *_sections in such cases.
(get_block_for_decl): New function, extracting some logic from
use_blocks_for_decl_p.
(change_symbol_section): Remove in favor of...
(change_symbol_block): ...this new function.
(use_blocks_for_decl_p): Remove checks now performed by
get_block_for_decl.
(make_decl_rtl): Use change_symbol_block and get_block_for_decl.
(ASM_EMIT_LOCAL, ASM_EMIT_BSS, ASM_EMIT_COMMON): Delete in favor of...
(emit_local, emit_bss, emit_common): ...these new functions.
Return true if the alignment was honored.
(emit_tls_common): New function.
(asm_emit_uninitialised): Delete.
(assemble_variable_noswitch): New function, split out from...
(assemble_variable): ...here.  Don't make decisions about common
variables here.  Globalize all public decls that go into non-common
sections.  Check whether SYMBOL_REF_BLOCK is null.
(output_constant_def_contents): Check whether SYMBOL_REF_BLOCK is null.
(output_constant_pool): Likewise.
(init_varasm_once): Initialize the new section variables.
(have_global_bss_p): New function.
(categorize_decl_for_section): Use bss_initializer_p.
(switch_to_section): Use SECTION_STYLE.  Abort for SECTION_NOSWITCH.
(place_block_symbol): Assert that the symbol must be in a block.
* target-def.h (TARGET_HAVE_SWITCHABLE_BSS_SECTIONS): New macro.
(TARGET_INITIALIZER): Include it.
* rtl.h (SYMBOL_REF_BLOCK): Document the null alternative.
* output.h (SECTION_STYLE_MASK, SECTION_COMMON): New macros.
(SECTION_MACH_DEP): Bump by two.
(SECTION_UNNAMED, SECTION_NOSWITCH): New macros.
(unnamed_section): Mention SECTION_UNNAMED in comment.
(named_section): Likewise SECTION_NAMED.
(noswitch_section_callback): New type.
(noswitch_section): New structure.
(section): Add a noswitch_section alternative.
(SECTION_STYLE): New macro.
(tls_comm_section, comm_section, lcomm_section): Declare.
(bss_noswitch_section, have_global_bss_p): Declare.
* config/elfos.h (TARGET_HAVE_SWITCHABLE_BSS_SECTIONS): Override.
* config/iq2000/iq2000.c (TARGET_HAVE_SWITCHABLE_BSS_SECTIONS):
Override.
* config/v850/v850.c (TARGET_HAVE_SWITCHABLE_BSS_SECTIONS): Override.
* config/stormy16/stormy16.c (TARGET_HAVE_SWITCHABLE_BSS_SECTIONS):
Override.

cp/
* decl.c (start_decl): Use have_global_bss_p when deciding
whether to make the decl common.

ada/
* utils.c (create_var_decl): Use have_global_bss_p when deciding
whether to make the decl common.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@111644 138bc75d-0d04-0410-961f-82ee72b054a4

17 files changed:
gcc/ChangeLog
gcc/ada/ChangeLog
gcc/ada/utils.c
gcc/config/elfos.h
gcc/config/iq2000/iq2000.c
gcc/config/stormy16/stormy16.c
gcc/config/v850/v850.c
gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/doc/rtl.texi
gcc/doc/tm.texi
gcc/explow.c
gcc/output.h
gcc/rtl.h
gcc/target-def.h
gcc/target.h
gcc/varasm.c

index 7967d68..55bb0ad 100644 (file)
@@ -1,3 +1,65 @@
+2006-03-02  Richard Sandiford  <richard@codesourcery.com>
+
+       * doc/tm.texi (TARGET_HAVE_SWITCHABLE_BSS_SECTIONS): Document.
+       (ASM_OUTPUT_BSS): Describe the two ways of handling global BSS,
+       and say that only one is needed.
+       * doc/rtl.texi (SYMBOL_REF_BLOCK): Say that the block can be null.
+       * target.h (have_switchable_bss_sections): New hook.
+       * explow.c (use_anchored_address): Check that the symbol is in a block.
+       * varasm.c (tls_comm_section, comm_section, lcomm_section)
+       (bss_noswitch_section): New variables.
+       (get_unnamed_section): Add SECTION_UNNAMED to the flags.
+       (get_noswitch_section): New function.
+       (get_block_for_section): Allow SECT to be null.
+       (unlikely_text_section_p): Use SECTION_STYLE.
+       (bss_initializer_p): New function.
+       (get_variable_section): Move earlier in file.  Take a new argument,
+       prefer_noswitch_p.  Move bss checks from assemble_variable to here.
+       Return one of the new *_sections in such cases.
+       (get_block_for_decl): New function, extracting some logic from
+       use_blocks_for_decl_p.
+       (change_symbol_section): Remove in favor of...
+       (change_symbol_block): ...this new function.
+       (use_blocks_for_decl_p): Remove checks now performed by
+       get_block_for_decl.
+       (make_decl_rtl): Use change_symbol_block and get_block_for_decl.
+       (ASM_EMIT_LOCAL, ASM_EMIT_BSS, ASM_EMIT_COMMON): Delete in favor of...
+       (emit_local, emit_bss, emit_common): ...these new functions.
+       Return true if the alignment was honored.
+       (emit_tls_common): New function.
+       (asm_emit_uninitialised): Delete.
+       (assemble_variable_noswitch): New function, split out from...
+       (assemble_variable): ...here.  Don't make decisions about common
+       variables here.  Globalize all public decls that go into non-common
+       sections.  Check whether SYMBOL_REF_BLOCK is null.
+       (output_constant_def_contents): Check whether SYMBOL_REF_BLOCK is null.
+       (output_constant_pool): Likewise.
+       (init_varasm_once): Initialize the new section variables.
+       (have_global_bss_p): New function.
+       (categorize_decl_for_section): Use bss_initializer_p.
+       (switch_to_section): Use SECTION_STYLE.  Abort for SECTION_NOSWITCH.
+       (place_block_symbol): Assert that the symbol must be in a block.
+       * target-def.h (TARGET_HAVE_SWITCHABLE_BSS_SECTIONS): New macro.
+       (TARGET_INITIALIZER): Include it.
+       * rtl.h (SYMBOL_REF_BLOCK): Document the null alternative.
+       * output.h (SECTION_STYLE_MASK, SECTION_COMMON): New macros.
+       (SECTION_MACH_DEP): Bump by two.
+       (SECTION_UNNAMED, SECTION_NOSWITCH): New macros.
+       (unnamed_section): Mention SECTION_UNNAMED in comment.
+       (named_section): Likewise SECTION_NAMED.
+       (noswitch_section_callback): New type.
+       (noswitch_section): New structure.
+       (section): Add a noswitch_section alternative.
+       (SECTION_STYLE): New macro.
+       (tls_comm_section, comm_section, lcomm_section): Declare.
+       (bss_noswitch_section, have_global_bss_p): Declare.
+       * config/elfos.h (TARGET_HAVE_SWITCHABLE_BSS_SECTIONS): Override.
+       * config/iq2000/iq2000.c (TARGET_HAVE_SWITCHABLE_BSS_SECTIONS):
+       Override.
+       * config/v850/v850.c (TARGET_HAVE_SWITCHABLE_BSS_SECTIONS): Override.
+       * config/stormy16/stormy16.c (TARGET_HAVE_SWITCHABLE_BSS_SECTIONS):
+       Override.
+
 2006-03-02  Daniel Berlin <dberlin@dberlin.org>
 
        * gcc/tree-vrp.c (execute_vrp): Return value.
 2006-03-02  Daniel Berlin <dberlin@dberlin.org>
 
        * gcc/tree-vrp.c (execute_vrp): Return value.
index c5ecc91..d87a8d6 100644 (file)
@@ -1,3 +1,8 @@
+2006-03-02  Richard Sandiford  <richard@codesourcery.com>
+
+       * utils.c (create_var_decl): Use have_global_bss_p when deciding
+       whether to make the decl common.
+
 2006-02-20 Rafael Ávila de Espíndola <rafael.espindola@gmail.com>
        * Make-lang.in (Ada): Remove
        (.PHONY): Remove Ada
 2006-02-20 Rafael Ávila de Espíndola <rafael.espindola@gmail.com>
        * Make-lang.in (Ada): Remove
        (.PHONY): Remove Ada
index 78c1237..a3fdb0d 100644 (file)
@@ -1293,10 +1293,10 @@ create_var_decl (tree var_name, tree asm_name, tree type, tree var_init,
      try to fiddle with DECL_COMMON.  However, on platforms that don't
      support global BSS sections, uninitialized global variables would
      go in DATA instead, thus increasing the size of the executable.  */
      try to fiddle with DECL_COMMON.  However, on platforms that don't
      support global BSS sections, uninitialized global variables would
      go in DATA instead, thus increasing the size of the executable.  */
-#if !defined(ASM_OUTPUT_BSS) && !defined(ASM_OUTPUT_ALIGNED_BSS)
-  if (TREE_CODE (var_decl) == VAR_DECL)
-    DECL_COMMON   (var_decl) = !flag_no_common;
-#endif
+  if (!flag_no_common
+      && TREE_CODE (var_decl) == VAR_DECL
+      && !have_global_bss_p ())
+    DECL_COMMON (var_decl) = 1;
   DECL_INITIAL  (var_decl) = var_init;
   TREE_READONLY (var_decl) = const_flag;
   DECL_EXTERNAL (var_decl) = extern_flag;
   DECL_INITIAL  (var_decl) = var_init;
   TREE_READONLY (var_decl) = const_flag;
   DECL_EXTERNAL (var_decl) = extern_flag;
index 181072c..31e309d 100644 (file)
@@ -221,6 +221,8 @@ Boston, MA 02110-1301, USA.  */
 #define TARGET_ASM_SELECT_RTX_SECTION default_elf_select_rtx_section
 #undef TARGET_ASM_SELECT_SECTION
 #define TARGET_ASM_SELECT_SECTION default_elf_select_section
 #define TARGET_ASM_SELECT_RTX_SECTION default_elf_select_rtx_section
 #undef TARGET_ASM_SELECT_SECTION
 #define TARGET_ASM_SELECT_SECTION default_elf_select_section
+#undef  TARGET_HAVE_SWITCHABLE_BSS_SECTIONS
+#define TARGET_HAVE_SWITCHABLE_BSS_SECTIONS true
 
 /* Define the strings used for the special svr4 .type and .size directives.
    These strings generally do not vary from one system running svr4 to
 
 /* Define the strings used for the special svr4 .type and .size directives.
    These strings generally do not vary from one system running svr4 to
index dd42fe9..4b1cb3e 100644 (file)
@@ -186,6 +186,11 @@ static int  iq2000_arg_partial_bytes  (CUMULATIVE_ARGS *, enum machine_mode,
 #undef  TARGET_ASM_SELECT_SECTION
 #define TARGET_ASM_SELECT_SECTION      iq2000_select_section
 
 #undef  TARGET_ASM_SELECT_SECTION
 #define TARGET_ASM_SELECT_SECTION      iq2000_select_section
 
+/* The assembler supports switchable .bss sections, but
+   iq2000_select_section doesn't yet make use of them.  */
+#undef  TARGET_HAVE_SWITCHABLE_BSS_SECTIONS
+#define TARGET_HAVE_SWITCHABLE_BSS_SECTIONS false
+
 #undef  TARGET_PROMOTE_FUNCTION_ARGS
 #define TARGET_PROMOTE_FUNCTION_ARGS   hook_bool_tree_true
 #undef  TARGET_PROMOTE_FUNCTION_RETURN
 #undef  TARGET_PROMOTE_FUNCTION_ARGS
 #define TARGET_PROMOTE_FUNCTION_ARGS   hook_bool_tree_true
 #undef  TARGET_PROMOTE_FUNCTION_RETURN
index 76becfc..32513d2 100644 (file)
@@ -2653,6 +2653,10 @@ xstormy16_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
 #undef TARGET_ENCODE_SECTION_INFO
 #define TARGET_ENCODE_SECTION_INFO xstormy16_encode_section_info
 
 #undef TARGET_ENCODE_SECTION_INFO
 #define TARGET_ENCODE_SECTION_INFO xstormy16_encode_section_info
 
+/* select_section doesn't handle .bss_below100.  */
+#undef  TARGET_HAVE_SWITCHABLE_BSS_SECTIONS
+#define TARGET_HAVE_SWITCHABLE_BSS_SECTIONS false
+
 #undef TARGET_ASM_OUTPUT_MI_THUNK
 #define TARGET_ASM_OUTPUT_MI_THUNK xstormy16_asm_output_mi_thunk
 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
 #undef TARGET_ASM_OUTPUT_MI_THUNK
 #define TARGET_ASM_OUTPUT_MI_THUNK xstormy16_asm_output_mi_thunk
 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
index 7629a7a..eb2771c 100644 (file)
@@ -117,6 +117,11 @@ static GTY(()) section *zbss_section;
 #undef  TARGET_ASM_SELECT_SECTION
 #define TARGET_ASM_SELECT_SECTION  v850_select_section
 
 #undef  TARGET_ASM_SELECT_SECTION
 #define TARGET_ASM_SELECT_SECTION  v850_select_section
 
+/* The assembler supports switchable .bss sections, but
+   v850_select_section doesn't yet make use of them.  */
+#undef  TARGET_HAVE_SWITCHABLE_BSS_SECTIONS
+#define TARGET_HAVE_SWITCHABLE_BSS_SECTIONS false
+
 #undef TARGET_ENCODE_SECTION_INFO
 #define TARGET_ENCODE_SECTION_INFO v850_encode_section_info
 
 #undef TARGET_ENCODE_SECTION_INFO
 #define TARGET_ENCODE_SECTION_INFO v850_encode_section_info
 
index c092c39..71541e1 100644 (file)
@@ -1,3 +1,8 @@
+2006-03-02  Richard Sandiford  <richard@codesourcery.com>
+
+       * decl.c (start_decl): Use have_global_bss_p when deciding
+       whether to make the decl common.
+
 2006-03-01  Mike Stump  <mrs@apple.com>
 
        PR darwin/25908
 2006-03-01  Mike Stump  <mrs@apple.com>
 
        PR darwin/25908
index 21ef001..a9aec67 100644 (file)
@@ -3824,16 +3824,17 @@ start_decl (const cp_declarator *declarator,
   if (tem == error_mark_node)
     return error_mark_node;
 
   if (tem == error_mark_node)
     return error_mark_node;
 
-#if ! defined (ASM_OUTPUT_BSS) && ! defined (ASM_OUTPUT_ALIGNED_BSS)
   /* Tell the back-end to use or not use .common as appropriate.  If we say
      -fconserve-space, we want this to save .data space, at the expense of
      wrong semantics.  If we say -fno-conserve-space, we want this to
      produce errors about redefs; to do this we force variables into the
      data segment.  */
   /* Tell the back-end to use or not use .common as appropriate.  If we say
      -fconserve-space, we want this to save .data space, at the expense of
      wrong semantics.  If we say -fno-conserve-space, we want this to
      produce errors about redefs; to do this we force variables into the
      data segment.  */
-  DECL_COMMON (tem) = ((TREE_CODE (tem) != VAR_DECL
-                       || !DECL_THREAD_LOCAL_P (tem))
-                      && (flag_conserve_space || ! TREE_PUBLIC (tem)));
-#endif
+  if (flag_conserve_space
+      && TREE_CODE (tem) == VAR_DECL
+      && TREE_PUBLIC (tem)
+      && !DECL_THREAD_LOCAL_P (tem)
+      && !have_global_bss_p ())
+    DECL_COMMON (tem) = 1;
 
   if (! processing_template_decl)
     start_decl_1 (tem);
 
   if (! processing_template_decl)
     start_decl_1 (tem);
index de4a8e7..76b3a3c 100644 (file)
@@ -528,7 +528,7 @@ the target's use.
 @findex SYMBOL_REF_BLOCK
 @item SYMBOL_REF_BLOCK (@var{x})
 If @samp{SYMBOL_REF_IN_BLOCK_P (@var{x})}, this is the @samp{object_block}
 @findex SYMBOL_REF_BLOCK
 @item SYMBOL_REF_BLOCK (@var{x})
 If @samp{SYMBOL_REF_IN_BLOCK_P (@var{x})}, this is the @samp{object_block}
-structure to which the symbol belongs.  The value is always nonnull.
+structure to which the symbol belongs, or @code{NULL} if none.
 
 @findex SYMBOL_REF_BLOCK_OFFSET
 @item SYMBOL_REF_BLOCK_OFFSET (@var{x})
 
 @findex SYMBOL_REF_BLOCK_OFFSET
 @item SYMBOL_REF_BLOCK_OFFSET (@var{x})
index 778ecc9..e99989f 100644 (file)
@@ -6477,6 +6477,13 @@ specify an alignment within the section directive need pay attention to
 This flag is true if the target supports @code{TARGET_ASM_NAMED_SECTION}.
 @end deftypefn
 
 This flag is true if the target supports @code{TARGET_ASM_NAMED_SECTION}.
 @end deftypefn
 
+@anchor{TARGET_HAVE_SWITCHABLE_BSS_SECTIONS}
+@deftypefn {Target Hook} bool TARGET_HAVE_SWITCHABLE_BSS_SECTIONS
+This flag is true if we can create zeroed data by switching to a BSS
+section and then using @code{ASM_OUTPUT_SKIP} to allocate the space.
+This is true on most ELF targets.
+@end deftypefn
+
 @deftypefn {Target Hook} {unsigned int} TARGET_SECTION_TYPE_FLAGS (tree @var{decl}, const char *@var{name}, int @var{reloc})
 Choose a set of section attributes for use by @code{TARGET_ASM_NAMED_SECTION}
 based on a variable or function decl, a section name, and whether or not the
 @deftypefn {Target Hook} {unsigned int} TARGET_SECTION_TYPE_FLAGS (tree @var{decl}, const char *@var{name}, int @var{reloc})
 Choose a set of section attributes for use by @code{TARGET_ASM_NAMED_SECTION}
 based on a variable or function decl, a section name, and whether or not the
@@ -6705,13 +6712,17 @@ defining this macro.  If unable, use the expression
 before and after that, output the additional assembler syntax for defining
 the name, and a newline.
 
 before and after that, output the additional assembler syntax for defining
 the name, and a newline.
 
-This macro controls how the assembler definitions of uninitialized global
-variables are output.  This macro exists to properly support languages like
-C++ which do not have @code{common} data.  However, this macro currently
-is not defined for all targets.  If this macro and
-@code{ASM_OUTPUT_ALIGNED_BSS} are not defined then @code{ASM_OUTPUT_COMMON}
-or @code{ASM_OUTPUT_ALIGNED_COMMON} or
-@code{ASM_OUTPUT_ALIGNED_DECL_COMMON} is used.
+There are two ways of handling global BSS.  One is to define either
+this macro or its aligned counterpart, @code{ASM_OUTPUT_ALIGNED_BSS}.
+The other is to have @code{TARGET_ASM_SELECT_SECTION} return a
+switchable BSS section (@pxref{TARGET_HAVE_SWITCHABLE_BSS_SECTIONS}).
+You do not need to do both.
+
+Some languages do not have @code{common} data, and require a
+non-common form of global BSS in order to handle uninitialized globals
+efficiently.  C++ is one example of this.  However, if the target does
+not support global BSS, the front end may choose to make globals
+common in order to save space in the object file.
 @end defmac
 
 @defmac ASM_OUTPUT_ALIGNED_BSS (@var{stream}, @var{decl}, @var{name}, @var{size}, @var{alignment})
 @end defmac
 
 @defmac ASM_OUTPUT_ALIGNED_BSS (@var{stream}, @var{decl}, @var{name}, @var{size}, @var{alignment})
index b56373c..361c717 100644 (file)
@@ -568,6 +568,7 @@ use_anchored_address (rtx x)
   if (GET_CODE (base) != SYMBOL_REF
       || !SYMBOL_REF_IN_BLOCK_P (base)
       || SYMBOL_REF_ANCHOR_P (base)
   if (GET_CODE (base) != SYMBOL_REF
       || !SYMBOL_REF_IN_BLOCK_P (base)
       || SYMBOL_REF_ANCHOR_P (base)
+      || SYMBOL_REF_BLOCK (base) == NULL
       || !targetm.use_anchors_for_symbol_p (base))
     return x;
 
       || !targetm.use_anchors_for_symbol_p (base))
     return x;
 
index 5fda5ea..8974351 100644 (file)
@@ -402,8 +402,22 @@ extern void no_asm_to_stream (FILE *);
 #define SECTION_TLS     0x40000        /* contains thread-local storage */
 #define SECTION_NOTYPE  0x80000        /* don't output @progbits */
 #define SECTION_DECLARED 0x100000      /* section has been used */
 #define SECTION_TLS     0x40000        /* contains thread-local storage */
 #define SECTION_NOTYPE  0x80000        /* don't output @progbits */
 #define SECTION_DECLARED 0x100000      /* section has been used */
-#define SECTION_NAMED   0x200000       /* section has a name */
-#define SECTION_MACH_DEP 0x400000      /* subsequent bits reserved for target */
+#define SECTION_STYLE_MASK 0x600000    /* bits used for SECTION_STYLE */
+#define SECTION_COMMON   0x800000      /* contains common data */
+#define SECTION_MACH_DEP 0x1000000     /* subsequent bits reserved for target */
+
+/* This SECTION_STYLE is used for unnamed sections that we can switch
+   to using a special assembler directive.  */
+#define SECTION_UNNAMED         0x000000
+
+/* This SECTION_STYLE is used for named sections that we can switch
+   to using a general section directive.  */
+#define SECTION_NAMED   0x200000
+
+/* This SECTION_STYLE is used for sections that we cannot switch to at
+   all.  The choice of section is implied by the directive that we use
+   to declare the object.  */
+#define SECTION_NOSWITCH 0x400000
 
 /* A helper function for default_elf_select_section and
    default_elf_unique_section.  Categorizes the DECL.  */
 
 /* A helper function for default_elf_select_section and
    default_elf_unique_section.  Categorizes the DECL.  */
@@ -448,7 +462,7 @@ struct section_common GTY(()) {
   unsigned int flags;
 };
 
   unsigned int flags;
 };
 
-/* Information that is provided by named sections.  */
+/* Information about a SECTION_NAMED section.  */
 struct named_section GTY(()) {
   struct section_common common;
 
 struct named_section GTY(()) {
   struct section_common common;
 
@@ -464,7 +478,7 @@ struct named_section GTY(()) {
    section.  The argument provides callback-specific data.  */
 typedef void (*unnamed_section_callback) (const void *);
 
    section.  The argument provides callback-specific data.  */
 typedef void (*unnamed_section_callback) (const void *);
 
-/* Information that is provided by unnamed sections.  */
+/* Information about a SECTION_UNNAMED section.  */
 struct unnamed_section GTY(()) {
   struct section_common common;
 
 struct unnamed_section GTY(()) {
   struct section_common common;
 
@@ -477,14 +491,39 @@ struct unnamed_section GTY(()) {
   section *next;
 };
 
   section *next;
 };
 
+/* A callback that writes the assembly code for a decl in a
+   SECTION_NOSWITCH section.  DECL is the decl that should be assembled
+   and NAME is the name of its SYMBOL_REF.  SIZE is the size of the decl
+   in bytes and ROUNDED is that size rounded up to the next
+   BIGGEST_ALIGNMENT / BITS_PER_UNIT boundary.
+
+   Return true if the callback used DECL_ALIGN to set the object's
+   alignment.  A false return value implies that we are relying
+   on the rounded size to align the decl.  */
+typedef bool (*noswitch_section_callback) (tree decl, const char *name,
+                                          unsigned HOST_WIDE_INT size,
+                                          unsigned HOST_WIDE_INT rounded);
+
+/* Information about a SECTION_NOSWITCH section.  */
+struct noswitch_section GTY(()) {
+  struct section_common common;
+
+  /* The callback used to assemble decls in this section.  */
+  noswitch_section_callback GTY ((skip)) callback;
+};
+
 /* Information about a section, which may be named or unnamed.  */
 /* Information about a section, which may be named or unnamed.  */
-union section GTY ((desc ("(%h).common.flags & SECTION_NAMED")))
+union section GTY ((desc ("SECTION_STYLE (&(%h))")))
 {
   struct section_common GTY ((skip)) common;
   struct named_section GTY ((tag ("SECTION_NAMED"))) named;
 {
   struct section_common GTY ((skip)) common;
   struct named_section GTY ((tag ("SECTION_NAMED"))) named;
-  struct unnamed_section GTY ((tag ("0"))) unnamed;
+  struct unnamed_section GTY ((tag ("SECTION_UNNAMED"))) unnamed;
+  struct noswitch_section GTY ((tag ("SECTION_NOSWITCH"))) noswitch;
 };
 
 };
 
+/* Return the style of section SECT.  */
+#define SECTION_STYLE(SECT) ((SECT)->common.flags & SECTION_STYLE_MASK)
+
 struct object_block;
 
 /* Special well-known sections.  */
 struct object_block;
 
 /* Special well-known sections.  */
@@ -498,6 +537,10 @@ extern GTY(()) section *bss_section;
 extern GTY(()) section *sbss_section;
 extern GTY(()) section *exception_section;
 extern GTY(()) section *eh_frame_section;
 extern GTY(()) section *sbss_section;
 extern GTY(()) section *exception_section;
 extern GTY(()) section *eh_frame_section;
+extern GTY(()) section *tls_comm_section;
+extern GTY(()) section *comm_section;
+extern GTY(()) section *lcomm_section;
+extern GTY(()) section *bss_noswitch_section;
 
 extern GTY(()) section *in_section;
 extern GTY(()) bool in_cold_section_p;
 
 extern GTY(()) section *in_section;
 extern GTY(()) bool in_cold_section_p;
@@ -523,6 +566,7 @@ extern void output_section_asm_op (const void *);
 extern unsigned int default_section_type_flags (tree, const char *, int);
 extern unsigned int default_section_type_flags_1 (tree, const char *, int, int);
 
 extern unsigned int default_section_type_flags (tree, const char *, int);
 extern unsigned int default_section_type_flags_1 (tree, const char *, int, int);
 
+extern bool have_global_bss_p (void);
 extern void default_no_named_section (const char *, unsigned int, tree);
 extern void default_elf_asm_named_section (const char *, unsigned int, tree);
 extern enum section_category categorize_decl_for_section (tree, int, int);
 extern void default_no_named_section (const char *, unsigned int, tree);
 extern void default_elf_asm_named_section (const char *, unsigned int, tree);
 extern enum section_category categorize_decl_for_section (tree, int, int);
index 4ee188c..236c8a1 100644 (file)
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -1331,8 +1331,8 @@ do {                                              \
 #define SYMBOL_FLAG_MACH_DEP_SHIFT     9
 #define SYMBOL_FLAG_MACH_DEP           (1 << SYMBOL_FLAG_MACH_DEP_SHIFT)
 
 #define SYMBOL_FLAG_MACH_DEP_SHIFT     9
 #define SYMBOL_FLAG_MACH_DEP           (1 << SYMBOL_FLAG_MACH_DEP_SHIFT)
 
-/* The block to which the given SYMBOL_REF belongs.  Only valid if
-   SYMBOL_REF_IN_BLOCK_P (RTX).  */
+/* The block to which the given SYMBOL_REF belongs, or NULL if none.
+   Only valid if SYMBOL_REF_IN_BLOCK_P (RTX).  */
 #define SYMBOL_REF_BLOCK(RTX) (BLOCK_SYMBOL_CHECK (RTX)->block)
 
 /* The byte offset of the given SYMBOL_REF from the start of its block,
 #define SYMBOL_REF_BLOCK(RTX) (BLOCK_SYMBOL_CHECK (RTX)->block)
 
 /* The byte offset of the given SYMBOL_REF from the start of its block,
index c292567..fa38166 100644 (file)
@@ -140,6 +140,10 @@ Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 # endif
 #endif
 
 # endif
 #endif
 
+#ifndef TARGET_HAVE_SWITCHABLE_BSS_SECTIONS
+#define TARGET_HAVE_SWITCHABLE_BSS_SECTIONS false
+#endif
+
 #ifndef TARGET_ASM_INIT_SECTIONS
 #define TARGET_ASM_INIT_SECTIONS hook_void_void
 #endif
 #ifndef TARGET_ASM_INIT_SECTIONS
 #define TARGET_ASM_INIT_SECTIONS hook_void_void
 #endif
@@ -651,6 +655,7 @@ Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
   TARGET_EXTRA_LIVE_ON_ENTRY,                    \
   TARGET_UNWIND_TABLES_DEFAULT,                        \
   TARGET_HAVE_NAMED_SECTIONS,                  \
   TARGET_EXTRA_LIVE_ON_ENTRY,                    \
   TARGET_UNWIND_TABLES_DEFAULT,                        \
   TARGET_HAVE_NAMED_SECTIONS,                  \
+  TARGET_HAVE_SWITCHABLE_BSS_SECTIONS,         \
   TARGET_HAVE_CTORS_DTORS,                     \
   TARGET_HAVE_TLS,                             \
   TARGET_HAVE_SRODATA_SECTION,                 \
   TARGET_HAVE_CTORS_DTORS,                     \
   TARGET_HAVE_TLS,                             \
   TARGET_HAVE_SRODATA_SECTION,                 \
index 63f5d4e..e6e6ba8 100644 (file)
@@ -734,6 +734,10 @@ struct gcc_target
   /* True if arbitrary sections are supported.  */
   bool have_named_sections;
 
   /* True if arbitrary sections are supported.  */
   bool have_named_sections;
 
+  /* True if we can create zeroed data by switching to a BSS section
+     and then using ASM_OUTPUT_SKIP to allocate the space.  */
+  bool have_switchable_bss_sections;
+
   /* True if "native" constructors and destructors are supported,
      false if we're using collect2 for the job.  */
   bool have_ctors_dtors;
   /* True if "native" constructors and destructors are supported,
      false if we're using collect2 for the job.  */
   bool have_ctors_dtors;
index f07ed39..801d11e 100644 (file)
@@ -138,9 +138,6 @@ static void asm_output_aligned_bss (FILE *, tree, const char *,
      ATTRIBUTE_UNUSED;
 #endif
 #endif /* BSS_SECTION_ASM_OP */
      ATTRIBUTE_UNUSED;
 #endif
 #endif /* BSS_SECTION_ASM_OP */
-static bool asm_emit_uninitialised (tree, const char*,
-                                   unsigned HOST_WIDE_INT,
-                                   unsigned HOST_WIDE_INT);
 static void mark_weak (tree);
 \f
 /* Well-known sections, each one associated with some sort of *_ASM_OP.  */
 static void mark_weak (tree);
 \f
 /* Well-known sections, each one associated with some sort of *_ASM_OP.  */
@@ -153,6 +150,15 @@ section *dtors_section;
 section *bss_section;
 section *sbss_section;
 
 section *bss_section;
 section *sbss_section;
 
+/* Various forms of common section.  All are guaranteed to be nonnull.  */
+section *tls_comm_section;
+section *comm_section;
+section *lcomm_section;
+
+/* A SECTION_NOSWITCH section used for declaring global BSS variables.
+   May be null.  */
+section *bss_noswitch_section;
+
 /* The section that holds the main exception table, when known.  The section
    is set either by the target's init_sections hook or by the first call to
    switch_to_exception_section.  */
 /* The section that holds the main exception table, when known.  The section
    is set either by the target's init_sections hook or by the first call to
    switch_to_exception_section.  */
@@ -245,7 +251,7 @@ get_unnamed_section (unsigned int flags, void (*callback) (const void *),
   section *sect;
 
   sect = ggc_alloc (sizeof (struct unnamed_section));
   section *sect;
 
   sect = ggc_alloc (sizeof (struct unnamed_section));
-  sect->unnamed.common.flags = flags;
+  sect->unnamed.common.flags = flags | SECTION_UNNAMED;
   sect->unnamed.callback = callback;
   sect->unnamed.data = data;
   sect->unnamed.next = unnamed_sections;
   sect->unnamed.callback = callback;
   sect->unnamed.data = data;
   sect->unnamed.next = unnamed_sections;
@@ -254,6 +260,20 @@ get_unnamed_section (unsigned int flags, void (*callback) (const void *),
   return sect;
 }
 
   return sect;
 }
 
+/* Return a SECTION_NOSWITCH section with the given fields.  */
+
+static section *
+get_noswitch_section (unsigned int flags, noswitch_section_callback callback)
+{
+  section *sect;
+
+  sect = ggc_alloc (sizeof (struct unnamed_section));
+  sect->noswitch.common.flags = flags | SECTION_NOSWITCH;
+  sect->noswitch.callback = callback;
+
+  return sect;
+}
+
 /* Return the named section structure associated with NAME.  Create
    a new section with the given fields if no such structure exists.  */
 
 /* Return the named section structure associated with NAME.  Create
    a new section with the given fields if no such structure exists.  */
 
@@ -300,7 +320,8 @@ use_object_blocks_p (void)
 }
 
 /* Return the object_block structure for section SECT.  Create a new
 }
 
 /* Return the object_block structure for section SECT.  Create a new
-   structure if we haven't created one already.  */
+   structure if we haven't created one already.  Return null if SECT
+   itself is null.  */
 
 static struct object_block *
 get_block_for_section (section *sect)
 
 static struct object_block *
 get_block_for_section (section *sect)
@@ -308,6 +329,9 @@ get_block_for_section (section *sect)
   struct object_block *block;
   void **slot;
 
   struct object_block *block;
   void **slot;
 
+  if (sect == NULL)
+    return NULL;
+
   slot = htab_find_slot_with_hash (object_block_htab, sect,
                                   hash_section (sect), INSERT);
   block = (struct object_block *) *slot;
   slot = htab_find_slot_with_hash (object_block_htab, sect,
                                   hash_section (sect), INSERT);
   block = (struct object_block *) *slot;
@@ -409,7 +433,7 @@ unlikely_text_section_p (section *sect)
 
   return (name
          && sect
 
   return (name
          && sect
-         && (sect->common.flags & SECTION_NAMED) != 0
+         && SECTION_STYLE (sect) == SECTION_NAMED
          && strcmp (name, sect->named.name) == 0);
 }
 
          && strcmp (name, sect->named.name) == 0);
 }
 
@@ -786,81 +810,127 @@ decode_reg_name (const char *asmspec)
   return -1;
 }
 \f
   return -1;
 }
 \f
-/* Return true if it is possible to put DECL in an object_block.  */
+/* Return true if DECL's initializer is suitable for a BSS section.  */
 
 static bool
 
 static bool
-use_blocks_for_decl_p (tree decl)
+bss_initializer_p (tree decl)
 {
 {
-  /* Only data DECLs can be placed into object blocks.  */
-  if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != CONST_DECL)
-    return false;
+  return (DECL_INITIAL (decl) == NULL
+         || DECL_INITIAL (decl) == error_mark_node
+         || (flag_zero_initialized_in_bss
+             /* Leave constant zeroes in .rodata so they
+                can be shared.  */
+             && !TREE_READONLY (decl)
+             && initializer_zerop (DECL_INITIAL (decl))));
+}
+
+/* Return the section into which the given VAR_DECL or CONST_DECL
+   should be placed.  PREFER_NOSWITCH_P is true if a noswitch
+   section should be used wherever possible.  */
+
+static section *
+get_variable_section (tree decl, bool prefer_noswitch_p)
+{
+  int reloc;
+
+  /* If the decl has been given an explicit section name, then it
+     isn't common, and shouldn't be handled as such.  */
+  if (DECL_COMMON (decl) && DECL_SECTION_NAME (decl) == NULL)
+    {
+      if (DECL_THREAD_LOCAL_P (decl))
+       return tls_comm_section;
+      if (TREE_PUBLIC (decl) && bss_initializer_p (decl))
+       return comm_section;
+    }
+
+  if (DECL_INITIAL (decl) == error_mark_node)
+    reloc = contains_pointers_p (TREE_TYPE (decl)) ? 3 : 0;
+  else if (DECL_INITIAL (decl))
+    reloc = compute_reloc_for_constant (DECL_INITIAL (decl));
+  else
+    reloc = 0;
+
+  resolve_unique_section (decl, reloc, flag_data_sections);
+  if (IN_NAMED_SECTION (decl))
+    return get_named_section (decl, NULL, reloc);
+
+  if (!DECL_THREAD_LOCAL_P (decl)
+      && !(prefer_noswitch_p && targetm.have_switchable_bss_sections)
+      && bss_initializer_p (decl))
+    {
+      if (!TREE_PUBLIC (decl))
+       return lcomm_section;
+      if (bss_noswitch_section)
+       return bss_noswitch_section;
+    }
+
+  return targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
+}
+
+/* Return the block into which object_block DECL should be placed.  */
+
+static struct object_block *
+get_block_for_decl (tree decl)
+{
+  section *sect;
 
   if (TREE_CODE (decl) == VAR_DECL)
     {
       /* The object must be defined in this translation unit.  */
       if (DECL_EXTERNAL (decl))
 
   if (TREE_CODE (decl) == VAR_DECL)
     {
       /* The object must be defined in this translation unit.  */
       if (DECL_EXTERNAL (decl))
-       return false;
+       return NULL;
 
       /* There's no point using object blocks for something that is
         isolated by definition.  */
       if (DECL_ONE_ONLY (decl))
 
       /* There's no point using object blocks for something that is
         isolated by definition.  */
       if (DECL_ONE_ONLY (decl))
-       return false;
-
-      /* Symbols that use .common cannot be put into blocks.  */
-      if (DECL_COMMON (decl) && DECL_INITIAL (decl) == NULL)
-       return false;
+       return NULL;
     }
 
   /* We can only calculate block offsets if the decl has a known
      constant size.  */
   if (DECL_SIZE_UNIT (decl) == NULL)
     }
 
   /* We can only calculate block offsets if the decl has a known
      constant size.  */
   if (DECL_SIZE_UNIT (decl) == NULL)
-    return false;
+    return NULL;
   if (!host_integerp (DECL_SIZE_UNIT (decl), 1))
   if (!host_integerp (DECL_SIZE_UNIT (decl), 1))
-    return false;
+    return NULL;
 
 
-  /* Detect decls created by dw2_force_const_mem.  Such decls are
-     special because DECL_INITIAL doesn't specify the decl's true value.
-     dw2_output_indirect_constants will instead call assemble_variable
-     with dont_output_data set to 1 and then print the contents itself.  */
-  if (DECL_INITIAL (decl) == decl)
-    return false;
+  /* Find out which section should contain DECL.  We cannot put it into
+     an object block if it requires a standalone definition.  */
+  sect = get_variable_section (decl, true);
+  if (SECTION_STYLE (sect) == SECTION_NOSWITCH)
+    return NULL;
 
 
-  return true;
+  return get_block_for_section (sect);
 }
 
 }
 
-/* Make sure block symbol SYMBOL is in section SECT, moving it to a
-   different block if necessary.  */
+/* Make sure block symbol SYMBOL is in block BLOCK.  */
 
 static void
 
 static void
-change_symbol_section (rtx symbol, section *sect)
+change_symbol_block (rtx symbol, struct object_block *block)
 {
 {
-  if (sect != SYMBOL_REF_BLOCK (symbol)->sect)
+  if (block != SYMBOL_REF_BLOCK (symbol))
     {
       gcc_assert (SYMBOL_REF_BLOCK_OFFSET (symbol) < 0);
     {
       gcc_assert (SYMBOL_REF_BLOCK_OFFSET (symbol) < 0);
-      SYMBOL_REF_BLOCK (symbol) = get_block_for_section (sect);
+      SYMBOL_REF_BLOCK (symbol) = block;
     }
 }
 
     }
 }
 
-/* Return the section into which the given VAR_DECL or CONST_DECL
-   should be placed.  */
+/* Return true if it is possible to put DECL in an object_block.  */
 
 
-static section *
-get_variable_section (tree decl)
+static bool
+use_blocks_for_decl_p (tree decl)
 {
 {
-  int reloc;
+  /* Only data DECLs can be placed into object blocks.  */
+  if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != CONST_DECL)
+    return false;
 
 
-  if (DECL_INITIAL (decl) == error_mark_node)
-    reloc = contains_pointers_p (TREE_TYPE (decl)) ? 3 : 0;
-  else if (DECL_INITIAL (decl))
-    reloc = compute_reloc_for_constant (DECL_INITIAL (decl));
-  else
-    reloc = 0;
+  /* Detect decls created by dw2_force_const_mem.  Such decls are
+     special because DECL_INITIAL doesn't specify the decl's true value.
+     dw2_output_indirect_constants will instead call assemble_variable
+     with dont_output_data set to 1 and then print the contents itself.  */
+  if (DECL_INITIAL (decl) == decl)
+    return false;
 
 
-  resolve_unique_section (decl, reloc, flag_data_sections);
-  if (IN_NAMED_SECTION (decl))
-    return get_named_section (decl, NULL, reloc);
-  else
-    return targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
+  return true;
 }
 
 /* Create the DECL_RTL for a VAR_DECL or FUNCTION_DECL.  DECL should
 }
 
 /* Create the DECL_RTL for a VAR_DECL or FUNCTION_DECL.  DECL should
@@ -921,7 +991,7 @@ make_decl_rtl (tree decl)
       if (MEM_P (x)
          && GET_CODE (XEXP (x, 0)) == SYMBOL_REF
          && SYMBOL_REF_IN_BLOCK_P (XEXP (x, 0)))
       if (MEM_P (x)
          && GET_CODE (XEXP (x, 0)) == SYMBOL_REF
          && SYMBOL_REF_IN_BLOCK_P (XEXP (x, 0)))
-       change_symbol_section (XEXP (x, 0), get_variable_section (decl));
+       change_symbol_block (XEXP (x, 0), get_block_for_decl (decl));
 
       /* Make this function static known to the mudflap runtime.  */
       if (flag_mudflap && TREE_CODE (decl) == VAR_DECL)
 
       /* Make this function static known to the mudflap runtime.  */
       if (flag_mudflap && TREE_CODE (decl) == VAR_DECL)
@@ -1020,10 +1090,7 @@ make_decl_rtl (tree decl)
     DECL_COMMON (decl) = 0;
 
   if (use_object_blocks_p () && use_blocks_for_decl_p (decl))
     DECL_COMMON (decl) = 0;
 
   if (use_object_blocks_p () && use_blocks_for_decl_p (decl))
-    {
-      section *sect = get_variable_section (decl);
-      x = create_block_symbol (name, get_block_for_section (sect), -1);
-    }
+    x = create_block_symbol (name, get_block_for_decl (decl), -1);
   else
     x = gen_rtx_SYMBOL_REF (Pmode, name);
   SYMBOL_REF_WEAK (x) = DECL_WEAK (decl);
   else
     x = gen_rtx_SYMBOL_REF (Pmode, name);
   SYMBOL_REF_WEAK (x) = DECL_WEAK (decl);
@@ -1458,100 +1525,110 @@ assemble_string (const char *p, int size)
 }
 
 \f
 }
 
 \f
-#if defined  ASM_OUTPUT_ALIGNED_DECL_LOCAL
-#define ASM_EMIT_LOCAL(decl, name, size, rounded) \
-  ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, decl, name, size, DECL_ALIGN (decl))
-#else
-#if defined  ASM_OUTPUT_ALIGNED_LOCAL
-#define ASM_EMIT_LOCAL(decl, name, size, rounded) \
-  ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, DECL_ALIGN (decl))
+/* A noswitch_section_callback for lcomm_section.  */
+
+static bool
+emit_local (tree decl ATTRIBUTE_UNUSED,
+           const char *name ATTRIBUTE_UNUSED,
+           unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
+           unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
+{
+#if defined ASM_OUTPUT_ALIGNED_DECL_LOCAL
+  ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, decl, name,
+                                size, DECL_ALIGN (decl));
+  return true;
+#elif defined ASM_OUTPUT_ALIGNED_LOCAL
+  ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, DECL_ALIGN (decl));
+  return true;
 #else
 #else
-#define ASM_EMIT_LOCAL(decl, name, size, rounded) \
-  ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded)
-#endif
+  ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
+  return false;
 #endif
 #endif
+}
 
 
+/* A noswitch_section_callback for bss_noswitch_section.  */
+
+#if defined ASM_OUTPUT_ALIGNED_BSS || defined ASM_OUTPUT_BSS
+static bool
+emit_bss (tree decl ATTRIBUTE_UNUSED,
+         const char *name ATTRIBUTE_UNUSED,
+         unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
+         unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
+{
 #if defined ASM_OUTPUT_ALIGNED_BSS
 #if defined ASM_OUTPUT_ALIGNED_BSS
-#define ASM_EMIT_BSS(decl, name, size, rounded) \
-  ASM_OUTPUT_ALIGNED_BSS (asm_out_file, decl, name, size, DECL_ALIGN (decl))
-#else
-#if defined ASM_OUTPUT_BSS
-#define ASM_EMIT_BSS(decl, name, size, rounded) \
-  ASM_OUTPUT_BSS (asm_out_file, decl, name, size, rounded)
+  ASM_OUTPUT_ALIGNED_BSS (asm_out_file, decl, name, size, DECL_ALIGN (decl));
+  return true;
 #else
 #else
-#undef  ASM_EMIT_BSS
+  ASM_OUTPUT_BSS (asm_out_file, decl, name, size, rounded);
+  return false;
 #endif
 #endif
+}
 #endif
 
 #endif
 
+/* A noswitch_section_callback for comm_section.  */
+
+static bool
+emit_common (tree decl ATTRIBUTE_UNUSED,
+            const char *name ATTRIBUTE_UNUSED,
+            unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
+            unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
+{
 #if defined ASM_OUTPUT_ALIGNED_DECL_COMMON
 #if defined ASM_OUTPUT_ALIGNED_DECL_COMMON
-#define ASM_EMIT_COMMON(decl, name, size, rounded) \
-  ASM_OUTPUT_ALIGNED_DECL_COMMON (asm_out_file, decl, name, size, DECL_ALIGN (decl))
-#else
-#if defined ASM_OUTPUT_ALIGNED_COMMON
-#define ASM_EMIT_COMMON(decl, name, size, rounded) \
-  ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, name, size, DECL_ALIGN (decl))
+  ASM_OUTPUT_ALIGNED_DECL_COMMON (asm_out_file, decl, name,
+                                 size, DECL_ALIGN (decl));
+  return true;
+#elif defined ASM_OUTPUT_ALIGNED_COMMON
+  ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, name, size, DECL_ALIGN (decl));
+  return true;
 #else
 #else
-#define ASM_EMIT_COMMON(decl, name, size, rounded) \
-  ASM_OUTPUT_COMMON (asm_out_file, name, size, rounded)
-#endif
+  ASM_OUTPUT_COMMON (asm_out_file, name, size, rounded);
+  return false;
 #endif
 #endif
+}
+
+/* A noswitch_section_callback for tls_comm_section.  */
 
 static bool
 
 static bool
-asm_emit_uninitialised (tree decl, const char *name,
-                       unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
-                       unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
+emit_tls_common (tree decl ATTRIBUTE_UNUSED,
+                const char *name ATTRIBUTE_UNUSED,
+                unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
+                unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
 {
 {
-  enum
-  {
-    asm_dest_common,
-    asm_dest_bss,
-    asm_dest_local
-  }
-  destination = asm_dest_local;
-
-  /* ??? We should handle .bss via select_section mechanisms rather than
-     via special target hooks.  That would eliminate this special case.  */
-  if (TREE_PUBLIC (decl))
-    {
-      if (!DECL_COMMON (decl))
-#ifdef ASM_EMIT_BSS
-       destination = asm_dest_bss;
+#ifdef ASM_OUTPUT_TLS_COMMON
+  ASM_OUTPUT_TLS_COMMON (asm_out_file, decl, name, size);
+  return true;
 #else
 #else
-       return false;
+  sorry ("thread-local COMMON data not implemented");
+  return true;
 #endif
 #endif
-      else
-       destination = asm_dest_common;
-    }
+}
 
 
-  if (destination != asm_dest_common)
-    {
-      resolve_unique_section (decl, 0, flag_data_sections);
-      /* Custom sections don't belong here.  */
-      if (DECL_SECTION_NAME (decl))
-        return false;
-    }
+/* Assemble DECL given that it belongs in SECTION_NOSWITCH section SECT.
+   NAME is the name of DECL's SYMBOL_REF.  */
 
 
-  if (destination == asm_dest_bss)
-    globalize_decl (decl);
+static void
+assemble_noswitch_variable (tree decl, const char *name, section *sect)
+{
+  unsigned HOST_WIDE_INT size, rounded;
 
 
-  switch (destination)
-    {
-#ifdef ASM_EMIT_BSS
-    case asm_dest_bss:
-      ASM_EMIT_BSS (decl, name, size, rounded);
-      break;
-#endif
-    case asm_dest_common:
-      ASM_EMIT_COMMON (decl, name, size, rounded);
-      break;
-    case asm_dest_local:
-      ASM_EMIT_LOCAL (decl, name, size, rounded);
-      break;
-    default:
-      gcc_unreachable ();
-    }
+  size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
+  rounded = size;
 
 
-  return true;
+  /* Don't allocate zero bytes of common,
+     since that means "undefined external" in the linker.  */
+  if (size == 0)
+    rounded = 1;
+
+  /* Round size up to multiple of BIGGEST_ALIGNMENT bits
+     so that each uninitialized object starts on such a boundary.  */
+  rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;
+  rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
+            * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
+
+  if (!sect->noswitch.callback (decl, name, size, rounded)
+      && (unsigned HOST_WIDE_INT) DECL_ALIGN_UNIT (decl) > rounded)
+    warning (0, "requested alignment for %q+D is greater than "
+            "implemented alignment of %wu", decl, rounded);
 }
 
 /* A subroutine of assemble_variable.  Output the label and contents of
 }
 
 /* A subroutine of assemble_variable.  Output the label and contents of
@@ -1602,8 +1679,8 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
 {
   const char *name;
   unsigned int align;
 {
   const char *name;
   unsigned int align;
-  rtx decl_rtl;
-  bool in_block_p;
+  rtx decl_rtl, symbol;
+  section *sect;
 
   if (lang_hooks.decls.prepare_assemble_variable)
     lang_hooks.decls.prepare_assemble_variable (decl);
 
   if (lang_hooks.decls.prepare_assemble_variable)
     lang_hooks.decls.prepare_assemble_variable (decl);
@@ -1675,8 +1752,8 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
 
   gcc_assert (MEM_P (decl_rtl));
   gcc_assert (GET_CODE (XEXP (decl_rtl, 0)) == SYMBOL_REF);
 
   gcc_assert (MEM_P (decl_rtl));
   gcc_assert (GET_CODE (XEXP (decl_rtl, 0)) == SYMBOL_REF);
-  in_block_p = SYMBOL_REF_IN_BLOCK_P (XEXP (decl_rtl, 0));
-  name = XSTR (XEXP (decl_rtl, 0), 0);
+  symbol = XEXP (decl_rtl, 0);
+  name = XSTR (symbol, 0);
   if (TREE_PUBLIC (decl) && DECL_NAME (decl))
     notice_global_symbol (decl);
 
   if (TREE_PUBLIC (decl) && DECL_NAME (decl))
     notice_global_symbol (decl);
 
@@ -1724,70 +1801,11 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
   if (DECL_PRESERVE_P (decl))
     targetm.asm_out.mark_decl_preserved (name);
 
   if (DECL_PRESERVE_P (decl))
     targetm.asm_out.mark_decl_preserved (name);
 
-  /* Handle uninitialized definitions.  */
-
-  /* If the decl has been given an explicit section name, then it
-     isn't common, and shouldn't be handled as such.  */
-  if (DECL_SECTION_NAME (decl) || dont_output_data)
-    ;
-  else if (DECL_THREAD_LOCAL_P (decl))
-    {
-      if (DECL_COMMON (decl))
-       {
-#ifdef ASM_OUTPUT_TLS_COMMON
-         unsigned HOST_WIDE_INT size;
-
-         size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
-         ASM_OUTPUT_TLS_COMMON (asm_out_file, decl, name, size);
-         return;
-#else
-         sorry ("thread-local COMMON data not implemented");
-#endif
-       }
-    }
-  /* Do not handle decls as common if they will be assigned a
-     specific section position.  */
-  else if (in_block_p)
-    ;
-  else if (DECL_INITIAL (decl) == 0
-          || DECL_INITIAL (decl) == error_mark_node
-          || (flag_zero_initialized_in_bss
-              /* Leave constant zeroes in .rodata so they can be shared.  */
-              && !TREE_READONLY (decl)
-              && initializer_zerop (DECL_INITIAL (decl))))
-    {
-      unsigned HOST_WIDE_INT size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
-      unsigned HOST_WIDE_INT rounded = size;
-
-      /* Don't allocate zero bytes of common,
-        since that means "undefined external" in the linker.  */
-      if (size == 0)
-       rounded = 1;
-
-      /* Round size up to multiple of BIGGEST_ALIGNMENT bits
-        so that each uninitialized object starts on such a boundary.  */
-      rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;
-      rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
-                * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
-
-#if !defined(ASM_OUTPUT_ALIGNED_COMMON) && !defined(ASM_OUTPUT_ALIGNED_DECL_COMMON) && !defined(ASM_OUTPUT_ALIGNED_BSS)
-      if ((unsigned HOST_WIDE_INT) DECL_ALIGN_UNIT (decl) > rounded)
-       warning (0, "requested alignment for %q+D is greater than "
-                 "implemented alignment of %wu", decl, rounded);
-#endif
-
-      /* If the target cannot output uninitialized but not common global data
-        in .bss, then we have to use .data, so fall through.  */
-      if (asm_emit_uninitialised (decl, name, size, rounded))
-       return;
-    }
-
-  /* Handle initialized definitions.
-     Also handle uninitialized global definitions if -fno-common and the
-     target doesn't support ASM_OUTPUT_BSS.  */
-
   /* First make the assembler name(s) global if appropriate.  */
   /* First make the assembler name(s) global if appropriate.  */
-  if (TREE_PUBLIC (decl) && DECL_NAME (decl))
+  sect = get_variable_section (decl, false);
+  if (TREE_PUBLIC (decl)
+      && DECL_NAME (decl)
+      && (sect->common.flags & SECTION_COMMON) == 0)
     globalize_decl (decl);
 
   /* Output any data that we will need to use the address of.  */
     globalize_decl (decl);
 
   /* Output any data that we will need to use the address of.  */
@@ -1801,14 +1819,16 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
   /* If the decl is part of an object_block, make sure that the decl
      has been positioned within its block, but do not write out its
      definition yet.  output_object_blocks will do that later.  */
   /* If the decl is part of an object_block, make sure that the decl
      has been positioned within its block, but do not write out its
      definition yet.  output_object_blocks will do that later.  */
-  if (in_block_p)
+  if (SYMBOL_REF_IN_BLOCK_P (symbol) && SYMBOL_REF_BLOCK (symbol))
     {
       gcc_assert (!dont_output_data);
     {
       gcc_assert (!dont_output_data);
-      place_block_symbol (XEXP (decl_rtl, 0));
+      place_block_symbol (symbol);
     }
     }
+  else if (SECTION_STYLE (sect) == SECTION_NOSWITCH)
+    assemble_noswitch_variable (decl, name, sect);
   else
     {
   else
     {
-      switch_to_section (get_variable_section (decl));
+      switch_to_section (sect);
       if (align > BITS_PER_UNIT)
        ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DECL_ALIGN_UNIT (decl)));
       assemble_variable_contents (decl, name, dont_output_data);
       if (align > BITS_PER_UNIT)
        ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DECL_ALIGN_UNIT (decl)));
       assemble_variable_contents (decl, name, dont_output_data);
@@ -2927,7 +2947,7 @@ output_constant_def_contents (rtx symbol)
   /* If the constant is part of an object block, make sure that the
      decl has been positioned within its block, but do not write out
      its definition yet.  output_object_blocks will do that later.  */
   /* If the constant is part of an object block, make sure that the
      decl has been positioned within its block, but do not write out
      its definition yet.  output_object_blocks will do that later.  */
-  if (SYMBOL_REF_IN_BLOCK_P (symbol))
+  if (SYMBOL_REF_IN_BLOCK_P (symbol) && SYMBOL_REF_BLOCK (symbol))
     place_block_symbol (symbol);
   else
     {
     place_block_symbol (symbol);
   else
     {
@@ -3488,7 +3508,7 @@ output_constant_pool (const char *fnname ATTRIBUTE_UNUSED,
           the constant has been positioned within its block, but do not
           write out its definition yet.  output_object_blocks will do
           that later.  */
           the constant has been positioned within its block, but do not
           write out its definition yet.  output_object_blocks will do
           that later.  */
-       if (SYMBOL_REF_IN_BLOCK_P (desc->sym))
+       if (SYMBOL_REF_IN_BLOCK_P (desc->sym) && SYMBOL_REF_BLOCK (desc->sym))
          place_block_symbol (desc->sym);
        else
          {
          place_block_symbol (desc->sym);
        else
          {
@@ -5085,6 +5105,18 @@ init_varasm_once (void)
                                      SBSS_SECTION_ASM_OP);
 #endif
 
                                      SBSS_SECTION_ASM_OP);
 #endif
 
+  tls_comm_section = get_noswitch_section (SECTION_WRITE | SECTION_BSS
+                                          | SECTION_COMMON, emit_tls_common);
+  lcomm_section = get_noswitch_section (SECTION_WRITE | SECTION_BSS
+                                       | SECTION_COMMON, emit_local);
+  comm_section = get_noswitch_section (SECTION_WRITE | SECTION_BSS
+                                      | SECTION_COMMON, emit_common);
+
+#if defined ASM_OUTPUT_ALIGNED_BSS || defined ASM_OUTPUT_BSS
+  bss_noswitch_section = get_noswitch_section (SECTION_WRITE | SECTION_BSS,
+                                              emit_bss);
+#endif
+
   targetm.asm_out.init_sections ();
 
   if (readonly_data_section == NULL)
   targetm.asm_out.init_sections ();
 
   if (readonly_data_section == NULL)
@@ -5191,6 +5223,16 @@ default_section_type_flags_1 (tree decl, const char *name, int reloc,
   return flags;
 }
 
   return flags;
 }
 
+/* Return true if the target supports some form of global BSS,
+   either through bss_noswitch_section, or by selecting a BSS
+   section in TARGET_ASM_SELECT_SECTION.  */
+
+bool
+have_global_bss_p (void)
+{
+  return bss_noswitch_section || targetm.have_switchable_bss_sections;
+}
+
 /* Output assembly to switch to section NAME with attribute FLAGS.
    Four variants for common object file formats.  */
 
 /* Output assembly to switch to section NAME with attribute FLAGS.
    Four variants for common object file formats.  */
 
@@ -5344,12 +5386,7 @@ categorize_decl_for_section (tree decl, int reloc, int shlib)
     }
   else if (TREE_CODE (decl) == VAR_DECL)
     {
     }
   else if (TREE_CODE (decl) == VAR_DECL)
     {
-      if (DECL_INITIAL (decl) == NULL
-         || DECL_INITIAL (decl) == error_mark_node
-         || (flag_zero_initialized_in_bss
-             /* Leave constant zeroes in .rodata so they can be shared.  */
-             && !TREE_READONLY (decl)
-             && initializer_zerop (DECL_INITIAL (decl))))
+      if (bss_initializer_p (decl))
        ret = SECCAT_BSS;
       else if (! TREE_READONLY (decl)
               || TREE_SIDE_EFFECTS (decl)
        ret = SECCAT_BSS;
       else if (! TREE_READONLY (decl)
               || TREE_SIDE_EFFECTS (decl)
@@ -5888,8 +5925,9 @@ switch_to_section (section *new_section)
   else
     in_section = new_section;
 
   else
     in_section = new_section;
 
-  if (new_section->common.flags & SECTION_NAMED)
+  switch (SECTION_STYLE (new_section))
     {
     {
+    case SECTION_NAMED:
       if (cfun
          && !cfun->unlikely_text_section_name
          && strcmp (new_section->named.name,
       if (cfun
          && !cfun->unlikely_text_section_name
          && strcmp (new_section->named.name,
@@ -5899,9 +5937,16 @@ switch_to_section (section *new_section)
       targetm.asm_out.named_section (new_section->named.name,
                                     new_section->named.common.flags,
                                     new_section->named.decl);
       targetm.asm_out.named_section (new_section->named.name,
                                     new_section->named.common.flags,
                                     new_section->named.decl);
+      break;
+
+    case SECTION_UNNAMED:
+      new_section->unnamed.callback (new_section->unnamed.data);
+      break;
+
+    case SECTION_NOSWITCH:
+      gcc_unreachable ();
+      break;
     }
     }
-  else
-    new_section->unnamed.callback (new_section->unnamed.data);
 
   new_section->common.flags |= SECTION_DECLARED;
 }
 
   new_section->common.flags |= SECTION_DECLARED;
 }
@@ -5918,6 +5963,7 @@ place_block_symbol (rtx symbol)
   struct object_block *block;
   tree decl;
 
   struct object_block *block;
   tree decl;
 
+  gcc_assert (SYMBOL_REF_BLOCK (symbol));
   if (SYMBOL_REF_BLOCK_OFFSET (symbol) >= 0)
     return;
 
   if (SYMBOL_REF_BLOCK_OFFSET (symbol) >= 0)
     return;