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
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index cd8b278..efaddf2 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -31,12 +31,11 @@
 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 @@
                                                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 @@
 
 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 @@
   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 @@
   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 @@
 }
 
 /// 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 @@
   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 @@
   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 @@
 }        
 
 
-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);
+  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).
+  llvm::Constant *MemPtr[2];
+  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);
+  }
   
   return llvm::ConstantStruct::get(CGM.getLLVMContext(),
-                                   Values, 2, /*Packed=*/false);
-}
-
-void ItaniumCXXABI::EmitMemberFunctionPointer(CodeGenFunction &CGF,
-                                              const CXXMethodDecl *MD,
-                                              llvm::Value *DestPtr,
-                                              bool VolatileDest) {
-  llvm::Constant *Values[2];
-  GetMemberFunctionPointer(MD, Values);
-
-  CGBuilderTy &Builder = CGF.Builder;
-  
-  llvm::Value *DstPtr = Builder.CreateStructGEP(DestPtr, 0, "memptr.ptr");
-  Builder.CreateStore(Values[0], DstPtr, VolatileDest);
-
-  llvm::Value *AdjPtr = Builder.CreateStructGEP(DestPtr, 1, "memptr.adj");
-  Builder.CreateStore(Values[1], AdjPtr, VolatileDest);
+                                   MemPtr, 2, /*Packed=*/false);
 }
 
 /// The comparison algorithm is pretty easy: the member pointers are
@@ -427,10 +381,8 @@
                                                    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 @@
 
   // 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 @@
   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 @@
   // 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,
                                                      "memptr.notvirtual");