diff mbox

Ping: Re: [PATCH 1/2] gcc: Remove unneeded global flag.

Message ID 20160914130048.GC31794@embecosm.com
State New
Headers show

Commit Message

Andrew Burgess Sept. 14, 2016, 1 p.m. UTC
In an attempt to get this patch merged (as I still think that its
correct) I've investigated, and documented a little more about how I
think things currently work.  I'm sure most people reading this will
already know this, but hopefully, if my understanding is wrong someone
can point it out.

I've updated the patch to include a few tests, however, I have a
little concern about the new test as they use '.text' and '.data'
section names specifically, and I guess there's likely targets that
don't use those names.  I've limited the tests to GNU/Linux systems,
but maybe I need to be even stricter?

Anyway, the following is a description of why I think this patch is
correct.  The updated patch can be found at the end of the email.

With a focus on the user_defined_section_attribute variable, here's
how things currently work:

1. The variable user_defined_section_attribute is initialised to false
   at compile time.  This is done in toplev.c

2. The only other place that user_defined_section_attribute is set to
   false is in the function rest_of_handle_final in final.c.  This is
   part of the final compiler optimisation pass.  The
   rest_of_handle_final function is called from the
   pass_final::execute method.

3. The user_defined_section_attribute is set to true in only one
   place, in handle_section_attribute in c-family/c-common.c.  Setting
   user_defined_section_attribute to true always happens when the
   handle_section_attribute function is called, unless the target does
   not support named sections.

4. The handle_section_attribute function is called whenever any
   function or data has the section attribute attached.

5. The attribute handling function handle_section_attribute is called
   with the following call-stack (as an example):
   1) handle_section_attribute
   2) decl_attributes
   3) c_decl_attributes
   4) start_decl
   5) c_parser_declaration
   6) c_parser_external_declaration
   7) c_parser_translation_unit
   8) c_parse_file
   9) c_common_parse_file
   10) compile_file
   11) do_compile
   12) toplev::main
   13) main
   The middle levels 2 to 8 could change depending on where the
   section attribute is encountered, but the interesting thing to take
   away is that calls to handle_section_attribute originate from a
   call to c_common_parse_file, which is called from do_compile.
   Right now I believe that this is always the case, this is crucial
   to the validity of this patch, if I've got this wrong then this
   patch is wrong.

6. Specifically, within the compile_file function (in toplev.c) it is
   the line 'lang_hooks.parse_file ();' which leads to the attribute
   handling functions being called.

7. The user_defined_section_attribute is checked in only one place,
   this is in the method pass_partition_blocks::gate, in the file
   bb-reorder.c.  Like the reset to false in final.c (mentioned above)
   this checking of user_defined_section_attribute is part of a
   compiler optimisation pass.

8. Like the file parsing, the compiler optimisation passes originate
   from a call in compile_file (in toplev.c), this call occurs after
   the call to parse the file (obviously).

The problem here that I see then is that we first parse the whole C
file, handling all attributes, we then perform the optimisation passes
on all functions.  As user_defined_section_attribute starts as false
and is set true during the C parsing whenever a section attribute is
encountered, the variable will be true by the end of the parse process
if there is any function or variable with a section attribute.

We then perform the partition-blocks pass on the first function, which
will be disabled (if user_defined_section_attribute) is true,
regardless of whether it was actually that function that has a section
attribute attached.

We then perform the final pass on the first function at which point we
reset the user_defined_section_attribute to false.

When we perform the partition-blocks pass on the second function we
will see user_defined_section_attribute set to false regardless of
whether the function has a section attribute or not (the attribute
handling functions are only called during file parse, not during the
optimisation passes).

There is another issue, that if a variable has a section attribute
this will also cause user_defined_section_attribute to be set to true,
(which makes sense based on the name 'user_defined_section_attribute')
however, given what user_defined_section_attribute is actually used
for, there's no reason to disable the partition-blocks pass just
because some variable is assigned to a specific section.

In the revised patch I disable the partition-blocks pass for a
function only when the function DECL has a section attribute
attached.  This information is already available on the function DECL,
so there's no need for us to keep a separate variable around, and so I
delete user_defined_section_attribute.

