* Re: C++ 'extern inline' magic possible?
2011-03-01 12:14 ` Kevin P. Fleming
@ 2011-03-01 12:39 ` Andrew Haley
2011-03-01 12:55 ` David Brown
` (2 subsequent siblings)
3 siblings, 0 replies; 13+ messages in thread
From: Andrew Haley @ 2011-03-01 12:39 UTC (permalink / raw)
To: gcc-help
On 03/01/2011 12:14 PM, Kevin P. Fleming wrote:
> On a slightly related note... I've seen a couple of pages (but not the
> GCC manual's 'inlining' page) mention that it's possible for virtual
> member functions to be inlined if they are inlinable (either defined in
> the class declaration or the function declaration is visible and marked
> 'inline') and the call to them is a 'direct virtual function call'. This
> last term doesn't make any sense to me, and based on my understanding of
> vtables I don't see how a virtual member function could *ever* be
> inlined unless it was called in a non-virtual fashion (i.e. calling it
> as "Foo::bar()" when Foo is the class making the call or one of its
> bases). In any other situation, the compiler cannot know at compile time
> which member function would actually be called. Does this sound like a
> correct statement?
Consider
new Foo()->bar();
Andrew.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: C++ 'extern inline' magic possible?
2011-03-01 12:14 ` Kevin P. Fleming
2011-03-01 12:39 ` Andrew Haley
@ 2011-03-01 12:55 ` David Brown
2011-03-02 12:35 ` Kevin P. Fleming
2011-03-01 15:39 ` Ian Lance Taylor
2011-03-01 21:52 ` Jonathan Wakely
3 siblings, 1 reply; 13+ messages in thread
From: David Brown @ 2011-03-01 12:55 UTC (permalink / raw)
To: gcc-help
On 01/03/2011 13:14, Kevin P. Fleming wrote:
> On 03/01/2011 02:55 AM, Jonathan Wakely wrote:
>> On 1 March 2011 03:53, Ian Lance Taylor wrote:
>>> Jonathan Wakely<jwakely.gcc@gmail.com> writes:
>>>
>>>> On 1 March 2011 00:25, Ian Lance Taylor wrote:
>>>>> "Kevin P. Fleming"<kpfleming@digium.com> writes:
>>>>>
>>>>>> I would like to come up with some construction like the 'extern
>>>>>> inline' that GCC supports for C mode, so that a.h could contain the
>>>>>> declaration *and* definition of 'bar', allowing code that includes
>>>>>> a.h
>>>>>> to have 'bar' be inlined if the compiler chooses to do so (and leave
>>>>>> an external reference to 'bar' if necessary so that the version built
>>>>>> from a.cpp will be used). So far my attempts have only resulted in
>>>>>> various re-definition or re-declaration errors.
>>>>>
>>>>> There is no equivalent to GNU C's "extern inline" in C++. By the way,
>>>>> "extern inline" is now actually known as __attribute__ ((gnu_inline)),
>>>>> as C99 defines "extern inline" to mean something different.
>>>>>
>>>>> In C++ you can simply define the function inline in a.h, and not
>>>>> define
>>>>> it at all in a.cpp. The right thing will happen.
>>>>
>>>> That will work in practice, but it's technically an ODR violation.
>>>
>>> No, it's not (there may be a misunderstanding somewhere). I am
>>> suggesting that there should be only one definition: the one in a.h.
>>> That is OK if the definition has inline linkage. It is certainly not an
>>> ODR violation, as there is only one definition.
>>
>> Yes sorry, I did misunderstand. But in that case a.h must be included
>> by all callers of the function. I thought the point was some callers
>> don't want to include the definition of the class and the function
>> that uses it.
>
> Yes, that was what my original post requested, but I now understand that
> any solution that offered that would be non-compliant with the C++
> standard. I believe this code base is only using this technique to shave
> some compile time for TUs that don't actually need the class definitions
> (they only receive and send around pointers to the classes), but it's a
> cause of lower performance and so I'll have to figure out whether
> removing the 'forward declaration only' mechanism will be worth the effort.
>
> Thanks for the replies; as usual the level of knowledge and helpfulness
> on this mailing list is stellar :-)
>
> On a slightly related note... I've seen a couple of pages (but not the
> GCC manual's 'inlining' page) mention that it's possible for virtual
> member functions to be inlined if they are inlinable (either defined in
> the class declaration or the function declaration is visible and marked
> 'inline') and the call to them is a 'direct virtual function call'. This
> last term doesn't make any sense to me, and based on my understanding of
> vtables I don't see how a virtual member function could *ever* be
> inlined unless it was called in a non-virtual fashion (i.e. calling it
> as "Foo::bar()" when Foo is the class making the call or one of its
> bases). In any other situation, the compiler cannot know at compile time
> which member function would actually be called. Does this sound like a
> correct statement?
>
The compiler is free to inline functions as part of its optimisations.
To do that, it needs to be sure what functions to call, and to have
access to the definition of the function. Marking a function "inline"
is a hint that you'd like inlining, but the compiler may not be able to
inline a function marked "inline", and it may also choose to inline
functions that are not marked.
This will apply equally to virtual methods. If the compiler can be sure
of which function is actually being called with the virtual method call,
it can remove the indirection and call the underlying function directly,
or inline it.
If you want the compiler to inline functions where practical, even
across different compilation units, and to use function calls when
necessary, then you should look hard at using LTO. This gives the
compiler the chance to inline function calls even though the definitions
are not available in the compilation unit in which they are used.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: C++ 'extern inline' magic possible?
2011-03-01 12:55 ` David Brown
@ 2011-03-02 12:35 ` Kevin P. Fleming
0 siblings, 0 replies; 13+ messages in thread
From: Kevin P. Fleming @ 2011-03-02 12:35 UTC (permalink / raw)
To: gcc-help
On 03/01/2011 07:53 AM, David Brown wrote:
> If you want the compiler to inline functions where practical, even
> across different compilation units, and to use function calls when
> necessary, then you should look hard at using LTO. This gives the
> compiler the chance to inline function calls even though the definitions
> are not available in the compilation unit in which they are used.
That is on my agenda as well to investigate, but since GCC+binutils that
support LTO are very, very new and won't be in LTS-type Linux
distributions for some time, we can't quite expect our users to have
them available.
--
Kevin P. Fleming
Digium, Inc. | Director of Software Technologies
445 Jan Davis Drive NW - Huntsville, AL 35806 - USA
skype: kpfleming | jabber: kfleming@digium.com
Check us out at www.digium.com & www.asterisk.org
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: C++ 'extern inline' magic possible?
2011-03-01 12:14 ` Kevin P. Fleming
2011-03-01 12:39 ` Andrew Haley
2011-03-01 12:55 ` David Brown
@ 2011-03-01 15:39 ` Ian Lance Taylor
2011-03-01 21:52 ` Jonathan Wakely
3 siblings, 0 replies; 13+ messages in thread
From: Ian Lance Taylor @ 2011-03-01 15:39 UTC (permalink / raw)
To: Kevin P. Fleming; +Cc: Jonathan Wakely, gcc-help
"Kevin P. Fleming" <kpfleming@digium.com> writes:
> On a slightly related note... I've seen a couple of pages (but not the
> GCC manual's 'inlining' page) mention that it's possible for virtual
> member functions to be inlined if they are inlinable (either defined
> in the class declaration or the function declaration is visible and
> marked 'inline') and the call to them is a 'direct virtual function
> call'. This last term doesn't make any sense to me, and based on my
> understanding of vtables I don't see how a virtual member function
> could *ever* be inlined unless it was called in a non-virtual fashion
> (i.e. calling it as "Foo::bar()" when Foo is the class making the call
> or one of its bases). In any other situation, the compiler cannot know
> at compile time which member function would actually be called. Does
> this sound like a correct statement?
The direct virtual function call is indeed the call to Foo::bar().
However, there are other cases where the compiler can inline a virtual
function call. If the compiler can see the use of the new operator
which created the object, then it knows the exact virtual table which
the object is using, and so can inline any virtual call. That is a
fairly common though obviously somewhat limited case. In gcc these
sorts of optimizations are implemented by -fdevirtualize, which is
enabled by default at -O2.
More subtly, the compiler can use profiling feedback to see which
virtual function is being called at any specific point in the code. In
many programs a specific call site will almost always call a specific
virtual function implementation. When the profiling feedback indicates
that, the compiler can insert a test for the expected virtual function.
If the test succeeds, the compiler can inline the call. If the test
fails, the compiler can generate a normal virtual function call. I
don't know off-hand whether gcc implements this optimization.
Ian
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: C++ 'extern inline' magic possible?
2011-03-01 12:14 ` Kevin P. Fleming
` (2 preceding siblings ...)
2011-03-01 15:39 ` Ian Lance Taylor
@ 2011-03-01 21:52 ` Jonathan Wakely
2011-03-02 13:00 ` Kevin P. Fleming
3 siblings, 1 reply; 13+ messages in thread
From: Jonathan Wakely @ 2011-03-01 21:52 UTC (permalink / raw)
To: Kevin P. Fleming; +Cc: gcc-help
On 1 March 2011 12:14, Kevin P. Fleming wrote:
>
> Yes, that was what my original post requested, but I now understand that any
> solution that offered that would be non-compliant with the C++ standard. I
> believe this code base is only using this technique to shave some compile
> time for TUs that don't actually need the class definitions (they only
> receive and send around pointers to the classes), but it's a cause of lower
> performance and so I'll have to figure out whether removing the 'forward
> declaration only' mechanism will be worth the effort.
There is another option, which I'm loathe to mention ...
// aF.h
class Foo;
void bar_ext(const Foo*);
#ifndef BAR_INLINED
#define BAR bar_ext
#endif
// a.h
class Foo { };
void bar_inl(const Foo*) { }
#undef BAR
#define BAR bar_inl
#define BAR_INLINED
this way you call BAR() and get the inline bar_inl if its definition
has been seen, or bar_ext otherwise.
But macros introduce their own problems so use with caution.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: C++ 'extern inline' magic possible?
2011-03-01 21:52 ` Jonathan Wakely
@ 2011-03-02 13:00 ` Kevin P. Fleming
2011-03-02 16:55 ` Jonathan Wakely
0 siblings, 1 reply; 13+ messages in thread
From: Kevin P. Fleming @ 2011-03-02 13:00 UTC (permalink / raw)
To: Jonathan Wakely; +Cc: gcc-help
On 03/01/2011 04:52 PM, Jonathan Wakely wrote:
> On 1 March 2011 12:14, Kevin P. Fleming wrote:
>>
>> Yes, that was what my original post requested, but I now understand that any
>> solution that offered that would be non-compliant with the C++ standard. I
>> believe this code base is only using this technique to shave some compile
>> time for TUs that don't actually need the class definitions (they only
>> receive and send around pointers to the classes), but it's a cause of lower
>> performance and so I'll have to figure out whether removing the 'forward
>> declaration only' mechanism will be worth the effort.
>
> There is another option, which I'm loathe to mention ...
<snip macro example which makes everyone shudder <G>>
Yes, I considered that. I did arrive at a potential solution, although I
can't use it in this particular code base because of other
complications, but...
== test.h ==
class Foo;
void opaqueBar(Foo*);
template <typename T>
void Bar(T* obj)
{
opaqueBar(obj);
}
== test1.h ==
#include "test.h"
static void test1(Foo* obj)
{
Bar(obj);
}
== test2.h ==
#include "test.h"
class Foo
{
public:
void realBar();
};
template <>
inline void Bar<Foo>(Foo* obj)
{
obj->realBar();
}
static void test2(Foo* obj)
{
Bar(obj);
}
I think this still might be an ODR violation though, since there will
end up being two definitions of Bar() for Foo.
--
Kevin P. Fleming
Digium, Inc. | Director of Software Technologies
445 Jan Davis Drive NW - Huntsville, AL 35806 - USA
skype: kpfleming | jabber: kfleming@digium.com
Check us out at www.digium.com & www.asterisk.org
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: C++ 'extern inline' magic possible?
2011-03-02 13:00 ` Kevin P. Fleming
@ 2011-03-02 16:55 ` Jonathan Wakely
0 siblings, 0 replies; 13+ messages in thread
From: Jonathan Wakely @ 2011-03-02 16:55 UTC (permalink / raw)
To: Kevin P. Fleming; +Cc: gcc-help
On 2 March 2011 13:00, Kevin P. Fleming wrote:
> On 03/01/2011 04:52 PM, Jonathan Wakely wrote:
>>
>> On 1 March 2011 12:14, Kevin P. Fleming wrote:
>>>
>>> Yes, that was what my original post requested, but I now understand that
>>> any
>>> solution that offered that would be non-compliant with the C++ standard.
>>> I
>>> believe this code base is only using this technique to shave some compile
>>> time for TUs that don't actually need the class definitions (they only
>>> receive and send around pointers to the classes), but it's a cause of
>>> lower
>>> performance and so I'll have to figure out whether removing the 'forward
>>> declaration only' mechanism will be worth the effort.
>>
>> There is another option, which I'm loathe to mention ...
>
> <snip macro example which makes everyone shudder <G>>
>
> Yes, I considered that. I did arrive at a potential solution, although I
> can't use it in this particular code base because of other complications,
> but...
>
> == test.h ==
> class Foo;
>
> void opaqueBar(Foo*);
>
> template <typename T>
> void Bar(T* obj)
> {
> opaqueBar(obj);
> }
>
> == test1.h ==
> #include "test.h"
>
> static void test1(Foo* obj)
> {
> Bar(obj);
> }
>
> == test2.h ==
> #include "test.h"
>
> class Foo
> {
> public:
> void realBar();
> };
>
> template <>
> inline void Bar<Foo>(Foo* obj)
>
> {
> obj->realBar();
> }
>
> static void test2(Foo* obj)
> {
> Bar(obj);
> }
>
> I think this still might be an ODR violation though, since there will end up
> being two definitions of Bar() for Foo.
Yep:
[templ.expl.spec]p6:
If a template, a member template or the member of a class template is
explicitly specialized then that
specialization shall be declared before the first use of that
specialization that would cause an implicit instantiation
to take place, in every translation unit in which such a use occurs;
no diagnostic is required.
The answer is to overload Bar as a non-template, not to specialize the
template function.
^ permalink raw reply [flat|nested] 13+ messages in thread