[ms-cxxabi] Implement MSVC virtual base adjustment

While we can't yet emit vbtables, this allows us to find virtual bases
of objects constructed in other TUs.

This make iostream hello world work, since basic_ostream virtually
inherits from basic_ios.

Differential Revision: http://llvm-reviews.chandlerc.com/D795

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@182870 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h
index 7f72e1d..f64a633 100644
--- a/lib/CodeGen/CGCXXABI.h
+++ b/lib/CodeGen/CGCXXABI.h
@@ -208,6 +208,11 @@
                                               llvm::Value *ptr,
                                               QualType type) = 0;
 
+  virtual llvm::Value *GetVirtualBaseClassOffset(CodeGenFunction &CGF,
+                                                 llvm::Value *This,
+                                                 const CXXRecordDecl *ClassDecl,
+                                        const CXXRecordDecl *BaseClassDecl) = 0;
+
   /// Build the signature of the given constructor variant by adding
   /// any required parameters.  For convenience, ResTy has been
   /// initialized to 'void', and ArgTys has been initialized with the
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index e4180a0..b3a1477 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -198,7 +198,8 @@
   // Compute the virtual offset.
   llvm::Value *VirtualOffset = 0;
   if (VBase) {
-    VirtualOffset = GetVirtualBaseClassOffset(Value, Derived, VBase);
+    VirtualOffset =
+      CGM.getCXXABI().GetVirtualBaseClassOffset(*this, Value, Derived, VBase);
   }
 
   // Apply both offsets.
@@ -1872,28 +1873,6 @@
   PushDestructorCleanup(D, Addr);
 }
 
-llvm::Value *
-CodeGenFunction::GetVirtualBaseClassOffset(llvm::Value *This,
-                                           const CXXRecordDecl *ClassDecl,
-                                           const CXXRecordDecl *BaseClassDecl) {
-  llvm::Value *VTablePtr = GetVTablePtr(This, Int8PtrTy);
-  CharUnits VBaseOffsetOffset = 
-    CGM.getVTableContext().getVirtualBaseOffsetOffset(ClassDecl, BaseClassDecl);
-  
-  llvm::Value *VBaseOffsetPtr = 
-    Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetOffset.getQuantity(), 
-                               "vbase.offset.ptr");
-  llvm::Type *PtrDiffTy = 
-    ConvertType(getContext().getPointerDiffType());
-  
-  VBaseOffsetPtr = Builder.CreateBitCast(VBaseOffsetPtr, 
-                                         PtrDiffTy->getPointerTo());
-                                         
-  llvm::Value *VBaseOffset = Builder.CreateLoad(VBaseOffsetPtr, "vbase.offset");
-  
-  return VBaseOffset;
-}
-
 void
 CodeGenFunction::InitializeVTablePointer(BaseSubobject Base, 
                                          const CXXRecordDecl *NearestVBase,
@@ -1933,8 +1912,10 @@
   if (CodeGenVTables::needsVTTParameter(CurGD) && NearestVBase) {
     // We need to use the virtual base offset offset because the virtual base
     // might have a different offset in the most derived class.
-    VirtualOffset = GetVirtualBaseClassOffset(LoadCXXThis(), VTableClass, 
-                                              NearestVBase);
+    VirtualOffset = CGM.getCXXABI().GetVirtualBaseClassOffset(*this,
+                                                              LoadCXXThis(),
+                                                              VTableClass,
+                                                              NearestVBase);
     NonVirtualOffset = OffsetFromNearestVBase;
   } else {
     // We can just use the base offset in the complete class.
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 8917a90..03147e3 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -1975,10 +1975,6 @@
                                         CastExpr::path_const_iterator PathEnd,
                                         bool NullCheckValue);
 
-  llvm::Value *GetVirtualBaseClassOffset(llvm::Value *This,
-                                         const CXXRecordDecl *ClassDecl,
-                                         const CXXRecordDecl *BaseClassDecl);
-
   /// GetVTTParameter - Return the VTT parameter that should be passed to a
   /// base constructor/destructor with virtual bases.
   /// FIXME: VTTs are Itanium ABI-specific, so the definition should move
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index f786956..6cf95b5 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -98,6 +98,11 @@
                                       llvm::Value *ptr,
                                       QualType type);
 
