Add generic support for noinit attribute.
authorChristophe Lyon <christophe.lyon@linaro.org>
Wed, 14 Aug 2019 13:14:59 +0000 (13:14 +0000)
committerChristophe Lyon <clyon@gcc.gnu.org>
Wed, 14 Aug 2019 13:14:59 +0000 (15:14 +0200)
    Similar to what already exists for TI msp430 or in TI compilers for
    arm, this patch adds support for the "noinit" attribute.

    It is convenient for embedded targets where the user wants to keep the
    value of some data when the program is restarted: such variables are
    not zero-initialized. It is mostly a helper/shortcut to placing
    variables in a dedicated section.

    It's probably desirable to add the following chunk to the GNU linker:
    diff --git a/ld/emulparams/armelf.sh b/ld/emulparams/armelf.sh
    index 272a8bc..9555cec 100644
    --- a/ld/emulparams/armelf.sh
    +++ b/ld/emulparams/armelf.sh
    @@ -10,7 +10,19 @@ OTHER_TEXT_SECTIONS='*(.glue_7t) *(.glue_7)
    *(.vfp11_veneer) *(.v4_bx)'
     OTHER_BSS_SYMBOLS="${CREATE_SHLIB+PROVIDE (}__bss_start__ =
    .${CREATE_SHLIB+)};"
     OTHER_BSS_END_SYMBOLS="${CREATE_SHLIB+PROVIDE (}_bss_end__ =
    .${CREATE_SHLIB+)}; ${CREATE_SHLIB+PROVIDE (}__bss_end__ =
    .${CREATE_SHLIB+)};"
     OTHER_END_SYMBOLS="${CREATE_SHLIB+PROVIDE (}__end__ = .${CREATE_SHLIB+)};"
     -OTHER_SECTIONS='.note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }'
     +OTHER_SECTIONS='
     +.note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
     +  /* This section contains data that is not initialised during load
     +     *or* application reset.  */
     +   .noinit (NOLOAD) :
     +   {
     +     . = ALIGN(2);
     +     PROVIDE (__noinit_start = .);
     +     *(.noinit)
     +     . = ALIGN(2);
     +     PROVIDE (__noinit_end = .);
     +   }
     +'

    so that the noinit section has the "NOLOAD" flag.

    I added a testcase if gcc.c-torture/execute, gated by the new noinit
    effective-target.

    Finally, I tested on arm-eabi, but not on msp430 for which I do not
    have the environment.

gcc/ChangeLog:

2019-08-14  Christophe Lyon  <christophe.lyon@linaro.org>

* doc/extend.texi: Add "noinit" attribute documentation.
* doc/sourcebuild.texi: Add noinit effective target documentation.
* varasm.c (default_section_type_flags): Add support for "noinit" section.
(default_elf_select_section): Add support for "noinit" attribute.
* config/msp430/msp430.c (msp430_attribute_table): Remove "noinit" entry.

gcc/c-family/ChangeLog:

2019-08-14  Christophe Lyon  <christophe.lyon@linaro.org>

* c-attribs.c (c_common_attribute_table): Add "noinit" entry. Add
exclusion with "section" attribute.
(attr_noinit_exclusions): New table.
(handle_noinit_attribute): New function.

gcc/testsuite/ChangeLog:

2019-08-14  Christophe Lyon  <christophe.lyon@linaro.org>

* lib/target-supports.exp (check_effective_target_noinit): New
proc.
* gcc.c-torture/execute/noinit-attribute.c: New test.

From-SVN: r274482

gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c-attribs.c
gcc/config/msp430/msp430.c
gcc/doc/extend.texi
gcc/doc/sourcebuild.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/execute/noinit-attribute.c [new file with mode: 0644]
gcc/testsuite/lib/target-supports.exp
gcc/varasm.c

