diff options
Diffstat (limited to 'lib/CodeGen')
-rw-r--r-- | lib/CodeGen/CGCXXABI.cpp | 26 | ||||
-rw-r--r-- | lib/CodeGen/CGCXXABI.h | 18 | ||||
-rw-r--r-- | lib/CodeGen/CGExpr.cpp | 1 | ||||
-rw-r--r-- | lib/CodeGen/CGExprAgg.cpp | 1 | ||||
-rw-r--r-- | lib/CodeGen/CGExprComplex.cpp | 1 | ||||
-rw-r--r-- | lib/CodeGen/CGExprConstant.cpp | 9 | ||||
-rw-r--r-- | lib/CodeGen/CGExprScalar.cpp | 1 | ||||
-rw-r--r-- | lib/CodeGen/ItaniumCXXABI.cpp | 122 |
8 files changed, 136 insertions, 43 deletions
diff --git a/lib/CodeGen/CGCXXABI.cpp b/lib/CodeGen/CGCXXABI.cpp index e5d3f2da6b..fc3f45d75b 100644 --- a/lib/CodeGen/CGCXXABI.cpp +++ b/lib/CodeGen/CGCXXABI.cpp @@ -71,6 +71,11 @@ llvm::Value *CGCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF, return GetBogusMemberPointer(CGM, E->getType()); } +llvm::Constant *CGCXXABI::EmitMemberPointerConversion(const CastExpr *E, + llvm::Constant *Src) { + return GetBogusMemberPointer(CGM, E->getType()); +} + llvm::Value * CGCXXABI::EmitMemberPointerComparison(CodeGenFunction &CGF, llvm::Value *L, @@ -172,3 +177,24 @@ void CGCXXABI::EmitGuardedInit(CodeGenFunction &CGF, bool PerformInit) { ErrorUnsupportedABI(CGF, "static local variable initialization"); } + +/// Returns the adjustment, in bytes, required for the given +/// member-pointer operation. Returns null if no adjustment is +/// required. +llvm::Constant *CGCXXABI::getMemberPointerAdjustment(const CastExpr *E) { + assert(E->getCastKind() == CK_DerivedToBaseMemberPointer || + E->getCastKind() == CK_BaseToDerivedMemberPointer); + + QualType derivedType; + if (E->getCastKind() == CK_DerivedToBaseMemberPointer) + derivedType = E->getSubExpr()->getType(); + else + derivedType = E->getType(); + + const CXXRecordDecl *derivedClass = + derivedType->castAs<MemberPointerType>()->getClass()->getAsCXXRecordDecl(); + + return CGM.GetNonVirtualBaseClassOffset(derivedClass, + E->path_begin(), + E->path_end()); +} diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h index 4bacd01403..4e045f5f32 100644 --- a/lib/CodeGen/CGCXXABI.h +++ b/lib/CodeGen/CGCXXABI.h @@ -100,12 +100,17 @@ public: llvm::Value *MemPtr, const MemberPointerType *MPT); - /// Perform a derived-to-base or base-to-derived member pointer - /// conversion. + /// Perform a derived-to-base, base-to-derived, or bitcast member + /// pointer conversion. virtual llvm::Value *EmitMemberPointerConversion(CodeGenFunction &CGF, const CastExpr *E, llvm::Value *Src); + /// Perform a derived-to-base, base-to-derived, or bitcast member + /// pointer conversion on a constant value. + virtual llvm::Constant *EmitMemberPointerConversion(const CastExpr *E, + llvm::Constant *Src); + /// Return true if the given member pointer can be zero-initialized /// (in the C++ sense) with an LLVM zeroinitializer. virtual bool isZeroInitializable(const MemberPointerType *MPT); @@ -137,6 +142,15 @@ public: llvm::Value *MemPtr, const MemberPointerType *MPT); +protected: + /// A utility method for computing the offset required for the given + /// base-to-derived or derived-to-base member-pointer conversion. + /// Does not handle virtual conversions (in case we ever fully + /// support an ABI that allows this). Returns null if no adjustment + /// is required. + llvm::Constant *getMemberPointerAdjustment(const CastExpr *E); + +public: /// Build the signature of the given constructor variant by adding /// any required parameters. For convenience, ResTy has been /// initialized to 'void', and ArgTys has been initialized with the diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 95bed1b0e6..f67025a32c 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -2090,6 +2090,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { case CK_DerivedToBaseMemberPointer: case CK_BaseToDerivedMemberPointer: case CK_MemberPointerToBoolean: + case CK_ReinterpretMemberPointer: case CK_AnyPointerToBlockPointerCast: case CK_ARCProduceObject: case CK_ARCConsumeObject: diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index a85cb9dbc3..91f9db0bfe 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -360,6 +360,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { case CK_BaseToDerivedMemberPointer: case CK_DerivedToBaseMemberPointer: case CK_MemberPointerToBoolean: + case CK_ReinterpretMemberPointer: case CK_IntegralToPointer: case CK_PointerToIntegral: case CK_PointerToBoolean: diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp index 53f7d65ef1..15fa225eb8 100644 --- a/lib/CodeGen/CGExprComplex.cpp +++ b/lib/CodeGen/CGExprComplex.cpp @@ -388,6 +388,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op, case CK_BaseToDerivedMemberPointer: case CK_DerivedToBaseMemberPointer: case CK_MemberPointerToBoolean: + case CK_ReinterpretMemberPointer: case CK_ConstructorConversion: case CK_IntegralToPointer: case CK_PointerToIntegral: diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 44531c0992..985e53227e 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -620,6 +620,11 @@ public: case CK_Dependent: llvm_unreachable("saw dependent cast!"); + case CK_ReinterpretMemberPointer: + case CK_DerivedToBaseMemberPointer: + case CK_BaseToDerivedMemberPointer: + return CGM.getCXXABI().EmitMemberPointerConversion(E, C); + // These will never be supported. case CK_ObjCObjectLValueCast: case CK_ARCProduceObject: @@ -630,18 +635,16 @@ public: // These don't need to be handled here because Evaluate knows how to // evaluate them in the cases where they can be folded. + case CK_BitCast: case CK_ToVoid: case CK_Dynamic: case CK_LValueBitCast: case CK_NullToMemberPointer: - case CK_DerivedToBaseMemberPointer: - case CK_BaseToDerivedMemberPointer: case CK_UserDefinedConversion: case CK_ConstructorConversion: case CK_CPointerToObjCPointerCast: case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: - case CK_BitCast: case CK_ArrayToPointerDecay: case CK_FunctionToPointerDecay: case CK_BaseToDerived: diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index d9b0e21238..8bd4c2b5aa 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -1122,6 +1122,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { return CGF.CGM.getCXXABI().EmitNullMemberPointer(MPT); } + case CK_ReinterpretMemberPointer: case CK_BaseToDerivedMemberPointer: case CK_DerivedToBaseMemberPointer: { Value *Src = Visit(E); diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index a8b9942882..8d06b6011c 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -73,6 +73,8 @@ public: llvm::Value *EmitMemberPointerConversion(CodeGenFunction &CGF, const CastExpr *E, llvm::Value *Src); + llvm::Constant *EmitMemberPointerConversion(const CastExpr *E, + llvm::Constant *Src); llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT); @@ -312,7 +314,10 @@ llvm::Value *ItaniumCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF, return Builder.CreateBitCast(Addr, PType); } -/// Perform a derived-to-base or base-to-derived member pointer conversion. +/// Perform a bitcast, derived-to-base, or base-to-derived member pointer +/// conversion. +/// +/// Bitcast conversions are always a no-op under Itanium. /// /// Obligatory offset/adjustment diagram: /// <-- offset --> <-- adjustment --> @@ -335,64 +340,105 @@ llvm::Value *ItaniumCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF, llvm::Value * ItaniumCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF, const CastExpr *E, - llvm::Value *Src) { + llvm::Value *src) { assert(E->getCastKind() == CK_DerivedToBaseMemberPointer || - E->getCastKind() == CK_BaseToDerivedMemberPointer); + E->getCastKind() == CK_BaseToDerivedMemberPointer || + E->getCastKind() == CK_ReinterpretMemberPointer); + + // Under Itanium, reinterprets don't require any additional processing. + if (E->getCastKind() == CK_ReinterpretMemberPointer) return src; + + // Use constant emission if we can. + if (isa<llvm::Constant>(src)) + return EmitMemberPointerConversion(E, cast<llvm::Constant>(src)); + + llvm::Constant *adj = getMemberPointerAdjustment(E); + if (!adj) return src; CGBuilderTy &Builder = CGF.Builder; + bool isDerivedToBase = (E->getCastKind() == CK_DerivedToBaseMemberPointer); + + const MemberPointerType *destTy = + E->getType()->castAs<MemberPointerType>(); - const MemberPointerType *SrcTy = - E->getSubExpr()->getType()->getAs<MemberPointerType>(); - const MemberPointerType *DestTy = E->getType()->getAs<MemberPointerType>(); + // For member data pointers, this is just a matter of adding the + // offset if the source is non-null. + if (destTy->isMemberDataPointer()) { + llvm::Value *dst; + if (isDerivedToBase) + dst = Builder.CreateNSWSub(src, adj, "adj"); + else + dst = Builder.CreateNSWAdd(src, adj, "adj"); - const CXXRecordDecl *SrcDecl = SrcTy->getClass()->getAsCXXRecordDecl(); - const CXXRecordDecl *DestDecl = DestTy->getClass()->getAsCXXRecordDecl(); + // 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); + } - bool DerivedToBase = - E->getCastKind() == CK_DerivedToBaseMemberPointer; + // The this-adjustment is left-shifted by 1 on ARM. + if (IsARM) { + uint64_t offset = cast<llvm::ConstantInt>(adj)->getZExtValue(); + offset <<= 1; + adj = llvm::ConstantInt::get(adj->getType(), offset); + } - const CXXRecordDecl *DerivedDecl; - if (DerivedToBase) - DerivedDecl = SrcDecl; + llvm::Value *srcAdj = Builder.CreateExtractValue(src, 1, "src.adj"); + llvm::Value *dstAdj; + if (isDerivedToBase) + dstAdj = Builder.CreateNSWSub(srcAdj, adj, "adj"); else - DerivedDecl = DestDecl; + dstAdj = Builder.CreateNSWAdd(srcAdj, adj, "adj"); + + return Builder.CreateInsertValue(src, dstAdj, 1); +} + +llvm::Constant * +ItaniumCXXABI::EmitMemberPointerConversion(const CastExpr *E, + llvm::Constant *src) { + assert(E->getCastKind() == CK_DerivedToBaseMemberPointer || + E->getCastKind() == CK_BaseToDerivedMemberPointer || + E->getCastKind() == CK_ReinterpretMemberPointer); - llvm::Constant *Adj = - CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, - E->path_begin(), - E->path_end()); - if (!Adj) return Src; + // Under Itanium, reinterprets don't require any additional processing. + if (E->getCastKind() == CK_ReinterpretMemberPointer) return src; + + // If the adjustment is trivial, we don't need to do anything. + llvm::Constant *adj = getMemberPointerAdjustment(E); + if (!adj) return src; + + bool isDerivedToBase = (E->getCastKind() == CK_DerivedToBaseMemberPointer); + + const MemberPointerType *destTy = + E->getType()->castAs<MemberPointerType>(); // 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"); + if (destTy->isMemberDataPointer()) { + // null maps to null. + if (src->isAllOnesValue()) return src; - // 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); + if (isDerivedToBase) + return llvm::ConstantExpr::getNSWSub(src, adj); + else + return llvm::ConstantExpr::getNSWAdd(src, adj); } // The this-adjustment is left-shifted by 1 on ARM. if (IsARM) { - uint64_t Offset = cast<llvm::ConstantInt>(Adj)->getZExtValue(); - Offset <<= 1; - Adj = llvm::ConstantInt::get(Adj->getType(), Offset); + uint64_t offset = cast<llvm::ConstantInt>(adj)->getZExtValue(); + offset <<= 1; + adj = llvm::ConstantInt::get(adj->getType(), offset); } - llvm::Value *SrcAdj = Builder.CreateExtractValue(Src, 1, "src.adj"); - llvm::Value *DstAdj; - if (DerivedToBase) - DstAdj = Builder.CreateNSWSub(SrcAdj, Adj, "adj"); + llvm::Constant *srcAdj = llvm::ConstantExpr::getExtractValue(src, 1); + llvm::Constant *dstAdj; + if (isDerivedToBase) + dstAdj = llvm::ConstantExpr::getNSWSub(srcAdj, adj); else - DstAdj = Builder.CreateNSWAdd(SrcAdj, Adj, "adj"); + dstAdj = llvm::ConstantExpr::getNSWAdd(srcAdj, adj); - return Builder.CreateInsertValue(Src, DstAdj, 1); + return llvm::ConstantExpr::getInsertValue(src, dstAdj, 1); } llvm::Constant * |