Hi rnk,

Hi Reid,

Can you please review this patch?

The only thing I'm not entirely sure is whether we want to use
a) a union of structs
or
b) should just duplicate a bunch of code and make the ABI-specific CG 
interfaces to pass around ABI-specific ThunkInfos.

(b) would likely require cast<>ing in a few places...
(a) sounds easier, so I picked unions :)

I'm planning to use a similar approach with virtual this adjustment in the 
following patch (that one is a bit more complex), so wanted to come up with a 
good decision in the simpler half of the whole refactor+fix patch.

--
Timur 

http://llvm-reviews.chandlerc.com/D2026

Files:
  include/clang/Basic/ABI.h
  lib/AST/ItaniumMangle.cpp
  lib/AST/VTableBuilder.cpp
  lib/CodeGen/CGCXXABI.h
  lib/CodeGen/CGVTables.cpp
  lib/CodeGen/ItaniumCXXABI.cpp
  lib/CodeGen/MicrosoftCXXABI.cpp
  test/CodeGenCXX/microsoft-abi-thunks.cpp
  test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance.cpp
  test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp
Index: include/clang/Basic/ABI.h
===================================================================
--- include/clang/Basic/ABI.h
+++ include/clang/Basic/ABI.h
@@ -39,19 +39,52 @@
   /// \brief The non-virtual adjustment from the derived object to its
   /// nearest virtual base.
   int64_t NonVirtual;
+
+  /// \brief Holds the ABI-specific information about the virtual return
+  /// adjustment, if needed.
+  union VirtualAdjustment {
+    // Itanium ABI
+    struct {
+      /// \brief The offset (in bytes), relative to the address point
+      /// of the virtual base class offset.
+      int64_t VBaseOffsetOffset;
+    };
+
+    // Microsoft ABI
+    struct {
+      /// \brief The offset (in bytes) of the vbptr, relative to the beginning
+      /// of the derived class.
+      uint32_t VBPtrOffset;
+
+      /// \brief Index of the virtual base in the vbtable.
+      uint32_t VBIndex;
+    };
+
+    VirtualAdjustment() {
+      memset(this, 0, sizeof(*this));
+    }
+
+    bool Equals(const VirtualAdjustment &Other) const {
+      return memcmp(this, &Other, sizeof(Other)) == 0;
+    }
+
+    bool isEmpty() const {
+      VirtualAdjustment Zero;
+      return Equals(Zero);
+    }
+
+    bool Less(const VirtualAdjustment &RHS) const {
+      return memcmp(this, &RHS, sizeof(RHS)) < 0;
+    }
+  } Virtual;
   
-  /// \brief The offset (in bytes), relative to the address point 
-  /// of the virtual base class offset.
-  int64_t VBaseOffsetOffset;
-  
-  ReturnAdjustment() : NonVirtual(0), VBaseOffsetOffset(0) { }
+  ReturnAdjustment() : NonVirtual(0) {}
   
-  bool isEmpty() const { return !NonVirtual && !VBaseOffsetOffset; }
+  bool isEmpty() const { return !NonVirtual && Virtual.isEmpty(); }
 
   friend bool operator==(const ReturnAdjustment &LHS, 
                          const ReturnAdjustment &RHS) {
-    return LHS.NonVirtual == RHS.NonVirtual && 
-      LHS.VBaseOffsetOffset == RHS.VBaseOffsetOffset;
+    return LHS.NonVirtual == RHS.NonVirtual && LHS.Virtual.Equals(RHS.Virtual);
   }
 
   friend bool operator!=(const ReturnAdjustment &LHS, const ReturnAdjustment &RHS) {
@@ -62,9 +95,8 @@
                         const ReturnAdjustment &RHS) {
     if (LHS.NonVirtual < RHS.NonVirtual)
       return true;
-    
-    return LHS.NonVirtual == RHS.NonVirtual && 
-      LHS.VBaseOffsetOffset < RHS.VBaseOffsetOffset;
+
+    return LHS.NonVirtual == RHS.NonVirtual && LHS.Virtual.Less(RHS.Virtual);
   }
 };
   
Index: lib/AST/ItaniumMangle.cpp
===================================================================
--- lib/AST/ItaniumMangle.cpp
+++ lib/AST/ItaniumMangle.cpp
@@ -3657,7 +3657,7 @@
   // Mangle the return pointer adjustment if there is one.
   if (!Thunk.Return.isEmpty())
     Mangler.mangleCallOffset(Thunk.Return.NonVirtual,
-                             Thunk.Return.VBaseOffsetOffset);
+                             Thunk.Return.Virtual.VBaseOffsetOffset);
   
   Mangler.mangleFunctionEncoding(MD);
 }
Index: lib/AST/VTableBuilder.cpp
===================================================================
--- lib/AST/VTableBuilder.cpp
+++ lib/AST/VTableBuilder.cpp
@@ -1203,10 +1203,10 @@
       // Get the virtual base offset offset.
       if (Offset.DerivedClass == MostDerivedClass) {
         // We can get the offset offset directly from our map.
-        Adjustment.VBaseOffsetOffset = 
+        Adjustment.Virtual.VBaseOffsetOffset =
           VBaseOffsetOffsets.lookup(Offset.VirtualBase).getQuantity();
       } else {
-        Adjustment.VBaseOffsetOffset = 
+        Adjustment.Virtual.VBaseOffsetOffset =
           VTables.getVirtualBaseOffsetOffset(Offset.DerivedClass,
                                              Offset.VirtualBase).getQuantity();
       }
@@ -1304,7 +1304,7 @@
       VCallOffsets = Builder.getVCallOffsets();
     }
       
-    Adjustment.VCallOffsetOffset = 
+    Adjustment.VCallOffsetOffset =
       VCallOffsets.getVCallOffsetOffset(MD).getQuantity();
   }
 
@@ -1996,8 +1996,8 @@
           Out << "\n       [return adjustment: ";
           Out << Thunk.Return.NonVirtual << " non-virtual";
           
