Search code examples
c++compiler-optimizationvirtual-functionsvtable

Virtual function optimization for repeated calls to the same function on the same object


Let's say there is such an abstract class:

class Base {
   public:

   virtual void f() = 0;

   virtual ~Base()  = default;
};

And some function:

void function (Base& x, bool flag1, bool flag2, bool flag3) {

   if(flag1)
      x.f();
   if(flag2)
      x.f();
   if(flag3)
      x.f();
}

In the main() function I load an instance of derived from this class from the shared library:

int main() {
  Base* x = /* load from shared lib*/;

  bool flag1 = getchar() == '1';
  bool flag2 = getchar() == '2';
  bool flag3 = getchar() == '3';

  function(*x, flag1, flag2, flag3);

  return 0;
}

Question: can I expect that within one call to the function void function (Base& x, bool flag1, bool flag2, bool flag3) the virtual function table will only be accessed once, even if all three flags are true? That is, can the compiler find the function in the table only once and use its address the other two times?

P.s. Loading an instance from a shared library is just an example, to rule out the possibility of inlining a function.


Solution

  • Even doing this:

    void function (Base& x, bool flag1, bool flag2, bool flag3) {
       if(flag1 || flag2 || flag3) {
          if(flag1)
             x.f();
          if(flag2)
             x.f();
          if(flag3)
             x.f();
       }
    }
    

    with GCC -O3 loads the vtable pointer (mov rax, QWORD PTR [rbx]) for every call:

    function(Base&, bool, bool, bool):
            push    r12
            mov     r12d, ecx
            push    rbp
            mov     ebp, edx
            push    rbx
            mov     rbx, rdi
            test    sil, sil
            jne     .L2
            test    dl, dl
            jne     .L2
    .L6:
            test    r12b, r12b
            jne     .L12
    .L9:
            pop     rbx
            pop     rbp
            pop     r12
            ret
    .L2:
            mov     rax, QWORD PTR [rbx]
            mov     rdx, QWORD PTR [rax]
            test    sil, sil
            je      .L7
            mov     rdi, rbx
            call    rdx
            test    bpl, bpl
            je      .L6
            mov     rax, QWORD PTR [rbx]
    .L7:
            mov     rdi, rbx
            call    [QWORD PTR [rax]]
            test    r12b, r12b
            je      .L9
    .L12:
            mov     rax, QWORD PTR [rbx]
            mov     rdi, rbx
            pop     rbx
            pop     rbp
            pop     r12
            mov     rax, QWORD PTR [rax]
            jmp     rax