index d745e1dfd74f1d2417490e97489c212c8f782857..30665a69f0ca869a175c95c9753327094f6907d6 100644 (file)
@@ -1,3 +1,12 @@
+2019-08-14  Christophe Lyon  <christophe.lyon@linaro.org>
+
+       * doc/extend.texi: Add "noinit" attribute documentation.
+       * doc/sourcebuild.texi: Add noinit effective target documentation.
+       * varasm.c (default_section_type_flags): Add support for "noinit"
+       section.
+       (default_elf_select_section): Add support for "noinit" attribute.
+       * config/msp430/msp430.c (msp430_attribute_table): Remove "noinit" entry.
+
 2019-08-14  Richard Biener  <rguenther@suse.de>
        Uroš Bizjak  <ubizjak@gmail.com>
 
index c3bd56cf4c6203d63fe6798d43d92842101ed183..48e59366123394d3e2ea1bab546689b5a1c2717d 100644 (file)
@@ -1,3 +1,10 @@
+2019-08-14  Christophe Lyon  <christophe.lyon@linaro.org>
+
+       * c-attribs.c (c_common_attribute_table): Add "noinit" entry. Add
+       exclusion with "section" attribute.
+       (attr_noinit_exclusions): New table.
+       (handle_noinit_attribute): New function.
+
 2019-08-13  Richard Sandiford  <richard.sandiford@arm.com>
 
        PR middle-end/91421
index 48819e74e5b619639fd4293b605d12d7ee6a809c..820c83fa3b96c6c6774f524c0b9261d58e10b657 100644 (file)
@@ -92,6 +92,7 @@ static tree handle_section_attribute (tree *, tree, tree, int, bool *);
 static tree handle_aligned_attribute (tree *, tree, tree, int, bool *);
 static tree handle_warn_if_not_aligned_attribute (tree *, tree, tree,
                                                  int, bool *);
+static tree handle_noinit_attribute (tree *, tree, tree, int, bool *);
 static tree handle_weak_attribute (tree *, tree, tree, int, bool *) ;
 static tree handle_noplt_attribute (tree *, tree, tree, int, bool *) ;
 static tree handle_alias_ifunc_attribute (bool, tree *, tree, tree, bool *);
@@ -235,6 +236,13 @@ static const struct attribute_spec::exclusions attr_const_pure_exclusions[] =
   ATTR_EXCL (NULL, false, false, false)
 };
 
+static const struct attribute_spec::exclusions attr_noinit_exclusions[] =
+{
+  ATTR_EXCL ("noinit", true, true, true),
+  ATTR_EXCL ("section", true, true, true),
+  ATTR_EXCL (NULL, false, false, false),
+};
+
 /* Table of machine-independent attributes common to all C-like languages.
 
    Current list of processed common attributes: nonnull.  */
@@ -307,7 +315,7 @@ const struct attribute_spec c_common_attribute_table[] =
   { "mode",                   1, 1, false,  true, false, false,
                              handle_mode_attribute, NULL },
   { "section",                1, 1, true,  false, false, false,
-                             handle_section_attribute, NULL },
+                             handle_section_attribute, attr_noinit_exclusions },
   { "aligned",                0, 1, false, false, false, false,
                              handle_aligned_attribute,
                              attr_aligned_exclusions },
@@ -458,6 +466,8 @@ const struct attribute_spec c_common_attribute_table[] =
                              handle_nocf_check_attribute, NULL },
   { "copy",                   1, 1, false, false, false, false,
                              handle_copy_attribute, NULL },
+  { "noinit",                0, 0, true,  false, false, false,
+                             handle_noinit_attribute, attr_noinit_exclusions },
   { NULL,                     0, 0, false, false, false, false, NULL, NULL }
 };
 
@@ -2224,6 +2234,54 @@ handle_weak_attribute (tree *node, tree name,
   return NULL_TREE;
 }
 