-          if (Thunk.Return.VBaseOffsetOffset) {
-            Out << ", " << Thunk.Return.VBaseOffsetOffset;
+          if (Thunk.Return.Virtual.VBaseOffsetOffset) {
+            Out << ", " << Thunk.Return.Virtual.VBaseOffsetOffset;
             Out << " vbase offset offset";
           }
 
@@ -2172,8 +2172,8 @@
         if (!Thunk.Return.isEmpty()) {
           Out << "return adjustment: " << Thunk.Return.NonVirtual;
           Out << " non-virtual";
-          if (Thunk.Return.VBaseOffsetOffset) {
-            Out << ", " << Thunk.Return.VBaseOffsetOffset;
+          if (Thunk.Return.Virtual.VBaseOffsetOffset) {
+            Out << ", " << Thunk.Return.Virtual.VBaseOffsetOffset;
             Out << " vbase offset offset";
           }
 
@@ -2933,9 +2933,11 @@
       ReturnAdjustment.NonVirtual =
           ReturnAdjustmentOffset.NonVirtualOffset.getQuantity();
       if (ReturnAdjustmentOffset.VirtualBase) {
-        // FIXME: We might want to create a VBIndex alias for VBaseOffsetOffset
-        // in the ReturnAdjustment struct.
-        ReturnAdjustment.VBaseOffsetOffset =
+        const ASTRecordLayout &DerivedLayout =
+            Context.getASTRecordLayout(ReturnAdjustmentOffset.DerivedClass);
+        ReturnAdjustment.Virtual.VBPtrOffset =
+            DerivedLayout.getVBPtrOffset().getQuantity();
+        ReturnAdjustment.Virtual.VBIndex =
             GetVBTableIndex(ReturnAdjustmentOffset.DerivedClass,
                             ReturnAdjustmentOffset.VirtualBase);
       }
@@ -2967,6 +2969,34 @@
   }
 };
 
+static void dumpMicrosoftThunkAdjustment(const ThunkInfo &TI, raw_ostream &Out,
+                                         bool ContinueFirstLine) {
+  const ReturnAdjustment &R = TI.Return;
+  bool Multiline = false;
+  const char *LinePrefix = "\n        ";
+  if (!R.isEmpty()) {
+    if (!ContinueFirstLine)
+      Out << LinePrefix;
+    Out << "return adjustment: ";
+    if (R.Virtual.VBPtrOffset)
+      Out << "vbptr at offset" << R.Virtual.VBPtrOffset << ", ";
+    if (R.Virtual.VBIndex)
+      Out << "vbase #" << R.Virtual.VBIndex << ", ";
+    Out << R.NonVirtual << " non-virtual";
+    Multiline = true;
+  }
+
+  const ThisAdjustment &T = TI.This;
+  if (!T.isEmpty()) {
+    if (Multiline || !ContinueFirstLine)
+      Out << LinePrefix;
+    Out << "this adjustment: ";
+    assert(TI.This.VCallOffsetOffset == 0 &&
+           "VtorDisp adjustment is not supported yet");
+    Out << T.NonVirtual << " non-virtual";
+  }
+}
+
 void VFTableBuilder::dumpLayout(raw_ostream &Out) {
   Out << "VFTable for ";
   PrintBasePath(WhichVFPtr.PathToBaseWithVFPtr, Out);
@@ -2999,23 +3029,8 @@
       }
 
       ThunkInfo Thunk = VTableThunks.lookup(I);
-      if (!Thunk.isEmpty()) {
-        // If this function pointer has a return adjustment, dump it.
-        if (!Thunk.Return.isEmpty()) {
-          Out << "\n       [return adjustment: ";
-          if (Thunk.Return.VBaseOffsetOffset)
-            Out << "vbase #" << Thunk.Return.VBaseOffsetOffset << ", ";
-          Out << Thunk.Return.NonVirtual << " non-virtual]";
-        }
-
-        // If this function pointer has a 'this' pointer adjustment, dump it.
-        if (!Thunk.This.isEmpty()) {
-          assert(!Thunk.This.VCallOffsetOffset &&
-                 "No virtual this adjustment in this ABI");
-          Out << "\n       [this adjustment: " << Thunk.This.NonVirtual
-              << " non-virtual]";
-        }
-      }
+      if (!Thunk.isEmpty())
+        dumpMicrosoftThunkAdjustment(Thunk, Out, /*ContinueFirstLine=*/false);
 
       break;
     }
@@ -3033,13 +3048,7 @@
       if (!Thunk.isEmpty()) {
         assert(Thunk.Return.isEmpty() &&
                "No return adjustment needed for destructors!");
-        // If this destructor has a 'this' pointer adjustment, dump it.
-        if (!Thunk.This.isEmpty()) {
-          assert(!Thunk.This.VCallOffsetOffset &&
-                 "No virtual this adjustment in this ABI");
-          Out << "\n       [this adjustment: " << Thunk.This.NonVirtual
-              << " non-virtual]";
-        }
+        dumpMicrosoftThunkAdjustment(Thunk, Out, /*ContinueFirstLine=*/false);
       }
 
       break;
@@ -3090,26 +3099,7 @@
         const ThunkInfo &Thunk = ThunksVector[I];
 
         Out << llvm::format("%4d | ", I);
-
-        // If this function pointer has a return pointer adjustment, dump it.
-        if (!Thunk.Return.isEmpty()) {
-          Out << "return adjustment: ";
-          if (Thunk.Return.VBaseOffsetOffset)
-            Out << "vbase #" << Thunk.Return.VBaseOffsetOffset << ", ";
-          Out << Thunk.Return.NonVirtual << " non-virtual";
-
-          if (!Thunk.This.isEmpty())
-            Out << "\n       ";
-        }
-
-        // If this function pointer has a 'this' pointer adjustment, dump it.
-        if (!Thunk.This.isEmpty()) {
-          assert(!Thunk.This.VCallOffsetOffset &&
-                 "No virtual this adjustment in this ABI");
-          Out << "this adjustment: ";
-          Out << Thunk.This.NonVirtual << " non-virtual";
-        }
-
+        dumpMicrosoftThunkAdjustment(Thunk, Out, /*ContinueFirstLine=*/true);
         Out << '\n';
       }
 
