diff options
author | John McCall <rjmccall@apple.com> | 2010-08-22 10:59:02 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2010-08-22 10:59:02 +0000 |
commit | d608cdb7c044365cf4e8764ade1e11e99c176078 (patch) | |
tree | 64048b57b20b73f88b0d6dc576241554929236cf | |
parent | e9fd7eb6c67676dc27e84eac429aec4f3be51f26 (diff) |
Experiment with using first-class aggregates to represent member function
pointers. I find the resulting code to be substantially cleaner, and it
makes it very easy to use the same APIs for data member pointers (which I have
conscientiously avoided here), and it avoids a plethora of potential
inefficiencies due to excessive memory copying, but we'll have to see if it
actually works.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111776 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/CodeGen/CGCXX.cpp | 41 | ||||
-rw-r--r-- | lib/CodeGen/CGCXXABI.h | 25 | ||||
-rw-r--r-- | lib/CodeGen/CGExpr.cpp | 36 | ||||
-rw-r--r-- | lib/CodeGen/CGExprAgg.cpp | 55 | ||||
-rw-r--r-- | lib/CodeGen/CGExprCXX.cpp | 3 | ||||
-rw-r--r-- | lib/CodeGen/CGExprConstant.cpp | 18 | ||||
-rw-r--r-- | lib/CodeGen/CGExprScalar.cpp | 29 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.cpp | 2 | ||||
-rw-r--r-- | lib/CodeGen/ItaniumCXXABI.cpp | 258 | ||||
-rw-r--r-- | lib/CodeGen/MicrosoftCXXABI.cpp | 2 | ||||
-rw-r--r-- | lib/CodeGen/TargetInfo.cpp | 27 | ||||
-rw-r--r-- | test/CodeGenCXX/member-function-pointers.cpp | 52 | ||||
-rw-r--r-- | test/CodeGenCXX/x86_32-arguments.cpp | 2 |
13 files changed, 229 insertions, 321 deletions
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 2d7b27b18b..b805d136c4 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -330,6 +330,11 @@ static void ErrorUnsupportedABI(CodeGenFunction &CGF, << S; } +static llvm::Constant *GetBogusMemberPointer(CodeGenModule &CGM, + QualType T) { + return llvm::Constant::getNullValue(CGM.getTypes().ConvertType(T)); +} + llvm::Value *CGCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, llvm::Value *&This, llvm::Value *MemPtr, @@ -341,32 +346,16 @@ llvm::Value *CGCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, const CXXRecordDecl *RD = cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl()); const llvm::FunctionType *FTy = - CGF.CGM.getTypes().GetFunctionType( - CGF.CGM.getTypes().getFunctionInfo(RD, FPT), - FPT->isVariadic()); + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT), + FPT->isVariadic()); return llvm::Constant::getNullValue(FTy->getPointerTo()); } -void CGCXXABI::EmitMemberFunctionPointerConversion(CodeGenFunction &CGF, - const CastExpr *E, - llvm::Value *Src, - llvm::Value *Dest, - bool VolatileDest) { +llvm::Value *CGCXXABI::EmitMemberFunctionPointerConversion(CodeGenFunction &CGF, + const CastExpr *E, + llvm::Value *Src) { ErrorUnsupportedABI(CGF, "member function pointer conversions"); -} - -void CGCXXABI::EmitNullMemberFunctionPointer(CodeGenFunction &CGF, - const MemberPointerType *MPT, - llvm::Value *Dest, - bool VolatileDest) { - ErrorUnsupportedABI(CGF, "null member function pointers"); -} - -void CGCXXABI::EmitMemberFunctionPointer(CodeGenFunction &CGF, - const CXXMethodDecl *MD, - llvm::Value *DestPtr, - bool VolatileDest) { - ErrorUnsupportedABI(CGF, "member function pointers"); + return GetBogusMemberPointer(CGM, E->getType()); } llvm::Value * @@ -390,16 +379,18 @@ CGCXXABI::EmitMemberFunctionPointerIsNotNull(CodeGenFunction &CGF, llvm::Constant * CGCXXABI::EmitMemberFunctionPointerConversion(llvm::Constant *C, const CastExpr *E) { - return 0; + return GetBogusMemberPointer(CGM, E->getType()); } llvm::Constant * CGCXXABI::EmitNullMemberFunctionPointer(const MemberPointerType *MPT) { - return 0; + return GetBogusMemberPointer(CGM, QualType(MPT, 0)); } llvm::Constant *CGCXXABI::EmitMemberFunctionPointer(const CXXMethodDecl *MD) { - return 0; + return GetBogusMemberPointer(CGM, + CGM.getContext().getMemberPointerType(MD->getType(), + MD->getParent()->getTypeForDecl())); } bool CGCXXABI::RequiresNonZeroInitializer(QualType T) { diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h index 8478df4816..d0bb0e864f 100644 --- a/lib/CodeGen/CGCXXABI.h +++ b/lib/CodeGen/CGCXXABI.h @@ -34,7 +34,13 @@ namespace CodeGen { /// Implements C++ ABI-specific code generation functions. class CGCXXABI { +protected: + CodeGenModule &CGM; + + CGCXXABI(CodeGenModule &CGM) : CGM(CGM) {} + public: + virtual ~CGCXXABI(); /// Gets the mangle context. @@ -46,18 +52,11 @@ public: llvm::Value *MemPtr, const MemberPointerType *MPT); - virtual void + virtual llvm::Value * EmitMemberFunctionPointerConversion(CodeGenFunction &CGF, const CastExpr *E, - llvm::Value *Src, - llvm::Value *Dest, - bool VolatileDest); - - virtual void EmitNullMemberFunctionPointer(CodeGenFunction &CGF, - const MemberPointerType *MPT, - llvm::Value *Dest, - bool VolatileDest); - + llvm::Value *Src); + // Manipulations on constant expressions. /// \brief Returns true if zero-initializing the given type requires @@ -73,10 +72,6 @@ public: EmitNullMemberFunctionPointer(const MemberPointerType *MPT); virtual llvm::Constant *EmitMemberFunctionPointer(const CXXMethodDecl *MD); - virtual void EmitMemberFunctionPointer(CodeGenFunction &CGF, - const CXXMethodDecl *MD, - llvm::Value *DestPtr, - bool VolatileDest); virtual llvm::Value * EmitMemberFunctionPointerComparison(CodeGenFunction &CGF, @@ -87,7 +82,7 @@ public: virtual llvm::Value * EmitMemberFunctionPointerIsNotNull(CodeGenFunction &CGF, - llvm::Value *Addr, + llvm::Value *MemPtr, const MemberPointerType *MPT); }; diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 753af76bf2..55abaa31cd 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -67,10 +67,8 @@ llvm::AllocaInst *CodeGenFunction::CreateMemTemp(QualType Ty, llvm::Value *CodeGenFunction::EvaluateExprAsBool(const Expr *E) { QualType BoolTy = getContext().BoolTy; if (E->getType()->isMemberFunctionPointerType()) { - LValue LV = EmitAggExprToLValue(E); - - return CGM.getCXXABI().EmitMemberFunctionPointerIsNotNull(CGF, - LV.getAddress(), + llvm::Value *MemPtr = EmitScalarExpr(E); + return CGM.getCXXABI().EmitMemberFunctionPointerIsNotNull(CGF, MemPtr, E->getType()->getAs<MemberPointerType>()); } if (!E->getType()->isAnyComplexType()) @@ -614,18 +612,15 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, QualType ExprType) { if (LV.isSimple()) { llvm::Value *Ptr = LV.getAddress(); - const llvm::Type *EltTy = - cast<llvm::PointerType>(Ptr->getType())->getElementType(); - // Simple scalar l-value. - // - // FIXME: We shouldn't have to use isSingleValueType here. - if (EltTy->isSingleValueType()) - return RValue::get(EmitLoadOfScalar(Ptr, LV.isVolatileQualified(), - LV.getAlignment(), ExprType)); + // Functions are l-values that don't require loading. + if (ExprType->isFunctionType()) + return RValue::get(Ptr); + + // Everything needs a load. + return RValue::get(EmitLoadOfScalar(Ptr, LV.isVolatileQualified(), + LV.getAlignment(), ExprType)); - assert(ExprType->isFunctionType() && "Unknown scalar value"); - return RValue::get(Ptr); } if (LV.isVectorElt()) { @@ -1177,12 +1172,19 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { return LV; } + // If we're emitting an instance method as an independent lvalue, + // we're actually emitting a member pointer. + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(ND)) + if (MD->isInstance()) { + llvm::Value *V = CGM.getCXXABI().EmitMemberFunctionPointer(MD); + return MakeAddrLValue(V, MD->getType(), Alignment); + } if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) return EmitFunctionDeclLValue(*this, E, FD); - // FIXME: the qualifier check does not seem sufficient here - if (E->getQualifier()) { - const FieldDecl *FD = cast<FieldDecl>(ND); + // If we're emitting a field as an independent lvalue, we're + // actually emitting a member pointer. + if (const FieldDecl *FD = dyn_cast<FieldDecl>(ND)) { llvm::Value *V = CGM.EmitPointerToDataMember(FD); return MakeAddrLValue(V, FD->getType(), Alignment); } diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index b75aeb13b8..890a07f9fb 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -108,7 +108,6 @@ public: void VisitPointerToDataMemberBinaryOperator(const BinaryOperator *BO); void VisitBinAssign(const BinaryOperator *E); void VisitBinComma(const BinaryOperator *E); - void VisitUnaryAddrOf(const UnaryOperator *E); void VisitObjCMessageExpr(ObjCMessageExpr *E); void VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { @@ -287,46 +286,9 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { Visit(E->getSubExpr()); break; - case CastExpr::CK_NullToMemberPointer: { - // If the subexpression's type is the C++0x nullptr_t, emit the - // subexpression, which may have side effects. - if (E->getSubExpr()->getType()->isNullPtrType()) - Visit(E->getSubExpr()); - - CGF.CGM.getCXXABI().EmitNullMemberFunctionPointer(CGF, - E->getType()->getAs<MemberPointerType>(), - DestPtr, VolatileDest); - - break; - } - case CastExpr::CK_LValueBitCast: llvm_unreachable("there are no lvalue bit-casts on aggregates"); break; - - case CastExpr::CK_BitCast: { - // This must be a member function pointer cast. - Visit(E->getSubExpr()); - break; - } - - case CastExpr::CK_DerivedToBaseMemberPointer: - case CastExpr::CK_BaseToDerivedMemberPointer: { - QualType SrcType = E->getSubExpr()->getType(); - - llvm::Value *Src = CGF.CreateMemTemp(SrcType, "tmp"); - CGF.EmitAggExpr(E->getSubExpr(), Src, SrcType.isVolatileQualified()); - - // Note that the AST doesn't distinguish between checked and - // unchecked member pointer conversions, so we always have to - // implement checked conversions here. This is inefficient for - // ABIs where an actual null check is thus required; fortunately, - // the Itanium and ARM ABIs ignore the adjustment value when - // considering null-ness. - CGF.CGM.getCXXABI().EmitMemberFunctionPointerConversion(CGF, E, Src, - DestPtr, VolatileDest); - break; - } } } @@ -362,23 +324,6 @@ void AggExprEmitter::VisitBinComma(const BinaryOperator *E) { /*IgnoreResult=*/false, IsInitializer); } -void AggExprEmitter::VisitUnaryAddrOf(const UnaryOperator *E) { - // We have a member function pointer. - assert(E->getType()->getAs<MemberPointerType>() - ->getPointeeType()->isFunctionProtoType() && - "Unexpected member pointer type!"); - - // The creation of member function pointers has no side effects; if - // there is no destination pointer, we have nothing to do. - if (!DestPtr) - return; - - const DeclRefExpr *DRE = cast<DeclRefExpr>(E->getSubExpr()); - const CXXMethodDecl *MD = cast<CXXMethodDecl>(DRE->getDecl()); - - CGF.CGM.getCXXABI().EmitMemberFunctionPointer(CGF, MD, DestPtr, VolatileDest); -} - void AggExprEmitter::VisitStmtExpr(const StmtExpr *E) { CGF.EmitCompoundStmt(*E->getSubStmt(), true, DestPtr, VolatileDest); } diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index fb5414016a..ad65b105f6 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -160,8 +160,7 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl()); // Get the member function pointer. - llvm::Value *MemFnPtr = CreateMemTemp(MemFnExpr->getType(), "mem.fn"); - EmitAggExpr(MemFnExpr, MemFnPtr, /*VolatileDest=*/false); + llvm::Value *MemFnPtr = EmitScalarExpr(MemFnExpr); // Emit the 'this' pointer. llvm::Value *This; diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index e0335b6559..b97e725ae8 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -460,7 +460,7 @@ public: llvm::Constant *VisitUnaryAddrOf(UnaryOperator *E) { if (const MemberPointerType *MPT = - E->getType()->getAs<MemberPointerType>()) { + E->getType()->getAs<MemberPointerType>()) { QualType T = MPT->getPointeeType(); DeclRefExpr *DRE = cast<DeclRefExpr>(E->getSubExpr()); @@ -533,13 +533,21 @@ public: llvm::StructType::get(C->getType()->getContext(), Types, false); return llvm::ConstantStruct::get(STy, Elts); } - case CastExpr::CK_NullToMemberPointer: - return CGM.getCXXABI().EmitNullMemberFunctionPointer( - E->getType()->getAs<MemberPointerType>()); + case CastExpr::CK_NullToMemberPointer: { + const MemberPointerType *MPT = E->getType()->getAs<MemberPointerType>(); + if (MPT->getPointeeType()->isFunctionType()) + return CGM.getCXXABI().EmitNullMemberFunctionPointer(MPT); + return CGM.EmitNullConstant(E->getType()); + } case CastExpr::CK_BaseToDerivedMemberPointer: { - Expr *SubExpr = E->getSubExpr(); + const MemberPointerType *MPT = E->getType()->getAs<MemberPointerType>(); + // TODO: support data-member conversions here! + if (!MPT->getPointeeType()->isFunctionType()) + return 0; + + Expr *SubExpr = E->getSubExpr(); llvm::Constant *C = CGM.EmitConstantExpr(SubExpr, SubExpr->getType(), CGF); if (!C) return 0; diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index d65c22a723..38a49ee138 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -238,6 +238,9 @@ public: Value *VisitUnaryAddrOf(const UnaryOperator *E) { + // If the sub-expression is an instance member reference, + // EmitDeclRefLValue will magically emit it with the appropriate + // value as the "address". return EmitLValue(E->getSubExpr()).getAddress(); } Value *VisitUnaryDeref(const Expr *E) { return EmitLoadOfLValue(E); } @@ -995,11 +998,31 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { return EmitLValue(E).getAddress(); case CastExpr::CK_NullToMemberPointer: + // If the subexpression's type is the C++0x nullptr_t, emit the + // subexpression, which may have side effects. + if (E->getType()->isNullPtrType()) + (void) Visit(E); + + if (CE->getType()->isMemberFunctionPointerType()) + return CGF.CGM.getCXXABI().EmitNullMemberFunctionPointer( + CE->getType()->getAs<MemberPointerType>()); + return CGF.CGM.EmitNullConstant(DestTy); case CastExpr::CK_BaseToDerivedMemberPointer: case CastExpr::CK_DerivedToBaseMemberPointer: { Value *Src = Visit(E); + + // Note that the AST doesn't distinguish between checked and + // unchecked member pointer conversions, so we always have to + // implement checked conversions here. This is inefficient when + // actual control flow may be required in order to perform the + // check, which it is for data member pointers (but not member + // function pointers on Itanium and ARM). + + if (CE->getType()->isMemberFunctionPointerType()) + return CGF.CGM.getCXXABI().EmitMemberFunctionPointerConversion(CGF, CE, + Src); // See if we need to adjust the pointer. const CXXRecordDecl *BaseDecl = @@ -1804,10 +1827,10 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc, if (LHSTy->isMemberFunctionPointerType()) { assert(E->getOpcode() == BinaryOperator::EQ || E->getOpcode() == BinaryOperator::NE); - Value *LHSPtr = CGF.EmitAnyExprToTemp(E->getLHS()).getAggregateAddr(); - Value *RHSPtr = CGF.EmitAnyExprToTemp(E->getRHS()).getAggregateAddr(); + Value *LHS = CGF.EmitScalarExpr(E->getLHS()); + Value *RHS = CGF.EmitScalarExpr(E->getRHS()); Result = CGF.CGM.getCXXABI().EmitMemberFunctionPointerComparison( - CGF, LHSPtr, RHSPtr, LHSTy->getAs<MemberPointerType>(), + CGF, LHS, RHS, LHSTy->getAs<MemberPointerType>(), E->getOpcode() == BinaryOperator::NE); } else if (!LHSTy->isAnyComplexType()) { Value *LHS = Visit(E->getLHS()); diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index ca4e698229..91442fa362 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -77,7 +77,7 @@ const llvm::Type *CodeGenFunction::ConvertType(QualType T) { bool CodeGenFunction::hasAggregateLLVMType(QualType T) { return T->isRecordType() || T->isArrayType() || T->isAnyComplexType() || - T->isMemberFunctionPointerType() || T->isObjCObjectType(); + T->isObjCObjectType(); } void CodeGenFunction::EmitReturnBlock() { diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index cd8b278fb5..efaddf217b 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -31,12 +31,11 @@ using namespace CodeGen; namespace { class ItaniumCXXABI : public CodeGen::CGCXXABI { protected: - CodeGenModule &CGM; CodeGen::MangleContext MangleCtx; bool IsARM; public: ItaniumCXXABI(CodeGen::CodeGenModule &CGM, bool IsARM = false) : - CGM(CGM), MangleCtx(CGM.getContext(), CGM.getDiags()), IsARM(IsARM) { } + CGCXXABI(CGM), MangleCtx(CGM.getContext(), CGM.getDiags()), IsARM(IsARM) { } CodeGen::MangleContext &getMangleContext() { return MangleCtx; @@ -50,27 +49,15 @@ public: llvm::Value *MemFnPtr, const MemberPointerType *MPT); - void EmitMemberFunctionPointerConversion(CodeGenFunction &CGF, - const CastExpr *E, - llvm::Value *Src, - llvm::Value *Dest, - bool VolatileDest); + llvm::Value *EmitMemberFunctionPointerConversion(CodeGenFunction &CGF, + const CastExpr *E, + llvm::Value *Src); llvm::Constant *EmitMemberFunctionPointerConversion(llvm::Constant *C, const CastExpr *E); - void EmitNullMemberFunctionPointer(CodeGenFunction &CGF, - const MemberPointerType *MPT, - llvm::Value *Dest, - bool VolatileDest); - llvm::Constant *EmitNullMemberFunctionPointer(const MemberPointerType *MPT); - void EmitMemberFunctionPointer(CodeGenFunction &CGF, - const CXXMethodDecl *MD, - llvm::Value *Dest, - bool VolatileDest); - llvm::Constant *EmitMemberFunctionPointer(const CXXMethodDecl *MD); llvm::Value *EmitMemberFunctionPointerComparison(CodeGenFunction &CGF, @@ -104,57 +91,6 @@ CodeGen::CGCXXABI *CodeGen::CreateARMCXXABI(CodeGenModule &CGM) { void ItaniumCXXABI::GetMemberFunctionPointer(const CXXMethodDecl *MD, llvm::Constant *(&MemPtr)[2]) { - 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()); - - // Get the function pointer (or index if this is a virtual function). - if (MD->isVirtual()) { - uint64_t Index = CGM.getVTables().getMethodVTableIndex(MD); - - // FIXME: We shouldn't use / 8 here. - uint64_t PointerWidthInBytes = - CGM.getContext().Target.getPointerWidth(0) / 8; - uint64_t VTableOffset = (Index * PointerWidthInBytes); - - if (IsARM) { - // ARM C++ ABI 3.2.1: - // This ABI specifies that adj contains twice the this - // adjustment, plus 1 if the member function is virtual. The - // least significant bit of adj then makes exactly the same - // discrimination as the least significant bit of ptr does for - // Itanium. - MemPtr[0] = llvm::ConstantInt::get(ptrdiff_t, VTableOffset); - MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 1); - } else { - // Itanium C++ ABI 2.3: - // For a virtual function, [the pointer field] is 1 plus the - // virtual table offset (in bytes) of the function, - // represented as a ptrdiff_t. - MemPtr[0] = llvm::ConstantInt::get(ptrdiff_t, VTableOffset + 1); - MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 0); - } - } else { - const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); - const llvm::Type *Ty; - // Check whether the function has a computable LLVM signature. - if (!CodeGenTypes::VerifyFuncTypeComplete(FPT)) { - // The function has a computable LLVM signature; use the correct type. - Ty = Types.GetFunctionType(Types.getFunctionInfo(MD), FPT->isVariadic()); - } else { - // Use an arbitrary non-function type to tell GetAddrOfFunction that the - // function type is incomplete. - Ty = ptrdiff_t; - } - - llvm::Constant *Addr = CGM.GetAddrOfFunction(MD, Ty); - MemPtr[0] = llvm::ConstantExpr::getPtrToInt(Addr, ptrdiff_t); - MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 0); - } } @@ -201,9 +137,8 @@ ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, llvm::BasicBlock *FnNonVirtual = CGF.createBasicBlock("memptr.nonvirtual"); llvm::BasicBlock *FnEnd = CGF.createBasicBlock("memptr.end"); - // Load memptr.adj, which is in the second field. - llvm::Value *RawAdj = Builder.CreateStructGEP(MemFnPtr, 1); - RawAdj = Builder.CreateLoad(RawAdj, "memptr.adj"); + // Extract memptr.adj, which is in the second field. + llvm::Value *RawAdj = Builder.CreateExtractValue(MemFnPtr, 1, "memptr.adj"); // Compute the true adjustment. llvm::Value *Adj = RawAdj; @@ -217,8 +152,7 @@ ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, This = Builder.CreateBitCast(Ptr, This->getType(), "this.adjusted"); // Load the function pointer. - llvm::Value *FnPtr = Builder.CreateStructGEP(MemFnPtr, 0); - llvm::Value *FnAsInt = Builder.CreateLoad(FnPtr, "memptr.ptr"); + llvm::Value *FnAsInt = Builder.CreateExtractValue(MemFnPtr, 0, "memptr.ptr"); // If the LSB in the function pointer is 1, the function pointer points to // a virtual function. @@ -266,14 +200,16 @@ ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, } /// Perform a derived-to-base or base-to-derived member pointer conversion. -void ItaniumCXXABI::EmitMemberFunctionPointerConversion(CodeGenFunction &CGF, - const CastExpr *E, - llvm::Value *Src, - llvm::Value *Dest, - bool VolatileDest) { +llvm::Value * +ItaniumCXXABI::EmitMemberFunctionPointerConversion(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); + CGBuilderTy &Builder = CGF.Builder; const MemberPointerType *SrcTy = @@ -283,17 +219,6 @@ void ItaniumCXXABI::EmitMemberFunctionPointerConversion(CodeGenFunction &CGF, const CXXRecordDecl *SrcDecl = SrcTy->getClass()->getAsCXXRecordDecl(); const CXXRecordDecl *DestDecl = DestTy->getClass()->getAsCXXRecordDecl(); - llvm::Value *SrcPtr = Builder.CreateStructGEP(Src, 0, "src.ptr"); - SrcPtr = Builder.CreateLoad(SrcPtr); - - llvm::Value *SrcAdj = Builder.CreateStructGEP(Src, 1, "src.adj"); - SrcAdj = Builder.CreateLoad(SrcAdj); - - llvm::Value *DstPtr = Builder.CreateStructGEP(Dest, 0, "dst.ptr"); - Builder.CreateStore(SrcPtr, DstPtr, VolatileDest); - - llvm::Value *DstAdj = Builder.CreateStructGEP(Dest, 1, "dst.adj"); - bool DerivedToBase = E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer; @@ -303,24 +228,33 @@ void ItaniumCXXABI::EmitMemberFunctionPointerConversion(CodeGenFunction &CGF, else BaseDecl = SrcDecl, DerivedDecl = DestDecl; - if (llvm::Constant *Adj = - CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, - E->path_begin(), - E->path_end())) { - // 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); - } + llvm::Constant *Adj = + CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, + E->path_begin(), + E->path_end()); + if (!Adj) return Src; - if (DerivedToBase) - SrcAdj = Builder.CreateSub(SrcAdj, Adj, "adj"); - else - SrcAdj = Builder.CreateAdd(SrcAdj, Adj, "adj"); - } + llvm::Value *SrcPtr = Builder.CreateExtractValue(Src, 0, "src.ptr"); + llvm::Value *SrcAdj = Builder.CreateExtractValue(Src, 1, "src.adj"); + + llvm::Value *Result = llvm::UndefValue::get(Src->getType()); + Result = Builder.CreateInsertValue(Result, SrcPtr, 0); - Builder.CreateStore(SrcAdj, DstAdj, VolatileDest); + // 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); + } + + llvm::Value *DstAdj; + if (DerivedToBase) + DstAdj = Builder.CreateSub(SrcAdj, Adj, "adj"); + else + DstAdj = Builder.CreateAdd(SrcAdj, Adj, "adj"); + + Result = Builder.CreateInsertValue(Result, DstAdj, 1); + return Result; } llvm::Constant * @@ -366,53 +300,73 @@ ItaniumCXXABI::EmitMemberFunctionPointerConversion(llvm::Constant *C, } -void ItaniumCXXABI::EmitNullMemberFunctionPointer(CodeGenFunction &CGF, - const MemberPointerType *MPT, - llvm::Value *Dest, - bool VolatileDest) { - // Should this be "unabstracted" and implemented in terms of the - // Constant version? - - CGBuilderTy &Builder = CGF.Builder; - - const llvm::IntegerType *PtrDiffTy = CGF.IntPtrTy; - llvm::Value *Zero = llvm::ConstantInt::get(PtrDiffTy, 0); - - llvm::Value *Ptr = Builder.CreateStructGEP(Dest, 0, "ptr"); - Builder.CreateStore(Zero, Ptr, VolatileDest); - - llvm::Value *Adj = Builder.CreateStructGEP(Dest, 1, "adj"); - Builder.CreateStore(Zero, Adj, VolatileDest); -} - llvm::Constant * ItaniumCXXABI::EmitNullMemberFunctionPointer(const MemberPointerType *MPT) { - return CGM.EmitNullConstant(QualType(MPT, 0)); + const llvm::Type *ptrdiff_t = + CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType()); + + llvm::Constant *Zero = llvm::ConstantInt::get(ptrdiff_t, 0); + llvm::Constant *Values[2] = { Zero, Zero }; + return llvm::ConstantStruct::get(CGM.getLLVMContext(), Values, 2, + /*Packed=*/false); } llvm::Constant * ItaniumCXXABI::EmitMemberFunctionPointer(const CXXMethodDecl *MD) { - llvm::Constant *Values[2]; - GetMemberFunctionPointer(MD, Values); - - return llvm::ConstantStruct::get(CGM.getLLVMContext(), - Values, 2, /*Packed=*/false); -} + assert(MD->isInstance() && "Member function must not be static!"); + MD = MD->getCanonicalDecl(); -void ItaniumCXXABI::EmitMemberFunctionPointer(CodeGenFunction &CGF, - const CXXMethodDecl *MD, - llvm::Value *DestPtr, - bool VolatileDest) { - llvm::Constant *Values[2]; - GetMemberFunctionPointer(MD, Values); + CodeGenTypes &Types = CGM.getTypes(); + const llvm::Type *ptrdiff_t = + Types.ConvertType(CGM.getContext().getPointerDiffType()); - CGBuilderTy &Builder = CGF.Builder; - - llvm::Value *DstPtr = Builder.CreateStructGEP(DestPtr, 0, "memptr.ptr"); - Builder.CreateStore(Values[0], DstPtr, VolatileDest); + // Get the function pointer (or index if this is a virtual function). + llvm::Constant *MemPtr[2]; + if (MD->isVirtual()) { + uint64_t Index = CGM.getVTables().getMethodVTableIndex(MD); - llvm::Value *AdjPtr = Builder.CreateStructGEP(DestPtr, 1, "memptr.adj"); - Builder.CreateStore(Values[1], AdjPtr, VolatileDest); + // FIXME: We shouldn't use / 8 here. + uint64_t PointerWidthInBytes = + CGM.getContext().Target.getPointerWidth(0) / 8; + uint64_t VTableOffset = (Index * PointerWidthInBytes); + + if (IsARM) { + // ARM C++ ABI 3.2.1: + // This ABI specifies that adj contains twice the this + // adjustment, plus 1 if the member function is virtual. The + // least significant bit of adj then makes exactly the same + // discrimination as the least significant bit of ptr does for + // Itanium. + MemPtr[0] = llvm::ConstantInt::get(ptrdiff_t, VTableOffset); + MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 1); + } else { + // Itanium C++ ABI 2.3: + // For a virtual function, [the pointer field] is 1 plus the + // virtual table offset (in bytes) of the function, + // represented as a ptrdiff_t. + MemPtr[0] = llvm::ConstantInt::get(ptrdiff_t, VTableOffset + 1); + MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 0); + } + } else { + const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); + const llvm::Type *Ty; + // Check whether the function has a computable LLVM signature. + if (!CodeGenTypes::VerifyFuncTypeComplete(FPT)) { + // The function has a computable LLVM signature; use the correct type. + Ty = Types.GetFunctionType(Types.getFunctionInfo(MD), FPT->isVariadic()); + } else { + // Use an arbitrary non-function type to tell GetAddrOfFunction that the + // function type is incomplete. + Ty = ptrdiff_t; + } + + llvm::Constant *Addr = CGM.GetAddrOfFunction(MD, Ty); + MemPtr[0] = llvm::ConstantExpr::getPtrToInt(Addr, ptrdiff_t); + MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 0); + } + + return llvm::ConstantStruct::get(CGM.getLLVMContext(), + MemPtr, 2, /*Packed=*/false); } /// The comparison algorithm is pretty easy: the member pointers are @@ -427,10 +381,8 @@ ItaniumCXXABI::EmitMemberFunctionPointerComparison(CodeGenFunction &CGF, bool Inequality) { CGBuilderTy &Builder = CGF.Builder; - llvm::Value *LPtr = Builder.CreateLoad(Builder.CreateStructGEP(L, 0), - "lhs.memptr.ptr"); - llvm::Value *RPtr = Builder.CreateLoad(Builder.CreateStructGEP(R, 0), - "rhs.memptr.ptr"); + 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)) @@ -465,10 +417,8 @@ ItaniumCXXABI::EmitMemberFunctionPointerComparison(CodeGenFunction &CGF, // This condition tests whether L.adj == R.adj. If this isn't // true, the pointers are unequal unless they're both null. - llvm::Value *LAdj = Builder.CreateLoad(Builder.CreateStructGEP(L, 1), - "lhs.memptr.adj"); - llvm::Value *RAdj = Builder.CreateLoad(Builder.CreateStructGEP(R, 1), - "rhs.memptr.adj"); + llvm::Value *LAdj = Builder.CreateExtractValue(L, 1, "lhs.memptr.adj"); + llvm::Value *RAdj = Builder.CreateExtractValue(R, 1, "rhs.memptr.adj"); llvm::Value *AdjEq = Builder.CreateICmp(Eq, LAdj, RAdj, "cmp.adj"); // Null member function pointers on ARM clear the low bit of Adj, @@ -498,8 +448,7 @@ ItaniumCXXABI::EmitMemberFunctionPointerIsNotNull(CodeGenFunction &CGF, CGBuilderTy &Builder = CGF.Builder; // In Itanium, a member function pointer is null if 'ptr' is null. - llvm::Value *Ptr = - Builder.CreateLoad(Builder.CreateStructGEP(MemPtr, 0), "memptr.ptr"); + llvm::Value *Ptr = Builder.CreateExtractValue(MemPtr, 0, "memptr.ptr"); llvm::Constant *Zero = llvm::ConstantInt::get(Ptr->getType(), 0); llvm::Value *Result = Builder.CreateICmpNE(Ptr, Zero, "memptr.tobool"); @@ -507,8 +456,7 @@ ItaniumCXXABI::EmitMemberFunctionPointerIsNotNull(CodeGenFunction &CGF, // In ARM, it's that, plus the low bit of 'adj' must be zero. if (IsARM) { llvm::Constant *One = llvm::ConstantInt::get(Ptr->getType(), 1); - llvm::Value *Adj = - Builder.CreateLoad(Builder.CreateStructGEP(MemPtr, 1), "memptr.adj"); + llvm::Value *Adj = Builder.CreateExtractValue(MemPtr, 1, "memptr.adj"); llvm::Value *VirtualBit = Builder.CreateAnd(Adj, One, "memptr.virtualbit"); llvm::Value *IsNotVirtual = Builder.CreateICmpEQ(VirtualBit, Zero, "me |