Bug 85509 - fails to promote local static to const
Summary: fails to promote local static to const
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: ipa (show other bugs)
Version: 7.3.0
: P3 enhancement
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: missed-optimization
Depends on:
Blocks:
 
Reported: 2018-04-23 20:12 UTC by ASA
Modified: 2021-08-30 07:49 UTC (History)
5 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2021-08-30 00:00:00


Attachments
This code demonstrates the problem (426 bytes, text/plain)
2018-04-23 20:12 UTC, ASA
Details

Note You need to log in before you can comment on or make changes to this bug.
Description ASA 2018-04-23 20:12:16 UTC
Created attachment 44010 [details]
This code demonstrates the problem

The attached code when compiled with optimizations in LLVM (I'm using 5.0.0) expands the call inline through the auto variables PerformQuickly and PerformSafely.

Adding const solves the issue but GCC should be able to determine that the function pointer can never be modified and inline the function invocations as LLVM is doing.
Comment 1 ASA 2018-04-24 04:05:26 UTC
I should add that without the static storage duration specifier even without const specified, it does inline the function invocation.
Comment 2 Richard Biener 2018-04-24 08:12:49 UTC
The issue is you fail to make PerformQuickly and PerformSafely const and GCC
doesn't have local analysis to promote it so and IPA analysis is too late
for that since it is also the last inlining point.

Slight complication is nested functions and OMP outlining which may refer to these variables.  But even the initial cgraph build should be able to figure
out the const-ness, no?

Workaround: make the vars const.
Comment 3 ASA 2018-04-25 01:01:05 UTC
(In reply to Richard Biener from comment #2)
> The issue is you fail to make PerformQuickly and PerformSafely const and GCC
> doesn't have local analysis to promote it so and IPA analysis is too late
> for that since it is also the last inlining point.
> 
> Slight complication is nested functions and OMP outlining which may refer to
> these variables.  But even the initial cgraph build should be able to figure
> out the const-ness, no?
> 
> Workaround: make the vars const.


I stated that const solves the issue in the description.  If the auto variables have automatic duration (remove the keyword static), the compiler is able to inline the invocation without the const qualifier.  As stated, LLVM (clang++) does inline the invocation even if it has static duration.

I would expect this is likely true for any non-const static duration function pointer, not just the case when the auto type specifier is used, but I have not confirmed it.
Comment 4 Richard Biener 2018-04-25 07:23:30 UTC
(In reply to ASA from comment #3)
> (In reply to Richard Biener from comment #2)
> > The issue is you fail to make PerformQuickly and PerformSafely const and GCC
> > doesn't have local analysis to promote it so and IPA analysis is too late
> > for that since it is also the last inlining point.
> > 
> > Slight complication is nested functions and OMP outlining which may refer to
> > these variables.  But even the initial cgraph build should be able to figure
> > out the const-ness, no?
> > 
> > Workaround: make the vars const.
> 
> 
> I stated that const solves the issue in the description.  If the auto
> variables have automatic duration (remove the keyword static), the compiler
> is able to inline the invocation without the const qualifier.  As stated,
> LLVM (clang++) does inline the invocation even if it has static duration.
> 
> I would expect this is likely true for any non-const static duration
> function pointer, not just the case when the auto type specifier is used,
> but I have not confirmed it.

But it is the case for any non-const static duration function pointer.
This has nothing to do with 'auto', changing the testcase to

static inline bool
RunTest( void ) {
    static bool (*PerformQuickly)(int &, const int &) = Perform< SumQuickly >;
    static bool (*PerformSafely)(int &, const int &) = Perform< SumSafely >;
    int i = 0;
    return PerformQuickly( i, 1 ) && !PerformSafely( i, INT_MAX );
}

has no effect.
Comment 5 ASA 2018-04-25 14:37:52 UTC
> > I would expect this is likely true for any non-const static duration
> > function pointer, not just the case when the auto type specifier is used,
> > but I have not confirmed it.
> 
> But it is the case for any non-const static duration function pointer.
> This has nothing to do with 'auto', changing the testcase to
> 
> static inline bool
> RunTest( void ) {
>     static bool (*PerformQuickly)(int &, const int &) = Perform< SumQuickly
> >;
>     static bool (*PerformSafely)(int &, const int &) = Perform< SumSafely >;
>     int i = 0;
>     return PerformQuickly( i, 1 ) && !PerformSafely( i, INT_MAX );
> }
> 
> has no effect.

Which is exactly what I stated I would have expected.  Thank you for the confirmation of that expectation, though very oddly worded.
Comment 6 Andrew Pinski 2021-08-30 05:28:30 UTC
For some reason CCP1 is not able to do it but CCP2 can; though CCP2 is after inlining so IPA so nothing is done with respect to inlining and such.

CCP1 dump:

Visiting statement:
# VUSE <.MEM_13>
PerformSafely.3_3 = _ZZL7RunTestvE13PerformSafelyD.2380;
which is likely CONSTANT
Lattice value changed to VARYING.  Adding SSA edges to worklist.

CCP2 dump:
Visiting statement:
# VUSE <.MEM_8>
# PT = nonlocal escaped null
PerformSafely.2_2 = _ZZ7RunTestvE13PerformSafelyD.2379;
which is likely CONSTANT
Lattice value changed to CONSTANT _Z7PerformIL_ZL9SumSafelyRiRKiEEbS0_S2_D.2380.  Adding SSA edges to worklist.
marking stmt to be not simulated again
Comment 7 Richard Biener 2021-08-30 07:49:14 UTC
CCP2 is after IPA promoting the variable 'const', but CCP2 is too late for inlining (and IPA opts don't do value-numbering to discover the indirect
inline target).