Index: lib/CodeGen/CGCXXABI.h
===================================================================
--- lib/CodeGen/CGCXXABI.h
+++ lib/CodeGen/CGCXXABI.h
@@ -356,6 +356,14 @@
 
   virtual void setThunkLinkage(llvm::Function *Thunk, bool ForVTable) = 0;
 
+  virtual llvm::Value *performThisAdjustment(CodeGenFunction &CGF,
+                                             llvm::Value *This,
+                                             const ThisAdjustment &TA) = 0;
+
+  virtual llvm::Value *performReturnAdjustment(CodeGenFunction &CGF,
+                                               llvm::Value *Ret,
+                                               const ReturnAdjustment &RA) = 0;
+
   virtual void EmitReturnFromThunk(CodeGenFunction &CGF,
                                    RValue RV, QualType ResultType);
 
Index: lib/CodeGen/CGVTables.cpp
===================================================================
--- lib/CodeGen/CGVTables.cpp
+++ lib/CodeGen/CGVTables.cpp
@@ -56,53 +56,6 @@
   return GetOrCreateLLVMFunction(Name, Ty, GD, /*ForVTable=*/true);
 }
 
-static llvm::Value *PerformTypeAdjustment(CodeGenFunction &CGF,
-                                          llvm::Value *Ptr,
-                                          int64_t NonVirtualAdjustment,
-                                          int64_t VirtualAdjustment,
-                                          bool IsReturnAdjustment) {
-  if (!NonVirtualAdjustment && !VirtualAdjustment)
-    return Ptr;
-
-  llvm::Type *Int8PtrTy = CGF.Int8PtrTy;
-  llvm::Value *V = CGF.Builder.CreateBitCast(Ptr, Int8PtrTy);
-
-  if (NonVirtualAdjustment && !IsReturnAdjustment) {
-    // Perform the non-virtual adjustment for a base-to-derived cast.
-    V = CGF.Builder.CreateConstInBoundsGEP1_64(V, NonVirtualAdjustment);
-  }
-
-  if (VirtualAdjustment) {
-    llvm::Type *PtrDiffTy = 
-      CGF.ConvertType(CGF.getContext().getPointerDiffType());
-
-    // Perform the virtual adjustment.
-    llvm::Value *VTablePtrPtr = 
-      CGF.Builder.CreateBitCast(V, Int8PtrTy->getPointerTo());
-    
-    llvm::Value *VTablePtr = CGF.Builder.CreateLoad(VTablePtrPtr);
-  
-    llvm::Value *OffsetPtr =
-      CGF.Builder.CreateConstInBoundsGEP1_64(VTablePtr, VirtualAdjustment);
-    
-    OffsetPtr = CGF.Builder.CreateBitCast(OffsetPtr, PtrDiffTy->getPointerTo());
-    
-    // Load the adjustment offset from the vtable.
-    llvm::Value *Offset = CGF.Builder.CreateLoad(OffsetPtr);
-    
-    // Adjust our pointer.
-    V = CGF.Builder.CreateInBoundsGEP(V, Offset);
-  }
-
-  if (NonVirtualAdjustment && IsReturnAdjustment) {
-    // Perform the non-virtual adjustment for a derived-to-base cast.
-    V = CGF.Builder.CreateConstInBoundsGEP1_64(V, NonVirtualAdjustment);
-  }
-
-  // Cast back to the original type.
-  return CGF.Builder.CreateBitCast(V, Ptr->getType());
-}
-
 static void setThunkVisibility(CodeGenModule &CGM, const CXXMethodDecl *MD,
                                const ThunkInfo &Thunk, llvm::Function *Fn) {
   CGM.setGlobalVisibility(Fn, MD);
@@ -181,12 +134,10 @@
     CGF.Builder.CreateCondBr(IsNull, AdjustNull, AdjustNotNull);
     CGF.EmitBlock(AdjustNotNull);
   }
-  
-  ReturnValue = PerformTypeAdjustment(CGF, ReturnValue, 
-                                      Thunk.Return.NonVirtual, 
-                                      Thunk.Return.VBaseOffsetOffset,
-                                      /*IsReturnAdjustment*/true);
-  
+
+  ReturnValue = CGF.CGM.getCXXABI().performReturnAdjustment(CGF, ReturnValue,
+                                                            Thunk.Return);
+
   if (NullCheckValue) {
     CGF.Builder.CreateBr(AdjustEnd);
     CGF.EmitBlock(AdjustNull);
@@ -266,11 +217,8 @@
   assert(ThisStore && "Store of this should be in entry block?");
   // Adjust "this", if necessary.
   Builder.SetInsertPoint(ThisStore);
-  llvm::Value *AdjustedThisPtr = 
-    PerformTypeAdjustment(*this, ThisPtr, 
-                          Thunk.This.NonVirtual, 
-                          Thunk.This.VCallOffsetOffset,
-                          /*IsReturnAdjustment*/false);
+  llvm::Value *AdjustedThisPtr =
+      CGM.getCXXABI().performThisAdjustment(*this, ThisPtr, Thunk.This);
   ThisStore->setOperand(0, AdjustedThisPtr);
 
   if (!Thunk.Return.isEmpty()) {
@@ -322,12 +270,9 @@
   CXXThisValue = CXXABIThisValue;
 
   // Adjust the 'this' pointer if necessary.
-  llvm::Value *AdjustedThisPtr = 
-    PerformTypeAdjustment(*this, LoadCXXThis(), 
-                          Thunk.This.NonVirtual, 
-                          Thunk.This.VCallOffsetOffset,
-                          /*IsReturnAdjustment*/false);
-  
+  llvm::Value *AdjustedThisPtr =
+      CGM.getCXXABI().performThisAdjustment(*this, LoadCXXThis(), Thunk.This);
+
   CallArgList CallArgs;
   
   // Add our adjusted 'this' pointer.
Index: lib/CodeGen/ItaniumCXXABI.cpp
===================================================================
--- lib/CodeGen/ItaniumCXXABI.cpp
+++ lib/CodeGen/ItaniumCXXABI.cpp
@@ -180,6 +180,12 @@
       Thunk->setLinkage(llvm::GlobalValue::AvailableExternallyLinkage);
   }
 
+  llvm::Value *performThisAdjustment(CodeGenFunction &CGF, llvm::Value *This,
+                                     const ThisAdjustment &TA);
+
+  llvm::Value *performReturnAdjustment(CodeGenFunction &CGF, llvm::Value *Ret,
+                                       const ReturnAdjustment &RA);
+
   StringRef GetPureVirtualCallName() { return "__cxa_pure_virtual"; }
   StringRef GetDeletedVirtualCallName() { return "__cxa_deleted_virtual"; }
 
@@ -1059,6 +1065,68 @@
   VTables.EmitVTTDefinition(VTT, CGM.getVTableLinkage(RD), RD);
 }
 