I've added three new tests in this latest revision of the patch.
These cover issues that I claim to fix; a section attribute on an
earlier function prevents a later function being partitioned, and a
section attribute on a variable stops a function being partitioned
(there's two variants of this one).

In all of the test cases GCC fails to partition a function that could
have been partitioned.  We will never partition a function that should
not be partitioned, though it is possible to craft a test file where
the partition blocks pass is run on a function that should NOT be
partitioned (due to a section attribute) however, in that case the
section attribute causes the function to placed in the specified
section thanks to the section selection code in varasm.c

I don't currently have GCC write access.  If the patch is approved,
then please could someone apply it.

Thanks

Andrew

---

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-common.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.
---
 gcc/bb-reorder.c                                |  3 +-
 gcc/c-family/c-common.c                         |  2 --
 gcc/final.c                                     |  2 --
 gcc/testsuite/ChangeLog                         |  6 ++++
 gcc/testsuite/gcc.dg/tree-prof/section-attr-1.c | 43 +++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/tree-prof/section-attr-2.c | 43 +++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/tree-prof/section-attr-3.c | 43 +++++++++++++++++++++++++
 gcc/toplev.c                                    |  5 ---
 gcc/toplev.h                                    |  5 ---
 9 files changed, 136 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

Comments

Jakub Jelinek Sept. 14, 2016, 1:07 p.m. UTC | #1
On Wed, Sep 14, 2016 at 02:00:48PM +0100, Andrew Burgess wrote:
> In an attempt to get this patch merged (as I still think that its
> correct) I've investigated, and documented a little more about how I
> think things currently work.  I'm sure most people reading this will
> already know this, but hopefully, if my understanding is wrong someone
> can point it out.

I wonder if user_defined_section_attribute instead shouldn't be moved
into struct function and be handled as a per-function flag then.

	Jakub
Andrew Burgess Sept. 15, 2016, 2:24 p.m. UTC | #2
* Jakub Jelinek <jakub@redhat.com> [2016-09-14 15:07:56 +0200]:

> On Wed, Sep 14, 2016 at 02:00:48PM +0100, Andrew Burgess wrote:
> > In an attempt to get this patch merged (as I still think that its
> > correct) I've investigated, and documented a little more about how I
> > think things currently work.  I'm sure most people reading this will
> > already know this, but hopefully, if my understanding is wrong someone
> > can point it out.
> 
> I wonder if user_defined_section_attribute instead shouldn't be moved
> into struct function and be handled as a per-function flag then.

That would certainly solve the problem I'm trying to address.  But I
wonder, how is that different to looking for a section attribute on
the function DECL?

Thanks,
Andrew
Jeff Law Oct. 28, 2016, 3:58 p.m. UTC | #3
On 09/15/2016 08:24 AM, Andrew Burgess wrote:
> * Jakub Jelinek <jakub@redhat.com> [2016-09-14 15:07:56 +0200]:
>
>> On Wed, Sep 14, 2016 at 02:00:48PM +0100, Andrew Burgess wrote:
>>> In an attempt to get this patch merged (as I still think that its
>>> correct) I've investigated, and documented a little more about how I
>>> think things currently work.  I'm sure most people reading this will
>>> already know this, but hopefully, if my understanding is wrong someone
>>> can point it out.
>>
>> I wonder if user_defined_section_attribute instead shouldn't be moved
>> into struct function and be handled as a per-function flag then.
>
> That would certainly solve the problem I'm trying to address.  But I
> wonder, how is that different to looking for a section attribute on
> the function DECL?
I'm not sure it is significantly different.  It seems like it's just an 
implementation detail.  I'd err on the side of putting this into the 
struct function rather than on the DECL node simply to keep the size of 
DECL nodes from increasing.  Even if you can find suitable free flag 
bits, those can likely be better used for other purposes.


I'm still pondering the actual patch.  It's not forgotten.

jeff
Andrew Burgess Oct. 28, 2016, 4:14 p.m. UTC | #4
* Jeff Law <law@redhat.com> [2016-10-28 09:58:14 -0600]:

> On 09/15/2016 08:24 AM, Andrew Burgess wrote:
> > * Jakub Jelinek <jakub@redhat.com> [2016-09-14 15:07:56 +0200]:
> > 
> > > On Wed, Sep 14, 2016 at 02:00:48PM +0100, Andrew Burgess wrote:
> > > > In an attempt to get this patch merged (as I still think that its
> > > > correct) I've investigated, and documented a little more about how I
> > > > think things currently work.  I'm sure most people reading this will
> > > > already know this, but hopefully, if my understanding is wrong someone
> > > > can point it out.
> > > 
> > > I wonder if user_defined_section_attribute instead shouldn't be moved
> > > into struct function and be handled as a per-function flag then.
> > 
> > That would certainly solve the problem I'm trying to address.  But I
> > wonder, how is that different to looking for a section attribute on
> > the function DECL?
> I'm not sure it is significantly different.  It seems like it's just an
> implementation detail.  I'd err on the side of putting this into the struct
> function rather than on the DECL node simply to keep the size of DECL nodes
> from increasing.  Even if you can find suitable free flag bits, those can
> likely be better used for other purposes.

I didn't add anything to the DECL, the information we need is already
there.  The relevant chunk of the patch is:

@@ -2890,7 +2889,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

I have not made any changes to add anything new to the DECL.  I guess
an argument _could_ be made that looking up an attribute is too
expensive to be used in a pass::gate function (I haven't looked into
how expensive it is) but I figured that initially at least it's better
to reuse the data we already have around than to add a new flag that
duplicates something we already have.

> I'm still pondering the actual patch.  It's not forgotten.

Would it help clarify things if I added some printf style tracing and
posted a trace?  This might help highlight how
USER_DEFINED_SECTION_ATTRIBUTE is set in a different phase of
compilation and so can't possibly be of any use when deciding whether
or not to perform the pass or not.

I'm still keen to see this merged, so any extra leg work I can do to
help move this forward, please let me know; I'm happy to help.

Thanks,
Andrew
Bernd Schmidt Nov. 3, 2016, 12:01 p.m. UTC | #5
On 09/14/2016 03:00 PM, Andrew Burgess wrote:
> In an attempt to get this patch merged (as I still think that its
> correct) I've investigated, and documented a little more about how I
> think things currently work.  I'm sure most people reading this will
> already know this, but hopefully, if my understanding is wrong someone
> can point it out.
> 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-common.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.

I think the explanation is perfectly reasonable and the patch looks 
good, except:

> +__attribute__((noinline))

Add noclone to all of these as well.


Bernd
Andrew Burgess Nov. 16, 2016, 8:09 p.m. UTC | #6
* Bernd Schmidt <bschmidt@redhat.com> [2016-11-03 13:01:32 +0100]:

> On 09/14/2016 03:00 PM, Andrew Burgess wrote:
> > In an attempt to get this patch merged (as I still think that its
> > correct) I've investigated, and documented a little more about how I
> > think things currently work.  I'm sure most people reading this will
> > already know this, but hopefully, if my understanding is wrong someone
> > can point it out.
> > 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-common.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.
> 
> I think the explanation is perfectly reasonable and the patch looks good,
> except:
> 
> > +__attribute__((noinline))
> 
> Add noclone to all of these as well.

Thanks.  Considering Jeff said, I'm thinking about it, and you've said
yes, and given Jeff's not got back, I'm considering this patch
approved (with the fix you suggest).

My only remaining concern is the new tests, I've tried to restrict
them to targets that I suspect they'll pass on with:

    /* { dg-final-use { scan-assembler "\.section\[\t \]*\.text\.unlikely\[\\n\\r\]+\[\t \]*\.size\[\t \]*foo\.cold\.0" { target *-*-linux* *-*-gnu* } } } */

but I'm still nervous that I'm going to introduce test failures.  Is
there any advice / guidance I should follow before I commit, or are
folk pretty relaxed so long as I've made a reasonable effort?

Thanks,
Andrew
Mike Stump Nov. 16, 2016, 8:59 p.m. UTC | #7
On Nov 16, 2016, at 12:09 PM, Andrew Burgess <andrew.burgess@embecosm.com> wrote:
> My only remaining concern is the new tests, I've tried to restrict
> them to targets that I suspect they'll pass on with:
> 
>    /* { dg-final-use { scan-assembler "\.section\[\t \]*\.text\.unlikely\[\\n\\r\]+\[\t \]*\.size\[\t \]*foo\.cold\.0" { target *-*-linux* *-*-gnu* } } } */
> 
> but I'm still nervous that I'm going to introduce test failures.  Is
> there any advice / guidance I should follow before I commit, or are
> folk pretty relaxed so long as I've made a reasonable effort?

So, if you are worried about the way the line is constructed, I usually test it by misspelling the *-*-linux* *-*-gnu* part as *-*-linNOTux* *-*-gnNOTu* and see if the test then doesn't run on your machine.  If it doesn't then you can be pretty confident that only machines that match the target triplet can be impacted.  I usually do this type of testing by running the test case in isolation (not the full tests suite).  Anyway, do the best you can, and don't worry about t it too much, learn from the experience, even if it goes wrong in some way.  If it did go wrong, just be responsive (don't check it in just before a 6 week vacation) about fixing it, if you can.
Andrew Burgess Nov. 16, 2016, 10:12 p.m. UTC | #8
* Mike Stump <mikestump@comcast.net> [2016-11-16 12:59:53 -0800]:

