diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2013-04-08 18:45:10 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2013-04-08 18:45:10 +0000 |
commit | 809500fc2c13c8173a16b052304d983864e4a1e1 (patch) | |
tree | 4fc2f184c499d106f29a386c452b49e5197bf63d /lib/CodeGen/MicrosoftCXXABI.cpp | |
parent | be7c9ec198dcdb5bf73a35bfbb00b3333cb87909 (diff) | |
download | src-test2-809500fc2c13c8173a16b052304d983864e4a1e1.tar.gz src-test2-809500fc2c13c8173a16b052304d983864e4a1e1.zip |
Notes
Diffstat (limited to 'lib/CodeGen/MicrosoftCXXABI.cpp')
-rw-r--r-- | lib/CodeGen/MicrosoftCXXABI.cpp | 278 |
1 files changed, 268 insertions, 10 deletions
diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index 8d205c3d0f5d..00b15c9a49c4 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -42,13 +42,12 @@ public: CanQualType &ResTy, SmallVectorImpl<CanQualType> &ArgTys); + llvm::BasicBlock *EmitCtorCompleteObjectHandler(CodeGenFunction &CGF); + void BuildDestructorSignature(const CXXDestructorDecl *Ctor, CXXDtorType Type, CanQualType &ResTy, - SmallVectorImpl<CanQualType> &ArgTys) { - // 'this' is already in place - // TODO: 'for base' flag - } + SmallVectorImpl<CanQualType> &ArgTys); void BuildInstanceFunctionParams(CodeGenFunction &CGF, QualType &ResTy, @@ -56,13 +55,25 @@ public: void EmitInstanceFunctionProlog(CodeGenFunction &CGF); + llvm::Value *EmitConstructorCall(CodeGenFunction &CGF, + const CXXConstructorDecl *D, + CXXCtorType Type, bool ForVirtualBase, + bool Delegating, + llvm::Value *This, + CallExpr::const_arg_iterator ArgBeg, + CallExpr::const_arg_iterator ArgEnd); + + 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); - void EmitVTables(const CXXRecordDecl *Class); - - // ==== Notes on array cookies ========= // // MSVC seems to only use cookies when the class has a destructor; a @@ -98,6 +109,33 @@ public: llvm::Value *allocPtr, CharUnits cookieSize); static bool needThisReturn(GlobalDecl GD); + +private: + llvm::Constant *getSimpleNullMemberPointer(const MemberPointerType *MPT); + + llvm::Constant *getZeroPtrDiff() { + return llvm::ConstantInt::get(CGM.PtrDiffTy, 0); + } + + llvm::Constant *getAllOnesPtrDiff() { + return llvm::Constant::getAllOnesValue(CGM.PtrDiffTy); + } + +public: + virtual llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT); + + virtual llvm::Constant *EmitMemberDataPointer(const MemberPointerType *MPT, + CharUnits offset); + + virtual llvm::Value *EmitMemberPointerIsNotNull(CodeGenFunction &CGF, + llvm::Value *MemPtr, + const MemberPointerType *MPT); + + virtual llvm::Value *EmitMemberDataPointerAddress(CodeGenFunction &CGF, + llvm::Value *Base, + llvm::Value *MemPtr, + const MemberPointerType *MPT); + }; } @@ -119,9 +157,57 @@ void MicrosoftCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor, CanQualType &ResTy, SmallVectorImpl<CanQualType> &ArgTys) { // 'this' is already in place - // TODO: 'for base' flag + // Ctor returns this ptr ResTy = ArgTys[0]; + + const CXXRecordDecl *Class = Ctor->getParent(); + if (Class->getNumVBases()) { + // Constructors of classes with virtual bases take an implicit parameter. + ArgTys.push_back(CGM.getContext().IntTy); + } +} + +llvm::BasicBlock *MicrosoftCXXABI::EmitCtorCompleteObjectHandler( + CodeGenFunction &CGF) { + llvm::Value *IsMostDerivedClass = getStructorImplicitParamValue(CGF); + assert(IsMostDerivedClass && + "ctor for a class with virtual bases must have an implicit parameter"); + llvm::Value *IsCompleteObject + = CGF.Builder.CreateIsNotNull(IsMostDerivedClass, "is_complete_object"); + + llvm::BasicBlock *CallVbaseCtorsBB = CGF.createBasicBlock("ctor.init_vbases"); + llvm::BasicBlock *SkipVbaseCtorsBB = CGF.createBasicBlock("ctor.skip_vbases"); + CGF.Builder.CreateCondBr(IsCompleteObject, + CallVbaseCtorsBB, SkipVbaseCtorsBB); + + CGF.EmitBlock(CallVbaseCtorsBB); + // FIXME: emit vbtables somewhere around here. + + // CGF will put the base ctor calls in this basic block for us later. + + return SkipVbaseCtorsBB; +} + +void MicrosoftCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor, + CXXDtorType Type, + CanQualType &ResTy, + SmallVectorImpl<CanQualType> &ArgTys) { + // 'this' is already in place + // TODO: 'for base' flag + + if (Type == Dtor_Deleting) { + // The scalar deleting destructor takes an implicit bool parameter. + ArgTys.push_back(CGM.getContext().BoolTy); + } +} + +static bool IsDeletingDtor(GlobalDecl GD) { + const CXXMethodDecl* MD = cast<CXXMethodDecl>(GD.getDecl()); + if (isa<CXXDestructorDecl>(MD)) { + return GD.getDtorType() == Dtor_Deleting; + } + return false; } void MicrosoftCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF, @@ -131,6 +217,26 @@ void MicrosoftCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF, if (needThisReturn(CGF.CurGD)) { ResTy = Params[0]->getType(); } + + ASTContext &Context = getContext(); + const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl()); + if (isa<CXXConstructorDecl>(MD) && MD->getParent()->getNumVBases()) { + ImplicitParamDecl *IsMostDerived + = ImplicitParamDecl::Create(Context, 0, + CGF.CurGD.getDecl()->getLocation(), + &Context.Idents.get("is_most_derived"), + Context.IntTy); + Params.push_back(IsMostDerived); + getStructorImplicitParamDecl(CGF) = IsMostDerived; + } else if (IsDeletingDtor(CGF.CurGD)) { + ImplicitParamDecl *ShouldDelete + = ImplicitParamDecl::Create(Context, 0, + CGF.CurGD.getDecl()->getLocation(), + &Context.Idents.get("should_call_delete"), + Context.BoolTy); + Params.push_back(ShouldDelete); + getStructorImplicitParamDecl(CGF) = ShouldDelete; + } } void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) { @@ -138,6 +244,73 @@ void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) { if (needThisReturn(CGF.CurGD)) { CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue); } + + const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl()); + if (isa<CXXConstructorDecl>(MD) && MD->getParent()->getNumVBases()) { + assert(getStructorImplicitParamDecl(CGF) && + "no implicit parameter for a constructor with virtual bases?"); + getStructorImplicitParamValue(CGF) + = CGF.Builder.CreateLoad( + CGF.GetAddrOfLocalVar(getStructorImplicitParamDecl(CGF)), + "is_most_derived"); + } + + if (IsDeletingDtor(CGF.CurGD)) { + assert(getStructorImplicitParamDecl(CGF) && + "no implicit parameter for a deleting destructor?"); + getStructorImplicitParamValue(CGF) + = CGF.Builder.CreateLoad( + CGF.GetAddrOfLocalVar(getStructorImplicitParamDecl(CGF)), + "should_call_delete"); + } +} + +llvm::Value *MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF, + const CXXConstructorDecl *D, + CXXCtorType Type, bool ForVirtualBase, + bool Delegating, + llvm::Value *This, + CallExpr::const_arg_iterator ArgBeg, + CallExpr::const_arg_iterator ArgEnd) { + assert(Type == Ctor_Complete || Type == Ctor_Base); + llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Ctor_Complete); + + llvm::Value *ImplicitParam = 0; + QualType ImplicitParamTy; + if (D->getParent()->getNumVBases()) { + ImplicitParam = llvm::ConstantInt::get(CGM.Int32Ty, Type == Ctor_Complete); + ImplicitParamTy = getContext().IntTy; + } + + // FIXME: Provide a source location here. + CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This, + ImplicitParam, ImplicitParamTy, + ArgBeg, ArgEnd); + return Callee; +} + +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, @@ -206,8 +379,93 @@ void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, CGF.EmitCXXGlobalVarDeclInit(D, DeclPtr, PerformInit); } -void MicrosoftCXXABI::EmitVTables(const CXXRecordDecl *Class) { - // FIXME: implement +// Returns true for member pointer types that we know how to represent with a +// simple ptrdiff_t. Currently we only know how to emit, test, and load member +// data pointers for complete single inheritance classes. +static bool isSimpleMemberPointer(const MemberPointerType *MPT) { + const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl(); + return (MPT->isMemberDataPointer() && + !MPT->getClass()->isIncompleteType() && + RD->getNumVBases() == 0); +} + +llvm::Constant * +MicrosoftCXXABI::getSimpleNullMemberPointer(const MemberPointerType *MPT) { + if (isSimpleMemberPointer(MPT)) { + const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl(); + // A null member data pointer is represented as -1 if the class is not + // polymorphic, and 0 otherwise. + if (RD->isPolymorphic()) + return getZeroPtrDiff(); + return getAllOnesPtrDiff(); + } + return GetBogusMemberPointer(QualType(MPT, 0)); +} + +llvm::Constant * +MicrosoftCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) { + if (isSimpleMemberPointer(MPT)) + return getSimpleNullMemberPointer(MPT); + // FIXME: Implement function member pointers. + return GetBogusMemberPointer(QualType(MPT, 0)); +} + +llvm::Constant * +MicrosoftCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT, + CharUnits offset) { + // Member data pointers are plain offsets when no virtual bases are involved. + if (isSimpleMemberPointer(MPT)) + return llvm::ConstantInt::get(CGM.PtrDiffTy, offset.getQuantity()); + // FIXME: Implement member pointers other inheritance models. + return GetBogusMemberPointer(QualType(MPT, 0)); +} + +llvm::Value * +MicrosoftCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF, + llvm::Value *MemPtr, + const MemberPointerType *MPT) { + CGBuilderTy &Builder = CGF.Builder; + + // For member data pointers, this is just a check against -1 or 0. + if (isSimpleMemberPointer(MPT)) { + llvm::Constant *Val = getSimpleNullMemberPointer(MPT); + return Builder.CreateICmpNE(MemPtr, Val, "memptr.tobool"); + } + + // FIXME: Implement member pointers other inheritance models. + ErrorUnsupportedABI(CGF, "function member pointer tests"); + return GetBogusMemberPointer(QualType(MPT, 0)); +} + +llvm::Value * +MicrosoftCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF, + llvm::Value *Base, + llvm::Value *MemPtr, + const MemberPointerType *MPT) { + unsigned AS = Base->getType()->getPointerAddressSpace(); + llvm::Type *PType = + CGF.ConvertTypeForMem(MPT->getPointeeType())->getPointerTo(AS); + CGBuilderTy &Builder = CGF.Builder; + + if (MPT->isMemberFunctionPointer()) { + ErrorUnsupportedABI(CGF, "function member pointer address"); + return llvm::Constant::getNullValue(PType); + } + + llvm::Value *Addr; + if (isSimpleMemberPointer(MPT)) { + // Add the offset with GEP and i8*. + assert(MemPtr->getType() == CGM.PtrDiffTy); + Base = Builder.CreateBitCast(Base, Builder.getInt8Ty()->getPointerTo(AS)); + Addr = Builder.CreateInBoundsGEP(Base, MemPtr, "memptr.offset"); + } else { + ErrorUnsupportedABI(CGF, "non-scalar member pointers"); + return llvm::Constant::getNullValue(PType); + } + + // Cast the address to the appropriate pointer type, adopting the address + // space of the base pointer. + return Builder.CreateBitCast(Addr, PType); } CGCXXABI *clang::CodeGen::CreateMicrosoftCXXABI(CodeGenModule &CGM) { |