summaryrefslogtreecommitdiff
path: root/lib/CodeGen/MicrosoftCXXABI.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2013-04-08 18:45:10 +0000
committerDimitry Andric <dim@FreeBSD.org>2013-04-08 18:45:10 +0000
commit809500fc2c13c8173a16b052304d983864e4a1e1 (patch)
tree4fc2f184c499d106f29a386c452b49e5197bf63d /lib/CodeGen/MicrosoftCXXABI.cpp
parentbe7c9ec198dcdb5bf73a35bfbb00b3333cb87909 (diff)
downloadsrc-test2-809500fc2c13c8173a16b052304d983864e4a1e1.tar.gz
src-test2-809500fc2c13c8173a16b052304d983864e4a1e1.zip
Notes
Diffstat (limited to 'lib/CodeGen/MicrosoftCXXABI.cpp')
-rw-r--r--lib/CodeGen/MicrosoftCXXABI.cpp278
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) {