> On Nov 16, 2016, at 12:09 PM, Andrew Burgess <andrew.burgess@embecosm.com> wrote:
> > My only remaining concern is the new tests, I've tried to restrict
> > them to targets that I suspect they'll pass on with:
> > 
> >    /* { dg-final-use { scan-assembler "\.section\[\t \]*\.text\.unlikely\[\\n\\r\]+\[\t \]*\.size\[\t \]*foo\.cold\.0" { target *-*-linux* *-*-gnu* } } } */
> > 
> > but I'm still nervous that I'm going to introduce test failures.  Is
> > there any advice / guidance I should follow before I commit, or are
> > folk pretty relaxed so long as I've made a reasonable effort?
> 
> So, if you are worried about the way the line is constructed, I usually test it by misspelling the *-*-linux* *-*-gnu* part as *-*-linNOTux* *-*-gnNOTu* and see if the test then doesn't run on your machine.  If it doesn't then you can be pretty confident that only machines that match the target triplet can be impacted.  I usually do this type of testing by running the test case in isolation (not the full tests suite).  Anyway, do the best you can, and don't worry about t it too much, learn from the experience, even if it goes wrong in some way.  If it did go wrong, just be responsive (don't check it in just before a 6 week vacation) about fixing it, if you can.
> 

Thanks for the feedback.

