r192312 - Initialize vtorDisp in class constructors and destructors
Timur Iskhodzhanov
timurrrr at google.com
Wed Oct 9 11:16:58 PDT 2013
Author: timurrrr
Date: Wed Oct 9 13:16:58 2013
New Revision: 192312
URL: http://llvm.org/viewvc/llvm-project?rev=192312&view=rev
Log:
Initialize vtorDisp in class constructors and destructors
Reviewed at http://llvm-reviews.chandlerc.com/D1867
Modified:
cfe/trunk/lib/CodeGen/CGCXXABI.h
cfe/trunk/lib/CodeGen/CGClass.cpp
cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp
Modified: cfe/trunk/lib/CodeGen/CGCXXABI.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.h?rev=192312&r1=192311&r2=192312&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXXABI.h (original)
+++ cfe/trunk/lib/CodeGen/CGCXXABI.h Wed Oct 9 13:16:58 2013
@@ -234,6 +234,12 @@ public:
virtual llvm::BasicBlock *EmitCtorCompleteObjectHandler(CodeGenFunction &CGF,
const CXXRecordDecl *RD);
+ /// Emit the code to initialize hidden members required
+ /// to handle virtual inheritance, if needed by the ABI.
+ virtual void
+ initializeHiddenVirtualInheritanceMembers(CodeGenFunction &CGF,
+ const CXXRecordDecl *RD) {}
+
/// Emit constructor variants required by this ABI.
virtual void EmitCXXConstructors(const CXXConstructorDecl *D) = 0;
Modified: cfe/trunk/lib/CodeGen/CGClass.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=192312&r1=192311&r2=192312&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGClass.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGClass.cpp Wed Oct 9 13:16:58 2013
@@ -1992,6 +1992,9 @@ void CodeGenFunction::InitializeVTablePo
/*NearestVBase=*/0,
/*OffsetFromNearestVBase=*/CharUnits::Zero(),
/*BaseIsNonVirtualPrimaryBase=*/false, RD, VBases);
+
+ if (RD->getNumVBases())
+ CGM.getCXXABI().initializeHiddenVirtualInheritanceMembers(*this, RD);
}
llvm::Value *CodeGenFunction::GetVTablePtr(llvm::Value *This,
Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=192312&r1=192311&r2=192312&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Wed Oct 9 13:16:58 2013
@@ -67,6 +67,9 @@ public:
llvm::BasicBlock *EmitCtorCompleteObjectHandler(CodeGenFunction &CGF,
const CXXRecordDecl *RD);
+ void initializeHiddenVirtualInheritanceMembers(CodeGenFunction &CGF,
+ const CXXRecordDecl *RD);
+
void EmitCXXConstructors(const CXXConstructorDecl *D);
// Background on MSVC destructors
@@ -456,6 +459,61 @@ MicrosoftCXXABI::EmitCtorCompleteObjectH
return SkipVbaseCtorsBB;
}
+void MicrosoftCXXABI::initializeHiddenVirtualInheritanceMembers(
+ CodeGenFunction &CGF, const CXXRecordDecl *RD) {
+ // In most cases, an override for a vbase virtual method can adjust
+ // the "this" parameter by applying a constant offset.
+ // However, this is not enough while a constructor or a destructor of some
+ // class X is being executed if all the following conditions are met:
+ // - X has virtual bases, (1)
+ // - X overrides a virtual method M of a vbase Y, (2)
+ // - X itself is a vbase of the most derived class.
+ //
+ // If (1) and (2) are true, the vtorDisp for vbase Y is a hidden member of X
+ // which holds the extra amount of "this" adjustment we must do when we use
+ // the X vftables (i.e. during X ctor or dtor).
+ // Outside the ctors and dtors, the values of vtorDisps are zero.
+
+ const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
+ typedef ASTRecordLayout::VBaseOffsetsMapTy VBOffsets;
+ const VBOffsets &VBaseMap = Layout.getVBaseOffsetsMap();
+ CGBuilderTy &Builder = CGF.Builder;
+
+ unsigned AS =
+ cast<llvm::PointerType>(getThisValue(CGF)->getType())->getAddressSpace();
+ llvm::Value *Int8This = 0; // Initialize lazily.
+
+ for (VBOffsets::const_iterator I = VBaseMap.begin(), E = VBaseMap.end();
+ I != E; ++I) {
+ if (!I->second.hasVtorDisp())
+ continue;
+
+ llvm::Value *VBaseOffset = CGM.getCXXABI().GetVirtualBaseClassOffset(
+ CGF, getThisValue(CGF), RD, I->first);
+ // FIXME: it doesn't look right that we SExt in GetVirtualBaseClassOffset()
+ // just to Trunc back immediately.
+ VBaseOffset = Builder.CreateTruncOrBitCast(VBaseOffset, CGF.Int32Ty);
+ uint64_t ConstantVBaseOffset =
+ Layout.getVBaseClassOffset(I->first).getQuantity();
+
+ // vtorDisp_for_vbase = vbptr[vbase_idx] - offsetof(RD, vbase).
+ llvm::Value *VtorDispValue = Builder.CreateSub(
+ VBaseOffset, llvm::ConstantInt::get(CGM.Int32Ty, ConstantVBaseOffset),
+ "vtordisp.value");
+
+ if (!Int8This)
+ Int8This = Builder.CreateBitCast(getThisValue(CGF),
+ CGF.Int8Ty->getPointerTo(AS));
+ llvm::Value *VtorDispPtr = Builder.CreateInBoundsGEP(Int8This, VBaseOffset);
+ // vtorDisp is always the 32-bits before the vbase in the class layout.
+ VtorDispPtr = Builder.CreateConstGEP1_32(VtorDispPtr, -4);
+ VtorDispPtr = Builder.CreateBitCast(
+ VtorDispPtr, CGF.Int32Ty->getPointerTo(AS), "vtordisp.ptr");
+
+ Builder.CreateStore(VtorDispValue, VtorDispPtr);
+ }
+}
+
void MicrosoftCXXABI::EmitCXXConstructors(const CXXConstructorDecl *D) {
// There's only one constructor type in this ABI.
CGM.EmitGlobal(GlobalDecl(D, Ctor_Complete));
Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp?rev=192312&r1=192311&r2=192312&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp Wed Oct 9 13:16:58 2013
@@ -1,6 +1,10 @@
// RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=i386-pc-win32 -emit-llvm -o - | FileCheck %s
+// For now, just make sure x86_64 doesn't crash.
+// RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=x86_64-pc-win32 -emit-llvm -o %t
+
struct VBase {
+ virtual ~VBase();
virtual void foo();
virtual void bar();
int field;
@@ -8,27 +12,74 @@ struct VBase {
struct B : virtual VBase {
B();
+ virtual ~B();
virtual void foo();
virtual void bar();
};
B::B() {
- // CHECK: @"\01??0B@@QAE at XZ"
+ // CHECK-LABEL: define x86_thiscallcc %struct.B* @"\01??0B@@QAE at XZ"
// CHECK: %[[THIS:.*]] = load %struct.B**
// CHECK: br i1 %{{.*}}, label %[[INIT_VBASES:.*]], label %[[SKIP_VBASES:.*]]
+
+ // Don't check the INIT_VBASES case as it's covered by the ctor tests.
+
// CHECK: %[[SKIP_VBASES]]
// CHECK: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8*
// CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 0
+ // ...
+ // CHECK: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8*
+ // CHECK: %[[VFPTR_i8:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 %{{.*}}
+ // CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VFPTR_i8]] to [3 x i8*]**
+ // CHECK: store [3 x i8*]* @"\01??_7B@@6B@", [3 x i8*]** %[[VFPTR]]
+
+ // Initialize vtorDisp:
+ // CHECK: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8*
+ // CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 0
+ // ...
+ // CHECK: %[[VBASE_OFFSET:.*]] = add nsw i32 0, %{{.*}}
+ // CHECK: %[[VTORDISP_VAL:.*]] = sub i32 %[[VBASE_OFFSET]], 8
+ // CHECK: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8*
+ // CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 %[[VBASE_OFFSET]]
+ // CHECK: %[[VTORDISP_i8:.*]] = getelementptr i8* %[[VBASE_i8]], i32 -4
+ // CHECK: %[[VTORDISP_PTR:.*]] = bitcast i8* %[[VTORDISP_i8]] to i32*
+ // CHECK: store i32 %[[VTORDISP_VAL]], i32* %[[VTORDISP_PTR]]
+
+ // CHECK: ret
+}
+
+B::~B() {
+ // CHECK-LABEL: define x86_thiscallcc void @"\01??1B@@UAE at XZ"
+ // CHECK: %[[THIS:.*]] = load %struct.B**
+
+ // Restore the vfptr that could have been changed by a subclass.
+ // CHECK: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8*
+ // CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 0
+ // ...
// CHECK: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8*
// CHECK: %[[VFPTR_i8:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 %{{.*}}
- // CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VFPTR_i8]] to [2 x i8*]**
- // CHECK: store [2 x i8*]* @"\01??_7B@@6B@", [2 x i8*]** %[[VFPTR]]
- // FIXME: Should initialize the vtorDisp here.
+ // CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VFPTR_i8]] to [3 x i8*]**
+ // CHECK: store [3 x i8*]* @"\01??_7B@@6B@", [3 x i8*]** %[[VFPTR]]
+
+ // Initialize vtorDisp:
+ // CHECK: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8*
+ // CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 0
+ // ...
+ // CHECK: %[[VBASE_OFFSET:.*]] = add nsw i32 0, %{{.*}}
+ // CHECK: %[[VTORDISP_VAL:.*]] = sub i32 %[[VBASE_OFFSET]], 8
+ // CHECK: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8*
+ // CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 %[[VBASE_OFFSET]]
+ // CHECK: %[[VTORDISP_i8:.*]] = getelementptr i8* %[[VBASE_i8]], i32 -4
+ // CHECK: %[[VTORDISP_PTR:.*]] = bitcast i8* %[[VTORDISP_i8]] to i32*
+ // CHECK: store i32 %[[VTORDISP_VAL]], i32* %[[VTORDISP_PTR]]
+
+ foo(); // Avoid the "trivial destructor" optimization.
+
// CHECK: ret
}
void B::foo() {
-// CHECK: define x86_thiscallcc void @"\01?foo at B@@UAEXXZ"(i8*
+// CHECK-LABEL: define x86_thiscallcc void @"\01?foo at B@@UAEXXZ"(i8*
//
// B::foo gets 'this' cast to VBase* in ECX (i.e. this+8) so we
// need to adjust 'this' before use.
@@ -58,7 +109,7 @@ void B::foo() {
}
void call_vbase_bar(B *obj) {
-// CHECK: define void @"\01?call_vbase_bar@@YAXPAUB@@@Z"(%struct.B* %obj)
+// CHECK-LABEL: define void @"\01?call_vbase_bar@@YAXPAUB@@@Z"(%struct.B* %obj)
// CHECK: %[[OBJ:.*]] = load %struct.B
obj->bar();
@@ -76,7 +127,7 @@ void call_vbase_bar(B *obj) {
// CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 %[[VBOFFSET]]
// CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VBASE_i8]] to void (i8*)***
// CHECK: %[[VFTABLE:.*]] = load void (i8*)*** %[[VFPTR]]
-// CHECK: %[[VFUN:.*]] = getelementptr inbounds void (i8*)** %[[VFTABLE]], i64 1
+// CHECK: %[[VFUN:.*]] = getelementptr inbounds void (i8*)** %[[VFTABLE]], i64 2
// CHECK: %[[VFUN_VALUE:.*]] = load void (i8*)** %[[VFUN]]
//
// CHECK: %[[OBJ_i8:.*]] = bitcast %struct.B* %[[OBJ]] to i8*
@@ -101,3 +152,38 @@ struct C : B {
// Used to crash on an assertion.
C::C() {}
+
+namespace multiple_vbases {
+struct A {
+ virtual void a();
+};
+
+struct B {
+ virtual void b();
+};
+
+struct C {
+ virtual void c();
+};
+
+struct D : virtual A, virtual B, virtual C {
+ virtual void a();
+ virtual void b();
+ virtual void c();
+ D();
+};
+
+D::D() {
+ // CHECK-LABEL: define x86_thiscallcc %"struct.multiple_vbases::D"* @"\01??0D at multiple_vbases@@QAE at XZ"
+ // Just make sure we emit 3 vtordisps after initializing vfptrs.
+ // CHECK: store [1 x i8*]* @"\01??_7D at multiple_vbases@@6BA at 1@@", [1 x i8*]** %{{.*}}
+ // CHECK: store [1 x i8*]* @"\01??_7D at multiple_vbases@@6BB at 1@@", [1 x i8*]** %{{.*}}
+ // CHECK: store [1 x i8*]* @"\01??_7D at multiple_vbases@@6BC at 1@@", [1 x i8*]** %{{.*}}
+ // ...
+ // CHECK: store i32 %{{.*}}, i32* %{{.*}}
+ // CHECK: store i32 %{{.*}}, i32* %{{.*}}
+ // CHECK: store i32 %{{.*}}, i32* %{{.*}}
+ // CHECK: ret
+}
+
+}
More information about the cfe-commits
mailing list