+static llvm::Value *performTypeAdjustment(CodeGenFunction &CGF,
+                                          llvm::Value *Ptr,
+                                          int64_t NonVirtualAdjustment,
+                                          int64_t VirtualAdjustment,
+                                          bool IsReturnAdjustment) {
+  if (!NonVirtualAdjustment && !VirtualAdjustment)
+    return Ptr;
+
+  llvm::Type *Int8PtrTy = CGF.Int8PtrTy;
+  llvm::Value *V = CGF.Builder.CreateBitCast(Ptr, Int8PtrTy);
+
+  if (NonVirtualAdjustment && !IsReturnAdjustment) {
+    // Perform the non-virtual adjustment for a base-to-derived cast.
+    V = CGF.Builder.CreateConstInBoundsGEP1_64(V, NonVirtualAdjustment);
+  }
+
+  if (VirtualAdjustment) {
+    llvm::Type *PtrDiffTy =
+        CGF.ConvertType(CGF.getContext().getPointerDiffType());
+
+    // Perform the virtual adjustment.
+    llvm::Value *VTablePtrPtr =
+        CGF.Builder.CreateBitCast(V, Int8PtrTy->getPointerTo());
+
+    llvm::Value *VTablePtr = CGF.Builder.CreateLoad(VTablePtrPtr);
+
+    llvm::Value *OffsetPtr =
+        CGF.Builder.CreateConstInBoundsGEP1_64(VTablePtr, VirtualAdjustment);
+
+    OffsetPtr = CGF.Builder.CreateBitCast(OffsetPtr, PtrDiffTy->getPointerTo());
+
+    // Load the adjustment offset from the vtable.
+    llvm::Value *Offset = CGF.Builder.CreateLoad(OffsetPtr);
+
+    // Adjust our pointer.
+    V = CGF.Builder.CreateInBoundsGEP(V, Offset);
+  }
+
+  if (NonVirtualAdjustment && IsReturnAdjustment) {
+    // Perform the non-virtual adjustment for a derived-to-base cast.
+    V = CGF.Builder.CreateConstInBoundsGEP1_64(V, NonVirtualAdjustment);
+  }
+
+  // Cast back to the original type.
+  return CGF.Builder.CreateBitCast(V, Ptr->getType());
+}
+
+llvm::Value *ItaniumCXXABI::performThisAdjustment(CodeGenFunction &CGF,
+                                                  llvm::Value *This,
+                                                  const ThisAdjustment &TA) {
+  return performTypeAdjustment(CGF, This, TA.NonVirtual, TA.VCallOffsetOffset,
+                               /*IsReturnAdjustment=*/false);
+}
+
+llvm::Value *
+ItaniumCXXABI::performReturnAdjustment(CodeGenFunction &CGF, llvm::Value *Ret,
+                                       const ReturnAdjustment &RA) {
+  return performTypeAdjustment(CGF, Ret, RA.NonVirtual,
+                               RA.Virtual.VBaseOffsetOffset,
+                               /*IsReturnAdjustment=*/true);
+}
+
 void ARMCXXABI::EmitReturnFromThunk(CodeGenFunction &CGF,
                                     RValue RV, QualType ResultType) {
   if (!isa<CXXDestructorDecl>(CGF.CurGD.getDecl()))
Index: lib/CodeGen/MicrosoftCXXABI.cpp
===================================================================
--- lib/CodeGen/MicrosoftCXXABI.cpp
+++ lib/CodeGen/MicrosoftCXXABI.cpp
@@ -190,6 +190,12 @@
     Thunk->setLinkage(llvm::GlobalValue::WeakAnyLinkage);
   }
 
+  llvm::Value *performThisAdjustment(CodeGenFunction &CGF, llvm::Value *This,
+                                     const ThisAdjustment &TA);
+
+  llvm::Value *performReturnAdjustment(CodeGenFunction &CGF, llvm::Value *Ret,
+                                       const ReturnAdjustment &RA);
+
   void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
                        llvm::GlobalVariable *DeclPtr,
                        bool PerformInit);
@@ -962,6 +968,56 @@
   }
 }
 
