зеркало из https://github.com/microsoft/clang-1.git
Abstract out emitting the vdtor calls and do it properly when using -cxx-abi microsoft; also fix vdtor calls for the ARM ABI
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@175271 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
a574c89097
Коммит
0f9827f5d6
|
@ -207,6 +207,14 @@ public:
|
|||
/// Emit the ABI-specific prolog for the function.
|
||||
virtual void EmitInstanceFunctionProlog(CodeGenFunction &CGF) = 0;
|
||||
|
||||
/// Emit the ABI-specific virtual destructor call.
|
||||
virtual RValue EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
||||
const CXXDestructorDecl *Dtor,
|
||||
CXXDtorType DtorType,
|
||||
SourceLocation CallLoc,
|
||||
ReturnValueSlot ReturnValue,
|
||||
llvm::Value *This) = 0;
|
||||
|
||||
virtual void EmitReturnFromThunk(CodeGenFunction &CGF,
|
||||
RValue RV, QualType ResultType);
|
||||
|
||||
|
|
|
@ -284,7 +284,12 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
|
|||
llvm::Value *Callee;
|
||||
if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD)) {
|
||||
if (UseVirtualCall) {
|
||||
Callee = BuildVirtualCall(Dtor, Dtor_Complete, This, Ty);
|
||||
assert(CE->arg_begin() == CE->arg_end() &&
|
||||
"Virtual destructor shouldn't have explicit parameters");
|
||||
return CGM.getCXXABI().EmitVirtualDestructorCall(*this, Dtor,
|
||||
Dtor_Complete,
|
||||
CE->getExprLoc(),
|
||||
ReturnValue, This);
|
||||
} else {
|
||||
if (getLangOpts().AppleKext &&
|
||||
MD->isVirtual() &&
|
||||
|
@ -1399,18 +1404,12 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
|
|||
completePtr, OperatorDelete,
|
||||
ElementType);
|
||||
}
|
||||
|
||||
llvm::Type *Ty =
|
||||
CGF.getTypes().GetFunctionType(
|
||||
CGF.getTypes().arrangeCXXDestructor(Dtor, Dtor_Complete));
|
||||
|
||||
llvm::Value *Callee
|
||||
= CGF.BuildVirtualCall(Dtor,
|
||||
UseGlobalDelete? Dtor_Complete : Dtor_Deleting,
|
||||
Ptr, Ty);
|
||||
|
||||
// FIXME: Provide a source location here.
|
||||
CGF.EmitCXXMemberCall(Dtor, SourceLocation(), Callee, ReturnValueSlot(),
|
||||
Ptr, /*ImplicitParam=*/0, QualType(), 0, 0);
|
||||
CXXDtorType DtorType = UseGlobalDelete ? Dtor_Complete : Dtor_Deleting;
|
||||
CGF.CGM.getCXXABI().EmitVirtualDestructorCall(CGF, Dtor, DtorType,
|
||||
SourceLocation(),
|
||||
ReturnValueSlot(), Ptr);
|
||||
|
||||
if (UseGlobalDelete) {
|
||||
CGF.PopCleanupBlock();
|
||||
|
|
|
@ -112,6 +112,13 @@ public:
|
|||
|
||||
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
|
||||
|
||||
RValue EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
||||
const CXXDestructorDecl *Dtor,
|
||||
CXXDtorType DtorType,
|
||||
SourceLocation CallLoc,
|
||||
ReturnValueSlot ReturnValue,
|
||||
llvm::Value *This);
|
||||
|
||||
StringRef GetPureVirtualCallName() { return "__cxa_pure_virtual"; }
|
||||
StringRef GetDeletedVirtualCallName() { return "__cxa_deleted_virtual"; }
|
||||
|
||||
|
@ -819,6 +826,23 @@ void ARMCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
|
|||
CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);
|
||||
}
|
||||
|
||||
RValue ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
||||
const CXXDestructorDecl *Dtor,
|
||||
CXXDtorType DtorType,
|
||||
SourceLocation CallLoc,
|
||||
ReturnValueSlot ReturnValue,
|
||||
llvm::Value *This) {
|
||||
assert(DtorType == Dtor_Deleting || DtorType == Dtor_Complete);
|
||||
|
||||
const CGFunctionInfo *FInfo
|
||||
= &CGM.getTypes().arrangeCXXDestructor(Dtor, DtorType);
|
||||
llvm::Type *Ty = CGF.CGM.getTypes().GetFunctionType(*FInfo);
|
||||
llvm::Value *Callee = CGF.BuildVirtualCall(Dtor, DtorType, This, Ty);
|
||||
|
||||
return CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValue, This,
|
||||
/*ImplicitParam=*/0, QualType(), 0, 0);
|
||||
}
|
||||
|
||||
void ARMCXXABI::EmitReturnFromThunk(CodeGenFunction &CGF,
|
||||
RValue RV, QualType ResultType) {
|
||||
if (!isa<CXXDestructorDecl>(CGF.CurGD.getDecl()))
|
||||
|
|
|
@ -53,6 +53,13 @@ public:
|
|||
|
||||
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
|
||||
|
||||
RValue EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
||||
const CXXDestructorDecl *Dtor,
|
||||
CXXDtorType DtorType,
|
||||
SourceLocation CallLoc,
|
||||
ReturnValueSlot ReturnValue,
|
||||
llvm::Value *This);
|
||||
|
||||
void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
|
||||
llvm::GlobalVariable *DeclPtr,
|
||||
bool PerformInit);
|
||||
|
@ -174,6 +181,30 @@ void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
|
|||
}
|
||||
}
|
||||
|
||||
RValue MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
||||
const CXXDestructorDecl *Dtor,
|
||||
CXXDtorType DtorType,
|
||||
SourceLocation CallLoc,
|
||||
ReturnValueSlot ReturnValue,
|
||||
llvm::Value *This) {
|
||||
assert(DtorType == Dtor_Deleting || DtorType == Dtor_Complete);
|
||||
|
||||
// We have only one destructor in the vftable but can get both behaviors
|
||||
// by passing an implicit bool parameter.
|
||||
const CGFunctionInfo *FInfo
|
||||
= &CGM.getTypes().arrangeCXXDestructor(Dtor, Dtor_Deleting);
|
||||
llvm::Type *Ty = CGF.CGM.getTypes().GetFunctionType(*FInfo);
|
||||
llvm::Value *Callee = CGF.BuildVirtualCall(Dtor, Dtor_Deleting, This, Ty);
|
||||
|
||||
ASTContext &Context = CGF.getContext();
|
||||
llvm::Value *ImplicitParam
|
||||
= llvm::ConstantInt::get(llvm::IntegerType::getInt1Ty(CGF.getLLVMContext()),
|
||||
DtorType == Dtor_Deleting);
|
||||
|
||||
return CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValue, This,
|
||||
ImplicitParam, Context.BoolTy, 0, 0);
|
||||
}
|
||||
|
||||
bool MicrosoftCXXABI::requiresArrayCookie(const CXXDeleteExpr *expr,
|
||||
QualType elementType) {
|
||||
// Microsoft seems to completely ignore the possibility of a
|
||||
|
|
|
@ -274,11 +274,11 @@ namespace test6 {
|
|||
// CHECK-NEXT: [[V:%.*]] = load [[A]]** [[AVAR]], align 4
|
||||
// CHECK-NEXT: [[ISNULL:%.*]] = icmp eq [[A]]* [[V]], null
|
||||
// CHECK-NEXT: br i1 [[ISNULL]]
|
||||
// CHECK: [[T0:%.*]] = bitcast [[A]]* [[V]] to [[A]]* ([[A]]*)***
|
||||
// CHECK-NEXT: [[T1:%.*]] = load [[A]]* ([[A]]*)*** [[T0]]
|
||||
// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[A]]* ([[A]]*)** [[T1]], i64 1
|
||||
// CHECK-NEXT: [[T3:%.*]] = load [[A]]* ([[A]]*)** [[T2]]
|
||||
// CHECK-NEXT: call [[A]]* [[T3]]([[A]]* [[V]])
|
||||
// CHECK: [[T0:%.*]] = bitcast [[A]]* [[V]] to void ([[A]]*)***
|
||||
// CHECK-NEXT: [[T1:%.*]] = load void ([[A]]*)*** [[T0]]
|
||||
// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds void ([[A]]*)** [[T1]], i64 1
|
||||
// CHECK-NEXT: [[T3:%.*]] = load void ([[A]]*)** [[T2]]
|
||||
// CHECK-NEXT: call void [[T3]]([[A]]* [[V]])
|
||||
// CHECK-NEXT: br label
|
||||
// CHECK: ret void
|
||||
delete a;
|
||||
|
|
|
@ -32,7 +32,9 @@ struct B {
|
|||
// DTORS: define {{.*}} x86_thiscallcc void @"\01??1B@@UAE@XZ"(%struct.B* %this)
|
||||
|
||||
// Then, the scalar deleting destructor (used in the vtable):
|
||||
// DTORS: define {{.*}} x86_thiscallcc void @"\01??_GB@@UAEPAXI@Z"(%struct.B* %this, i1 zeroext %should_call_delete)
|
||||
// FIXME: add a test that verifies that the out-of-line scalar deleting
|
||||
// destructor is linkonce_odr too.
|
||||
// DTORS: define linkonce_odr x86_thiscallcc void @"\01??_GB@@UAEPAXI@Z"(%struct.B* %this, i1 zeroext %should_call_delete)
|
||||
// DTORS: %[[FROMBOOL:[0-9a-z]+]] = zext i1 %should_call_delete to i8
|
||||
// DTORS-NEXT: store i8 %[[FROMBOOL]], i8* %[[SHOULD_DELETE_VAR:[0-9a-z._]+]], align 1
|
||||
// DTORS: %[[SHOULD_DELETE_VALUE:[0-9a-z._]+]] = load i8* %[[SHOULD_DELETE_VAR]]
|
||||
|
@ -61,17 +63,29 @@ void check_vftable_offset() {
|
|||
// CHECK: store i8** getelementptr inbounds ([2 x i8*]* @"\01??_7B@@6B@", i64 0, i64 0), i8*** [[THIS_PTR]]
|
||||
}
|
||||
|
||||
// FIXME: Enable the following block and add expectations when calls
|
||||
// to virtual complete dtor are supported.
|
||||
#if 0
|
||||
void call_complete_dtor(B *obj_ptr) {
|
||||
// CHECK: define void @"\01?call_complete_dtor@@YAXPAUB@@@Z"(%struct.B* %obj_ptr)
|
||||
obj_ptr->~B();
|
||||
// CHECK: %[[OBJ_PTR_VALUE:.*]] = load %struct.B** %{{.*}}, align 4
|
||||
// CHECK-NEXT: %[[PVTABLE:.*]] = bitcast %struct.B* %[[OBJ_PTR_VALUE]] to void (%struct.B*, i1)***
|
||||
// CHECK-NEXT: %[[VTABLE:.*]] = load void (%struct.B*, i1)*** %[[PVTABLE]]
|
||||
// CHECK-NEXT: %[[PVDTOR:.*]] = getelementptr inbounds void (%struct.B*, i1)** %[[VTABLE]], i64 0
|
||||
// CHECK-NEXT: %[[VDTOR:.*]] = load void (%struct.B*, i1)** %[[PVDTOR]]
|
||||
// CHECK-NEXT: call x86_thiscallcc void %[[VDTOR]](%struct.B* %[[OBJ_PTR_VALUE]], i1 zeroext false)
|
||||
// CHECK-NEXT: ret void
|
||||
}
|
||||
#endif
|
||||
|
||||
void call_deleting_dtor(B *obj_ptr) {
|
||||
// FIXME: Add CHECKs when calls to virtual deleting dtor are generated properly.
|
||||
// CHECK: define void @"\01?call_deleting_dtor@@YAXPAUB@@@Z"(%struct.B* %obj_ptr)
|
||||
delete obj_ptr;
|
||||
// CHECK: %[[OBJ_PTR_VALUE:.*]] = load %struct.B** %{{.*}}, align 4
|
||||
// CHECK: {{.*}}:{{%{0,1}[0-9]*}}
|
||||
// CHECK-NEXT: %[[PVTABLE:.*]] = bitcast %struct.B* %[[OBJ_PTR_VALUE]] to void (%struct.B*, i1)***
|
||||
// CHECK-NEXT: %[[VTABLE:.*]] = load void (%struct.B*, i1)*** %[[PVTABLE]]
|
||||
// CHECK-NEXT: %[[PVDTOR:.*]] = getelementptr inbounds void (%struct.B*, i1)** %[[VTABLE]], i64 0
|
||||
// CHECK-NEXT: %[[VDTOR:.*]] = load void (%struct.B*, i1)** %[[PVDTOR]]
|
||||
// CHECK-NEXT: call x86_thiscallcc void %[[VDTOR]](%struct.B* %[[OBJ_PTR_VALUE]], i1 zeroext true)
|
||||
// CHECK: ret void
|
||||
}
|
||||
|
||||
struct C {
|
||||
|
|
Загрузка…
Ссылка в новой задаче