+  llvm::Value *GetVirtualBaseClassOffset(CodeGenFunction &CGF,
+                                         llvm::Value *This,
+                                         const CXXRecordDecl *ClassDecl,
+                                         const CXXRecordDecl *BaseClassDecl);
+
   void BuildConstructorSignature(const CXXConstructorDecl *Ctor,
                                  CXXCtorType T,
                                  CanQualType &ResTy,
@@ -720,6 +725,27 @@
   return CGF.Builder.CreateInBoundsGEP(ptr, offset);
 }
 
+llvm::Value *
+ItaniumCXXABI::GetVirtualBaseClassOffset(CodeGenFunction &CGF,
+                                         llvm::Value *This,
+                                         const CXXRecordDecl *ClassDecl,
+                                         const CXXRecordDecl *BaseClassDecl) {
+  llvm::Value *VTablePtr = CGF.GetVTablePtr(This, CGM.Int8PtrTy);
+  CharUnits VBaseOffsetOffset =
+    CGM.getVTableContext().getVirtualBaseOffsetOffset(ClassDecl, BaseClassDecl);
+
+  llvm::Value *VBaseOffsetPtr =
+    CGF.Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetOffset.getQuantity(),
+                                   "vbase.offset.ptr");
+  VBaseOffsetPtr = CGF.Builder.CreateBitCast(VBaseOffsetPtr,
+                                             CGM.PtrDiffTy->getPointerTo());
+
+  llvm::Value *VBaseOffset =
+    CGF.Builder.CreateLoad(VBaseOffsetPtr, "vbase.offset");
+
+  return VBaseOffset;
+}
+
 /// The generic ABI passes 'this', plus a VTT if it's initializing a
 /// base subobject.
 void ItaniumCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor,
diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp
index 79af5af..c6614f2 100644
--- a/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -48,6 +48,11 @@
                                       llvm::Value *ptr,
                                       QualType type);
 