Change committed as revision 242519.  If anyone sees any issues just
let me know.

Thanks,
Andrew
Jeff Law Nov. 17, 2016, 5:59 p.m. UTC | #9
On 11/16/2016 03:12 PM, Andrew Burgess wrote:
> * Mike Stump <mikestump@comcast.net> [2016-11-16 12:59:53 -0800]:
>
>> On Nov 16, 2016, at 12:09 PM, Andrew Burgess <andrew.burgess@embecosm.com> wrote:
>>> My only remaining concern is the new tests, I've tried to restrict
>>> them to targets that I suspect they'll pass on with:
>>>
>>>    /* { dg-final-use { scan-assembler "\.section\[\t \]*\.text\.unlikely\[\\n\\r\]+\[\t \]*\.size\[\t \]*foo\.cold\.0" { target *-*-linux* *-*-gnu* } } } */
>>>
>>> but I'm still nervous that I'm going to introduce test failures.  Is
>>> there any advice / guidance I should follow before I commit, or are
>>> folk pretty relaxed so long as I've made a reasonable effort?
>>
>> So, if you are worried about the way the line is constructed, I usually test it by misspelling the *-*-linux* *-*-gnu* part as *-*-linNOTux* *-*-gnNOTu* and see if the test then doesn't run on your machine.  If it doesn't then you can be pretty confident that only machines that match the target triplet can be impacted.  I usually do this type of testing by running the test case in isolation (not the full tests suite).  Anyway, do the best you can, and don't worry about t it too much, learn from the experience, even if it goes wrong in some way.  If it did go wrong, just be responsive (don't check it in just before a 6 week vacation) about fixing it, if you can.
>>
>
> Thanks for the feedback.
>
> Change committed as revision 242519.  If anyone sees any issues just
> let me know.
Thanks.  And thanks for seeing this through... I know it's a pain sometimes.

