[cfe-commits] r111774 - in /cfe/trunk/lib/CodeGen: CGCXX.cpp CGCXXABI.h CGExpr.cpp CGExprScalar.cpp ItaniumCXXABI.cpp

John McCall rjmccall at apple.com
Sun Aug 22 01:30:07 PDT 2010


Author: rjmccall
Date: Sun Aug 22 03:30:07 2010
New Revision: 111774

URL: http://llvm.org/viewvc/llvm-project?rev=111774&view=rev
Log:
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.


Modified:
    cfe/trunk/lib/CodeGen/CGCXX.cpp
    cfe/trunk/lib/CodeGen/CGCXXABI.h
    cfe/trunk/lib/CodeGen/CGExpr.cpp
    cfe/trunk/lib/CodeGen/CGExprScalar.cpp
    cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp

Modified: cfe/trunk/lib/CodeGen/CGCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXX.cpp?rev=111774&r1=111773&r2=111774&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCXX.cpp Sun Aug 22 03:30:07 2010
@@ -369,6 +369,24 @@
   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) {

Modified: cfe/trunk/lib/CodeGen/CGCXXABI.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.h?rev=111774&r1=111773&r2=111774&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXXABI.h (original)
+++ cfe/trunk/lib/CodeGen/CGCXXABI.h Sun Aug 22 03:30:07 2010
@@ -77,6 +77,18 @@
                                          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.

Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=111774&r1=111773&r2=111774&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Sun Aug 22 03:30:07 2010
@@ -69,17 +69,9 @@
   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);

Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprScalar.cpp?rev=111774&r1=111773&r2=111774&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprScalar.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Sun Aug 22 03:30:07 2010
@@ -1802,32 +1802,13 @@
   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());

Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=111774&r1=111773&r2=111774&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Sun Aug 22 03:30:07 2010
@@ -73,6 +73,16 @@
 
   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 @@
   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);





More information about the cfe-commits mailing list