+  llvm::Value *GetVirtualBaseClassOffset(CodeGenFunction &CGF,
+                                         llvm::Value *This,
+                                         const CXXRecordDecl *ClassDecl,
+                                         const CXXRecordDecl *BaseClassDecl);
+
   void BuildConstructorSignature(const CXXConstructorDecl *Ctor,
                                  CXXCtorType Type,
                                  CanQualType &ResTy,
@@ -142,6 +147,22 @@
   GetNullMemberPointerFields(const MemberPointerType *MPT,
                              llvm::SmallVectorImpl<llvm::Constant *> &fields);
 
+  /// \brief Finds the offset from the base of RD to the vbptr it uses, even if
+  /// it is reusing a vbptr from a non-virtual base.  RD must have morally
+  /// virtual bases.
+  CharUnits GetVBPtrOffsetFromBases(const CXXRecordDecl *RD);
+
+  /// \brief Shared code for virtual base adjustment.  Returns the offset from
+  /// the vbptr to the virtual base.  Optionally returns the address of the
+  /// vbptr itself.
+  llvm::Value *GetVBaseOffsetFromVBPtr(CodeGenFunction &CGF,
+                                       llvm::Value *Base,
+                                       llvm::Value *VBPtrOffset,
+                                       llvm::Value *VBTableOffset,
+                                       llvm::Value **VBPtr = 0);
+
+  /// \brief Performs a full virtual base adjustment.  Used to dereference
+  /// pointers to members of virtual bases.
   llvm::Value *AdjustVirtualBase(CodeGenFunction &CGF, const CXXRecordDecl *RD,
                                  llvm::Value *Base,
                                  llvm::Value *VirtualBaseAdjustmentOffset,
@@ -212,6 +233,68 @@
   return ptr;
 }
 
+CharUnits MicrosoftCXXABI::GetVBPtrOffsetFromBases(const CXXRecordDecl *RD) {
+  assert(RD->getNumVBases());
+  CharUnits Total = CharUnits::Zero();
+  while (RD) {
+    const ASTRecordLayout &RDLayout = getContext().getASTRecordLayout(RD);
+    CharUnits VBPtrOffset = RDLayout.getVBPtrOffset();
+    // -1 is the sentinel for no vbptr.
+    if (VBPtrOffset != CharUnits::fromQuantity(-1)) {
+      Total += VBPtrOffset;
+      break;
+    }
+
+    // RD is reusing the vbptr of a non-virtual base.  Find it and continue.
+    const CXXRecordDecl *FirstNVBaseWithVBases = 0;
+    for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+         E = RD->bases_end(); I != E; ++I) {
+      const CXXRecordDecl *Base = I->getType()->getAsCXXRecordDecl();
+      if (!I->isVirtual() && Base->getNumVBases() > 0) {
+        FirstNVBaseWithVBases = Base;
+        break;
+      }
+    }
+    assert(FirstNVBaseWithVBases);
+    Total += RDLayout.getBaseClassOffset(FirstNVBaseWithVBases);
+    RD = FirstNVBaseWithVBases;
+  }
+  return Total;
+}
+
+llvm::Value *
+MicrosoftCXXABI::GetVirtualBaseClassOffset(CodeGenFunction &CGF,
+                                           llvm::Value *This,
+                                           const CXXRecordDecl *ClassDecl,
+                                           const CXXRecordDecl *BaseClassDecl) {
+  int64_t VBPtrChars = GetVBPtrOffsetFromBases(ClassDecl).getQuantity();
+  llvm::Value *VBPtrOffset = llvm::ConstantInt::get(CGM.PtrDiffTy, VBPtrChars);
+
+  // The vbtable is an array of i32 offsets.  The first entry is a self entry,
+  // and the rest are offsets from the vbptr to virtual bases.  The bases are
+  // ordered the same way our vbases are ordered: as they appear in a
+  // left-to-right depth-first search of the hierarchy.
+  unsigned VBTableIndex = 1;  // Start with one to skip the self entry.
+  for (CXXRecordDecl::base_class_const_iterator I = ClassDecl->vbases_begin(),
+       E = ClassDecl->vbases_end(); I != E; ++I) {
+    if (I->getType()->getAsCXXRecordDecl() == BaseClassDecl)
+      break;
+    VBTableIndex++;
+  }
+  assert(VBTableIndex != 1 + ClassDecl->getNumVBases() &&
+         "BaseClassDecl must be a vbase of ClassDecl");
+  CharUnits IntSize = getContext().getTypeSizeInChars(getContext().IntTy);
+  CharUnits VBTableChars = IntSize * VBTableIndex;
+  llvm::Value *VBTableOffset =
+    llvm::ConstantInt::get(CGM.IntTy, VBTableChars.getQuantity());
+
+  llvm::Value *VBPtrToNewBase =
+    GetVBaseOffsetFromVBPtr(CGF, This, VBTableOffset, VBPtrOffset);
+  VBPtrToNewBase =
+    CGF.Builder.CreateSExtOrBitCast(VBPtrToNewBase, CGM.PtrDiffTy);
+  return CGF.Builder.CreateNSWAdd(VBPtrOffset, VBPtrToNewBase);
+}
+
 bool MicrosoftCXXABI::needThisReturn(GlobalDecl GD) {
   const CXXMethodDecl* MD = cast<CXXMethodDecl>(GD.getDecl());
   return isa<CXXConstructorDecl>(MD);
@@ -781,12 +864,33 @@
   return I == E;
 }
 
