From a2ea37fb4c8084421784c80bfd1a4e065980314c Mon Sep 17 00:00:00 2001 From: Andrew Burgess Date: Wed, 16 Nov 2016 22:10:52 +0000 Subject: [PATCH] gcc: remove unneeded global related to hot/cold partitioning The `user_defined_section_attribute' is used as part of the condition to determine if GCC should partition blocks within a function into hot and cold blocks. This global is initially false, and is set to true from within the file parse phase of GCC, as part of the attribute handling hook. The `user_defined_section_attribute' is reset to false as part of the final pass of GCC. However, the final pass is part of the optimisation phase of the compiler, and so if at any point during the file parse phase any function, or data, has a section attribute the global `user_defined_section_attribute' will be set to true. When GCC performs the block partitioning pass on the first function, if `user_defined_section_attribute' is true then the function will not be partitioned. Notice though, that due to the above, whether we partition this first function or not has nothing to do with whether the function has a section attribute, instead, if any function or data in the parsed file has a section attribute then we don't partition the first function. After performing (or not) the block partitioning pass on the first function we perform the final pass on the first function, at which point we reset `user_defined_section_attribute' to false. As parsing is complete by this point, we will never set `user_defined_section_attribute' to true after that, and so all of the following functions will have the partition blocks pass performed on them, even if the function has a section attribute, and will not be partitioned. Luckily we don't end up partitioning functions that should not be partitioned though. Due to the way that functions are selected during the assembler writing phase, if a function has a section attribute this takes priority over any hot/cold block partitioning that has been done. What we see from the above then is that the `user_defined_section_attribute' mechanism is broken. It was originally created when GCC parsed, optimised, and generated assembler function at a time. Now that we deal with the whole file in one go, we need to update the mechanism used to gate the block partitioning pass. This patch does this by looking specifically for a section attribute on the function DECL, which removes the need for a global variable, and will work whether we parse the whole file in one go, or one function at a time. A few new tests have been added. These check for the case where a function is not partitioned when it could be. gcc/ChangeLog: * gcc/bb-reorder.c: Remove 'toplev.h' include. (pass_partition_blocks::gate): No longer check user_defined_section_attribute, instead check the function decl for a section attribute. * gcc/c-family/c-attribs.c (handle_section_attribute): No longer set user_defined_section_attribute. * gcc/final.c (rest_of_handle_final): Likewise. * gcc/toplev.c: Remove definition of user_defined_section_attribute. * gcc/toplev.h: Remove declaration of user_defined_section_attribute. gcc/testsuiteChangeLog: * gcc.dg/tree-prof/section-attr-1.c: New file. * gcc.dg/tree-prof/section-attr-2.c: New file. * gcc.dg/tree-prof/section-attr-3.c: New file. From-SVN: r242519 --- gcc/ChangeLog | 13 ++++++ gcc/bb-reorder.c | 3 +- gcc/c-family/c-attribs.c | 2 - gcc/final.c | 2 - gcc/testsuite/ChangeLog | 6 +++ .../gcc.dg/tree-prof/section-attr-1.c | 45 +++++++++++++++++++ .../gcc.dg/tree-prof/section-attr-2.c | 44 ++++++++++++++++++ .../gcc.dg/tree-prof/section-attr-3.c | 45 +++++++++++++++++++ gcc/toplev.c | 5 --- gcc/toplev.h | 5 --- 10 files changed, 154 insertions(+), 16 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-prof/section-attr-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-prof/section-attr-2.c create mode 100644 gcc/testsuite/gcc.dg/tree-prof/section-attr-3.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9b0462151fb..bd70d4ea54d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2016-11-16 Andrew Burgess + + * gcc/bb-reorder.c: Remove 'toplev.h' include. + (pass_partition_blocks::gate): No longer check + user_defined_section_attribute, instead check the function decl + for a section attribute. + * gcc/c-family/c-attribs.c (handle_section_attribute): No longer + set user_defined_section_attribute. + * gcc/final.c (rest_of_handle_final): Likewise. + * gcc/toplev.c: Remove definition of user_defined_section_attribute. + * gcc/toplev.h: Remove declaration of + user_defined_section_attribute. + 2016-11-16 Maciej W. Rozycki * config/mips/mips.md (casesi_internal_mips16_): diff --git a/gcc/bb-reorder.c b/gcc/bb-reorder.c index 85bc5698090..e51ec085ca0 100644 --- a/gcc/bb-reorder.c +++ b/gcc/bb-reorder.c @@ -107,7 +107,6 @@ #include "output.h" #include "expr.h" #include "params.h" -#include "toplev.h" /* user_defined_section_attribute */ #include "tree-pass.h" #include "cfgrtl.h" #include "cfganal.h" @@ -2894,7 +2893,7 @@ pass_partition_blocks::gate (function *fun) we are going to omit the reordering. */ && optimize_function_for_speed_p (fun) && !DECL_COMDAT_GROUP (current_function_decl) - && !user_defined_section_attribute); + && !lookup_attribute ("section", DECL_ATTRIBUTES (fun->decl))); } unsigned diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c index 925f1b20c50..964efe94bb7 100644 --- a/gcc/c-family/c-attribs.c +++ b/gcc/c-family/c-attribs.c @@ -1438,8 +1438,6 @@ handle_section_attribute (tree *node, tree ARG_UNUSED (name), tree args, goto fail; } - user_defined_section_attribute = true; - if (!VAR_OR_FUNCTION_DECL_P (decl)) { error ("section attribute not allowed for %q+D", *node); diff --git a/gcc/final.c b/gcc/final.c index 5709d0e2406..d3a53c3cbe6 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -4484,8 +4484,6 @@ rest_of_handle_final (void) assemble_end_function (current_function_decl, fnname); - user_defined_section_attribute = false; - /* Free up reg info memory. */ free_reg_info (); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 3707e7c29d2..8958f86b898 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2016-11-16 Andrew Burgess + + * gcc.dg/tree-prof/section-attr-1.c: New file. + * gcc.dg/tree-prof/section-attr-2.c: New file. + * gcc.dg/tree-prof/section-attr-3.c: New file. + 2016-11-16 Maciej W. Rozycki * gcc.target/mips/code-readable-4.c (dg-final): Expect `dla' diff --git a/gcc/testsuite/gcc.dg/tree-prof/section-attr-1.c b/gcc/testsuite/gcc.dg/tree-prof/section-attr-1.c new file mode 100644 index 00000000000..ee6662ea6e5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-prof/section-attr-1.c @@ -0,0 +1,45 @@ +/* Checks for a bug where a function with a section attribute would prevent + all later functions from being partitioned into hot and cold blocks. */ +/* { dg-require-effective-target freorder } */ +/* { dg-options "-O2 -fno-profile-reorder-functions -freorder-blocks-and-partition -save-temps" } */ + +#define SIZE 10000 + +#define NOINLINE __attribute__((noinline)) __attribute__ ((noclone)) + +const char *sarr[SIZE]; +const char *buf_hot; +const char *buf_cold; + +void foo (int path); + +__attribute__((section(".text"))) +int +main (int argc, char *argv[]) +{ + int i; + buf_hot = "hello"; + buf_cold = "world"; + for (i = 0; i < 1000000; i++) + foo (argc); + return 0; +} + + +void NOINLINE +foo (int path) +{ + int i; + if (path) + { + for (i = 0; i < SIZE; i++) + sarr[i] = buf_hot; + } + else + { + for (i = 0; i < SIZE; i++) + sarr[i] = buf_cold; + } +} + +/* { dg-final-use { scan-assembler "\.section\[\t \]*\.text\.unlikely\[\\n\\r\]+\[\t \]*\.size\[\t \]*foo\.cold\.0" { target *-*-linux* *-*-gnu* } } } */ diff --git a/gcc/testsuite/gcc.dg/tree-prof/section-attr-2.c b/gcc/testsuite/gcc.dg/tree-prof/section-attr-2.c new file mode 100644 index 00000000000..898a395cd7e --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-prof/section-attr-2.c @@ -0,0 +1,44 @@ +/* Checks for a bug where static data with a section attribute within a + function would stop the function being partitioned into hot and cold + blocks. */ +/* { dg-require-effective-target freorder } */ +/* { dg-options "-O2 -fno-profile-reorder-functions -freorder-blocks-and-partition -save-temps" } */ + +#define SIZE 10000 + +#define NOINLINE __attribute__((noinline)) __attribute__ ((noclone)) + +const char *sarr[SIZE]; +const char *buf_hot; +const char *buf_cold; + +void foo (int path); + +int +main (int argc, char *argv[]) +{ + int i; + buf_hot = "hello"; + buf_cold = "world"; + for (i = 0; i < 1000000; i++) + foo (argc); + return 0; +} + +void NOINLINE +foo (int path) +{ + static int i __attribute__((section(".data"))); + if (path) + { + for (i = 0; i < SIZE; i++) + sarr[i] = buf_hot; + } + else + { + for (i = 0; i < SIZE; i++) + sarr[i] = buf_cold; + } +} + +/* { dg-final-use { scan-assembler "\.section\[\t \]*\.text\.unlikely\[\\n\\r\]+\[\t \]*\.size\[\t \]*foo\.cold\.0" { target *-*-linux* *-*-gnu* } } } */ diff --git a/gcc/testsuite/gcc.dg/tree-prof/section-attr-3.c b/gcc/testsuite/gcc.dg/tree-prof/section-attr-3.c new file mode 100644 index 00000000000..36829dcb7a0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-prof/section-attr-3.c @@ -0,0 +1,45 @@ +/* Checks for a bug where static data with a section attribute within a + function would stop the function being partitioned into hot and cold + blocks. */ +/* { dg-require-effective-target freorder } */ +/* { dg-options "-O2 -fno-profile-reorder-functions -freorder-blocks-and-partition -save-temps" } */ + +#define SIZE 10000 + +#define NOINLINE __attribute__((noinline)) __attribute__ ((noclone)) + +const char *sarr[SIZE]; +const char *buf_hot __attribute__ ((section (".data"))); +const char *buf_cold; + +void foo (int path); + +int +main (int argc, char *argv[]) +{ + int i; + buf_hot = "hello"; + buf_cold = "world"; + for (i = 0; i < 1000000; i++) + foo (argc); + return 0; +} + + +void NOINLINE +foo (int path) +{ + int i; + if (path) + { + for (i = 0; i < SIZE; i++) + sarr[i] = buf_hot; + } + else + { + for (i = 0; i < SIZE; i++) + sarr[i] = buf_cold; + } +} + +/* { dg-final-use { scan-assembler "\.section\[\t \]*\.text\.unlikely\[\\n\\r\]+\[\t \]*\.size\[\t \]*foo\.cold\.0" { target *-*-linux* *-*-gnu* } } } */ diff --git a/gcc/toplev.c b/gcc/toplev.c index 59b84eb4d4b..d43234a65c1 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -151,11 +151,6 @@ HOST_WIDE_INT random_seed; the support provided depends on the backend. */ rtx stack_limit_rtx; -/* True if the user has tagged the function with the 'section' - attribute. */ - -bool user_defined_section_attribute = false; - struct target_flag_state default_target_flag_state; #if SWITCHABLE_TARGET struct target_flag_state *this_target_flag_state = &default_target_flag_state; diff --git a/gcc/toplev.h b/gcc/toplev.h index 06923cf0c94..f62a172cc52 100644 --- a/gcc/toplev.h +++ b/gcc/toplev.h @@ -74,11 +74,6 @@ extern void target_reinit (void); /* A unique local time stamp, might be zero if none is available. */ extern unsigned local_tick; -/* True if the user has tagged the function with the 'section' - attribute. */ - -extern bool user_defined_section_attribute; - /* See toplev.c. */ extern int flag_rerun_cse_after_global_opts; -- 2.30.2