diff options
author | John McCall <rjmccall@apple.com> | 2010-08-22 08:30:07 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2010-08-22 08:30:07 +0000 |
commit | 131d97d80923ab4a068ee8a5fc3dbed5c97bd15e (patch) | |
tree | 08df0959e02fb7a55a482106c11d0425603d7cf7 /clang/lib/CodeGen | |
parent | 6f33bd9345dd9610676450b86ac5758704628ede (diff) | |
download | bcm5719-llvm-131d97d80923ab4a068ee8a5fc3dbed5c97bd15e.tar.gz bcm5719-llvm-131d97d80923ab4a068ee8a5fc3dbed5c97bd15e.zip |
Extract member function pointer comparison and null comparison into
the ABI code. Implement correct semantics for these on ARM.
I believe this completes the implementation of member function pointers
on ARM.
I think I'm going to switch member function pointers over to be
non-aggregates while I have all this in mind.
llvm-svn: 111774
Diffstat (limited to 'clang/lib/CodeGen')
-rw-r--r-- | clang/lib/CodeGen/CGCXX.cpp | 18 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGCXXABI.h | 12 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExpr.cpp | 14 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExprScalar.cpp | 29 | ||||
-rw-r--r-- | clang/lib/CodeGen/ItaniumCXXABI.cpp | 112 |
5 files changed, 150 insertions, 35 deletions
diff --git a/clang/lib/CodeGen/CGCXX.cpp b/clang/lib/CodeGen/CGCXX.cpp index 29346575319..2d7b27b18b5 100644 --- a/clang/lib/CodeGen/CGCXX.cpp +++ b/clang/lib/CodeGen/CGCXX.cpp @@ -369,6 +369,24 @@ void CGCXXABI::EmitMemberFunctionPointer(CodeGenFunction &CGF, ErrorUnsupportedABI(CGF, "member function pointers"); } +llvm::Value * +CGCXXABI::EmitMemberFunctionPointerComparison(CodeGenFunction &CGF, + llvm::Value *L, + llvm::Value *R, + const MemberPointerType *MPT, + bool Inequality) { + ErrorUnsupportedABI(CGF, "member function pointer comparison"); + return CGF.Builder.getFalse(); +} + +llvm::Value * +CGCXXABI::EmitMemberFunctionPointerIsNotNull(CodeGenFunction &CGF, + llvm::Value *MemPtr, + const MemberPointerType *MPT) { + ErrorUnsupportedABI(CGF, "member function pointer null testing"); + return CGF.Builder.getFalse(); +} + llvm::Constant * CGCXXABI::EmitMemberFunctionPointerConversion(llvm::Constant *C, const CastExpr *E) { diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h index a07b98c1eae..8478df48160 100644 --- a/clang/lib/CodeGen/CGCXXABI.h +++ b/clang/lib/CodeGen/CGCXXABI.h @@ -77,6 +77,18 @@ public: const CXXMethodDecl *MD, llvm::Value *DestPtr, bool VolatileDest); + + virtual llvm::Value * + EmitMemberFunctionPointerComparison(CodeGenFunction &CGF, + llvm::Value *L, + llvm::Value *R, + const MemberPointerType *MPT, + bool Inequality); + + virtual llvm::Value * + EmitMemberFunctionPointerIsNotNull(CodeGenFunction &CGF, + llvm::Value *Addr, + const MemberPointerType *MPT); }; /// Creates an instance of a C++ ABI class. diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index cbe19825f9b..753af76bf24 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -69,17 +69,9 @@ llvm::Value *CodeGenFunction::EvaluateExprAsBool(const Expr *E) { if (E->getType()->isMemberFunctionPointerType()) { LValue LV = EmitAggExprToLValue(E); - // Get the pointer. - llvm::Value *FuncPtr = Builder.CreateStructGEP(LV.getAddress(), 0, - "src.ptr"); - FuncPtr = Builder.CreateLoad(FuncPtr); - - llvm::Value *IsNotNull = - Builder.CreateICmpNE(FuncPtr, - llvm::Constant::getNullValue(FuncPtr->getType()), - "tobool"); - - return IsNotNull; + return CGM.getCXXABI().EmitMemberFunctionPointerIsNotNull(CGF, + LV.getAddress(), + E->getType()->getAs<MemberPointerType>()); } if (!E->getType()->isAnyComplexType()) return EmitScalarConversion(EmitScalarExpr(E), E->getType(), BoolTy); diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index ef4577435cf..d65c22a723a 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -1802,32 +1802,13 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc, Value *Result; QualType LHSTy = E->getLHS()->getType(); 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(); - llvm::Value *LHSFunc = Builder.CreateStructGEP(LHSPtr, 0); - LHSFunc = Builder.CreateLoad(LHSFunc); - llvm::Value *RHSFunc = Builder.CreateStructGEP(RHSPtr, 0); - RHSFunc = Builder.CreateLoad(RHSFunc); - Value *ResultF = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc, - LHSFunc, RHSFunc, "cmp.func"); - Value *NullPtr = llvm::Constant::getNullValue(LHSFunc->getType()); - Value *ResultNull = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc, - LHSFunc, NullPtr, "cmp.null"); - llvm::Value *LHSAdj = Builder.CreateStructGEP(LHSPtr, 1); - LHSAdj = Builder.CreateLoad(LHSAdj); - llvm::Value *RHSAdj = Builder.CreateStructGEP(RHSPtr, 1); - RHSAdj = Builder.CreateLoad(RHSAdj); - Value *ResultA = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc, - LHSAdj, RHSAdj, "cmp.adj"); - if (E->getOpcode() == BinaryOperator::EQ) { - Result = Builder.CreateOr(ResultNull, ResultA, "or.na"); - Result = Builder.CreateAnd(Result, ResultF, "and.f"); - } else { - assert(E->getOpcode() == BinaryOperator::NE && - "Member pointer comparison other than == or != ?"); - Result = Builder.CreateAnd(ResultNull, ResultA, "and.na"); - Result = Builder.CreateOr(Result, ResultF, "or.f"); - } + Result = CGF.CGM.getCXXABI().EmitMemberFunctionPointerComparison( + CGF, LHSPtr, RHSPtr, LHSTy->getAs<MemberPointerType>(), + E->getOpcode() == BinaryOperator::NE); } else if (!LHSTy->isAnyComplexType()) { Value *LHS = Visit(E->getLHS()); Value *RHS = Visit(E->getRHS()); diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index ac394956c8d..cd8b278fb55 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -73,6 +73,16 @@ public: llvm::Constant *EmitMemberFunctionPointer(const CXXMethodDecl *MD); + llvm::Value *EmitMemberFunctionPointerComparison(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]); @@ -405,6 +415,108 @@ void ItaniumCXXABI::EmitMemberFunctionPointer(CodeGenFunction &CGF, Builder.CreateStore(Values[1], AdjPtr, VolatileDest); } +/// The comparison algorithm is pretty easy: the member pointers are +/// the same if they're either bitwise identical *or* both null. +/// +/// 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) { + 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"); + + // 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) { + 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; + } + + // 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"); + + // This condition, together with the assumption that L.ptr == R.ptr, + // tests whether the pointers are both null. ARM imposes an extra + // condition. + llvm::Value *Zero = llvm::Constant::getNullValue(LPtr->getType()); + llvm::Value *EqZero = Builder.CreateICmp(Eq, LPtr, Zero, "cmp.ptr.null"); + + // 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 *AdjEq = Builder.CreateICmp(Eq, LAdj, RAdj, "cmp.adj"); + + // Null member function pointers on ARM clear the low bit of Adj, + // so the zero condition has to check that neither low bit is set. + if (IsARM) { + llvm::Value *One = llvm::ConstantInt::get(LPtr->getType(), 1); + + // Compute (l.adj | r.adj) & 1 and test it against zero. + llvm::Value *OrAdj = Builder.CreateOr(LAdj, RAdj, "or.adj"); + llvm::Value *OrAdjAnd1 = Builder.CreateAnd(OrAdj, One); + llvm::Value *OrAdjAnd1EqZero = Builder.CreateICmp(Eq, OrAdjAnd1, Zero, + "cmp.or.adj"); + EqZero = Builder.CreateBinOp(And, EqZero, OrAdjAnd1EqZero); + } + + // Tie together all our conditions. + llvm::Value *Result = Builder.CreateBinOp(Or, EqZero, AdjEq); + Result = Builder.CreateBinOp(And, PtrEq, Result, + Inequality ? "memptr.ne" : "memptr.eq"); + return Result; +} + +llvm::Value * +ItaniumCXXABI::EmitMemberFunctionPointerIsNotNull(CodeGenFunction &CGF, + llvm::Value *MemPtr, + const MemberPointerType *MPT) { + 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::Constant *Zero = llvm::ConstantInt::get(Ptr->getType(), 0); + llvm::Value *Result = Builder.CreateICmpNE(Ptr, Zero, "memptr.tobool"); + + // 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 *VirtualBit = Builder.CreateAnd(Adj, One, "memptr.virtualbit"); + llvm::Value *IsNotVirtual = Builder.CreateICmpEQ(VirtualBit, Zero, + "memptr.notvirtual"); + Result = Builder.CreateAnd(Result, IsNotVirtual); + } + + return Result; +} bool ItaniumCXXABI::RequiresNonZeroInitializer(QualType T) { return CGM.getTypes().ContainsPointerToDataMember(T); |