When working with virtual inheritance in C++, I notice that Clang seems to generate duplicated LLVM IR for a virtual inheritance class. Here is my test code:
// test.c
#include <stdio.h>
class A {
public:
virtual int f() { return 1; }
};
class B: public A {
};
class C: virtual public A {
};
int main(int argc, char **argv) {
B *pb = new B;
C *pc = new C; // Clang generates duplicate IR for the constructor of C
return 0;
}
Here is my compilation command:
clang virtual-inheritance-1-test.cpp -O0 -c -emit-llvm -fno-rtti
And here is part of the generated bitcode:
%class.B = type { %class.A }
%class.A = type { i32 (...)** }
%class.C = type { %class.A }
@_ZTV1B = linkonce_odr dso_local unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* null, i8* bitcast (i32 (%class.A*)* @_ZN1A1fEv to i8*)] }, comdat, align 8
@_ZTV1A = linkonce_odr dso_local unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* null, i8* bitcast (i32 (%class.A*)* @_ZN1A1fEv to i8*)] }, comdat, align 8
@_ZTV1C = linkonce_odr dso_local unnamed_addr constant { [5 x i8*] } { [5 x i8*] [i8* null, i8* null, i8* null, i8* null, i8* bitcast (i32 (%class.A*)* @_ZN1A1fEv to i8*)] }, comdat, align 8
@_ZTT1C = linkonce_odr dso_local unnamed_addr constant [2 x i8*] [i8* bitcast (i8** getelementptr inbounds ({ [5 x i8*] }, { [5 x i8*] }* @_ZTV1C, i32 0, inrange i32 0, i32 4) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [5 x i8*] }, { [5 x i8*] }* @_ZTV1C, i32 0, inrange i32 0, i32 4) to i8*)], comdat, align 8
; Function Attrs: noinline norecurse optnone uwtable
define dso_local i32 @main(i32 %0, i8** %1) #0 {
%3 = alloca i32, align 4
%4 = alloca i32, align 4
%5 = alloca i8**, align 8
%6 = alloca %class.B*, align 8
%7 = alloca %class.C*, align 8
store i32 0, i32* %3, align 4
store i32 %0, i32* %4, align 4
store i8** %1, i8*** %5, align 8
%8 = call i8* @_Znwm(i64 8) #3
%9 = bitcast i8* %8 to %class.B*
call void @_ZN1BC2Ev(%class.B* %9) #4
store %class.B* %9, %class.B** %6, align 8
%10 = call i8* @_Znwm(i64 8) #3
%11 = bitcast i8* %10 to %class.C*
call void @_ZN1CC1Ev(%class.C* %11) #4
store %class.C* %11, %class.C** %7, align 8
ret i32 0
}
; Function Attrs: nobuiltin
declare dso_local noalias i8* @_Znwm(i64) #1
; Function Attrs: noinline nounwind optnone uwtable
define linkonce_odr dso_local void @_ZN1BC2Ev(%class.B* %0) unnamed_addr #2 comdat align 2 {
%2 = alloca %class.B*, align 8
store %class.B* %0, %class.B** %2, align 8
%3 = load %class.B*, %class.B** %2, align 8
%4 = bitcast %class.B* %3 to %class.A*
call void @_ZN1AC2Ev(%class.A* %4) #4
%5 = bitcast %class.B* %3 to i32 (...)***
store i32 (...)** bitcast (i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTV1B, i32 0, inrange i32 0, i32 2) to i32 (...)**), i32 (...)*** %5, align 8
ret void
}
; Function Attrs: noinline nounwind optnone uwtable
define linkonce_odr dso_local void @_ZN1CC1Ev(%class.C* %0) unnamed_addr #2 comdat align 2 {
%2 = alloca %class.C*, align 8
store %class.C* %0, %class.C** %2, align 8
%3 = load %class.C*, %class.C** %2, align 8
%4 = bitcast %class.C* %3 to %class.A*
call void @_ZN1AC2Ev(%class.A* %4) #4
%5 = bitcast %class.C* %3 to i32 (...)***
store i32 (...)** bitcast (i8** getelementptr inbounds ({ [5 x i8*] }, { [5 x i8*] }* @_ZTV1C, i32 0, inrange i32 0, i32 4) to i32 (...)**), i32 (...)*** %5, align 8
%6 = bitcast %class.C* %3 to i32 (...)***
store i32 (...)** bitcast (i8** getelementptr inbounds ({ [5 x i8*] }, { [5 x i8*] }* @_ZTV1C, i32 0, inrange i32 0, i32 4) to i32 (...)**), i32 (...)*** %6, align 8
ret void
}
; Function Attrs: noinline nounwind optnone uwtable
define linkonce_odr dso_local void @_ZN1AC2Ev(%class.A* %0) unnamed_addr #2 comdat align 2 {
%2 = alloca %class.A*, align 8
store %class.A* %0, %class.A** %2, align 8
%3 = load %class.A*, %class.A** %2, align 8
%4 = bitcast %class.A* %3 to i32 (...)***
store i32 (...)** bitcast (i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTV1A, i32 0, inrange i32 0, i32 2) to i32 (...)**), i32 (...)*** %4, align 8
ret void
}
; Function Attrs: noinline nounwind optnone uwtable
define linkonce_odr dso_local i32 @_ZN1A1fEv(%class.A* %0) unnamed_addr #2 comdat align 2 {
%2 = alloca %class.A*, align 8
store %class.A* %0, %class.A** %2, align 8
%3 = load %class.A*, %class.A** %2, align 8
ret i32 1
}
I notice in the constructor of the class C
, there is a duplication of IR generated for %5
and %6
.
; Function Attrs: noinline nounwind optnone uwtable
define linkonce_odr dso_local void @_ZN1CC1Ev(%class.C* %0) unnamed_addr #2 comdat align 2 {
%2 = alloca %class.C*, align 8
store %class.C* %0, %class.C** %2, align 8
%3 = load %class.C*, %class.C** %2, align 8
%4 = bitcast %class.C* %3 to %class.A*
call void @_ZN1AC2Ev(%class.A* %4) #4
%5 = bitcast %class.C* %3 to i32 (...)***
store i32 (...)** bitcast (i8** getelementptr inbounds ({ [5 x i8*] }, { [5 x i8*] }* @_ZTV1C, i32 0, inrange i32 0, i32 4) to i32 (...)**), i32 (...)*** %5, align 8
%6 = bitcast %class.C* %3 to i32 (...)***
store i32 (...)** bitcast (i8** getelementptr inbounds ({ [5 x i8*] }, { [5 x i8*] }* @_ZTV1C, i32 0, inrange i32 0, i32 4) to i32 (...)**), i32 (...)*** %6, align 8
ret void
}
In particular, the two pairs of following instructions of _ZN1CC1Ev
seem to perform exactly the same action.
%5 = bitcast %class.C* %3 to i32 (...)***
store i32 (...)** bitcast (i8** getelementptr inbounds ({ [5 x i8*] }, { [5 x i8*] }* @_ZTV1C, i32 0, inrange i32 0, i32 4) to i32 (...)**), i32 (...)*** %5, align 8
and
%6 = bitcast %class.C* %3 to i32 (...)***
store i32 (...)** bitcast (i8** getelementptr inbounds ({ [5 x i8*] }, { [5 x i8*] }* @_ZTV1C, i32 0, inrange i32 0, i32 4) to i32 (...)**), i32 (...)*** %6, align 8
Does anybody know why such duplicated code are generated?
Thank you for spending your time on my question!