+/* Handle a "noinit" attribute; arguments as in struct
+   attribute_spec.handler.  Check whether the attribute is allowed
+   here and add the attribute to the variable decl tree or otherwise
+   issue a diagnostic.  This function checks NODE is of the expected
+   type and issues diagnostics otherwise using NAME.  If it is not of
+   the expected type *NO_ADD_ATTRS will be set to true.  */
+
+static tree
+handle_noinit_attribute (tree * node,
+                 tree   name,
+                 tree   args,
+                 int    flags ATTRIBUTE_UNUSED,
+                 bool *no_add_attrs)
+{
+  const char *message = NULL;
+
+  gcc_assert (DECL_P (*node));
+  gcc_assert (args == NULL);
+
+  if (TREE_CODE (*node) != VAR_DECL)
+    message = G_("%qE attribute only applies to variables");
+
+  /* Check that it's possible for the variable to have a section.  */
+  else if ((TREE_STATIC (*node) || DECL_EXTERNAL (*node) || in_lto_p)
+          && DECL_SECTION_NAME (*node))
+    message = G_("%qE attribute cannot be applied to variables "
+                "with specific sections");
+
+  else if (!targetm.have_switchable_bss_sections)
+    message = G_("%qE attribute is specific to ELF targets");
+
+  if (message)
+    {
+      warning (OPT_Wattributes, message, name);
+      *no_add_attrs = true;
+    }
+  else
+    /* If this var is thought to be common, then change this.  Common
+       variables are assigned to sections before the backend has a
+       chance to process them.  Do this only if the attribute is
+       valid.  */
+    if (DECL_COMMON (*node))
+      DECL_COMMON (*node) = 0;
+
+  return NULL_TREE;
+}
+
+
 /* Handle a "noplt" attribute; arguments as in
    struct attribute_spec.handler.  */
 
index 72e62d2f785962d10541707d8380237d39719492..369cb264e89f578a5643d52568ee6bb2024dd7d9 100644 (file)
@@ -1521,8 +1521,6 @@ const struct attribute_spec msp430_attribute_table[] =
   { ATTR_EITHER,      0, 0, true,  false, false, false, msp430_section_attr,
     NULL },
 
-  { ATTR_NOINIT,      0, 0, true,  false, false, false, msp430_data_attr,
-    NULL },
   { ATTR_PERSIST,     0, 0, true,  false, false, false, msp430_data_attr,
     NULL },
 
