summaryrefslogtreecommitdiffstats
path: root/lib/CodeGen/MicrosoftCXXABI.cpp
diff options
context:
space:
mode:
authordim <dim@FreeBSD.org>2013-06-10 20:45:12 +0000
committerdim <dim@FreeBSD.org>2013-06-10 20:45:12 +0000
commitea266cad53e3d49771fa38103913d3ec7a166694 (patch)
tree8f7776b7310bebaf415ac5b69e46e9f928c37144 /lib/CodeGen/MicrosoftCXXABI.cpp
parentc72c57c9e9b69944e3e009cd5e209634839581d3 (diff)
downloadFreeBSD-src-ea266cad53e3d49771fa38103913d3ec7a166694.zip
FreeBSD-src-ea266cad53e3d49771fa38103913d3ec7a166694.tar.gz
Vendor import of clang tags/RELEASE_33/final r183502 (effectively, 3.3
release): http://llvm.org/svn/llvm-project/cfe/tags/RELEASE_33/final@183502
Diffstat (limited to 'lib/CodeGen/MicrosoftCXXABI.cpp')
-rw-r--r--lib/CodeGen/MicrosoftCXXABI.cpp488
1 files changed, 436 insertions, 52 deletions
diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp
index 00b15c9..f5242ea 100644
--- a/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -28,6 +28,17 @@ class MicrosoftCXXABI : public CGCXXABI {
public:
MicrosoftCXXABI(CodeGenModule &CGM) : CGCXXABI(CGM) {}
+ bool isReturnTypeIndirect(const CXXRecordDecl *RD) const {
+ // Structures that are not C++03 PODs are always indirect.
+ return !RD->isPOD();
+ }
+
+ RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const {
+ if (RD->hasNonTrivialCopyConstructor())
+ return RAA_DirectInMemory;
+ return RAA_Default;
+ }
+
StringRef GetPureVirtualCallName() { return "_purecall"; }
// No known support for deleted functions in MSVC yet, so this choice is
// arbitrary.
@@ -111,21 +122,46 @@ public:
static bool needThisReturn(GlobalDecl GD);
private:
- llvm::Constant *getSimpleNullMemberPointer(const MemberPointerType *MPT);
-
- llvm::Constant *getZeroPtrDiff() {
- return llvm::ConstantInt::get(CGM.PtrDiffTy, 0);
+ llvm::Constant *getZeroInt() {
+ return llvm::ConstantInt::get(CGM.IntTy, 0);
}
- llvm::Constant *getAllOnesPtrDiff() {
- return llvm::Constant::getAllOnesValue(CGM.PtrDiffTy);
+ llvm::Constant *getAllOnesInt() {
+ return llvm::Constant::getAllOnesValue(CGM.IntTy);
}
+ void
+ GetNullMemberPointerFields(const MemberPointerType *MPT,
+ llvm::SmallVectorImpl<llvm::Constant *> &fields);
+
+ llvm::Value *AdjustVirtualBase(CodeGenFunction &CGF, const CXXRecordDecl *RD,
+ llvm::Value *Base,
+ 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);
+
+ virtual bool isZeroInitializable(const MemberPointerType *MPT);
+
virtual llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT);
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,
+ llvm::Value *R,
+ const MemberPointerType *MPT,
+ bool Inequality);
virtual llvm::Value *EmitMemberPointerIsNotNull(CodeGenFunction &CGF,
llvm::Value *MemPtr,
@@ -136,6 +172,12 @@ public:
llvm::Value *MemPtr,
const MemberPointerType *MPT);
+ virtual llvm::Value *
+ EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
+ llvm::Value *&This,
+ llvm::Value *MemPtr,
+ const MemberPointerType *MPT);
+
};
}
@@ -375,49 +417,259 @@ void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
// Not sure whether we want thread-safe static local variables as VS
// doesn't make them thread-safe.
+ if (D.getTLSKind())
+ CGM.ErrorUnsupported(&D, "dynamic TLS initialization");
+
// Emit the initializer and add a global destructor if appropriate.
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) {
+// Member pointer helpers.
+static bool hasVBPtrOffsetField(MSInheritanceModel Inheritance) {
+ return Inheritance == MSIM_Unspecified;
+}
+
+static bool hasOnlyOneField(MSInheritanceModel Inheritance) {
+ return Inheritance <= MSIM_SinglePolymorphic;
+}
+
+// Only member pointers to functions need a this adjustment, since it can be
+// combined with the field offset for data pointers.
+static bool hasNonVirtualBaseAdjustmentField(bool IsMemberFunction,
+ MSInheritanceModel Inheritance) {
+ return (IsMemberFunction && Inheritance >= MSIM_Multiple);
+}
+
+static bool hasVirtualBaseAdjustmentField(MSInheritanceModel Inheritance) {
+ return Inheritance >= MSIM_Virtual;
+}
+
+// Use zero for the field offset of a null data member pointer if we can
+// guarantee that zero is not a valid field offset, or if the member pointer has
+// multiple fields. Polymorphic classes have a vfptr at offset zero, so we can
+// use zero for null. If there are multiple fields, we can use zero even if it
+// is a valid field offset because null-ness testing will check the other
+// fields.
+static bool nullFieldOffsetIsZero(MSInheritanceModel Inheritance) {
+ return Inheritance != MSIM_Multiple && Inheritance != MSIM_Single;
+}
+
+bool MicrosoftCXXABI::isZeroInitializable(const MemberPointerType *MPT) {
+ // Null-ness for function memptrs only depends on the first field, which is
+ // the function pointer. The rest don't matter, so we can zero initialize.
+ if (MPT->isMemberFunctionPointer())
+ return true;
+
+ // The virtual base adjustment field is always -1 for null, so if we have one
+ // we can't zero initialize. The field offset is sometimes also -1 if 0 is a
+ // valid field offset.
const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
- return (MPT->isMemberDataPointer() &&
- !MPT->getClass()->isIncompleteType() &&
- RD->getNumVBases() == 0);
+ MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
+ return (!hasVirtualBaseAdjustmentField(Inheritance) &&
+ nullFieldOffsetIsZero(Inheritance));
}
-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();
+llvm::Type *
+MicrosoftCXXABI::ConvertMemberPointerType(const MemberPointerType *MPT) {
+ const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
+ MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
+ llvm::SmallVector<llvm::Type *, 4> fields;
+ if (MPT->isMemberFunctionPointer())
+ fields.push_back(CGM.VoidPtrTy); // FunctionPointerOrVirtualThunk
+ else
+ fields.push_back(CGM.IntTy); // FieldOffset
+
+ if (hasNonVirtualBaseAdjustmentField(MPT->isMemberFunctionPointer(),
+ Inheritance))
+ fields.push_back(CGM.IntTy);
+ if (hasVBPtrOffsetField(Inheritance))
+ fields.push_back(CGM.IntTy);
+ if (hasVirtualBaseAdjustmentField(Inheritance))
+ fields.push_back(CGM.IntTy); // VirtualBaseAdjustmentOffset
+
+ if (fields.size() == 1)
+ return fields[0];
+ return llvm::StructType::get(CGM.getLLVMContext(), fields);
+}
+
+void MicrosoftCXXABI::
+GetNullMemberPointerFields(const MemberPointerType *MPT,
+ llvm::SmallVectorImpl<llvm::Constant *> &fields) {
+ assert(fields.empty());
+ const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
+ MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
+ if (MPT->isMemberFunctionPointer()) {
+ // FunctionPointerOrVirtualThunk
+ fields.push_back(llvm::Constant::getNullValue(CGM.VoidPtrTy));
+ } else {
+ if (nullFieldOffsetIsZero(Inheritance))
+ fields.push_back(getZeroInt()); // FieldOffset
+ else
+ fields.push_back(getAllOnesInt()); // FieldOffset
}
- return GetBogusMemberPointer(QualType(MPT, 0));
+
+ if (hasNonVirtualBaseAdjustmentField(MPT->isMemberFunctionPointer(),
+ Inheritance))
+ fields.push_back(getZeroInt());
+ if (hasVBPtrOffsetField(Inheritance))
+ fields.push_back(getZeroInt());
+ if (hasVirtualBaseAdjustmentField(Inheritance))
+ fields.push_back(getAllOnesInt());
}
llvm::Constant *
MicrosoftCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) {
- if (isSimpleMemberPointer(MPT))
- return getSimpleNullMemberPointer(MPT);
- // FIXME: Implement function member pointers.
- return GetBogusMemberPointer(QualType(MPT, 0));
+ llvm::SmallVector<llvm::Constant *, 4> fields;
+ GetNullMemberPointerFields(MPT, fields);
+ if (fields.size() == 1)
+ return fields[0];
+ llvm::Constant *Res = llvm::ConstantStruct::getAnon(fields);
+ assert(Res->getType() == ConvertMemberPointerType(MPT));
+ return Res;
+}
+
+llvm::Constant *
+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<llvm::Constant *, 4> fields;
+ 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));
+ }
+
+ // The rest of the fields are adjusted by conversions to a more derived class.
+ if (hasVirtualBaseAdjustmentField(Inheritance))
+ fields.push_back(getZeroInt());
+
+ return llvm::ConstantStruct::getAnon(fields);
}
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));
+ 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<FunctionProtoType>();
+ 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<MemberPointerType>()->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.
+llvm::Value *
+MicrosoftCXXABI::EmitMemberPointerComparison(CodeGenFunction &CGF,
+ llvm::Value *L,
+ llvm::Value *R,
+ const MemberPointerType *MPT,
+ bool Inequality) {
+ CGBuilderTy &Builder = CGF.Builder;
+
+ // Handle != comparisons by switching the sense of all boolean operations.
+ llvm::ICmpInst::Predicate Eq;
+ llvm::Instruction::BinaryOps And, Or;
+ if (Inequality) {
+ Eq = llvm::ICmpInst::ICMP_NE;
+ And = llvm::Instruction::Or;
+ Or = llvm::Instruction::And;
+ } else {
+ Eq = llvm::ICmpInst::ICMP_EQ;
+ And = llvm::Instruction::And;
+ Or = llvm::Instruction::Or;
+ }
+
+ // If this is a single field member pointer (single inheritance), this is a
+ // single icmp.
+ const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
+ MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
+ if (hasOnlyOneField(Inheritance))
+ return Builder.CreateICmp(Eq, L, R);
+
+ // Compare the first field.
+ llvm::Value *L0 = Builder.CreateExtractValue(L, 0, "lhs.0");
+ llvm::Value *R0 = Builder.CreateExtractValue(R, 0, "rhs.0");
+ llvm::Value *Cmp0 = Builder.CreateICmp(Eq, L0, R0, "memptr.cmp.first");
+
+ // Compare everything other than the first field.
+ llvm::Value *Res = 0;
+ llvm::StructType *LType = cast<llvm::StructType>(L->getType());
+ for (unsigned I = 1, E = LType->getNumElements(); I != E; ++I) {
+ llvm::Value *LF = Builder.CreateExtractValue(L, I);
+ llvm::Value *RF = Builder.CreateExtractValue(R, I);
+ llvm::Value *Cmp = Builder.CreateICmp(Eq, LF, RF, "memptr.cmp.rest");
+ if (Res)
+ Res = Builder.CreateBinOp(And, Res, Cmp);
+ else
+ Res = Cmp;
+ }
+
+ // Check if the first field is 0 if this is a function pointer.
+ if (MPT->isMemberFunctionPointer()) {
+ // (l1 == r1 && ...) || l0 == 0
+ llvm::Value *Zero = llvm::Constant::getNullValue(L0->getType());
+ llvm::Value *IsZero = Builder.CreateICmp(Eq, L0, Zero, "memptr.cmp.iszero");
+ Res = Builder.CreateBinOp(Or, Res, IsZero);
+ }
+
+ // Combine the comparison of the first field, which must always be true for
+ // this comparison to succeeed.
+ return Builder.CreateBinOp(And, Res, Cmp0, "memptr.cmp");
}
llvm::Value *
@@ -425,16 +677,90 @@ MicrosoftCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF,
llvm::Value *MemPtr,
const MemberPointerType *MPT) {
CGBuilderTy &Builder = CGF.Builder;
+ llvm::SmallVector<llvm::Constant *, 4> fields;
+ // We only need one field for member functions.
+ if (MPT->isMemberFunctionPointer())
+ fields.push_back(llvm::Constant::getNullValue(CGM.VoidPtrTy));
+ else
+ GetNullMemberPointerFields(MPT, fields);
+ assert(!fields.empty());
+ llvm::Value *FirstField = MemPtr;
+ if (MemPtr->getType()->isStructTy())
+ FirstField = Builder.CreateExtractValue(MemPtr, 0);
+ llvm::Value *Res = Builder.CreateICmpNE(FirstField, fields[0], "memptr.cmp0");
+
+ // For function member pointers, we only need to test the function pointer
+ // field. The other fields if any can be garbage.
+ if (MPT->isMemberFunctionPointer())
+ return Res;
+
+ // Otherwise, emit a series of compares and combine the results.
+ for (int I = 1, E = fields.size(); I < E; ++I) {
+ llvm::Value *Field = Builder.CreateExtractValue(MemPtr, I);
+ llvm::Value *Next = Builder.CreateICmpNE(Field, fields[I], "memptr.cmp");
+ Res = Builder.CreateAnd(Res, Next, "memptr.tobool");
+ }
+ return Res;
+}
- // 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");
+// Returns an adjusted base cast to i8*, since we do more address arithmetic on
+// it.
+llvm::Value *
+MicrosoftCXXABI::AdjustVirtualBase(CodeGenFunction &CGF,
+ const CXXRecordDecl *RD, llvm::Value *Base,
+ llvm::Value *VirtualBaseAdjustmentOffset,
+ llvm::Value *VBPtrOffset) {
+ CGBuilderTy &Builder = CGF.Builder;
+ Base = Builder.CreateBitCast(Base, CGM.Int8PtrTy);
+ llvm::BasicBlock *OriginalBB = 0;
+ llvm::BasicBlock *SkipAdjustBB = 0;
+ llvm::BasicBlock *VBaseAdjustBB = 0;
+
+ // In the unspecified inheritance model, there might not be a vbtable at all,
+ // in which case we need to skip the virtual base lookup. If there is a
+ // vbtable, the first entry is a no-op entry that gives back the original
+ // base, so look for a virtual base adjustment offset of zero.
+ if (VBPtrOffset) {
+ OriginalBB = Builder.GetInsertBlock();
+ VBaseAdjustBB = CGF.createBasicBlock("memptr.vadjust");
+ SkipAdjustBB = CGF.createBasicBlock("memptr.skip_vadjust");
+ llvm::Value *IsVirtual =
+ Builder.CreateICmpNE(VirtualBaseAdjustmentOffset, getZeroInt(),
+ "memptr.is_vbase");
+ Builder.CreateCondBr(IsVirtual, VBaseAdjustBB, SkipAdjustBB);
+ CGF.EmitBlock(VBaseAdjustBB);
}
- // FIXME: Implement member pointers other inheritance models.
- ErrorUnsupportedABI(CGF, "function member pointer tests");
- return GetBogusMemberPointer(QualType(MPT, 0));
+ // If we weren't given a dynamic vbptr offset, RD should be complete and we'll
+ // know the vbptr offset.
+ if (!VBPtrOffset) {
+ CharUnits offs = getContext().getASTRecordLayout(RD).getVBPtrOffset();
+ VBPtrOffset = llvm::ConstantInt::get(CGM.IntTy, offs.getQuantity());
+ }
+ // Load the vbtable pointer from the vbtable offset in the instance.
+ llvm::Value *VBPtr =
+ Builder.CreateInBoundsGEP(Base, VBPtrOffset, "memptr.vbptr");
+ llvm::Value *VBTable =
+ Builder.CreateBitCast(VBPtr, CGM.Int8PtrTy->getPointerTo(0));
+ VBTable = Builder.CreateLoad(VBTable, "memptr.vbtable");
+ // Load an i32 offset from the vb-table.
+ llvm::Value *VBaseOffs =
+ Builder.CreateInBoundsGEP(VBTable, VirtualBaseAdjustmentOffset);
+ VBaseOffs = Builder.CreateBitCast(VBaseOffs, CGM.Int32Ty->getPointerTo(0));
+ VBaseOffs = Builder.CreateLoad(VBaseOffs, "memptr.vbase_offs");
+ // Add it to VBPtr. GEP will sign extend the i32 value for us.
+ llvm::Value *AdjustedBase = Builder.CreateInBoundsGEP(VBPtr, VBaseOffs);
+
+ // Merge control flow with the case where we didn't have to adjust.
+ if (VBaseAdjustBB) {
+ Builder.CreateBr(SkipAdjustBB);
+ CGF.EmitBlock(SkipAdjustBB);
+ llvm::PHINode *Phi = Builder.CreatePHI(CGM.Int8PtrTy, 2, "memptr.base");
+ Phi->addIncoming(Base, OriginalBB);
+ Phi->addIncoming(AdjustedBase, VBaseAdjustBB);
+ return Phi;
+ }
+ return AdjustedBase;
}
llvm::Value *
@@ -442,32 +768,90 @@ MicrosoftCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF,
llvm::Value *Base,
llvm::Value *MemPtr,
const MemberPointerType *MPT) {
+ assert(MPT->isMemberDataPointer());
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);
+ const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
+ MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
+
+ // Extract the fields we need, regardless of model. We'll apply them if we
+ // have them.
+ llvm::Value *FieldOffset = MemPtr;
+ llvm::Value *VirtualBaseAdjustmentOffset = 0;
+ llvm::Value *VBPtrOffset = 0;
+ if (MemPtr->getType()->isStructTy()) {
+ // We need to extract values.
+ unsigned I = 0;
+ FieldOffset = Builder.CreateExtractValue(MemPtr, I++);
+ if (hasVBPtrOffsetField(Inheritance))
+ VBPtrOffset = Builder.CreateExtractValue(MemPtr, I++);
+ if (hasVirtualBaseAdjustmentField(Inheritance))
+ VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(MemPtr, I++);
}
- 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);
+ if (VirtualBaseAdjustmentOffset) {
+ Base = AdjustVirtualBase(CGF, RD, Base, VirtualBaseAdjustmentOffset,
+ VBPtrOffset);
}
+ llvm::Value *Addr =
+ Builder.CreateInBoundsGEP(Base, FieldOffset, "memptr.offset");
// Cast the address to the appropriate pointer type, adopting the address
// space of the base pointer.
return Builder.CreateBitCast(Addr, PType);
}
+llvm::Value *
+MicrosoftCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
+ llvm::Value *&This,
+ llvm::Value *MemPtr,
+ const MemberPointerType *MPT) {
+ assert(MPT->isMemberFunctionPointer());
+ const FunctionProtoType *FPT =
+ MPT->getPointeeType()->castAs<FunctionProtoType>();
+ const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
+ llvm::FunctionType *FTy =
+ CGM.getTypes().GetFunctionType(
+ CGM.getTypes().arrangeCXXMethodType(RD, FPT));
+ CGBuilderTy &Builder = CGF.Builder;
+
+ MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
+
+ // Extract the fields we need, regardless of model. We'll apply them if we
+ // have them.
+ llvm::Value *FunctionPointer = MemPtr;
+ llvm::Value *NonVirtualBaseAdjustment = NULL;
+ llvm::Value *VirtualBaseAdjustmentOffset = NULL;
+ llvm::Value *VBPtrOffset = NULL;
+ if (MemPtr->getType()->isStructTy()) {
+ // We need to extract values.
+ unsigned I = 0;
+ FunctionPointer = 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++);
+ }
+
+ if (VirtualBaseAdjustmentOffset) {
+ This = AdjustVirtualBase(CGF, RD, This, VirtualBaseAdjustmentOffset,
+ VBPtrOffset);
+ }
+
+ if (NonVirtualBaseAdjustment) {
+ // Apply the adjustment and cast back to the original struct type.
+ llvm::Value *Ptr = Builder.CreateBitCast(This, Builder.getInt8PtrTy());
+ Ptr = Builder.CreateInBoundsGEP(Ptr, NonVirtualBaseAdjustment);
+ This = Builder.CreateBitCast(Ptr, This->getType(), "this.adjusted");
+ }
+
+ return Builder.CreateBitCast(FunctionPointer, FTy->getPointerTo());
+}
+
CGCXXABI *clang::CodeGen::CreateMicrosoftCXXABI(CodeGenModule &CGM) {
return new MicrosoftCXXABI(CGM);
}
OpenPOWER on IntegriCloud