jeff
Christophe Lyon Nov. 18, 2016, 12:21 p.m. UTC | #10
On 16 November 2016 at 23:12, Andrew Burgess
<andrew.burgess@embecosm.com> wrote:
> * Mike Stump <mikestump@comcast.net> [2016-11-16 12:59:53 -0800]:
>
>> On Nov 16, 2016, at 12:09 PM, Andrew Burgess <andrew.burgess@embecosm.com> wrote:
>> > My only remaining concern is the new tests, I've tried to restrict
>> > them to targets that I suspect they'll pass on with:
>> >
>> >    /* { dg-final-use { scan-assembler "\.section\[\t \]*\.text\.unlikely\[\\n\\r\]+\[\t \]*\.size\[\t \]*foo\.cold\.0" { target *-*-linux* *-*-gnu* } } } */
>> >
>> > but I'm still nervous that I'm going to introduce test failures.  Is
>> > there any advice / guidance I should follow before I commit, or are
>> > folk pretty relaxed so long as I've made a reasonable effort?
>>
>> So, if you are worried about the way the line is constructed, I usually test it by misspelling the *-*-linux* *-*-gnu* part as *-*-linNOTux* *-*-gnNOTu* and see if the test then doesn't run on your machine.  If it doesn't then you can be pretty confident that only machines that match the target triplet can be impacted.  I usually do this type of testing by running the test case in isolation (not the full tests suite).  Anyway, do the best you can, and don't worry about t it too much, learn from the experience, even if it goes wrong in some way.  If it did go wrong, just be responsive (don't check it in just before a 6 week vacation) about fixing it, if you can.
>>
>
> Thanks for the feedback.
>
> Change committed as revision 242519.  If anyone sees any issues just
> let me know.
>

Hi Andrew,

Sorry for the delay, there are so many commits these days, with so
many regression
reports to check manually before reporting here....

So, your new test fails on arm* targets:

  gcc.dg/tree-prof/section-attr-1.c scan-assembler .section[\t
]*.text.unlikely[\\n\\r]+[\t ]*.size[\t ]*foo.cold.0
  gcc.dg/tree-prof/section-attr-2.c scan-assembler .section[\t
]*.text.unlikely[\\n\\r]+[\t ]*.size[\t ]*foo.cold.0
  gcc.dg/tree-prof/section-attr-3.c scan-assembler .section[\t
]*.text.unlikely[\\n\\r]+[\t ]*.size[\t ]*foo.cold.0

Christophe



> Thanks,
> Andrew
diff mbox

Patch

diff --git a/gcc/bb-reorder.c b/gcc/bb-reorder.c
index bb8435f..0a482e6 100644
--- a/gcc/bb-reorder.c
+++ b/gcc/bb-reorder.c
@@ -106,7 +106,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"
@@ -2890,7 +2889,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-common.c b/gcc/c-family/c-common.c
index 1132a03..2d7107d 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -7751,8 +7751,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 eccc3d8..b407b85 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -4478,8 +4478,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/gcc.dg/tree-prof/section-attr-1.c b/gcc/testsuite/gcc.dg/tree-prof/section-attr-1.c
new file mode 100644
index 0000000..51e38cf
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-prof/section-attr-1.c
@@ -0,0 +1,43 @@ 
+/* 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
+
+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;
+}
+
+__attribute__((noinline))
+void
+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 0000000..cbfa5fa
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-prof/section-attr-2.c
@@ -0,0 +1,43 @@ 
+/* 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
+
+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;
+}
+
+__attribute__((noinline))
+void
+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 0000000..593a94a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-prof/section-attr-3.c
@@ -0,0 +1,43 @@ 
+/* 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
+
+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;
+}
+
+__attribute__((noinline))
+void
+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 66099ec..113fc7f 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -149,11 +149,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 06923cf..f62a172 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;