diff options
-rw-r--r-- | lib/CodeGen/CGCXXABI.cpp | 18 | ||||
-rw-r--r-- | lib/CodeGen/CGCXXABI.h | 6 | ||||
-rw-r--r-- | lib/CodeGen/MicrosoftCXXABI.cpp | 116 | ||||
-rwxr-xr-x | test/CodeGenCXX/microsoft-abi-member-pointers.cpp | 51 |
4 files changed, 181 insertions, 10 deletions
diff --git a/lib/CodeGen/CGCXXABI.cpp b/lib/CodeGen/CGCXXABI.cpp index f9fea57ea6..0c0a76f346 100644 --- a/lib/CodeGen/CGCXXABI.cpp +++ b/lib/CodeGen/CGCXXABI.cpp @@ -19,8 +19,7 @@ using namespace CodeGen; CGCXXABI::~CGCXXABI() { } -static void ErrorUnsupportedABI(CodeGenFunction &CGF, - StringRef S) { +void CGCXXABI::ErrorUnsupportedABI(CodeGenFunction &CGF, StringRef S) { DiagnosticsEngine &Diags = CGF.CGM.getDiags(); unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, "cannot yet compile %0 in this ABI"); @@ -29,8 +28,7 @@ static void ErrorUnsupportedABI(CodeGenFunction &CGF, << S; } -static llvm::Constant *GetBogusMemberPointer(CodeGenModule &CGM, - QualType T) { +llvm::Constant *CGCXXABI::GetBogusMemberPointer(QualType T) { return llvm::Constant::getNullValue(CGM.getTypes().ConvertType(T)); } @@ -67,12 +65,12 @@ llvm::Value *CGCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF, const CastExpr *E, llvm::Value *Src) { ErrorUnsupportedABI(CGF, "member function pointer conversions"); - return GetBogusMemberPointer(CGM, E->getType()); + return GetBogusMemberPointer(E->getType()); } llvm::Constant *CGCXXABI::EmitMemberPointerConversion(const CastExpr *E, llvm::Constant *Src) { - return GetBogusMemberPointer(CGM, E->getType()); + return GetBogusMemberPointer(E->getType()); } llvm::Value * @@ -95,22 +93,22 @@ CGCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF, llvm::Constant * CGCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) { - return GetBogusMemberPointer(CGM, QualType(MPT, 0)); + return GetBogusMemberPointer(QualType(MPT, 0)); } llvm::Constant *CGCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) { - return GetBogusMemberPointer(CGM, + return GetBogusMemberPointer( CGM.getContext().getMemberPointerType(MD->getType(), MD->getParent()->getTypeForDecl())); } llvm::Constant *CGCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT, CharUnits offset) { - return GetBogusMemberPointer(CGM, QualType(MPT, 0)); + return GetBogusMemberPointer(QualType(MPT, 0)); } llvm::Constant *CGCXXABI::EmitMemberPointer(const APValue &MP, QualType MPT) { - return GetBogusMemberPointer(CGM, MPT); + return GetBogusMemberPointer(MPT); } bool CGCXXABI::isZeroInitializable(const MemberPointerType *MPT) { diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h index d0384ecc12..702e59b71a 100644 --- a/lib/CodeGen/CGCXXABI.h +++ b/lib/CodeGen/CGCXXABI.h @@ -54,6 +54,12 @@ protected: return CGF.CXXABIThisValue; } + /// Issue a diagnostic about unsupported features in the ABI. + void ErrorUnsupportedABI(CodeGenFunction &CGF, StringRef S); + + /// Get a null value for unsupported member pointers. + llvm::Constant *GetBogusMemberPointer(QualType T); + // FIXME: Every place that calls getVTT{Decl,Value} is something // that needs to be abstracted properly. ImplicitParamDecl *&getVTTDecl(CodeGenFunction &CGF) { diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index 85d926023f..00b15c9a49 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -109,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); + }; } @@ -352,6 +379,95 @@ void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, CGF.EmitCXXGlobalVarDeclInit(D, DeclPtr, PerformInit); } +// 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) { return new MicrosoftCXXABI(CGM); } diff --git a/test/CodeGenCXX/microsoft-abi-member-pointers.cpp b/test/CodeGenCXX/microsoft-abi-member-pointers.cpp new file mode 100755 index 0000000000..997e007086 --- /dev/null +++ b/test/CodeGenCXX/microsoft-abi-member-pointers.cpp @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s + +struct POD { + int a; + int b; +}; + +void podMemPtrs() { + int POD::*memptr; + memptr = &POD::a; + memptr = &POD::b; + if (memptr) + memptr = 0; +// Check that member pointers use the right offsets and that null is -1. +// CHECK: define void @"\01?podMemPtrs@@YAXXZ"() #0 { +// CHECK: %[[memptr:.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 0, i32* %[[memptr]], align 4 +// CHECK-NEXT: store i32 4, i32* %[[memptr]], align 4 +// CHECK-NEXT: %[[memptr_val:.*]] = load i32* %[[memptr]], align 4 +// CHECK-NEXT: %{{.*}} = icmp ne i32 %[[memptr_val]], -1 +// CHECK-NEXT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}} +// CHECK: store i32 -1, i32* %[[memptr]], align 4 +// CHECK: ret void +// CHECK: } +} + +struct Polymorphic { + virtual void myVirtual(); + int a; + int b; +}; + +void polymorphicMemPtrs() { + int Polymorphic::*memptr; + memptr = &Polymorphic::a; + memptr = &Polymorphic::b; + if (memptr) + memptr = 0; +// Member pointers for polymorphic classes include the vtable slot in their +// offset and use 0 to represent null. +// CHECK: define void @"\01?polymorphicMemPtrs@@YAXXZ"() #0 { +// CHECK: %[[memptr:.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 4, i32* %[[memptr]], align 4 +// CHECK-NEXT: store i32 8, i32* %[[memptr]], align 4 +// CHECK-NEXT: %[[memptr_val:.*]] = load i32* %[[memptr]], align 4 +// CHECK-NEXT: %{{.*}} = icmp ne i32 %[[memptr_val]], 0 +// CHECK-NEXT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}} +// CHECK: store i32 0, i32* %[[memptr]], align 4 +// CHECK: ret void +// CHECK: } +} |