[llvm-dev] Call via Vtable

David Blaikie via llvm-dev llvm-dev at lists.llvm.org
Tue Jul 13 00:20:49 PDT 2021


if you add 'main' that has an instance of 'Bar' - then all of it can
be inlined and optimized away. Specifically the ctor of 'Bar' can be
inlined, so the initialization of the vtable pointer is visible, so
the optimizer can look through the vtable lookup to devirtualize.

If you add any intervening unoptimizable call (or if the ctor itself
is not available/not inline) - then you'll lose the optimization
again.

On Mon, Jul 12, 2021 at 9:57 PM Madhur Amilkanthwar via llvm-dev
<llvm-dev at lists.llvm.org> wrote:
>
> Hi Richard,
> What makes it different when we add main()? Isn't the complexity be same?
>
>
>
>
> On Tue, Jul 13, 2021, 10:21 AM Richard Smith via llvm-dev <llvm-dev at lists.llvm.org> wrote:
>>
>> On Sun, 11 Jul 2021 at 23:00, Santanu Das via llvm-dev <llvm-dev at lists.llvm.org> wrote:
>>>
>>> Hello community members,
>>>
>>>
>>>
>>> I was experimenting to see whether LLVM is able to devirtualize calls via vtable. I have this particular example:
>>>
>>>
>>>
>>> ========
>>>
>>> class Foo {
>>>
>>> public:
>>>
>>>   virtual int foo() const = 0;
>>>
>>>   int baz() const { return foo(); }
>>>
>>> };
>>>
>>>
>>>
>>> class Bar : public Foo {
>>>
>>> public:
>>>
>>>   int foo() const override final { return 0xdeadbeef; }
>>>
>>> };
>>>
>>>
>>>
>>> int fred(Bar &x) {
>>>
>>>   return x.baz();
>>>
>>> }
>>>
>>> ========
>>>
>>>
>>>
>>> As we can see, there is a call to Bar::foo(), via  Foo::baz(), which returns a constant.
>>>
>>> The Bar::foo() function has final specifier, hence this implementation cannot be overridden by any child class.  In this case, the compiler should be able to call Bar::foo() directly instead of calling via vtable, and then should be able to inline the const value.
>>>
>>>
>>>
>>> When I compile with LLVM main branch, I see this piece of code being generated below. It makes a call to the function via vtable entry.
>>>
>>>
>>>
>>> _Z4fredR3Bar:
>>>
>>> movq    (%rdi), %rax
>>>
>>> jmpq    *(%rax)
>>>
>>>
>>>
>>>
>>>
>>> When I compile with GCC, I see that it is able to correctly identify that it should call Bar::foo() directly and successfully inlines the const value.
>>>
>>>
>>>
>>> _Z4fredR3Bar:
>>>
>>> movq    (%rdi), %rax
>>>
>>> movq    (%rax), %rax
>>>
>>> cmpq    $_ZNK3Bar3fooEv, %rax
>>>
>>> jne     .L5
>>>
>>> movl    $-559038737, %eax
>>>
>>> ret
>>>
>>>
>>>
>>>
>>>
>>> Should LLVM be optimizing this call, or am I missing something?
>>
>>
>> LLVM knows nothing about whether functions are "final"; most facts about the C++ type system are not representable in LLVM IR. The optimizations based on "final" are all done by Clang as part of lowering to LLVM IR. Clang would happily devirtualize a call to x.foo(), because it can locally see that would be a virtual call to a final function, so must call Bar::foo(), but in this example Clang can't do anything because it only reasons about the program before optimization, and LLVM can't do anything because the "final" information is not represented in LLVM IR.
>>
>> The information we'd need to propagate into the optimizer here would be moderately complex: we don't know what x's vptr is at the point of the call to baz() (it could be that of Bar or of a class derived from Bar), but we do know what a certain slot in that vptr contains (or at least, we know a function that is equivalent to that slot's value -- I don't think there's a guarantee it's actually the same value). It'd probably be feasible to add support to LLVM to model that kind of thing, but it would probably require a fair bit of work.
>>
>>>
>>> -
>>>
>>> Santanu Das
>>>
>>> _______________________________________________
>>> LLVM Developers mailing list
>>> llvm-dev at lists.llvm.org
>>> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
>>
>> _______________________________________________
>> LLVM Developers mailing list
>> llvm-dev at lists.llvm.org
>> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
>
> _______________________________________________
> LLVM Developers mailing list
> llvm-dev at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev


More information about the llvm-dev mailing list