summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen/MicrosoftCXXABI.cpp
diff options
context:
space:
mode:
authorReid Kleckner <reid@kleckner.net>2013-05-09 21:01:17 +0000
committerReid Kleckner <reid@kleckner.net>2013-05-09 21:01:17 +0000
commit452abac4b344742c94703c1165dc0f51caeff8e3 (patch)
tree018e2872760236d164959a5968bb51a8ac3fd499 /clang/lib/CodeGen/MicrosoftCXXABI.cpp
parentf03b2e8385b476546c2f5f54fe3685cd36605e6e (diff)
downloadbcm5719-llvm-452abac4b344742c94703c1165dc0f51caeff8e3.tar.gz
bcm5719-llvm-452abac4b344742c94703c1165dc0f51caeff8e3.zip
[ms-cxxabi] Implement member pointer conversions
Summary: This only supports converting along non-virtual inheritance paths by changing the field offset or the non-virtual base adjustment. This implements three kinds of conversions: - codegen for Value conversions - Constant emission for APValue - Constant folding for CastExprs In almost all constant initialization settings EmitMemberPointer(APValue) is called, except when the expression contains a reinterpret cast. reinterpret casts end up being a big corner case because the null value changes between different kinds of member pointers. Reviewers: rsmith CC: cfe-commits Differential Revision: http://llvm-reviews.chandlerc.com/D741 llvm-svn: 181543
Diffstat (limited to 'clang/lib/CodeGen/MicrosoftCXXABI.cpp')
-rw-r--r--clang/lib/CodeGen/MicrosoftCXXABI.cpp304
1 files changed, 285 insertions, 19 deletions
diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
index f5242eaaa2f..79af5af0363 100644
--- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -130,6 +130,14 @@ private:
return llvm::Constant::getAllOnesValue(CGM.IntTy);
}
+ llvm::Constant *getConstantOrZeroInt(llvm::Constant *C) {
+ return C ? C : getZeroInt();
+ }
+
+ llvm::Value *getValueOrZeroInt(llvm::Value *C) {
+ return C ? C : getZeroInt();
+ }
+
void
GetNullMemberPointerFields(const MemberPointerType *MPT,
llvm::SmallVectorImpl<llvm::Constant *> &fields);
@@ -143,7 +151,15 @@ private:
/// function member pointers.
llvm::Constant *EmitFullMemberPointer(llvm::Constant *FirstField,
bool IsMemberFunction,
- const CXXRecordDecl *RD);
+ const CXXRecordDecl *RD,
+ CharUnits NonVirtualBaseAdjustment);
+
+ llvm::Constant *BuildMemberPointer(const CXXRecordDecl *RD,
+ const CXXMethodDecl *MD,
+ CharUnits NonVirtualBaseAdjustment);
+
+ bool MemberPointerConstantIsNull(const MemberPointerType *MPT,
+ llvm::Constant *MP);
public:
virtual llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT);
@@ -172,6 +188,13 @@ public:
llvm::Value *MemPtr,
const MemberPointerType *MPT);
+ virtual llvm::Value *EmitMemberPointerConversion(CodeGenFunction &CGF,
+ const CastExpr *E,
+ llvm::Value *Src);
+
+ virtual llvm::Constant *EmitMemberPointerConversion(const CastExpr *E,
+ llvm::Constant *Src);
+
virtual llvm::Value *
EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
llvm::Value *&This,
@@ -429,8 +452,10 @@ static bool hasVBPtrOffsetField(MSInheritanceModel Inheritance) {
return Inheritance == MSIM_Unspecified;
}
-static bool hasOnlyOneField(MSInheritanceModel Inheritance) {
- return Inheritance <= MSIM_SinglePolymorphic;
+static bool hasOnlyOneField(bool IsMemberFunction,
+ MSInheritanceModel Inheritance) {
+ return Inheritance <= MSIM_SinglePolymorphic ||
+ (!IsMemberFunction && Inheritance <= MSIM_MultiplePolymorphic);
}
// Only member pointers to functions need a this adjustment, since it can be
@@ -531,22 +556,25 @@ MicrosoftCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) {
llvm::Constant *
MicrosoftCXXABI::EmitFullMemberPointer(llvm::Constant *FirstField,
bool IsMemberFunction,
- const CXXRecordDecl *RD)
+ const CXXRecordDecl *RD,
+ CharUnits NonVirtualBaseAdjustment)
{
MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
// Single inheritance class member pointer are represented as scalars instead
// of aggregates.
- if (hasOnlyOneField(Inheritance))
+ if (hasOnlyOneField(IsMemberFunction, Inheritance))
return FirstField;
llvm::SmallVector<llvm::Constant *, 4> fields;
fields.push_back(FirstField);
if (hasNonVirtualBaseAdjustmentField(IsMemberFunction, Inheritance))
- fields.push_back(getZeroInt());
+ fields.push_back(llvm::ConstantInt::get(
+ CGM.IntTy, NonVirtualBaseAdjustment.getQuantity()));
if (hasVBPtrOffsetField(Inheritance)) {
+ // FIXME: We actually need to search non-virtual bases for vbptrs.
int64_t VBPtrOffset =
getContext().getASTRecordLayout(RD).getVBPtrOffset().getQuantity();
if (VBPtrOffset == -1)
@@ -567,14 +595,40 @@ MicrosoftCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT,
const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
llvm::Constant *FirstField =
llvm::ConstantInt::get(CGM.IntTy, offset.getQuantity());
- return EmitFullMemberPointer(FirstField, /*IsMemberFunction=*/false, RD);
+ return EmitFullMemberPointer(FirstField, /*IsMemberFunction=*/false, RD,
+ CharUnits::Zero());
+}
+
+llvm::Constant *MicrosoftCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) {
+ return BuildMemberPointer(MD->getParent(), MD, CharUnits::Zero());
+}
+
+llvm::Constant *MicrosoftCXXABI::EmitMemberPointer(const APValue &MP,
+ QualType MPType) {
+ const MemberPointerType *MPT = MPType->castAs<MemberPointerType>();
+ const ValueDecl *MPD = MP.getMemberPointerDecl();
+ if (!MPD)
+ return EmitNullMemberPointer(MPT);
+
+ CharUnits ThisAdjustment = getMemberPointerPathAdjustment(MP);
+
+ // FIXME PR15713: Support virtual inheritance paths.
+
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MPD))
+ return BuildMemberPointer(MPT->getClass()->getAsCXXRecordDecl(),
+ MD, ThisAdjustment);
+
+ CharUnits FieldOffset =
+ getContext().toCharUnitsFromBits(getContext().getFieldOffset(MPD));
+ return EmitMemberDataPointer(MPT, ThisAdjustment + FieldOffset);
}
llvm::Constant *
-MicrosoftCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) {
+MicrosoftCXXABI::BuildMemberPointer(const CXXRecordDecl *RD,
+ const CXXMethodDecl *MD,
+ CharUnits NonVirtualBaseAdjustment) {
assert(MD->isInstance() && "Member function must not be static!");
MD = MD->getCanonicalDecl();
- const CXXRecordDecl *RD = MD->getParent();
CodeGenTypes &Types = CGM.getTypes();
llvm::Constant *FirstField;
@@ -599,15 +653,8 @@ MicrosoftCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) {
}
// 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);
+ return EmitFullMemberPointer(FirstField, /*IsMemberFunction=*/true, RD,
+ NonVirtualBaseAdjustment);
}
/// Member pointers are the same if they're either bitwise identical *or* both
@@ -638,7 +685,7 @@ MicrosoftCXXABI::EmitMemberPointerComparison(CodeGenFunction &CGF,
// single icmp.
const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
- if (hasOnlyOneField(Inheritance))
+ if (hasOnlyOneField(MPT->isMemberFunctionPointer(), Inheritance))
return Builder.CreateICmp(Eq, L, R);
// Compare the first field.
@@ -703,6 +750,37 @@ MicrosoftCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF,
return Res;
}
+bool MicrosoftCXXABI::MemberPointerConstantIsNull(const MemberPointerType *MPT,
+ llvm::Constant *Val) {
+ // Function pointers are null if the pointer in the first field is null.
+ if (MPT->isMemberFunctionPointer()) {
+ llvm::Constant *FirstField = Val->getType()->isStructTy() ?
+ Val->getAggregateElement(0U) : Val;
+ return FirstField->isNullValue();
+ }
+
+ // If it's not a function pointer and it's zero initializable, we can easily
+ // check zero.
+ if (isZeroInitializable(MPT) && Val->isNullValue())
+ return true;
+
+ // Otherwise, break down all the fields for comparison. Hopefully these
+ // little Constants are reused, while a big null struct might not be.
+ llvm::SmallVector<llvm::Constant *, 4> Fields;
+ GetNullMemberPointerFields(MPT, Fields);
+ if (Fields.size() == 1) {
+ assert(Val->getType()->isIntegerTy());
+ return Val == Fields[0];
+ }
+
+ unsigned I, E;
+ for (I = 0, E = Fields.size(); I != E; ++I) {
+ if (Val->getAggregateElement(I) != Fields[I])
+ break;
+ }
+ return I == E;
+}
+
// Returns an adjusted base cast to i8*, since we do more address arithmetic on
// it.
llvm::Value *
@@ -803,6 +881,194 @@ MicrosoftCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF,
return Builder.CreateBitCast(Addr, PType);
}
+static MSInheritanceModel
+getInheritanceFromMemptr(const MemberPointerType *MPT) {
+ return MPT->getClass()->getAsCXXRecordDecl()->getMSInheritanceModel();
+}
+
+llvm::Value *
+MicrosoftCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF,
+ const CastExpr *E,
+ llvm::Value *Src) {
+ assert(E->getCastKind() == CK_DerivedToBaseMemberPointer ||
+ E->getCastKind() == CK_BaseToDerivedMemberPointer ||
+ E->getCastKind() == CK_ReinterpretMemberPointer);
+
+ // Use constant emission if we can.
+ if (isa<llvm::Constant>(Src))
+ return EmitMemberPointerConversion(E, cast<llvm::Constant>(Src));
+
+ // We may be adding or dropping fields from the member pointer, so we need
+ // both types and the inheritance models of both records.
+ const MemberPointerType *SrcTy =
+ E->getSubExpr()->getType()->castAs<MemberPointerType>();
+ const MemberPointerType *DstTy = E->getType()->castAs<MemberPointerType>();
+ MSInheritanceModel SrcInheritance = getInheritanceFromMemptr(SrcTy);
+ MSInheritanceModel DstInheritance = getInheritanceFromMemptr(DstTy);
+ bool IsFunc = SrcTy->isMemberFunctionPointer();
+
+ // If the classes use the same null representation, reinterpret_cast is a nop.
+ bool IsReinterpret = E->getCastKind() == CK_ReinterpretMemberPointer;
+ if (IsReinterpret && (IsFunc ||
+ nullFieldOffsetIsZero(SrcInheritance) ==
+ nullFieldOffsetIsZero(DstInheritance)))
+ return Src;
+
+ CGBuilderTy &Builder = CGF.Builder;
+
+ // Branch past the conversion if Src is null.
+ llvm::Value *IsNotNull = EmitMemberPointerIsNotNull(CGF, Src, SrcTy);
+ llvm::Constant *DstNull = EmitNullMemberPointer(DstTy);
+
+ // C++ 5.2.10p9: The null member pointer value is converted to the null member
+ // pointer value of the destination type.
+ if (IsReinterpret) {
+ // For reinterpret casts, sema ensures that src and dst are both functions
+ // or data and have the same size, which means the LLVM types should match.
+ assert(Src->getType() == DstNull->getType());
+ return Builder.CreateSelect(IsNotNull, Src, DstNull);
+ }
+
+ llvm::BasicBlock *OriginalBB = Builder.GetInsertBlock();
+ llvm::BasicBlock *ConvertBB = CGF.createBasicBlock("memptr.convert");
+ llvm::BasicBlock *ContinueBB = CGF.createBasicBlock("memptr.converted");
+ Builder.CreateCondBr(IsNotNull, ConvertBB, ContinueBB);
+ CGF.EmitBlock(ConvertBB);
+
+ // Decompose src.
+ llvm::Value *FirstField = Src;
+ llvm::Value *NonVirtualBaseAdjustment = 0;
+ llvm::Value *VirtualBaseAdjustmentOffset = 0;
+ llvm::Value *VBPtrOffset = 0;
+ if (!hasOnlyOneField(IsFunc, SrcInheritance)) {
+ // We need to extract values.
+ unsigned I = 0;
+ FirstField = Builder.CreateExtractValue(Src, I++);
+ if (hasNonVirtualBaseAdjustmentField(IsFunc, SrcInheritance))
+ NonVirtualBaseAdjustment = Builder.CreateExtractValue(Src, I++);
+ if (hasVBPtrOffsetField(SrcInheritance))
+ VBPtrOffset = Builder.CreateExtractValue(Src, I++);
+ if (hasVirtualBaseAdjustmentField(SrcInheritance))
+ VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(Src, I++);
+ }
+
+ // For data pointers, we adjust the field offset directly. For functions, we
+ // have a separate field.
+ llvm::Constant *Adj = getMemberPointerAdjustment(E);
+ if (Adj) {
+ Adj = llvm::ConstantExpr::getTruncOrBitCast(Adj, CGM.IntTy);
+ llvm::Value *&NVAdjustField = IsFunc ? NonVirtualBaseAdjustment : FirstField;
+ bool isDerivedToBase = (E->getCastKind() == CK_DerivedToBaseMemberPointer);
+ if (!NVAdjustField) // If this field didn't exist in src, it's zero.
+ NVAdjustField = getZeroInt();
+ if (isDerivedToBase)
+ NVAdjustField = Builder.CreateNSWSub(NVAdjustField, Adj, "adj");
+ else
+ NVAdjustField = Builder.CreateNSWAdd(NVAdjustField, Adj, "adj");
+ }
+
+ // FIXME PR15713: Support conversions through virtually derived classes.
+
+ // Recompose dst from the null struct and the adjusted fields from src.
+ llvm::Value *Dst;
+ if (hasOnlyOneField(IsFunc, DstInheritance)) {
+ Dst = FirstField;
+ } else {
+ Dst = llvm::UndefValue::get(DstNull->getType());
+ unsigned Idx = 0;
+ Dst = Builder.CreateInsertValue(Dst, FirstField, Idx++);
+ if (hasNonVirtualBaseAdjustmentField(IsFunc, DstInheritance))
+ Dst = Builder.CreateInsertValue(
+ Dst, getValueOrZeroInt(NonVirtualBaseAdjustment), Idx++);
+ if (hasVBPtrOffsetField(DstInheritance))
+ Dst = Builder.CreateInsertValue(
+ Dst, getValueOrZeroInt(VBPtrOffset), Idx++);
+ if (hasVirtualBaseAdjustmentField(DstInheritance))
+ Dst = Builder.CreateInsertValue(
+ Dst, getValueOrZeroInt(VirtualBaseAdjustmentOffset), Idx++);
+ }
+ Builder.CreateBr(ContinueBB);
+
+ // In the continuation, choose between DstNull and Dst.
+ CGF.EmitBlock(ContinueBB);
+ llvm::PHINode *Phi = Builder.CreatePHI(DstNull->getType(), 2, "memptr.converted");
+ Phi->addIncoming(DstNull, OriginalBB);
+ Phi->addIncoming(Dst, ConvertBB);
+ return Phi;
+}
+
+llvm::Constant *
+MicrosoftCXXABI::EmitMemberPointerConversion(const CastExpr *E,
+ llvm::Constant *Src) {
+ const MemberPointerType *SrcTy =
+ E->getSubExpr()->getType()->castAs<MemberPointerType>();
+ const MemberPointerType *DstTy = E->getType()->castAs<MemberPointerType>();
+
+ // If src is null, emit a new null for dst. We can't return src because dst
+ // might have a new representation.
+ if (MemberPointerConstantIsNull(SrcTy, Src))
+ return EmitNullMemberPointer(DstTy);
+
+ // We don't need to do anything for reinterpret_casts of non-null member
+ // pointers. We should only get here when the two type representations have
+ // the same size.
+ if (E->getCastKind() == CK_ReinterpretMemberPointer)
+ return Src;
+
+ MSInheritanceModel SrcInheritance = getInheritanceFromMemptr(SrcTy);
+ MSInheritanceModel DstInheritance = getInheritanceFromMemptr(DstTy);
+
+ // Decompose src.
+ llvm::Constant *FirstField = Src;
+ llvm::Constant *NonVirtualBaseAdjustment = 0;
+ llvm::Constant *VirtualBaseAdjustmentOffset = 0;
+ llvm::Constant *VBPtrOffset = 0;
+ bool IsFunc = SrcTy->isMemberFunctionPointer();
+ if (!hasOnlyOneField(IsFunc, SrcInheritance)) {
+ // We need to extract values.
+ unsigned I = 0;
+ FirstField = Src->getAggregateElement(I++);
+ if (hasNonVirtualBaseAdjustmentField(IsFunc, SrcInheritance))
+ NonVirtualBaseAdjustment = Src->getAggregateElement(I++);
+ if (hasVBPtrOffsetField(SrcInheritance))
+ VBPtrOffset = Src->getAggregateElement(I++);
+ if (hasVirtualBaseAdjustmentField(SrcInheritance))
+ VirtualBaseAdjustmentOffset = Src->getAggregateElement(I++);
+ }
+
+ // For data pointers, we adjust the field offset directly. For functions, we
+ // have a separate field.
+ llvm::Constant *Adj = getMemberPointerAdjustment(E);
+ if (Adj) {
+ Adj = llvm::ConstantExpr::getTruncOrBitCast(Adj, CGM.IntTy);
+ llvm::Constant *&NVAdjustField =
+ IsFunc ? NonVirtualBaseAdjustment : FirstField;
+ bool IsDerivedToBase = (E->getCastKind() == CK_DerivedToBaseMemberPointer);
+ if (!NVAdjustField) // If this field didn't exist in src, it's zero.
+ NVAdjustField = getZeroInt();
+ if (IsDerivedToBase)
+ NVAdjustField = llvm::ConstantExpr::getNSWSub(NVAdjustField, Adj);
+ else
+ NVAdjustField = llvm::ConstantExpr::getNSWAdd(NVAdjustField, Adj);
+ }
+
+ // FIXME PR15713: Support conversions through virtually derived classes.
+
+ // Recompose dst from the null struct and the adjusted fields from src.
+ if (hasOnlyOneField(IsFunc, DstInheritance))
+ return FirstField;
+
+ llvm::SmallVector<llvm::Constant *, 4> Fields;
+ Fields.push_back(FirstField);
+ if (hasNonVirtualBaseAdjustmentField(IsFunc, DstInheritance))
+ Fields.push_back(getConstantOrZeroInt(NonVirtualBaseAdjustment));
+ if (hasVBPtrOffsetField(DstInheritance))
+ Fields.push_back(getConstantOrZeroInt(VBPtrOffset));
+ if (hasVirtualBaseAdjustmentField(DstInheritance))
+ Fields.push_back(getConstantOrZeroInt(VirtualBaseAdjustmentOffset));
+ return llvm::ConstantStruct::getAnon(Fields);
+}
+
llvm::Value *
MicrosoftCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
llvm::Value *&This,
OpenPOWER on IntegriCloud