+llvm::Value *
+MicrosoftCXXABI::GetVBaseOffsetFromVBPtr(CodeGenFunction &CGF,
+                                         llvm::Value *This,
+                                         llvm::Value *VBTableOffset,
+                                         llvm::Value *VBPtrOffset,
+                                         llvm::Value **VBPtrOut) {
+  CGBuilderTy &Builder = CGF.Builder;
+  // Load the vbtable pointer from the vbptr in the instance.
+  This = Builder.CreateBitCast(This, CGM.Int8PtrTy);
+  llvm::Value *VBPtr =
+    Builder.CreateInBoundsGEP(This, VBPtrOffset, "vbptr");
+  if (VBPtrOut) *VBPtrOut = VBPtr;
+  VBPtr = Builder.CreateBitCast(VBPtr, CGM.Int8PtrTy->getPointerTo(0));
+  llvm::Value *VBTable = Builder.CreateLoad(VBPtr, "vbtable");
+
+  // Load an i32 offset from the vb-table.
+  llvm::Value *VBaseOffs = Builder.CreateInBoundsGEP(VBTable, VBTableOffset);
+  VBaseOffs = Builder.CreateBitCast(VBaseOffs, CGM.Int32Ty->getPointerTo(0));
+  return Builder.CreateLoad(VBaseOffs, "vbase_offs");
+}
+
 // Returns an adjusted base cast to i8*, since we do more address arithmetic on
 // it.
 llvm::Value *
 MicrosoftCXXABI::AdjustVirtualBase(CodeGenFunction &CGF,
                                    const CXXRecordDecl *RD, llvm::Value *Base,
-                                   llvm::Value *VirtualBaseAdjustmentOffset,
+                                   llvm::Value *VBTableOffset,
                                    llvm::Value *VBPtrOffset) {
   CGBuilderTy &Builder = CGF.Builder;
   Base = Builder.CreateBitCast(Base, CGM.Int8PtrTy);
@@ -803,7 +907,7 @@
     VBaseAdjustBB = CGF.createBasicBlock("memptr.vadjust");
     SkipAdjustBB = CGF.createBasicBlock("memptr.skip_vadjust");
     llvm::Value *IsVirtual =
-      Builder.CreateICmpNE(VirtualBaseAdjustmentOffset, getZeroInt(),
+      Builder.CreateICmpNE(VBTableOffset, getZeroInt(),
                            "memptr.is_vbase");
     Builder.CreateCondBr(IsVirtual, VBaseAdjustBB, SkipAdjustBB);
     CGF.EmitBlock(VBaseAdjustBB);
@@ -812,21 +916,15 @@
   // If we weren't given a dynamic vbptr offset, RD should be complete and we'll
   // know the vbptr offset.
   if (!VBPtrOffset) {
-    CharUnits offs = getContext().getASTRecordLayout(RD).getVBPtrOffset();
+    CharUnits offs = CharUnits::Zero();
+    if (RD->getNumVBases()) {
+      offs = GetVBPtrOffsetFromBases(RD);
+    }
     VBPtrOffset = llvm::ConstantInt::get(CGM.IntTy, offs.getQuantity());
   }
-  // Load the vbtable pointer from the vbtable offset in the instance.
-  llvm::Value *VBPtr =
-    Builder.CreateInBoundsGEP(Base, VBPtrOffset, "memptr.vbptr");
-  llvm::Value *VBTable =
-    Builder.CreateBitCast(VBPtr, CGM.Int8PtrTy->getPointerTo(0));
-  VBTable = Builder.CreateLoad(VBTable, "memptr.vbtable");
-  // Load an i32 offset from the vb-table.
+  llvm::Value *VBPtr = 0;
   llvm::Value *VBaseOffs =
-    Builder.CreateInBoundsGEP(VBTable, VirtualBaseAdjustmentOffset);
-  VBaseOffs = Builder.CreateBitCast(VBaseOffs, CGM.Int32Ty->getPointerTo(0));
-  VBaseOffs = Builder.CreateLoad(VBaseOffs, "memptr.vbase_offs");
-  // Add it to VBPtr.  GEP will sign extend the i32 value for us.
+    GetVBaseOffsetFromVBPtr(CGF, Base, VBTableOffset, VBPtrOffset, &VBPtr);
   llvm::Value *AdjustedBase = Builder.CreateInBoundsGEP(VBPtr, VBaseOffs);
 
   // Merge control flow with the case where we didn't have to adjust.
diff --git a/test/CodeGenCXX/virtual-base-cast.cpp b/test/CodeGenCXX/virtual-base-cast.cpp
index f469636..40e68f6 100644
--- a/test/CodeGenCXX/virtual-base-cast.cpp
+++ b/test/CodeGenCXX/virtual-base-cast.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -emit-llvm %s -o - -triple i686-pc-linux-gnu | FileCheck %s
+// RUN: %clang_cc1 -cxx-abi microsoft -emit-llvm %s -o - -triple i686-pc-win32 | FileCheck -check-prefix MSVC %s
 
 struct A { int a; virtual int aa(); };
 struct B { int b; virtual int bb(); };
@@ -17,6 +18,16 @@
 // CHECK: load i32* [[CASTVBASEOFFSETPTRA]]
 // CHECK: }
 
+// MSVC: @"\01?a@@YAPAUA@@XZ"() [[NUW:#[0-9]+]] {
+// MSVC:   %[[vbptr_off:.*]] = getelementptr inbounds i8* {{.*}}, i32 0
+// MSVC:   %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to i8**
+// MSVC:   %[[vbtable:.*]] = load i8** %[[vbptr]]
+// MSVC:   %[[entry:.*]] = getelementptr inbounds i8* {{.*}}, i32 4
+// MSVC:   %[[entry_i32:.*]] = bitcast i8* %[[entry]] to i32*
+// MSVC:   %[[offset:.*]] = load i32* %[[entry_i32]]
+// MSVC:   add nsw i32 0, %[[offset]]
+// MSVC: }
+
 B* b() { return x; }
 // CHECK: @_Z1bv() [[NUW]]
 // CHECK: [[VBASEOFFSETPTRA:%[a-zA-Z0-9\.]+]] = getelementptr i8* {{.*}}, i64 -20
@@ -24,6 +35,18 @@
 // CHECK: load i32* [[CASTVBASEOFFSETPTRA]]
 // CHECK: }
 
+// Same as 'a' except we use a different vbtable offset.
+// MSVC: @"\01?b@@YAPAUB@@XZ"() [[NUW:#[0-9]+]] {
+// MSVC:   %[[vbptr_off:.*]] = getelementptr inbounds i8* {{.*}}, i32 0
+// MSVC:   %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to i8**
+// MSVC:   %[[vbtable:.*]] = load i8** %[[vbptr]]
+// MSVC:   %[[entry:.*]] = getelementptr inbounds i8* {{.*}}, i32 8
+// MSVC:   %[[entry_i32:.*]] = bitcast i8* %[[entry]] to i32*
+// MSVC:   %[[offset:.*]] = load i32* %[[entry_i32]]
+// MSVC:   add nsw i32 0, %[[offset]]
+// MSVC: }
+
+
 BB* c() { return x; }
 // CHECK: @_Z1cv() [[NUW]]
 // CHECK: [[VBASEOFFSETPTRC:%[a-zA-Z0-9\.]+]] = getelementptr i8* {{.*}}, i64 -24
@@ -32,4 +55,35 @@
 // CHECK: add i32 [[VBASEOFFSETC]], 8
 // CHECK: }
 
+// Same as 'a' except we use a different vbtable offset.
+// MSVC: @"\01?c@@YAPAUBB@@XZ"() [[NUW:#[0-9]+]] {
+// MSVC:   %[[vbptr_off:.*]] = getelementptr inbounds i8* {{.*}}, i32 0
+// MSVC:   %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to i8**
+// MSVC:   %[[vbtable:.*]] = load i8** %[[vbptr]]
+// MSVC:   %[[entry:.*]] = getelementptr inbounds i8* {{.*}}, i32 16
+// MSVC:   %[[entry_i32:.*]] = bitcast i8* %[[entry]] to i32*
+// MSVC:   %[[offset:.*]] = load i32* %[[entry_i32]]
+// MSVC:   add nsw i32 0, %[[offset]]
+// MSVC: }
+
+// Put the vbptr at a non-zero offset inside a non-virtual base.
+struct E { int e; };
+struct F : E, D { int f; };
+
+F* y;
+
+BB* d() { return y; }
+
+// Same as 'c' except the vbptr offset is 4, changing the initial GEP and the
+// final add.
+// MSVC: @"\01?d@@YAPAUBB@@XZ"() [[NUW:#[0-9]+]] {
+// MSVC:   %[[vbptr_off:.*]] = getelementptr inbounds i8* {{.*}}, i32 4
+// MSVC:   %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to i8**
+// MSVC:   %[[vbtable:.*]] = load i8** %[[vbptr]]
+// MSVC:   %[[entry:.*]] = getelementptr inbounds i8* {{.*}}, i32 16
+// MSVC:   %[[entry_i32:.*]] = bitcast i8* %[[entry]] to i32*
+// MSVC:   %[[offset:.*]] = load i32* %[[entry_i32]]
+// MSVC:   add nsw i32 4, %[[offset]]
+// MSVC: }
+
 // CHECK: attributes [[NUW]] = { nounwind{{.*}} }