diff options
Diffstat (limited to 'clang/lib/CodeGen/ItaniumCXXABI.cpp')
| -rw-r--r-- | clang/lib/CodeGen/ItaniumCXXABI.cpp | 250 |
1 files changed, 186 insertions, 64 deletions
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 37244398f33..f6864059de0 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -19,10 +19,12 @@ //===----------------------------------------------------------------------===// #include "CGCXXABI.h" +#include "CGRecordLayout.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "Mangle.h" #include <clang/AST/Type.h> +#include <llvm/Target/TargetData.h> #include <llvm/Value.h> using namespace clang; @@ -30,12 +32,26 @@ using namespace CodeGen; namespace { class ItaniumCXXABI : public CodeGen::CGCXXABI { +private: + const llvm::IntegerType *PtrDiffTy; protected: CodeGen::MangleContext MangleCtx; bool IsARM; + + // It's a little silly for us to cache this. + const llvm::IntegerType *getPtrDiffTy() { + if (!PtrDiffTy) { + QualType T = CGM.getContext().getPointerDiffType(); + const llvm::Type *Ty = CGM.getTypes().ConvertTypeRecursive(T); + PtrDiffTy = cast<llvm::IntegerType>(Ty); + } + return PtrDiffTy; + } + public: ItaniumCXXABI(CodeGen::CodeGenModule &CGM, bool IsARM = false) : - CGCXXABI(CGM), MangleCtx(CGM.getContext(), CGM.getDiags()), IsARM(IsARM) { } + CGCXXABI(CGM), PtrDiffTy(0), MangleCtx(CGM.getContext(), CGM.getDiags()), + IsARM(IsARM) { } CodeGen::MangleContext &getMangleContext() { return MangleCtx; @@ -43,35 +59,34 @@ public: bool isZeroInitializable(const MemberPointerType *MPT); + const llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT); + llvm::Value *EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, llvm::Value *&This, llvm::Value *MemFnPtr, const MemberPointerType *MPT); - llvm::Value *EmitMemberFunctionPointerConversion(CodeGenFunction &CGF, - const CastExpr *E, - llvm::Value *Src); + llvm::Value *EmitMemberPointerConversion(CodeGenFunction &CGF, + const CastExpr *E, + llvm::Value *Src); - llvm::Constant *EmitMemberFunctionPointerConversion(llvm::Constant *C, - const CastExpr *E); + llvm::Constant *EmitMemberPointerConversion(llvm::Constant *C, + const CastExpr *E); - llvm::Constant *EmitNullMemberFunctionPointer(const MemberPointerType *MPT); + llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT); - llvm::Constant *EmitMemberFunctionPointer(const CXXMethodDecl *MD); + llvm::Constant *EmitMemberPointer(const CXXMethodDecl *MD); + llvm::Constant *EmitMemberPointer(const FieldDecl *FD); - llvm::Value *EmitMemberFunctionPointerComparison(CodeGenFunction &CGF, - llvm::Value *L, - llvm::Value *R, - const MemberPointerType *MPT, - bool Inequality); + llvm::Value *EmitMemberPointerComparison(CodeGenFunction &CGF, + llvm::Value *L, + llvm::Value *R, + const MemberPointerType *MPT, + bool Inequality); - llvm::Value *EmitMemberFunctionPointerIsNotNull(CodeGenFunction &CGF, - llvm::Value *Addr, - const MemberPointerType *MPT); - -private: - void GetMemberFunctionPointer(const CXXMethodDecl *MD, - llvm::Constant *(&Array)[2]); + llvm::Value *EmitMemberPointerIsNotNull(CodeGenFunction &CGF, + llvm::Value *Addr, + const MemberPointerType *MPT); }; class ARMCXXABI : public ItaniumCXXABI { @@ -88,11 +103,15 @@ CodeGen::CGCXXABI *CodeGen::CreateARMCXXABI(CodeGenModule &CGM) { return new ARMCXXABI(CGM); } -void ItaniumCXXABI::GetMemberFunctionPointer(const CXXMethodDecl *MD, - llvm::Constant *(&MemPtr)[2]) { +const llvm::Type * +ItaniumCXXABI::ConvertMemberPointerType(const MemberPointerType *MPT) { + if (MPT->isMemberDataPointer()) + return getPtrDiffTy(); + else + return llvm::StructType::get(CGM.getLLVMContext(), + getPtrDiffTy(), getPtrDiffTy(), NULL); } - /// In the Itanium and ARM ABIs, method pointers have the form: /// struct { ptrdiff_t ptr; ptrdiff_t adj; } memptr; /// @@ -129,7 +148,7 @@ ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT), FPT->isVariadic()); - const llvm::IntegerType *ptrdiff = CGF.IntPtrTy; + const llvm::IntegerType *ptrdiff = getPtrDiffTy(); llvm::Constant *ptrdiff_1 = llvm::ConstantInt::get(ptrdiff, 1); llvm::BasicBlock *FnVirtual = CGF.createBasicBlock("memptr.virtual"); @@ -199,15 +218,34 @@ ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, } /// Perform a derived-to-base or base-to-derived member pointer conversion. +/// +/// Obligatory offset/adjustment diagram: +/// <-- offset --> <-- adjustment --> +/// |--------------------------|----------------------|--------------------| +/// ^Derived address point ^Base address point ^Member address point +/// +/// So when converting a base member pointer to a derived member pointer, +/// we add the offset to the adjustment because the address point has +/// decreased; and conversely, when converting a derived MP to a base MP +/// we subtract the offset from the adjustment because the address point +/// has increased. +/// +/// The standard forbids (at compile time) conversion to and from +/// virtual bases, which is why we don't have to consider them here. +/// +/// The standard forbids (at run time) casting a derived MP to a base +/// MP when the derived MP does not point to a member of the base. +/// This is why -1 is a reasonable choice for null data member +/// pointers. llvm::Value * -ItaniumCXXABI::EmitMemberFunctionPointerConversion(CodeGenFunction &CGF, - const CastExpr *E, - llvm::Value *Src) { +ItaniumCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF, + const CastExpr *E, + llvm::Value *Src) { assert(E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer || E->getCastKind() == CastExpr::CK_BaseToDerivedMemberPointer); if (isa<llvm::Constant>(Src)) - return EmitMemberFunctionPointerConversion(cast<llvm::Constant>(Src), E); + return EmitMemberPointerConversion(cast<llvm::Constant>(Src), E); CGBuilderTy &Builder = CGF.Builder; @@ -233,6 +271,21 @@ ItaniumCXXABI::EmitMemberFunctionPointerConversion(CodeGenFunction &CGF, E->path_end()); if (!Adj) return Src; + // For member data pointers, this is just a matter of adding the + // offset if the source is non-null. + if (SrcTy->isMemberDataPointer()) { + llvm::Value *Dst; + if (DerivedToBase) + Dst = Builder.CreateNSWSub(Src, Adj, "adj"); + else + Dst = Builder.CreateNSWAdd(Src, Adj, "adj"); + + // Null check. + llvm::Value *Null = llvm::Constant::getAllOnesValue(Src->getType()); + llvm::Value *IsNull = Builder.CreateICmpEQ(Src, Null, "memptr.isnull"); + return Builder.CreateSelect(IsNull, Src, Dst); + } + // The this-adjustment is left-shifted by 1 on ARM. if (IsARM) { uint64_t Offset = cast<llvm::ConstantInt>(Adj)->getZExtValue(); @@ -243,16 +296,16 @@ ItaniumCXXABI::EmitMemberFunctionPointerConversion(CodeGenFunction &CGF, llvm::Value *SrcAdj = Builder.CreateExtractValue(Src, 1, "src.adj"); llvm::Value *DstAdj; if (DerivedToBase) - DstAdj = Builder.CreateSub(SrcAdj, Adj, "adj"); + DstAdj = Builder.CreateNSWSub(SrcAdj, Adj, "adj"); else - DstAdj = Builder.CreateAdd(SrcAdj, Adj, "adj"); + DstAdj = Builder.CreateNSWAdd(SrcAdj, Adj, "adj"); return Builder.CreateInsertValue(Src, DstAdj, 1); } llvm::Constant * -ItaniumCXXABI::EmitMemberFunctionPointerConversion(llvm::Constant *C, - const CastExpr *E) { +ItaniumCXXABI::EmitMemberPointerConversion(llvm::Constant *C, + const CastExpr *E) { const MemberPointerType *SrcTy = E->getSubExpr()->getType()->getAs<MemberPointerType>(); const MemberPointerType *DestTy = @@ -275,28 +328,68 @@ ItaniumCXXABI::EmitMemberFunctionPointerConversion(llvm::Constant *C, // If there's no offset, we're done. if (!Offset) return C; + // If the source is a member data pointer, we have to do a null + // check and then add the offset. In the common case, we can fold + // away the offset. + if (SrcTy->isMemberDataPointer()) { + assert(C->getType() == getPtrDiffTy()); + + // If it's a constant int, just create a new constant int. + if (llvm::ConstantInt *CI = dyn_cast<llvm::ConstantInt>(C)) { + int64_t Src = CI->getSExtValue(); + + // Null converts to null. + if (Src == -1) return CI; + + // Otherwise, just add the offset. + int64_t OffsetV = cast<llvm::ConstantInt>(Offset)->getSExtValue(); + int64_t Dst = (DerivedToBase ? Src - OffsetV : Src + OffsetV); + return llvm::ConstantInt::get(CI->getType(), Dst, /*signed*/ true); + } + + // Otherwise, we have to form a constant select expression. + llvm::Constant *Null = llvm::Constant::getAllOnesValue(C->getType()); + + llvm::Constant *IsNull = + llvm::ConstantExpr::getICmp(llvm::ICmpInst::ICMP_EQ, C, Null); + + llvm::Constant *Dst; + if (DerivedToBase) + Dst = llvm::ConstantExpr::getNSWSub(C, Offset); + else + Dst = llvm::ConstantExpr::getNSWAdd(C, Offset); + + return llvm::ConstantExpr::getSelect(IsNull, Null, Dst); + } + // The this-adjustment is left-shifted by 1 on ARM. if (IsARM) { - uint64_t OffsetV = cast<llvm::ConstantInt>(Offset)->getZExtValue(); + int64_t OffsetV = cast<llvm::ConstantInt>(Offset)->getSExtValue(); OffsetV <<= 1; Offset = llvm::ConstantInt::get(Offset->getType(), OffsetV); } llvm::ConstantStruct *CS = cast<llvm::ConstantStruct>(C); - llvm::Constant *Values[2] = { - CS->getOperand(0), - llvm::ConstantExpr::getAdd(CS->getOperand(1), Offset) - }; + llvm::Constant *Values[2] = { CS->getOperand(0), 0 }; + if (DerivedToBase) + Values[1] = llvm::ConstantExpr::getSub(CS->getOperand(1), Offset); + else + Values[1] = llvm::ConstantExpr::getAdd(CS->getOperand(1), Offset); + return llvm::ConstantStruct::get(CGM.getLLVMContext(), Values, 2, /*Packed=*/false); } llvm::Constant * -ItaniumCXXABI::EmitNullMemberFunctionPointer(const MemberPointerType *MPT) { - const llvm::Type *ptrdiff_t = - CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType()); +ItaniumCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) { + const llvm::Type *ptrdiff_t = getPtrDiffTy(); + + // Itanium C++ ABI 2.3: + // A NULL pointer is represented as -1. + if (MPT->isMemberDataPointer()) + return llvm::ConstantInt::get(ptrdiff_t, -1ULL, /*isSigned=*/true); llvm::Constant *Zero = llvm::ConstantInt::get(ptrdiff_t, 0); llvm::Constant *Values[2] = { Zero, Zero }; @@ -304,14 +397,29 @@ ItaniumCXXABI::EmitNullMemberFunctionPointer(const MemberPointerType *MPT) { /*Packed=*/false); } -llvm::Constant * -ItaniumCXXABI::EmitMemberFunctionPointer(const CXXMethodDecl *MD) { +llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const FieldDecl *FD) { + // Itanium C++ ABI 2.3: + // A pointer to data member is an offset from the base address of + // the class object containing it, represented as a ptrdiff_t + + QualType ClassType = CGM.getContext().getTypeDeclType(FD->getParent()); + const llvm::StructType *ClassLTy = + cast<llvm::StructType>(CGM.getTypes().ConvertType(ClassType)); + + const CGRecordLayout &RL = CGM.getTypes().getCGRecordLayout(FD->getParent()); + unsigned FieldNo = RL.getLLVMFieldNo(FD); + uint64_t Offset = + CGM.getTargetData().getStructLayout(ClassLTy)->getElementOffset(FieldNo); + + return llvm::ConstantInt::get(getPtrDiffTy(), Offset); +} + +llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) { assert(MD->isInstance() && "Member function must not be static!"); MD = MD->getCanonicalDecl(); CodeGenTypes &Types = CGM.getTypes(); - const llvm::Type *ptrdiff_t = - Types.ConvertType(CGM.getContext().getPointerDiffType()); + const llvm::Type *ptrdiff_t = getPtrDiffTy(); // Get the function pointer (or index if this is a virtual function). llvm::Constant *MemPtr[2]; @@ -367,25 +475,13 @@ ItaniumCXXABI::EmitMemberFunctionPointer(const CXXMethodDecl *MD) { /// /// ARM is different here only because null-ness is more complicated. llvm::Value * -ItaniumCXXABI::EmitMemberFunctionPointerComparison(CodeGenFunction &CGF, - llvm::Value *L, - llvm::Value *R, - const MemberPointerType *MPT, - bool Inequality) { +ItaniumCXXABI::EmitMemberPointerComparison(CodeGenFunction &CGF, + llvm::Value *L, + llvm::Value *R, + const MemberPointerType *MPT, + bool Inequality) { CGBuilderTy &Builder = CGF.Builder; - llvm::Value *LPtr = Builder.CreateExtractValue(L, 0, "lhs.memptr.ptr"); - llvm::Value *RPtr = Builder.CreateExtractValue(R, 0, "rhs.memptr.ptr"); - - // The Itanium tautology is: - // (L == R) <==> (L.ptr == R.ptr /\ (L.ptr == 0 \/ L.adj == R.adj)) - // The ARM tautology is: - // (L == R) <==> (L.ptr == R.ptr /\ - // (L.adj == R.adj \/ - // (L.ptr == 0 /\ ((L.adj|R.adj) & 1) == 0))) - // The inequality tautologies have exactly the same structure, except - // applying De Morgan's laws. - llvm::ICmpInst::Predicate Eq; llvm::Instruction::BinaryOps And, Or; if (Inequality) { @@ -398,6 +494,24 @@ ItaniumCXXABI::EmitMemberFunctionPointerComparison(CodeGenFunction &CGF, Or = llvm::Instruction::Or; } + // Member data pointers are easy because there's a unique null + // value, so it just comes down to bitwise equality. + if (MPT->isMemberDataPointer()) + return Builder.CreateICmp(Eq, L, R); + + // For member function pointers, the tautologies are more complex. + // The Itanium tautology is: + // (L == R) <==> (L.ptr == R.ptr /\ (L.ptr == 0 \/ L.adj == R.adj)) + // The ARM tautology is: + // (L == R) <==> (L.ptr == R.ptr /\ + // (L.adj == R.adj \/ + // (L.ptr == 0 /\ ((L.adj|R.adj) & 1) == 0))) + // The inequality tautologies have exactly the same structure, except + // applying De Morgan's laws. + + llvm::Value *LPtr = Builder.CreateExtractValue(L, 0, "lhs.memptr.ptr"); + llvm::Value *RPtr = Builder.CreateExtractValue(R, 0, "rhs.memptr.ptr"); + // This condition tests whether L.ptr == R.ptr. This must always be // true for equality to hold. llvm::Value *PtrEq = Builder.CreateICmp(Eq, LPtr, RPtr, "cmp.ptr"); @@ -435,10 +549,18 @@ ItaniumCXXABI::EmitMemberFunctionPointerComparison(CodeGenFunction &CGF, } llvm::Value * -ItaniumCXXABI::EmitMemberFunctionPointerIsNotNull(CodeGenFunction &CGF, - llvm::Value *MemPtr, - const MemberPointerType *MPT) { +ItaniumCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF, + llvm::Value *MemPtr, + const MemberPointerType *MPT) { CGBuilderTy &Builder = CGF.Builder; + + /// For member data pointers, this is just a check against -1. + if (MPT->isMemberDataPointer()) { + assert(MemPtr->getType() == getPtrDiffTy()); + llvm::Value *NegativeOne = + llvm::Constant::getAllOnesValue(MemPtr->getType()); + return Builder.CreateICmpNE(MemPtr, NegativeOne, "memptr.tobool"); + } // In Itanium, a member function pointer is null if 'ptr' is null. llvm::Value *Ptr = Builder.CreateExtractValue(MemPtr, 0, "memptr.ptr"); |

