From 79e0291be71adb4c38431e27a683faa40bbedc61 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Fri, 3 May 2013 01:15:11 +0000 Subject: [PATCH] [ms-cxxabi] Emit non-virtual member function pointers Without any conversion, this is pretty straightforward. Most of the fields can be zeros. The order is: - field offset or pointer - nonvirtual adjustment (for MI functions) - vbptr offset (for unspecified) - virtual adjustment offset (for virtual inheritance) Differential Revision: http://llvm-reviews.chandlerc.com/D699 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@180985 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/MicrosoftCXXABI.cpp | 105 +++++++++++++++--- .../microsoft-abi-member-pointers.cpp | 59 +++++++++- 2 files changed, 142 insertions(+), 22 deletions(-) diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index d22a5e9072..f5242eaaa2 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -139,6 +139,12 @@ private: llvm::Value *VirtualBaseAdjustmentOffset, llvm::Value *VBPtrOffset /* optional */); + /// \brief Emits a full member pointer with the fields common to data and + /// function member pointers. + llvm::Constant *EmitFullMemberPointer(llvm::Constant *FirstField, + bool IsMemberFunction, + const CXXRecordDecl *RD); + public: virtual llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT); @@ -148,6 +154,8 @@ public: virtual llvm::Constant *EmitMemberDataPointer(const MemberPointerType *MPT, CharUnits offset); + virtual llvm::Constant *EmitMemberPointer(const CXXMethodDecl *MD); + virtual llvm::Constant *EmitMemberPointer(const APValue &MP, QualType MPT); virtual llvm::Value *EmitMemberPointerComparison(CodeGenFunction &CGF, llvm::Value *L, @@ -427,10 +435,9 @@ static bool hasOnlyOneField(MSInheritanceModel Inheritance) { // Only member pointers to functions need a this adjustment, since it can be // combined with the field offset for data pointers. -static bool hasNonVirtualBaseAdjustmentField(const MemberPointerType *MPT, +static bool hasNonVirtualBaseAdjustmentField(bool IsMemberFunction, MSInheritanceModel Inheritance) { - return (MPT->isMemberFunctionPointer() && - Inheritance >= MSIM_Multiple); + return (IsMemberFunction && Inheritance >= MSIM_Multiple); } static bool hasVirtualBaseAdjustmentField(MSInheritanceModel Inheritance) { @@ -472,9 +479,10 @@ MicrosoftCXXABI::ConvertMemberPointerType(const MemberPointerType *MPT) { else fields.push_back(CGM.IntTy); // FieldOffset - if (hasVBPtrOffsetField(Inheritance)) + if (hasNonVirtualBaseAdjustmentField(MPT->isMemberFunctionPointer(), + Inheritance)) fields.push_back(CGM.IntTy); - if (hasNonVirtualBaseAdjustmentField(MPT, Inheritance)) + if (hasVBPtrOffsetField(Inheritance)) fields.push_back(CGM.IntTy); if (hasVirtualBaseAdjustmentField(Inheritance)) fields.push_back(CGM.IntTy); // VirtualBaseAdjustmentOffset @@ -500,9 +508,10 @@ GetNullMemberPointerFields(const MemberPointerType *MPT, fields.push_back(getAllOnesInt()); // FieldOffset } - if (hasVBPtrOffsetField(Inheritance)) + if (hasNonVirtualBaseAdjustmentField(MPT->isMemberFunctionPointer(), + Inheritance)) fields.push_back(getZeroInt()); - if (hasNonVirtualBaseAdjustmentField(MPT, Inheritance)) + if (hasVBPtrOffsetField(Inheritance)) fields.push_back(getZeroInt()); if (hasVirtualBaseAdjustmentField(Inheritance)) fields.push_back(getAllOnesInt()); @@ -520,27 +529,87 @@ MicrosoftCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) { } llvm::Constant * -MicrosoftCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT, - CharUnits offset) { - const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl(); +MicrosoftCXXABI::EmitFullMemberPointer(llvm::Constant *FirstField, + bool IsMemberFunction, + const CXXRecordDecl *RD) +{ MSInheritanceModel Inheritance = RD->getMSInheritanceModel(); + + // Single inheritance class member pointer are represented as scalars instead + // of aggregates. + if (hasOnlyOneField(Inheritance)) + return FirstField; + llvm::SmallVector fields; - fields.push_back(llvm::ConstantInt::get(CGM.IntTy, offset.getQuantity())); + fields.push_back(FirstField); + + if (hasNonVirtualBaseAdjustmentField(IsMemberFunction, Inheritance)) + fields.push_back(getZeroInt()); + if (hasVBPtrOffsetField(Inheritance)) { int64_t VBPtrOffset = getContext().getASTRecordLayout(RD).getVBPtrOffset().getQuantity(); + if (VBPtrOffset == -1) + VBPtrOffset = 0; fields.push_back(llvm::ConstantInt::get(CGM.IntTy, VBPtrOffset)); } - assert(!hasNonVirtualBaseAdjustmentField(MPT, Inheritance)); - // The virtual base field starts out zero. It is adjusted by conversions to - // member pointer types of a more derived class. See http://llvm.org/PR15713 + + // The rest of the fields are adjusted by conversions to a more derived class. if (hasVirtualBaseAdjustmentField(Inheritance)) fields.push_back(getZeroInt()); - if (fields.size() == 1) - return fields[0]; + return llvm::ConstantStruct::getAnon(fields); } +llvm::Constant * +MicrosoftCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT, + CharUnits offset) { + const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl(); + llvm::Constant *FirstField = + llvm::ConstantInt::get(CGM.IntTy, offset.getQuantity()); + return EmitFullMemberPointer(FirstField, /*IsMemberFunction=*/false, RD); +} + +llvm::Constant * +MicrosoftCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) { + assert(MD->isInstance() && "Member function must not be static!"); + MD = MD->getCanonicalDecl(); + const CXXRecordDecl *RD = MD->getParent(); + CodeGenTypes &Types = CGM.getTypes(); + + llvm::Constant *FirstField; + if (MD->isVirtual()) { + // FIXME: We have to instantiate a thunk that loads the vftable and jumps to + // the right offset. + FirstField = llvm::Constant::getNullValue(CGM.VoidPtrTy); + } else { + const FunctionProtoType *FPT = MD->getType()->castAs(); + llvm::Type *Ty; + // Check whether the function has a computable LLVM signature. + if (Types.isFuncTypeConvertible(FPT)) { + // The function has a computable LLVM signature; use the correct type. + Ty = Types.GetFunctionType(Types.arrangeCXXMethodDeclaration(MD)); + } else { + // Use an arbitrary non-function type to tell GetAddrOfFunction that the + // function type is incomplete. + Ty = CGM.PtrDiffTy; + } + FirstField = CGM.GetAddrOfFunction(MD, Ty); + FirstField = llvm::ConstantExpr::getBitCast(FirstField, CGM.VoidPtrTy); + } + + // The rest of the fields are common with data member pointers. + return EmitFullMemberPointer(FirstField, /*IsMemberFunction=*/true, RD); +} + +llvm::Constant * +MicrosoftCXXABI::EmitMemberPointer(const APValue &MP, QualType MPT) { + // FIXME PR15875: Implement member pointer conversions for Constants. + const CXXRecordDecl *RD = MPT->castAs()->getClass()->getAsCXXRecordDecl(); + return EmitFullMemberPointer(llvm::Constant::getNullValue(CGM.VoidPtrTy), + /*IsMemberFunction=*/true, RD); +} + /// Member pointers are the same if they're either bitwise identical *or* both /// null. Null-ness for function members is determined by the first field, /// while for data member pointers we must compare all fields. @@ -760,10 +829,10 @@ MicrosoftCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, // We need to extract values. unsigned I = 0; FunctionPointer = Builder.CreateExtractValue(MemPtr, I++); - if (hasVBPtrOffsetField(Inheritance)) - VBPtrOffset = Builder.CreateExtractValue(MemPtr, I++); if (hasNonVirtualBaseAdjustmentField(MPT, Inheritance)) NonVirtualBaseAdjustment = Builder.CreateExtractValue(MemPtr, I++); + if (hasVBPtrOffsetField(Inheritance)) + VBPtrOffset = Builder.CreateExtractValue(MemPtr, I++); if (hasVirtualBaseAdjustmentField(Inheritance)) VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(MemPtr, I++); } diff --git a/test/CodeGenCXX/microsoft-abi-member-pointers.cpp b/test/CodeGenCXX/microsoft-abi-member-pointers.cpp index 292f9d2c69..3fffc9d72c 100644 --- a/test/CodeGenCXX/microsoft-abi-member-pointers.cpp +++ b/test/CodeGenCXX/microsoft-abi-member-pointers.cpp @@ -1,13 +1,21 @@ // RUN: %clang_cc1 -fno-rtti -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s struct B1 { + void foo(); int b; }; -struct B2 { }; -struct Single : B1 { }; -struct Multiple : B1, B2 { }; +struct B2 { + void foo(); +}; +struct Single : B1 { + void foo(); +}; +struct Multiple : B1, B2 { + void foo(); +}; struct Virtual : virtual B1 { int v; + void foo(); }; struct POD { @@ -30,7 +38,7 @@ struct NonZeroVBPtr : POD, Virtual { struct Unspecified; -// Check that we can lower the LLVM types and get the initializers right. +// Check that we can lower the LLVM types and get the null initializers right. int Single ::*s_d_memptr; int Polymorphic::*p_d_memptr; int Multiple ::*m_d_memptr; @@ -54,6 +62,49 @@ void (Virtual ::*v_f_memptr)(); // CHECK: @"\01?m_f_memptr@@3P8Multiple@@AEXXZA" = global { i8*, i32 } zeroinitializer, align 4 // CHECK: @"\01?v_f_memptr@@3P8Virtual@@AEXXZA" = global { i8*, i32, i32 } zeroinitializer, align 4 +// We can define Unspecified after locking in the inheritance model. +struct Unspecified : Virtual { + void foo(); + int u; +}; + +struct UnspecWithVBPtr; +int UnspecWithVBPtr::*forceUnspecWithVBPtr; +struct UnspecWithVBPtr : B1, virtual B2 { + int u; + void foo(); +}; + +// Test emitting non-virtual member pointers in a non-constexpr setting. +void EmitNonVirtualMemberPointers() { + void (Single ::*s_f_memptr)() = &Single::foo; + void (Multiple ::*m_f_memptr)() = &Multiple::foo; + void (Virtual ::*v_f_memptr)() = &Virtual::foo; + void (Unspecified::*u_f_memptr)() = &Unspecified::foo; + void (UnspecWithVBPtr::*u2_f_memptr)() = &UnspecWithVBPtr::foo; +// CHECK: define void @"\01?EmitNonVirtualMemberPointers@@YAXXZ"() #0 { +// CHECK: alloca i8*, align 4 +// CHECK: alloca { i8*, i32 }, align 4 +// CHECK: alloca { i8*, i32, i32 }, align 4 +// CHECK: alloca { i8*, i32, i32, i32 }, align 4 +// CHECK: store i8* bitcast (void (%{{.*}}*)* @"\01?foo@Single@@QAEXXZ" to i8*), i8** %{{.*}}, align 4 +// CHECK: store { i8*, i32 } +// CHECK: { i8* bitcast (void (%{{.*}}*)* @"\01?foo@Multiple@@QAEXXZ" to i8*), i32 0 }, +// CHECK: { i8*, i32 }* %{{.*}}, align 4 +// CHECK: store { i8*, i32, i32 } +// CHECK: { i8* bitcast (void (%{{.*}}*)* @"\01?foo@Virtual@@QAEXXZ" to i8*), i32 0, i32 0 }, +// CHECK: { i8*, i32, i32 }* %{{.*}}, align 4 +// CHECK: store { i8*, i32, i32, i32 } +// CHECK: { i8* bitcast (void (%{{.*}}*)* @"\01?foo@Unspecified@@QAEXXZ" to i8*), i32 0, i32 0, i32 0 }, +// CHECK: { i8*, i32, i32, i32 }* %{{.*}}, align 4 +// CHECK: store { i8*, i32, i32, i32 } +// CHECK: { i8* bitcast (void (%{{.*}}*)* @"\01?foo@UnspecWithVBPtr@@QAEXXZ" to i8*), +// CHECK: i32 0, i32 4, i32 0 }, +// CHECK: { i8*, i32, i32, i32 }* %{{.*}}, align 4 +// CHECK: ret void +// CHECK: } +} + void podMemPtrs() { int POD::*memptr; memptr = &POD::a; -- 2.40.0