summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2010-08-22 08:30:07 +0000
committerJohn McCall <rjmccall@apple.com>2010-08-22 08:30:07 +0000
commit131d97d80923ab4a068ee8a5fc3dbed5c97bd15e (patch)
tree08df0959e02fb7a55a482106c11d0425603d7cf7 /clang/lib/CodeGen
parent6f33bd9345dd9610676450b86ac5758704628ede (diff)
downloadbcm5719-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.cpp18
-rw-r--r--clang/lib/CodeGen/CGCXXABI.h12
-rw-r--r--clang/lib/CodeGen/CGExpr.cpp14
-rw-r--r--clang/lib/CodeGen/CGExprScalar.cpp29
-rw-r--r--clang/lib/CodeGen/ItaniumCXXABI.cpp112
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);
OpenPOWER on IntegriCloud