@@ -1751,6 +1749,8 @@ msp430_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align)
     {
       if (TREE_CODE (decl) == FUNCTION_DECL)
        return text_section;
+      /* FIXME: ATTR_NOINIT is handled generically in
+        default_elf_select_section.  */
       else if (has_attr (ATTR_NOINIT, decl))
        return noinit_section;
       else if (has_attr (ATTR_PERSIST, decl))
index 1666972d5ebd556f096b9748171c8376128d8beb..2ba9b74811aecbb2bffde0f85b4417fd557b9193 100644 (file)
@@ -7156,6 +7156,14 @@ The @code{visibility} attribute is described in
 The @code{weak} attribute is described in
 @ref{Common Function Attributes}.
 
+@item noinit
+@cindex @code{noinit} variable attribute
+Any data with the @code{noinit} attribute will not be initialized by
+the C runtime startup code, or the program loader.  Not initializing
+data in this way can reduce program startup times.  This attribute is
+specific to ELF targets and relies on the linker to place such data in
+the right location
+
 @end table
 
 @node ARC Variable Attributes
index 73186c5853704acfaefb22de859dc53aa37c136f..f9fcd0916b3a55fb1ea5708a13efd7fb1a7cd568 100644 (file)
@@ -2302,6 +2302,9 @@ Target uses natural alignment (aligned to type size) for types of
 Target uses natural alignment (aligned to type size) for types of
 64 bits or less.
 
+@item noinit
+Target supports the @code{noinit} variable attribute.
+
 @item nonpic
 Target does not generate PIC by default.
 
index afe27ee58bb4a5f861da535748c5c8380a4ee9cc..3a5155e202bce88a2c5ba00e299867e6598c8472 100644 (file)
@@ -1,3 +1,9 @@
+2019-08-14  Christophe Lyon  <christophe.lyon@linaro.org>
+
+       * lib/target-supports.exp (check_effective_target_noinit): New
+       proc.
+       * gcc.c-torture/execute/noinit-attribute.c: New test.
+
 2019-08-14  Richard Biener  <rguenther@suse.de>
 
        PR target/91154
diff --git a/gcc/testsuite/gcc.c-torture/execute/noinit-attribute.c b/gcc/testsuite/gcc.c-torture/execute/noinit-attribute.c
new file mode 100644 (file)
index 0000000..ffcf8c6
--- /dev/null
@@ -0,0 +1,59 @@
+/* { dg-do run } */
+/* { dg-require-effective-target noinit */
+/* { dg-options "-O2" } */
+
+/* This test checks that noinit data is handled correctly.  */
+
+extern void _start (void) __attribute__ ((noreturn));
+extern void abort (void) __attribute__ ((noreturn));
+extern void exit (int) __attribute__ ((noreturn));
+
+int var_common;
+int var_zero = 0;
+int var_one = 1;
+int __attribute__((noinit)) var_noinit;
+int var_init = 2;
+
+int __attribute__((noinit)) func(); /* { dg-warning "attribute only applies to variables" } */
+int __attribute__((section ("mysection"), noinit)) var_section1; /* { dg-warning "because it conflicts with attribute" } */
+int __attribute__((noinit, section ("mysection"))) var_section2; /* { dg-warning "because it conflicts with attribute" } */
+
+
+int
+main (void)
+{
+  /* Make sure that the C startup code has correctly initialized the ordinary variables.  */
+  if (var_common != 0)
+    abort ();
+
+  /* Initialized variables are not re-initialized during startup, so
+     check their original values only during the first run of this
+     test.  */
+  if (var_init == 2)
+    if (var_zero != 0 || var_one != 1)
+      abort ();
+
+  switch (var_init)
+    {
+    case 2:
+      /* First time through - change all the values.  */
+      var_common = var_zero = var_one = var_noinit = var_init = 3;
+      break;
+
+    case 3:
+      /* Second time through - make sure that d has not been reset.  */
+      if (var_noinit != 3)
+       abort ();
+      exit (0);
+
+    default:
+      /* Any other value for var_init is an error.  */
+      abort ();
+    }
+
+  /* Simulate a processor reset by calling the C startup code.  */
+  _start ();
+
+  /* Should never reach here.  */
+  abort ();
+}
index a33822f76313d1a6f52b52bde99880b8439cba76..300d22a2d650b8f556b51b3e12d612855bbbfa73 100644 (file)
@@ -364,6 +364,18 @@ proc check_weak_override_available { } {
     return [check_weak_available]
 }
 
+# The noinit attribute is only supported by some targets.
+# This proc returns 1 if it's supported, 0 if it's not.
+
+proc check_effective_target_noinit { } {
+    if { [istarget arm*-*-eabi]
+        || [istarget msp430-*-*] } {
+       return 1
+    }
+
+    return 0
+}
+
 ###############################
 # proc check_visibility_available { what_kind }
 ###############################
index e886cdc71b8a8470a6644222a34fb53705067802..ae25f4d9c1672e6e9f215e693290d139b0ab634d 100644 (file)
@@ -6430,6 +6430,9 @@ default_section_type_flags (tree decl, const char *name, int reloc)
       || strncmp (name, ".gnu.linkonce.tb.", 17) == 0)
     flags |= SECTION_TLS | SECTION_BSS;
 
+  if (strcmp (name, ".noinit") == 0)
+    flags |= SECTION_WRITE | SECTION_BSS | SECTION_NOTYPE;
+
   /* Various sections have special ELF types that the assembler will
      assign by default based on the name.  They are neither SHT_PROGBITS
      nor SHT_NOBITS, so when changing sections we don't want to print a
@@ -6755,6 +6758,7 @@ default_elf_select_section (tree decl, int reloc,
                            unsigned HOST_WIDE_INT align)
 {
   const char *sname;
+
   switch (categorize_decl_for_section (decl, reloc))
     {
     case SECCAT_TEXT:
@@ -6792,6 +6796,13 @@ default_elf_select_section (tree decl, int reloc,
       sname = ".tdata";
       break;
     case SECCAT_BSS:
+      if (DECL_P (decl)
+         && lookup_attribute ("noinit", DECL_ATTRIBUTES (decl)) != NULL_TREE)
+       {
+         sname = ".noinit";
+         break;
+       }
+
       if (bss_section)
        return bss_section;
       sname = ".bss";