Extract calls to method pointers out as an ABI routine.
No functionality change.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111752 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index bd396d2..f9152db 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -19,21 +19,32 @@
 //===----------------------------------------------------------------------===//
 
 #include "CGCXXABI.h"
+#include "CodeGenFunction.h"
 #include "CodeGenModule.h"
 #include "Mangle.h"
+#include <clang/AST/Type.h>
+#include <llvm/Value.h>
 
 using namespace clang;
+using namespace CodeGen;
 
 namespace {
 class ItaniumCXXABI : public CodeGen::CGCXXABI {
+protected:
+  CodeGenModule &CGM;
   CodeGen::MangleContext MangleCtx;
 public:
   ItaniumCXXABI(CodeGen::CodeGenModule &CGM) :
-    MangleCtx(CGM.getContext(), CGM.getDiags()) { }
+    CGM(CGM), MangleCtx(CGM.getContext(), CGM.getDiags()) { }
 
   CodeGen::MangleContext &getMangleContext() {
     return MangleCtx;
   }
+
+  llvm::Value *EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
+                                               llvm::Value *&This,
+                                               llvm::Value *MemFnPtr,
+                                               const MemberPointerType *MPT);
 };
 
 class ARMCXXABI : public ItaniumCXXABI {
@@ -50,3 +61,77 @@
   return new ARMCXXABI(CGM);
 }
 
+llvm::Value *
+ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
+                                               llvm::Value *&This,
+                                               llvm::Value *MemFnPtr,
+                                               const MemberPointerType *MPT) {
+  CGBuilderTy &Builder = CGF.Builder;
+
+  const FunctionProtoType *FPT = 
+    MPT->getPointeeType()->getAs<FunctionProtoType>();
+  const CXXRecordDecl *RD = 
+    cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl());
+
+  const llvm::FunctionType *FTy = 
+    CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT),
+                                   FPT->isVariadic());
+
+  llvm::BasicBlock *FnVirtual = CGF.createBasicBlock("fn.virtual");
+  llvm::BasicBlock *FnNonVirtual = CGF.createBasicBlock("fn.nonvirtual");
+  llvm::BasicBlock *FnEnd = CGF.createBasicBlock("fn.end");
+
+  // Load the adjustment, which is in the second field.
+  llvm::Value *Adj = Builder.CreateStructGEP(MemFnPtr, 1);
+  Adj = Builder.CreateLoad(Adj, "mem.fn.adj");
+
+  // Apply the adjustment and cast back to the original struct type
+  // for consistency.
+  llvm::Value *Ptr = Builder.CreateBitCast(This, Builder.getInt8PtrTy(), "ptr");
+  Ptr = Builder.CreateInBoundsGEP(Ptr, Adj, "adj");
+  This = Builder.CreateBitCast(Ptr, This->getType(), "this");
+  
+  // Load the function pointer.
+  llvm::Value *FnPtr = Builder.CreateStructGEP(MemFnPtr, 0, "mem.fn.ptr");
+  llvm::Value *FnAsInt = Builder.CreateLoad(FnPtr, "fn");
+  
+  // If the LSB in the function pointer is 1, the function pointer points to
+  // a virtual function.
+  llvm::Constant *iptr_1 = llvm::ConstantInt::get(FnAsInt->getType(), 1);
+  llvm::Value *IsVirtual = Builder.CreateAnd(FnAsInt, iptr_1);
+  IsVirtual = Builder.CreateIsNotNull(IsVirtual);
+  Builder.CreateCondBr(IsVirtual, FnVirtual, FnNonVirtual);
+
+  // In the virtual path, the adjustment left 'This' pointing to the
+  // vtable of the correct base subobject.  The "function pointer" is an
+  // offset within the vtable (+1 for the virtual flag).
+  CGF.EmitBlock(FnVirtual);
+
+  // Cast the adjusted this to a pointer to vtable pointer and load.
+  const llvm::Type *VTableTy = Builder.getInt8PtrTy();
+  llvm::Value *VTable = Builder.CreateBitCast(This, VTableTy->getPointerTo());
+  VTable = Builder.CreateLoad(VTable);
+
+  // Apply the offset.
+  llvm::Value *VTableOffset = Builder.CreateSub(FnAsInt, iptr_1);
+  VTable = Builder.CreateGEP(VTable, VTableOffset, "fn");
+
+  // Load the virtual function to call.
+  VTable = Builder.CreateBitCast(VTable, FTy->getPointerTo()->getPointerTo());
+  llvm::Value *VirtualFn = Builder.CreateLoad(VTable, "virtualfn");
+  CGF.EmitBranch(FnEnd);
+
+  // In the non-virtual path, the function pointer is actually a
+  // function pointer.
+  CGF.EmitBlock(FnNonVirtual);
+  llvm::Value *NonVirtualFn =
+    Builder.CreateIntToPtr(FnAsInt, FTy->getPointerTo());
+  
+  // We're done.
+  CGF.EmitBlock(FnEnd);
+  llvm::PHINode *Callee = Builder.CreatePHI(FTy->getPointerTo());
+  Callee->reserveOperandSpace(2);
+  Callee->addIncoming(VirtualFn, FnVirtual);
+  Callee->addIncoming(NonVirtualFn, FnNonVirtual);
+  return Callee;
+}