[cfe-commits] r111766 - /cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp

John McCall rjmccall at apple.com
Sat Aug 21 17:59:17 PDT 2010


Author: rjmccall
Date: Sat Aug 21 19:59:17 2010
New Revision: 111766

URL: http://llvm.org/viewvc/llvm-project?rev=111766&view=rev
Log:
Implement the call parts of the member-function-pointer ARM C++ ABI.


Modified:
    cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp

Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=111766&r1=111765&r2=111766&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Sat Aug 21 19:59:17 2010
@@ -33,9 +33,10 @@
 protected:
   CodeGenModule &CGM;
   CodeGen::MangleContext MangleCtx;
+  bool IsARM;
 public:
-  ItaniumCXXABI(CodeGen::CodeGenModule &CGM) :
-    CGM(CGM), MangleCtx(CGM.getContext(), CGM.getDiags()) { }
+  ItaniumCXXABI(CodeGen::CodeGenModule &CGM, bool IsARM = false) :
+    CGM(CGM), MangleCtx(CGM.getContext(), CGM.getDiags()), IsARM(IsARM) { }
 
   CodeGen::MangleContext &getMangleContext() {
     return MangleCtx;
@@ -49,7 +50,7 @@
 
 class ARMCXXABI : public ItaniumCXXABI {
 public:
-  ARMCXXABI(CodeGen::CodeGenModule &CGM) : ItaniumCXXABI(CGM) {}
+  ARMCXXABI(CodeGen::CodeGenModule &CGM) : ItaniumCXXABI(CGM, /*ARM*/ true) {}
 };
 }
 
@@ -61,6 +62,26 @@
   return new ARMCXXABI(CGM);
 }
 
+/// In the Itanium and ARM ABIs, method pointers have the form:
+///   struct { ptrdiff_t ptr; ptrdiff_t adj; } memptr;
+///
+/// In the Itanium ABI:
+///  - method pointers are virtual if (memptr.ptr & 1) is nonzero
+///  - the this-adjustment is (memptr.adj)
+///  - the virtual offset is (memptr.ptr - 1)
+///
+/// In the ARM ABI:
+///  - method pointers are virtual if (memptr.adj & 1) is nonzero
+///  - the this-adjustment is (memptr.adj >> 1)
+///  - the virtual offset is (memptr.ptr)
+/// ARM uses 'adj' for the virtual flag because Thumb functions
+/// may be only single-byte aligned.
+///
+/// If the member is virtual, the adjusted 'this' pointer points
+/// to a vtable pointer from which the virtual offset is applied.
+///
+/// If the member is non-virtual, memptr.ptr is the address of
+/// the function to call.
 llvm::Value *
 ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
                                                llvm::Value *&This,
@@ -77,55 +98,67 @@
     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");
+  const llvm::IntegerType *ptrdiff = CGF.IntPtrTy;
+  llvm::Constant *ptrdiff_1 = llvm::ConstantInt::get(ptrdiff, 1);
+
+  llvm::BasicBlock *FnVirtual = CGF.createBasicBlock("memptr.virtual");
+  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");
+
+  // Compute the true adjustment.
+  llvm::Value *Adj = RawAdj;
+  if (IsARM)
+    Adj = Builder.CreateAShr(Adj, ptrdiff_1, "memptr.adj.shifted");
 
   // 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");
+  llvm::Value *Ptr = Builder.CreateBitCast(This, Builder.getInt8PtrTy());
+  Ptr = Builder.CreateInBoundsGEP(Ptr, Adj);
+  This = Builder.CreateBitCast(Ptr, This->getType(), "this.adjusted");
   
   // Load the function pointer.
-  llvm::Value *FnPtr = Builder.CreateStructGEP(MemFnPtr, 0, "mem.fn.ptr");
-  llvm::Value *FnAsInt = Builder.CreateLoad(FnPtr, "fn");
+  llvm::Value *FnPtr = Builder.CreateStructGEP(MemFnPtr, 0);
+  llvm::Value *FnAsInt = Builder.CreateLoad(FnPtr, "memptr.ptr");
   
   // 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);
+  llvm::Value *IsVirtual;
+  if (IsARM)
+    IsVirtual = Builder.CreateAnd(RawAdj, ptrdiff_1);
+  else
+    IsVirtual = Builder.CreateAnd(FnAsInt, ptrdiff_1);
+  IsVirtual = Builder.CreateIsNotNull(IsVirtual, "memptr.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).
+  // offset within the vtable (+1 for the virtual flag on non-ARM).
   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);
+  VTable = Builder.CreateLoad(VTable, "memptr.vtable");
 
   // Apply the offset.
-  llvm::Value *VTableOffset = Builder.CreateSub(FnAsInt, iptr_1);
-  VTable = Builder.CreateGEP(VTable, VTableOffset, "fn");
+  llvm::Value *VTableOffset = FnAsInt;
+  if (!IsARM) VTableOffset = Builder.CreateSub(VTableOffset, ptrdiff_1);
+  VTable = Builder.CreateGEP(VTable, VTableOffset);
 
   // Load the virtual function to call.
   VTable = Builder.CreateBitCast(VTable, FTy->getPointerTo()->getPointerTo());
-  llvm::Value *VirtualFn = Builder.CreateLoad(VTable, "virtualfn");
+  llvm::Value *VirtualFn = Builder.CreateLoad(VTable, "memptr.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());
+    Builder.CreateIntToPtr(FnAsInt, FTy->getPointerTo(), "memptr.nonvirtualfn");
   
   // We're done.
   CGF.EmitBlock(FnEnd);





More information about the cfe-commits mailing list