[llvm-dev] Call via Vtable
Madhur Amilkanthwar via llvm-dev
llvm-dev at lists.llvm.org
Mon Jul 12 21:57:12 PDT 2021
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
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20210713/53333d39/attachment.html>
More information about the llvm-dev
mailing list