]> granicus.if.org Git - clang/commitdiff
Extract member function pointer comparison and null comparison into
authorJohn McCall <rjmccall@apple.com>
Sun, 22 Aug 2010 08:30:07 +0000 (08:30 +0000)
committerJohn McCall <rjmccall@apple.com>
Sun, 22 Aug 2010 08:30:07 +0000 (08:30 +0000)
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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111774 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGCXX.cpp
lib/CodeGen/CGCXXABI.h
lib/CodeGen/CGExpr.cpp
lib/CodeGen/CGExprScalar.cpp
lib/CodeGen/ItaniumCXXABI.cpp

index 29346575319820d2eac892937bd9222c1ed6bca7..2d7b27b18b5754b79564134269bf6a677071293e 100644 (file)
@@ -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) {
index a07b98c1eaeb199edafbdac5cec7815f4e2924cf..8478df48160ed2643b86350139a5f5f1bb1d324e 100644 (file)
@@ -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.
index cbe19825f9bad7f9d99299ecef91b71fc3614224..753af76bf24d6210331171cba934a731cb7b86df 100644 (file)
@@ -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);
index ef4577435cfa4464f0788f5601a99df08831ec8b..d65c22a723a2ae4dd925be72f35f24639a26d900 100644 (file)
@@ -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());
index ac394956c8d3978282f598afd5861261c8317f87..cd8b278fb554684609661deb730f58920f721ec5 100644 (file)
@@ -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);