Search code examples
c++assemblyx86polymorphismvtable

Has the compiler optimized-out the virtual call?


I have this C++ which creates two derived objects and then invokes a virtual function call many times:

Parent* d;
Child1 d1[1];
Child2 d2[1];

if(__rdtsc() & 1 != 0){
    d = d1;
}
else{
    d = d2;
}

for(unsigned long long i =0; i<9000000000; ++i){
    sum += d->process2();
}

and it produces this assembler:

        for(unsigned long long i =0; i<9000000000; ++i){
000000013F4241A5  mov         qword ptr [rsp+100h],0  
000000013F4241B1  jmp         main+2B6h (013F4241C6h)  
000000013F4241B3  mov         rax,qword ptr [rsp+100h]  
000000013F4241BB  inc         rax  
000000013F4241BE  mov         qword ptr [rsp+100h],rax  
000000013F4241C6  mov         rax,218711A00h  
000000013F4241D0  cmp         qword ptr [rsp+100h],rax  
000000013F4241D8  jae         main+306h (013F424216h)  
            sum += d->process2();
000000013F4241DA  mov         rax,qword ptr [rsp+0F8h]  
000000013F4241E2  mov         rax,qword ptr [rax]  
000000013F4241E5  mov         rcx,qword ptr [rsp+0F8h]  
000000013F4241ED  call        qword ptr [rax+8]  
000000013F4241F0  mov         qword ptr [rsp+1D8h],rax  
000000013F4241F8  mov         rax,qword ptr [rsp+1D8h]  
000000013F424200  mov         rcx,qword ptr [sum (013F4385D8h)]  
000000013F424207  add         rcx,rax  
000000013F42420A  mov         rax,rcx  
000000013F42420D  mov         qword ptr [sum (013F4385D8h)],rax  
        }

Based on the assembler could somebody please confirm that the compiler cannot optimize the virtual call in the loop (even though every iteration calls the same derived object) because the compiler cannot possibly know whether d1 or d2 was selected, due to the call to __rdtsc() only being resolvable at run-time?

(If anyone could give me some advice how to read the assembler for the d->process2() call it would be most appreciated)


Solution

  • 000000013F4241DA  mov     rax,qword ptr [rsp+0F8h] //load "this" into rax
    000000013F4241E2  mov     rax,qword ptr [rax]      //load vtable pointer
    000000013F4241E5  mov     rcx,qword ptr [rsp+0F8h] //load "this" into rcx
    000000013F4241ED  call    qword ptr [rax+8]        //call second entry in vtable?
    

    Clearly, call to virtual function is not optimized away. You are right, it is because of random factor.