+llvm::Value *MicrosoftCXXABI::performThisAdjustment(CodeGenFunction &CGF,
+                                                    llvm::Value *This,
+                                                    const ThisAdjustment &TA) {
+  if (TA.isEmpty())
+    return This;
+
+  llvm::Type *Int8PtrTy = CGF.Int8PtrTy;
+  llvm::Value *V = CGF.Builder.CreateBitCast(This, Int8PtrTy);
+
+  assert(TA.VCallOffsetOffset == 0 &&
+         "VtorDisp adjustment is not supported yet");
+
+  if (TA.NonVirtual) {
+    // Non-virtual adjustment might result in a pointer outside the allocated
+    // object, e.g. if the final overrider class is laid out after the virtual
+    // base that declares a method in the most derived class.
+    V = CGF.Builder.CreateConstGEP1_32(V, TA.NonVirtual);
+  }
+
+  // Don't need to bitcast back, the call CodeGen will handle this.
+  return V;
+}
+
+llvm::Value *
+MicrosoftCXXABI::performReturnAdjustment(CodeGenFunction &CGF, llvm::Value *Ret,
+                                         const ReturnAdjustment &RA) {
+  if (RA.isEmpty())
+    return Ret;
+
+  llvm::Type *Int8PtrTy = CGF.Int8PtrTy;
+  llvm::Value *V = CGF.Builder.CreateBitCast(Ret, Int8PtrTy);
+
+  if (RA.Virtual.VBIndex) {
+    assert(RA.Virtual.VBIndex > 0);
+    llvm::Value *VBPtr,
+        *VBPtrOffset =
+            llvm::ConstantInt::get(CGM.IntTy, RA.Virtual.VBPtrOffset),
+        *VBOffset = llvm::ConstantInt::get(CGM.IntTy, 4 * RA.Virtual.VBIndex),
+        *VBaseOffset =
+            GetVBaseOffsetFromVBPtr(CGF, V, VBOffset, VBPtrOffset, &VBPtr);
+    V = CGF.Builder.CreateInBoundsGEP(VBPtr, VBaseOffset);
+  }
+
+  if (RA.NonVirtual)
+    V = CGF.Builder.CreateConstInBoundsGEP1_32(V, RA.NonVirtual);
+
+  // Cast back to the original type.
+  return CGF.Builder.CreateBitCast(V, Ret->getType());
+}
+
 bool MicrosoftCXXABI::requiresArrayCookie(const CXXDeleteExpr *expr,
                                    QualType elementType) {
   // Microsoft seems to completely ignore the possibility of a
Index: test/CodeGenCXX/microsoft-abi-thunks.cpp
===================================================================
--- test/CodeGenCXX/microsoft-abi-thunks.cpp
+++ test/CodeGenCXX/microsoft-abi-thunks.cpp
@@ -61,14 +61,14 @@
 
 C::C() {}  // Emits vftable and forces thunk generation.
 
-// CODEGEN: define weak x86_thiscallcc void @"\01??_EC@@W3AEPAXI@Z"(%struct.C* %this, i32 %should_call_delete)
-// CODEGEN:   getelementptr inbounds i8* {{.*}}, i64 -4
+// CODEGEN-LABEL: define weak x86_thiscallcc void @"\01??_EC@@W3AEPAXI@Z"(%struct.C* %this, i32 %should_call_delete)
+// CODEGEN:   getelementptr i8* {{.*}}, i32 -4
 // FIXME: should actually call _EC, not _GC.
 // CODEGEN:   call x86_thiscallcc void @"\01??_GC@@UAEPAXI@Z"
 // CODEGEN: ret
 
-// CODEGEN: define weak x86_thiscallcc void @"\01?public_f@C@@W3AEXXZ"(%struct.C*
-// CODEGEN:   getelementptr inbounds i8* {{.*}}, i64 -4
+// CODEGEN-LABEL: define weak x86_thiscallcc void @"\01?public_f@C@@W3AEXXZ"(%struct.C*
+// CODEGEN:   getelementptr i8* {{.*}}, i32 -4
 // CODEGEN:   call x86_thiscallcc void @"\01?public_f@C@@UAEXXZ"(%struct.C*
 // CODEGEN: ret
 
@@ -81,21 +81,23 @@
 };
 
 struct E : D {
+  E();
   virtual C* goo();
   // MANGLING-DAG: @"\01?goo@E@@UAEPAUC@@XZ"
   // MANGLING-DAG: @"\01?goo@E@@QAEPAUB@@XZ"
   // MANGLING-X64-DAG: @"\01?goo@E@@UEAAPEAUC@@XZ"
   // MANGLING-X64-DAG: @"\01?goo@E@@QEAAPEAUB@@XZ"
 };
 
-E e;  // Emits vftable and forces thunk generation.
+E::E() {}  // Emits vftable and forces thunk generation.
 
-// CODEGEN: define weak x86_thiscallcc %struct.C* @"\01?goo@E@@QAEPAUB@@XZ"
+// CODEGEN-LABEL: define weak x86_thiscallcc %struct.C* @"\01?goo@E@@QAEPAUB@@XZ"
 // CODEGEN:   call x86_thiscallcc %struct.C* @"\01?goo@E@@UAEPAUC@@XZ"
-// CODEGEN:   getelementptr inbounds i8* {{.*}}, i64 4
+// CODEGEN:   getelementptr inbounds i8* {{.*}}, i32 4
 // CODEGEN: ret
 
 struct F : virtual A, virtual B {
+  virtual void own_method();
   virtual ~F();
 };
 
@@ -115,6 +117,27 @@
 
 H h;
 
