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/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.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.
50eec24 gcc: remove unneeded global related to hot/cold partitioning
gcc/ChangeLog | 13 +++++++
gcc/bb-reorder.c | 3 +-
gcc/c-family/c-attribs.c | 2 -
gcc/final.c | 2 -
gcc/testsuite/ChangeLog | 6 +++
gcc/testsuite/gcc.dg/tree-prof/section-attr-1.c | 45 +++++++++++++++++++++++
gcc/testsuite/gcc.dg/tree-prof/section-attr-2.c | 44 ++++++++++++++++++++++
gcc/testsuite/gcc.dg/tree-prof/section-attr-3.c | 45 +++++++++++++++++++++++
gcc/toplev.c | 5 ---
gcc/toplev.h | 5 ---
10 files changed, 154 insertions(+), 16 deletions(-)