gcc: remove unneeded global related to hot/cold partitioning
authorAndrew Burgess <andrew.burgess@embecosm.com>
Wed, 16 Nov 2016 22:10:52 +0000 (22:10 +0000)
committerAndrew Burgess <aburgess@gcc.gnu.org>
Wed, 16 Nov 2016 22:10:52 +0000 (22:10 +0000)
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
gcc/bb-reorder.c
gcc/c-family/c-attribs.c
gcc/final.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-prof/section-attr-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-prof/section-attr-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-prof/section-attr-3.c [new file with mode: 0644]
gcc/toplev.c
gcc/toplev.h

index 9b04621..bd70d4e 100644 (file)
@@ -1,3 +1,16 @@
+2016-11-16  Andrew Burgess  <andrew.burgess@embecosm.com>
+
+       * 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  <macro@imgtec.com>
 
        * config/mips/mips.md (casesi_internal_mips16_<mode>):
index 85bc569..e51ec08 100644 (file)
 #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
index 925f1b2..964efe9 100644 (file)
@@ -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);
index 5709d0e..d3a53c3 100644 (file)
@@ -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 ();
 
index 3707e7c..8958f86 100644 (file)
@@ -1,3 +1,9 @@
+2016-11-16  Andrew Burgess  <andrew.burgess@embecosm.com>
+
+       * 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  <macro@imgtec.com>
 
        * 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 (file)
index 0000000..ee6662e
--- /dev/null
@@ -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 (file)
index 0000000..898a395
--- /dev/null
@@ -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 (file)
index 0000000..36829dc
--- /dev/null
@@ -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* } } } */
index 59b84eb..d43234a 100644 (file)
@@ -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;
index 06923cf..f62a172 100644 (file)
@@ -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;