-2

Here's a simple inheritance usinig a virtual base class (code available on Compiler Explorer).

class B {
public:
    int i = 1;
};

class D : virtual public B {
public:
    int j = 2;
};

void Assign(B *b) {
    b->i = 2;
}

int main() {
    B *b = new D();
    Assign(b);
    return 0;
}

The assembly listing of the main() function looks like this:

09  main: # @main
10    push rbp
11    mov rbp, rsp
12    sub rsp, 32
13    mov eax, 16
14    mov edi, eax
15    mov dword ptr [rbp - 4], 0
16    call operator new(unsigned long)
17    xor esi, esi
18    mov ecx, 16
19    mov edx, ecx
20    mov rdi, rax
21    mov qword ptr [rbp - 24], rax # 8-byte Spill
22    call memset
23    mov rdi, qword ptr [rbp - 24] # 8-byte Reload
24    call D::D() [complete object constructor]
25    xor ecx, ecx
26    mov eax, ecx

27    mov rdx, qword ptr [rbp - 24] # 8-byte Reload
28    cmp rdx, 0
29    mov qword ptr [rbp - 32], rax # 8-byte Spill
30    je .LBB1_2
31    mov rax, qword ptr [rbp - 24] # 8-byte Reload
32    mov rcx, qword ptr [rax]
33    mov rcx, qword ptr [rcx - 24]
34    add rax, rcx
35    mov qword ptr [rbp - 32], rax # 8-byte Spill
36  .LBB1_2:
37    mov rax, qword ptr [rbp - 32] # 8-byte Reload
38    mov qword ptr [rbp - 16], rax

39    mov rdi, qword ptr [rbp - 16]
40    call Assign(B*)
41    xor eax, eax
42    add rsp, 32
43    pop rbp
44    ret

What is the effect of line 27-38 of the assembly?

What is the value of rax in line 29?

Why is there a branch statement?

1201ProgramAlarm
  • 32,384
  • 7
  • 42
  • 56
chaosink
  • 1,329
  • 13
  • 27
  • 2
    Can you still get similar code with `-Og`? `-O0` debug mode is a mess. IDK if gcc would be doing speculative devirtualization at `-O0` but it might be. – Peter Cordes Aug 29 '19 at 15:46
  • Hint: pay attention to the "vtable for D" symbol, first member! – curiousguy Aug 31 '19 at 02:17
  • @curiousguy What do you mean? – chaosink Aug 31 '19 at 11:39
  • @chaosink The 1st field of the vtable of the derived class contains the information the compiler needs here: "`vtable for D: .quad 12`" It means that base is at offset +12 from the `D` base class (lax) subobject in the most derived object `D`. (It's easier to speak in term of lax subobject where a derived object is a subobject of itself.) Be careful the vptr doesn't point to the beginning of the vtable! By historical convention `vptr[0]` is the first virtual function (if there is any, or the one of the end of the virtual function array). The offsets are at negative offsets WRT vptr. – curiousguy Aug 31 '19 at 14:58

1 Answers1

2

The effect of lines 27-38 is to convert a D * to a B *. Because B is a virtual base class, it can have a variable offset from the start of D. Those 12 lines calculate where the B object is, in an unoptimized way.

The value of eax on line 29 is 0 (see lines 25-26).

The branch statement on line 30 is the result of a NULL pointer check. If the pointer to D is NULL, the conversion to a B * will also be NULL and the extra code to determine the correct offset is not wanted in that case.

1201ProgramAlarm
  • 32,384
  • 7
  • 42
  • 56
  • 1
    It makes it easier to see it if you split out the `D*` to `B*` conversion into a separate statement. And even easier if you put it into a *function* so you can enable optimization without removing it. https://godbolt.org/z/4-deOJ – Peter Cordes Aug 29 '19 at 19:03