+struct I : D {
+  I();
+  virtual F* goo();
+};
+
+I::I() {}  // Emits vftable and forces thunk generation.
+
+// CODEGEN-LABEL: define weak x86_thiscallcc %struct.{{[BF]}}* @"\01?goo@I@@QAEPAUB@@XZ"
+// CODEGEN: %[[ORIG_RET:.*]] = call x86_thiscallcc %struct.F* @"\01?goo@I@@UAEPAUF@@XZ"
+// CODEGEN: %[[ORIG_RET_i8:.*]] = bitcast %struct.F* %[[ORIG_RET]] to i8*
+// CODEGEN: %[[VBPTR_i8:.*]] = getelementptr inbounds i8* %[[ORIG_RET_i8]], i32 4
+// CODEGEN: %[[VBPTR:.*]] = bitcast i8* %[[VBPTR_i8]] to i8**
+// CODEGEN: %[[VBTABLE:.*]] = load i8** %[[VBPTR]]
+// CODEGEN: %[[VBASE_OFFSET_PTR_i8:.*]] = getelementptr inbounds i8* %[[VBTABLE]], i32 8
+// CODEGEN: %[[VBASE_OFFSET_PTR:.*]] = bitcast i8* %[[VBASE_OFFSET_PTR_i8]] to i32*
+// CODEGEN: %[[VBASE_OFFSET:.*]] = load i32* %[[VBASE_OFFSET_PTR]]
+// CODEGEN: %[[RES_i8:.*]] = getelementptr inbounds i8* %[[VBPTR_i8]], i32 %[[VBASE_OFFSET]]
+// CODEGEN: %[[RES:.*]] = bitcast i8* %[[RES_i8]] to %struct.F*
+// CODEGEN: phi %struct.F* {{.*}} %[[RES]]
+// CODEGEN: ret %struct.{{[BF]}}*
+
 // FIXME: Write vtordisp adjusting thunk tests
 
 namespace CrashOnThunksForAttributedType {
Index: test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance.cpp
===================================================================
--- test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance.cpp
+++ test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance.cpp
@@ -272,7 +272,7 @@
 
   // THIS-THUNKS-Test1: VFTable for 'C' in 'this_adjustment::Test1' (1 entries).
   // THIS-THUNKS-Test1-NEXT: 0 | void this_adjustment::Test1::g()
-  // THIS-THUNKS-Test1-NEXT:     [this adjustment: -4 non-virtual]
+  // THIS-THUNKS-Test1-NEXT:     this adjustment: -4 non-virtual
 
   // THIS-THUNKS-Test1: Thunks for 'void this_adjustment::Test1::g()' (1 entry).
   // THIS-THUNKS-Test1-NEXT: 0 | this adjustment: -4 non-virtual
@@ -298,7 +298,7 @@
 
   // THIS-THUNKS-Test2: VFTable for 'C' in 'this_adjustment::Test2' (1 entries).
   // THIS-THUNKS-Test2-NEXT: 0 | void this_adjustment::Test2::g()
-  // THIS-THUNKS-Test2-NEXT:     [this adjustment: -4 non-virtual]
+  // THIS-THUNKS-Test2-NEXT:     this adjustment: -4 non-virtual
 
   // THIS-THUNKS-Test2: Thunks for 'void this_adjustment::Test2::g()' (1 entry).
   // THIS-THUNKS-Test2-NEXT: 0 | this adjustment: -4 non-virtual
@@ -327,14 +327,14 @@
 
   // THIS-THUNKS-Test3: VFTable for 'A' in 'no_thunks::Test2' in 'this_adjustment::Test3' (1 entries).
   // THIS-THUNKS-Test3-NEXT: 0 | void this_adjustment::Test3::f()
-  // THIS-THUNKS-Test3-NEXT: [this adjustment: -8 non-virtual]
+  // THIS-THUNKS-Test3-NEXT:     this adjustment: -8 non-virtual
 
   // THIS-THUNKS-Test3: Thunks for 'void this_adjustment::Test3::f()' (1 entry).
   // THIS-THUNKS-Test3-NEXT: 0 | this adjustment: -8 non-virtual
 
   // THIS-THUNKS-Test3: VFTable for 'B' in 'no_thunks::Test2' in 'this_adjustment::Test3' (2 entries).
   // THIS-THUNKS-Test3-NEXT: 0 | void this_adjustment::Test3::g()
-  // THIS-THUNKS-Test3-NEXT: [this adjustment: -8 non-virtual]
+  // THIS-THUNKS-Test3-NEXT:     this adjustment: -8 non-virtual
   // THIS-THUNKS-Test3-NEXT: 1 | void B::h()
 
   // THIS-THUNKS-Test3: Thunks for 'void this_adjustment::Test3::g()' (1 entry).
@@ -370,7 +370,7 @@
 
   // VDTOR-THUNKS-Test3: VFTable for 'vdtor::Test2' in 'vdtor::Test3' (1 entries).
   // VDTOR-THUNKS-Test3-NEXT: 0 | vdtor::Test3::~Test3() [scalar deleting]
-  // VDTOR-THUNKS-Test3-NEXT:     [this adjustment: -4 non-virtual]
+  // VDTOR-THUNKS-Test3-NEXT:     this adjustment: -4 non-virtual
 
   // VDTOR-THUNKS-Test3: Thunks for 'vdtor::Test3::~Test3()' (1 entry).
   // VDTOR-THUNKS-Test3-NEXT: 0 | this adjustment: -4 non-virtual
@@ -395,7 +395,7 @@
 
   // VDTOR-THUNKS-Test5: VFTable for 'vdtor::Test2' in 'vdtor::Test5' (1 entries).
   // VDTOR-THUNKS-Test5-NEXT: 0 | vdtor::Test5::~Test5() [scalar deleting]
-  // VDTOR-THUNKS-Test5-NEXT:     [this adjustment: -4 non-virtual]
+  // VDTOR-THUNKS-Test5-NEXT:     this adjustment: -4 non-virtual
 
   // VDTOR-THUNKS-Test5: Thunks for 'vdtor::Test5::~Test5()' (1 entry).
   // VDTOR-THUNKS-Test5-NEXT: 0 | this adjustment: -4 non-virtual
@@ -415,7 +415,7 @@
 
   // VDTOR-THUNKS-Test6: VFTable for 'vdtor::Test2' in 'vdtor::Test6' (1 entries).
   // VDTOR-THUNKS-Test6-NEXT: 0 | vdtor::Test6::~Test6() [scalar deleting]
-  // VDTOR-THUNKS-Test6-NEXT:     [this adjustment: -4 non-virtual]
+  // VDTOR-THUNKS-Test6-NEXT:     this adjustment: -4 non-virtual
 
   // VDTOR-THUNKS-Test6: Thunks for 'vdtor::Test6::~Test6()' (1 entry).
   // VDTOR-THUNKS-Test6-NEXT: 0 | this adjustment: -4 non-virtual
@@ -433,7 +433,7 @@
 
   // VDTOR-THUNKS-Test7: VFTable for 'vdtor::Test2' in 'vdtor::Test5' in 'vdtor::Test7' (1 entries).
   // VDTOR-THUNKS-Test7-NEXT: 0 | vdtor::Test7::~Test7() [scalar deleting]
-  // VDTOR-THUNKS-Test7-NEXT:     [this adjustment: -4 non-virtual]
+  // VDTOR-THUNKS-Test7-NEXT:     this adjustment: -4 non-virtual
 
   // VDTOR-THUNKS-Test7: Thunks for 'vdtor::Test7::~Test7()' (1 entry).
   // VDTOR-THUNKS-Test7-NEXT: 0 | this adjustment: -4 non-virtual
@@ -458,7 +458,7 @@
 struct Test1 : Ret1 {
   // RET-THUNKS-Test1: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test1' (3 entries).
   // RET-THUNKS-Test1-NEXT: 0 | this_adjustment::Test1 *return_adjustment::Test1::foo()
-  // RET-THUNKS-Test1-NEXT:     [return adjustment: 4 non-virtual]
+  // RET-THUNKS-Test1-NEXT:     return adjustment: 4 non-virtual
   // RET-THUNKS-Test1-NEXT: 1 | void return_adjustment::Ret1::z()
   // RET-THUNKS-Test1-NEXT: 2 | this_adjustment::Test1 *return_adjustment::Test1::foo()
 
@@ -477,10 +477,10 @@
 struct Test2 : Test1 {
   // RET-THUNKS-Test2: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test1' in 'return_adjustment::Test2' (4 entries).
   // RET-THUNKS-Test2-NEXT: 0 | return_adjustment::Ret2 *return_adjustment::Test2::foo()
-  // RET-THUNKS-Test2-NEXT:     [return adjustment: 8 non-virtual]
+  // RET-THUNKS-Test2-NEXT:     return adjustment: 8 non-virtual
   // RET-THUNKS-Test2-NEXT: 1 | void return_adjustment::Ret1::z()
   // RET-THUNKS-Test2-NEXT: 2 | return_adjustment::Ret2 *return_adjustment::Test2::foo()
-  // RET-THUNKS-Test2-NEXT:     [return adjustment: 4 non-virtual]
+  // RET-THUNKS-Test2-NEXT:     return adjustment: 4 non-virtual
   // RET-THUNKS-Test2-NEXT: 3 | return_adjustment::Ret2 *return_adjustment::Test2::foo()
 
   // RET-THUNKS-Test2: VFTable indices for 'return_adjustment::Test2' (1 entries).
@@ -498,7 +498,7 @@
 
   // RET-THUNKS-Test3: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test3' (3 entries).
   // RET-THUNKS-Test3-NEXT: 0 | this_adjustment::Test1 *return_adjustment::Test3::foo()
-  // RET-THUNKS-Test3-NEXT:     [return adjustment: 4 non-virtual]
+  // RET-THUNKS-Test3-NEXT:     return adjustment: 4 non-virtual
   // RET-THUNKS-Test3-NEXT: 1 | void return_adjustment::Ret1::z()
   // RET-THUNKS-Test3-NEXT: 2 | this_adjustment::Test1 *return_adjustment::Test3::foo()
 
@@ -518,10 +518,10 @@
 
   // RET-THUNKS-Test4: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test3' in 'return_adjustment::Test4' (4 entries).
   // RET-THUNKS-Test4-NEXT: 0 | return_adjustment::Ret2 *return_adjustment::Test4::foo()
-  // RET-THUNKS-Test4-NEXT:     [return adjustment: 8 non-virtual]
+  // RET-THUNKS-Test4-NEXT:     return adjustment: 8 non-virtual
   // RET-THUNKS-Test4-NEXT: 1 | void return_adjustment::Ret1::z()
   // RET-THUNKS-Test4-NEXT: 2 | return_adjustment::Ret2 *return_adjustment::Test4::foo()
-  // RET-THUNKS-Test4-NEXT:     [return adjustment: 4 non-virtual]
+  // RET-THUNKS-Test4-NEXT:     return adjustment: 4 non-virtual
   // RET-THUNKS-Test4-NEXT: 3 | return_adjustment::Ret2 *return_adjustment::Test4::foo()
 
   // RET-THUNKS-Test4: VFTable indices for 'return_adjustment::Test4' (1 entries).
@@ -536,20 +536,20 @@
 struct Test5 : Ret1, Test1 {
   // RET-THUNKS-Test5: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test5' (3 entries).
   // RET-THUNKS-Test5-NEXT: 0 | return_adjustment::Ret2 *return_adjustment::Test5::foo()
-  // RET-THUNKS-Test5-NEXT:     [return adjustment: 8 non-virtual]
+  // RET-THUNKS-Test5-NEXT:     return adjustment: 8 non-virtual
   // RET-THUNKS-Test5-NEXT: 1 | void return_adjustment::Ret1::z()
   // RET-THUNKS-Test5-NEXT: 2 | return_adjustment::Ret2 *return_adjustment::Test5::foo()
 
   // RET-THUNKS-Test5: VFTable for 'return_adjustment::Ret1' in  'return_adjustment::Test1' in 'return_adjustment::Test5' (4 entries).
   // RET-THUNKS-Test5-NEXT: 0 | return_adjustment::Ret2 *return_adjustment::Test5::foo()
-  // RET-THUNKS-Test5-NEXT:     [return adjustment: 8 non-virtual]
-  // RET-THUNKS-Test5-NEXT:     [this adjustment: -4 non-virtual]
+  // RET-THUNKS-Test5-NEXT:     return adjustment: 8 non-virtual
+  // RET-THUNKS-Test5-NEXT:     this adjustment: -4 non-virtual
   // RET-THUNKS-Test5-NEXT: 1 | void return_adjustment::Ret1::z()
   // RET-THUNKS-Test5-NEXT: 2 | return_adjustment::Ret2 *return_adjustment::Test5::foo()
-  // RET-THUNKS-Test5-NEXT:     [return adjustment: 4 non-virtual]
-  // RET-THUNKS-Test5-NEXT:     [this adjustment: -4 non-virtual]
+  // RET-THUNKS-Test5-NEXT:     return adjustment: 4 non-virtual
+  // RET-THUNKS-Test5-NEXT:     this adjustment: -4 non-virtual
   // RET-THUNKS-Test5-NEXT: 3 | return_adjustment::Ret2 *return_adjustment::Test5::foo()
-  // RET-THUNKS-Test5-NEXT:     [this adjustment: -4 non-virtual]
+  // RET-THUNKS-Test5-NEXT:     this adjustment: -4 non-virtual
 
   // RET-THUNKS-Test5: VFTable indices for 'return_adjustment::Test5' (1 entries).
   // RET-THUNKS-Test5-NEXT: 2 | return_adjustment::Ret2 *return_adjustment::Test5::foo()
@@ -565,7 +565,7 @@
   virtual Ret3* foo();
   // RET-THUNKS-Test6: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test1' in 'return_adjustment::Test6' (4 entries).
   // RET-THUNKS-Test6-NEXT: 0 | return_adjustment::Ret3 *return_adjustment::Test6::foo()
-  // RET-THUNKS-Test6-NEXT:     [return adjustment: 4 non-virtual]
+  // RET-THUNKS-Test6-NEXT:     return adjustment: 4 non-virtual
   // RET-THUNKS-Test6-NEXT: 1 | void return_adjustment::Ret1::z()
   // RET-THUNKS-Test6-NEXT: 2 | return_adjustment::Ret3 *return_adjustment::Test6::foo()
   // RET-THUNKS-Test6-NEXT: 3 | return_adjustment::Ret3 *return_adjustment::Test6::foo()
Index: test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp
===================================================================
--- test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp
+++ test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp
@@ -151,7 +151,7 @@
 
   // TEST4: VFTable for 'A' in 'C' in 'Test4::X' (2 entries).
   // TEST4-NEXT: 0 | void C::f()
-  // TEST4-NEXT: [this adjustment: 8 non-virtual]
+  // TEST4-NEXT:     this adjustment: 8 non-virtual
   // TEST4-NEXT: 1 | void A::z()
 
   // TEST4-NOT: VFTable indices for 'Test4::X'
@@ -218,7 +218,7 @@
 struct Y : virtual X {
   // TEST7: VFTable for 'A' in 'C' in 'Test7::X' in 'Test7::Y' (2 entries).
   // TEST7-NEXT: 0 | void C::f()
-  // TEST7-NEXT:     [this adjustment: 8 non-virtual]
+  // TEST7-NEXT:     this adjustment: 8 non-virtual
   // TEST7-NEXT: 1 | void A::z()
 
   // TEST7: Thunks for 'void C::f()' (1 entry).
@@ -317,7 +317,7 @@
 
   // TEST9-W: VFTable for 'A' in 'D' in 'Test9::W' (2 entries).
   // TEST9-W-NEXT: 0 | void D::f()
-  // TEST9-W-NEXT:     [this adjustment: -8 non-virtual]
+  // TEST9-W-NEXT:     this adjustment: -8 non-virtual
   // TEST9-W-NEXT: 1 | void A::z()
 
   // TEST9-W: Thunks for 'void D::f()' (1 entry).
@@ -351,16 +351,16 @@
 
   // TEST9-T: VFTable for 'D' in 'Test9::T' (1 entries).
   // TEST9-T-NEXT: 0 | void Test9::T::h()
-  // TEST9-T-NEXT:     [this adjustment: -8 non-virtual]
+  // TEST9-T-NEXT:     this adjustment: -8 non-virtual
 
   // TEST9-T: Thunks for 'void Test9::T::h()' (1 entry).
   // TEST9-T-NEXT: 0 | this adjustment: -8 non-virtual
 
   // TEST9-T: VFTable for 'A' in 'D' in 'Test9::T' (2 entries).
   // TEST9-T-NEXT: 0 | void Test9::T::f()
-  // TEST9-T-NEXT:     [this adjustment: -8 non-virtual]
+  // TEST9-T-NEXT:     this adjustment: -8 non-virtual
   // TEST9-T-NEXT: 1 | void Test9::T::z()
-  // TEST9-T-NEXT:     [this adjustment: -8 non-virtual]
+  // TEST9-T-NEXT:     this adjustment: -8 non-virtual
 
   // TEST9-T: Thunks for 'void Test9::T::f()' (1 entry).
   // TEST9-T-NEXT: 0 | this adjustment: -8 non-virtual
@@ -443,7 +443,7 @@
 
   // VDTORS-U: VFTable for 'vdtors::X' in 'vdtors::W' in 'vdtors::U' (2 entries).
   // VDTORS-U-NEXT: 0 | vdtors::U::~U() [scalar deleting]
-  // VDTORS-U-NEXT:     [this adjustment: -4 non-virtual]
+  // VDTORS-U-NEXT:     this adjustment: -4 non-virtual
   // VDTORS-U-NEXT: 1 | void vdtors::X::zzz()
 
   // VDTORS-U: Thunks for 'vdtors::W::~W()' (1 entry).
@@ -463,7 +463,7 @@
 
   // VDTORS-V: VFTable for 'vdtors::X' in 'vdtors::W' in 'vdtors::V' (2 entries).
   // VDTORS-V-NEXT: 0 | vdtors::V::~V() [scalar deleting]
-  // VDTORS-V-NEXT:     [this adjustment: -4 non-virtual]
+  // VDTORS-V-NEXT:     this adjustment: -4 non-virtual
   // VDTORS-V-NEXT: 1 | void vdtors::X::zzz()
 
   // VDTORS-V: Thunks for 'vdtors::W::~W()' (1 entry).
@@ -510,7 +510,7 @@
 struct W : Z {
   // RET-W: VFTable for 'return_adjustment::Z' in 'return_adjustment::W' (2 entries).
   // RET-W-NEXT: 0 | return_adjustment::X *return_adjustment::W::foo()
-  // RET-W-NEXT:     [return adjustment: vbase #1, 0 non-virtual]
+  // RET-W-NEXT:     return adjustment: vbase #1, 0 non-virtual
   // RET-W-NEXT: 1 | return_adjustment::X *return_adjustment::W::foo()
 
   // RET-W: VFTable indices for 'return_adjustment::W' (1 entries).
@@ -524,9 +524,9 @@
 struct T : W {
   // RET-T: VFTable for 'return_adjustment::Z' in 'return_adjustment::W' in 'return_adjustment::T' (3 entries).
   // RET-T-NEXT: 0 | return_adjustment::Y *return_adjustment::T::foo()
-  // RET-T-NEXT:     [return adjustment: vbase #1, 0 non-virtual]
+  // RET-T-NEXT:     return adjustment: vbase #1, 0 non-virtual
   // RET-T-NEXT: 1 | return_adjustment::Y *return_adjustment::T::foo()
-  // RET-T-NEXT:     [return adjustment: vbase #2, 0 non-virtual]
+  // RET-T-NEXT:     return adjustment: vbase #2, 0 non-virtual
   // RET-T-NEXT: 2 | return_adjustment::Y *return_adjustment::T::foo()
 
   // RET-T: VFTable indices for 'return_adjustment::T' (1 entries).
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to