From: Christophe Lyon <christophe.lyon@linaro.org>
To: Kyrill Tkachov <kyrylo.tkachov@foss.arm.com>
Cc: gcc Patches <gcc-patches@gcc.gnu.org>
Subject: Re: [PATCH][ARM] Add support for "noinit" attribute
Date: Tue, 02 Jul 2019 15:01:00 -0000 [thread overview]
Message-ID: <CAKdteOZSZDeCgMDFj5rj=1aGx6topGaW7NKyC6=aC8HqBfQr4w@mail.gmail.com> (raw)
In-Reply-To: <b44490f1-0c1b-94eb-9e54-0edb4de72bc3@foss.arm.com>
[-- Attachment #1: Type: text/plain, Size: 10008 bytes --]
Hi Kyrill,
On Mon, 1 Jul 2019 at 17:58, Kyrill Tkachov <kyrylo.tkachov@foss.arm.com> wrote:
>
> Hi Christophe,
>
> On 6/13/19 4:13 PM, Christophe Lyon wrote:
> > Hi,
> >
> > Similar to what already exists for TI msp430 or in TI compilers for
> > arm, this patch adds support for "noinit" attribute for arm. It's very
> > similar to the corresponding code in GCC for msp430.
> >
> > It is useful 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'll submit that part separately to the binutils project if OK.
> >
> > OK?
> >
>
> This is mostly ok by me, with a few code comments inline.
>
> I wonder whether this is something we could implement for all targets in
> the midend, but this would require linker script support for the target
> to be effective...
>
> Thanks,
>
> Kyrill
>
> > Thanks,
> >
> > Christophe
>
> diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
> index e3e71ea..332c41b 100644
> --- a/gcc/config/arm/arm.c
> +++ b/gcc/config/arm/arm.c
> @@ -151,6 +151,7 @@ static tree arm_handle_notshared_attribute (tree *, tree, tree, int, bool *);
> #endif
> static tree arm_handle_cmse_nonsecure_entry (tree *, tree, tree, int, bool *);
> static tree arm_handle_cmse_nonsecure_call (tree *, tree, tree, int, bool *);
> +static tree arm_data_attr (tree *, tree, tree, int, bool *);
> static void arm_output_function_epilogue (FILE *);
> static void arm_output_function_prologue (FILE *);
> static int arm_comp_type_attributes (const_tree, const_tree);
> @@ -375,7 +376,8 @@ static const struct attribute_spec arm_attribute_table[] =
> arm_handle_cmse_nonsecure_entry, NULL },
> { "cmse_nonsecure_call", 0, 0, true, false, false, true,
> arm_handle_cmse_nonsecure_call, NULL },
> - { NULL, 0, 0, false, false, false, false, NULL, NULL }
> + { "noinit", 0, 0, true, false, false, false, arm_data_attr, NULL },
> + { NULL, 0, 0, false, false, false, false, NULL, NULL },
> };
>
> /* Initialize the GCC target structure. */
> @@ -808,6 +810,10 @@ static const struct attribute_spec arm_attribute_table[] =
>
> #undef TARGET_CONSTANT_ALIGNMENT
> #define TARGET_CONSTANT_ALIGNMENT arm_constant_alignment
> +
> +#undef TARGET_ASM_SELECT_SECTION
> +#define TARGET_ASM_SELECT_SECTION arm_select_section
> +
>
> /* Obstack for minipool constant handling. */
> static struct obstack minipool_obstack;
> @@ -7150,6 +7156,47 @@ arm_handle_cmse_nonsecure_call (tree *node, tree name,
> return NULL_TREE;
> }
>
> +/* Called when the noinit attribute is used. 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
> +arm_data_attr (tree * node,
> + tree name,
> + tree args ATTRIBUTE_UNUSED,
> + int flags ATTRIBUTE_UNUSED,
> + bool * no_add_attrs ATTRIBUTE_UNUSED)
> +{
>
> no_add_attrs is set in this function, so should not be ATTRIBUTE_UNUSED?
Right! Guess what? There's the same mistake in msp430.c :-)
> Arguably args is also checked against NULL, so it's technically not unused either.
Right.
> + const char * message = NULL;
> +
> + gcc_assert (DECL_P (* node));
>
> The house style doesn't have a space after '*'. Same elsewhere in the patch.
OK
>
> + 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. */
> + 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");
> +
> + /* 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. */
> + if (DECL_COMMON (* node))
> + DECL_COMMON (* node) = 0;
> +
> + if (message)
> + {
> + warning (OPT_Wattributes, message, name);
> + * no_add_attrs = true;
> + }
> +
> + return NULL_TREE;
> +}
> +
> /* Return 0 if the attributes for two types are incompatible, 1 if they
> are compatible, and 2 if they are nearly compatible (which causes a
> warning to be generated). */
> @@ -27890,6 +27937,8 @@ arm_asm_emit_except_personality (rtx personality)
>
> /* Implement TARGET_ASM_INITIALIZE_SECTIONS. */
>
> +static section *noinit_section;
> +
> static void
> arm_asm_init_sections (void)
> {
> @@ -27902,6 +27951,19 @@ arm_asm_init_sections (void)
> if (target_pure_code)
> text_section->unnamed.data = "\t.section .text,\"0x20000006\",%progbits";
> #endif
> +
> + noinit_section = get_unnamed_section (0, output_section_asm_op, ".section .noinit,\"aw\"");
> +}
> +
> +static section *
> +arm_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align)
> +{
>
> Please add a function comment.
OK
>
> + gcc_assert (decl != NULL_TREE);
> +
> + if (DECL_P (decl) && lookup_attribute ("noinit", DECL_ATTRIBUTES (decl)) != NULL_TREE)
> + return noinit_section;
> + else
> + return default_elf_select_section (decl, reloc, align);
> }
>
> /* Output unwind directives for the start/end of a function. */
> @@ -31520,6 +31582,9 @@ arm_elf_section_type_flags (tree decl, const char *name, int reloc)
> if (decl && TREE_CODE (decl) == FUNCTION_DECL && target_pure_code)
> flags |= SECTION_ARM_PURECODE;
>
> + if (strcmp (name, ".noinit") == 0)
> + flags = SECTION_WRITE | SECTION_BSS | SECTION_NOTYPE;
> +
>
>
> You're overwriting the flags here. Are you sure you don't want "flags |= ..." here?
Indeed!
Here is an updated patch, which also addresses Sandra's comments.
Thanks
>
>
> return flags;
> }
>
> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
> index 2520835..d544527 100644
> --- a/gcc/doc/extend.texi
> +++ b/gcc/doc/extend.texi
> @@ -6684,6 +6684,7 @@ attributes.
> @menu
> * Common Variable Attributes::
> * ARC Variable Attributes::
> +* ARM Variable Attributes::
> * AVR Variable Attributes::
> * Blackfin Variable Attributes::
> * H8/300 Variable Attributes::
> @@ -7131,6 +7132,18 @@ given via attribute argument.
>
> @end table
>
> +@node ARM Variable Attributes
> +@subsection ARM Variable Attributes
> +
> +@table @code
> +@item noinit
> +@cindex @code{noinit} variable attribute, ARM
> +Any data with the @code{noinit} attribute will not be initialised by
> +the C runtime startup code, or the program loader. Not initialising
> +data in this way can reduce program startup times.
> +
> +@end table
> +
> @node AVR Variable Attributes
> @subsection AVR Variable Attributes
>
> diff --git a/gcc/testsuite/gcc.target/arm/data-attributes.c b/gcc/testsuite/gcc.target/arm/data-attributes.c
> new file mode 100644
> index 0000000..323c8e0
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/arm/data-attributes.c
> @@ -0,0 +1,51 @@
> +/* { dg-do run { target { ! *-*-linux* } } } */
> +/* { 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
> +main (void)
> +{
> + /* Make sure that the C startup code has correctly initialised the ordinary variables. */
> + if (var_common != 0)
> + abort ();
> +
> + /* Initialised variables are not re-initialised 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 ();
> +}
>
[-- Attachment #2: noinit-v4.patch.txt --]
[-- Type: text/plain, Size: 7075 bytes --]
commit d1f3585a50b0b4ff3df6c833d99c4be0065f1363
Author: Christophe Lyon <christophe.lyon@linaro.org>
Date: Tue Jun 11 21:09:08 2019 +0000
Add support for noinit attribute.
Change-Id: Ib7090c037f67e521ad9753e1a78ed5731996fefe
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index e3e71ea..caac216 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -151,6 +151,7 @@ static tree arm_handle_notshared_attribute (tree *, tree, tree, int, bool *);
#endif
static tree arm_handle_cmse_nonsecure_entry (tree *, tree, tree, int, bool *);
static tree arm_handle_cmse_nonsecure_call (tree *, tree, tree, int, bool *);
+static tree arm_data_attr (tree *, tree, tree, int, bool *);
static void arm_output_function_epilogue (FILE *);
static void arm_output_function_prologue (FILE *);
static int arm_comp_type_attributes (const_tree, const_tree);
@@ -375,7 +376,8 @@ static const struct attribute_spec arm_attribute_table[] =
arm_handle_cmse_nonsecure_entry, NULL },
{ "cmse_nonsecure_call", 0, 0, true, false, false, true,
arm_handle_cmse_nonsecure_call, NULL },
- { NULL, 0, 0, false, false, false, false, NULL, NULL }
+ { "noinit", 0, 0, true, false, false, false, arm_data_attr, NULL },
+ { NULL, 0, 0, false, false, false, false, NULL, NULL },
};
\f
/* Initialize the GCC target structure. */
@@ -808,6 +810,10 @@ static const struct attribute_spec arm_attribute_table[] =
#undef TARGET_CONSTANT_ALIGNMENT
#define TARGET_CONSTANT_ALIGNMENT arm_constant_alignment
+
+#undef TARGET_ASM_SELECT_SECTION
+#define TARGET_ASM_SELECT_SECTION arm_select_section
+
\f
/* Obstack for minipool constant handling. */
static struct obstack minipool_obstack;
@@ -7150,6 +7156,47 @@ arm_handle_cmse_nonsecure_call (tree *node, tree name,
return NULL_TREE;
}
+/* Called when the noinit attribute is used. 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
+arm_data_attr (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. */
+ 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");
+
+ /* 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. */
+ if (DECL_COMMON (* node))
+ DECL_COMMON (* node) = 0;
+
+ if (message)
+ {
+ warning (OPT_Wattributes, message, name);
+ * no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
/* Return 0 if the attributes for two types are incompatible, 1 if they
are compatible, and 2 if they are nearly compatible (which causes a
warning to be generated). */
@@ -27890,6 +27937,8 @@ arm_asm_emit_except_personality (rtx personality)
/* Implement TARGET_ASM_INITIALIZE_SECTIONS. */
+static section *noinit_section;
+
static void
arm_asm_init_sections (void)
{
@@ -27902,6 +27951,21 @@ arm_asm_init_sections (void)
if (target_pure_code)
text_section->unnamed.data = "\t.section .text,\"0x20000006\",%progbits";
#endif
+
+ noinit_section = get_unnamed_section (0, output_section_asm_op, ".section .noinit,\"aw\"");
+}
+
+/* Select noinit_section if DECL has the "noinit" attribute, use the
+ default ELF rules otherwise. */
+static section *
+arm_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align)
+{
+ gcc_assert (decl != NULL_TREE);
+
+ if (DECL_P (decl) && lookup_attribute ("noinit", DECL_ATTRIBUTES (decl)) != NULL_TREE)
+ return noinit_section;
+ else
+ return default_elf_select_section (decl, reloc, align);
}
/* Output unwind directives for the start/end of a function. */
@@ -31520,6 +31584,9 @@ arm_elf_section_type_flags (tree decl, const char *name, int reloc)
if (decl && TREE_CODE (decl) == FUNCTION_DECL && target_pure_code)
flags |= SECTION_ARM_PURECODE;
+ if (strcmp (name, ".noinit") == 0)
+ flags |= SECTION_WRITE | SECTION_BSS | SECTION_NOTYPE;
+
return flags;
}
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 2520835..d27ebf9 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -6684,6 +6684,7 @@ attributes.
@menu
* Common Variable Attributes::
* ARC Variable Attributes::
+* ARM Variable Attributes::
* AVR Variable Attributes::
* Blackfin Variable Attributes::
* H8/300 Variable Attributes::
@@ -7131,6 +7132,18 @@ given via attribute argument.
@end table
+@node ARM Variable Attributes
+@subsection ARM Variable Attributes
+
+@table @code
+@item noinit
+@cindex @code{noinit} variable attribute, ARM
+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.
+
+@end table
+
@node AVR Variable Attributes
@subsection AVR Variable Attributes
diff --git a/gcc/testsuite/gcc.target/arm/data-attributes.c b/gcc/testsuite/gcc.target/arm/data-attributes.c
new file mode 100644
index 0000000..323c8e0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/data-attributes.c
@@ -0,0 +1,51 @@
+/* { dg-do run { target { ! *-*-linux* } } } */
+/* { 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
+main (void)
+{
+ /* Make sure that the C startup code has correctly initialised the ordinary variables. */
+ if (var_common != 0)
+ abort ();
+
+ /* Initialised variables are not re-initialised 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 ();
+}
next prev parent reply other threads:[~2019-07-02 15:01 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-06-13 15:13 Christophe Lyon
2019-07-01 12:16 ` Christophe Lyon
2019-07-01 15:58 ` Kyrill Tkachov
2019-07-02 8:39 ` Richard Earnshaw
2019-07-02 8:44 ` Richard Earnshaw
2019-07-02 10:13 ` Richard Earnshaw
2019-07-02 10:30 ` Richard Earnshaw
2019-07-02 14:49 ` Christophe Lyon
2019-07-03 9:51 ` Richard Earnshaw
2019-07-03 12:56 ` Christophe Lyon
2019-07-02 15:01 ` Christophe Lyon [this message]
2019-07-02 15:44 ` Martin Sebor
2019-07-02 17:12 ` Segher Boessenkool
2019-07-01 21:35 ` Sandra Loosemore
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAKdteOZSZDeCgMDFj5rj=1aGx6topGaW7NKyC6=aC8HqBfQr4w@mail.gmail.com' \
--to=christophe.lyon@linaro.org \
--cc=gcc-patches@gcc.gnu.org \
--cc=kyrylo.tkachov@foss.arm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).