r192220 - Abstract out parts of thunk emission code, add support for simple thunks when using -cxx-abi microsoft

Timur Iskhodzhanov timurrrr at google.com
Tue Oct 8 12:15:39 PDT 2013


Author: timurrrr
Date: Tue Oct  8 14:15:38 2013
New Revision: 192220

URL: http://llvm.org/viewvc/llvm-project?rev=192220&view=rev
Log:
Abstract out parts of thunk emission code, add support for simple thunks when using -cxx-abi microsoft

Reviewed at http://llvm-reviews.chandlerc.com/D1787

Added:
    cfe/trunk/test/CodeGenCXX/microsoft-abi-thunks.cpp
Modified:
    cfe/trunk/include/clang/AST/VTableBuilder.h
    cfe/trunk/include/clang/Basic/ABI.h
    cfe/trunk/lib/AST/MicrosoftMangle.cpp
    cfe/trunk/lib/AST/VTableBuilder.cpp
    cfe/trunk/lib/CodeGen/CGCXXABI.h
    cfe/trunk/lib/CodeGen/CGVTables.cpp
    cfe/trunk/lib/CodeGen/CGVTables.h
    cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
    cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
    cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp
    cfe/trunk/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance.cpp
    cfe/trunk/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp

Modified: cfe/trunk/include/clang/AST/VTableBuilder.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/VTableBuilder.h?rev=192220&r1=192219&r2=192220&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/VTableBuilder.h (original)
+++ cfe/trunk/include/clang/AST/VTableBuilder.h Tue Oct  8 14:15:38 2013
@@ -200,7 +200,6 @@ private:
 class VTableLayout {
 public:
   typedef std::pair<uint64_t, ThunkInfo> VTableThunkTy;
-  typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy;
 
   typedef const VTableComponent *vtable_component_iterator;
   typedef const VTableThunkTy *vtable_thunk_iterator;
@@ -210,7 +209,7 @@ private:
   uint64_t NumVTableComponents;
   llvm::OwningArrayPtr<VTableComponent> VTableComponents;
 
-  /// \brief Contains thunks needed by vtables.
+  /// \brief Contains thunks needed by vtables, sorted by indices.
   uint64_t NumVTableThunks;
   llvm::OwningArrayPtr<VTableThunkTy> VTableThunks;
 
@@ -285,9 +284,12 @@ protected:
   virtual ~VTableContextBase() {}
 
 public:
-  const ThunkInfoVectorTy *getThunkInfo(const CXXMethodDecl *MD) {
+  virtual const ThunkInfoVectorTy *getThunkInfo(GlobalDecl GD) {
+    const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()->getCanonicalDecl());
     computeVTableRelatedInformation(MD->getParent());
 
+    // This assumes that all the destructors present in the vtable
+    // use exactly the same set of thunks.
     ThunksMapTy::const_iterator I = Thunks.find(MD);
     if (I == Thunks.end()) {
       // We did not find a thunk for this method.
@@ -483,6 +485,14 @@ public:
                                        CharUnits VFPtrOffset);
 
   const MethodVFTableLocation &getMethodVFTableLocation(GlobalDecl GD);
+
+  const ThunkInfoVectorTy *getThunkInfo(GlobalDecl GD) {
+    // Complete destructors don't have a slot in a vftable, so no thunks needed.
+    if (isa<CXXDestructorDecl>(GD.getDecl()) &&
+        GD.getDtorType() == Dtor_Complete)
+      return 0;
+    return VTableContextBase::getThunkInfo(GD);
+  }
 };
 }
 

Modified: cfe/trunk/include/clang/Basic/ABI.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/ABI.h?rev=192220&r1=192219&r2=192220&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/ABI.h (original)
+++ cfe/trunk/include/clang/Basic/ABI.h Tue Oct  8 14:15:38 2013
@@ -54,6 +54,10 @@ struct ReturnAdjustment {
       LHS.VBaseOffsetOffset == RHS.VBaseOffsetOffset;
   }
 
+  friend bool operator!=(const ReturnAdjustment &LHS, const ReturnAdjustment &RHS) {
+    return !(LHS == RHS);
+  }
+
   friend bool operator<(const ReturnAdjustment &LHS,
                         const ReturnAdjustment &RHS) {
     if (LHS.NonVirtual < RHS.NonVirtual)
@@ -83,6 +87,10 @@ struct ThisAdjustment {
     return LHS.NonVirtual == RHS.NonVirtual && 
       LHS.VCallOffsetOffset == RHS.VCallOffsetOffset;
   }
+
+  friend bool operator!=(const ThisAdjustment &LHS, const ThisAdjustment &RHS) {
+    return !(LHS == RHS);
+  }
   
   friend bool operator<(const ThisAdjustment &LHS,
                         const ThisAdjustment &RHS) {
@@ -94,6 +102,8 @@ struct ThisAdjustment {
   }
 };
 
+class CXXMethodDecl;
+
 /// \brief The \c this pointer adjustment as well as an optional return
 /// adjustment for a thunk.
 struct ThunkInfo {
@@ -103,23 +113,25 @@ struct ThunkInfo {
   /// \brief The return adjustment.
   ReturnAdjustment Return;
 
-  ThunkInfo() { }
-
-  ThunkInfo(const ThisAdjustment &This, const ReturnAdjustment &Return)
-    : This(This), Return(Return) { }
+  /// \brief Holds a pointer to the overridden method this thunk is for,
+  /// if needed by the ABI to distinguish different thunks with equal
+  /// adjustments. Otherwise, null.
+  /// CAUTION: In the unlikely event you need to sort ThunkInfos, consider using
+  /// an ABI-specific comparator.
+  const CXXMethodDecl *Method;
+
+  ThunkInfo() : Method(0) { }
+
+  ThunkInfo(const ThisAdjustment &This, const ReturnAdjustment &Return,
+            const CXXMethodDecl *Method = 0)
+      : This(This), Return(Return), Method(Method) {}
 
   friend bool operator==(const ThunkInfo &LHS, const ThunkInfo &RHS) {
-    return LHS.This == RHS.This && LHS.Return == RHS.Return;
-  }
-
-  friend bool operator<(const ThunkInfo &LHS, const ThunkInfo &RHS) {
-    if (LHS.This < RHS.This)
-      return true;
-      
-    return LHS.This == RHS.This && LHS.Return < RHS.Return;
+    return LHS.This == RHS.This && LHS.Return == RHS.Return &&
+           LHS.Method == RHS.Method;
   }
 
-  bool isEmpty() const { return This.isEmpty() && Return.isEmpty(); }
+  bool isEmpty() const { return This.isEmpty() && Return.isEmpty() && Method == 0; }
 };  
 
 } // end namespace clang

Modified: cfe/trunk/lib/AST/MicrosoftMangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/MicrosoftMangle.cpp?rev=192220&r1=192219&r2=192220&view=diff
==============================================================================
--- cfe/trunk/lib/AST/MicrosoftMangle.cpp (original)
+++ cfe/trunk/lib/AST/MicrosoftMangle.cpp Tue Oct  8 14:15:38 2013
@@ -15,6 +15,7 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Attr.h"
 #include "clang/AST/CharUnits.h"
+#include "clang/AST/CXXInheritance.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclObjC.h"
@@ -1405,7 +1406,8 @@ void MicrosoftCXXNameMangler::mangleFunc
   //                   ::= Z # global far
   if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
     switch (MD->getAccess()) {
-      default:
+      case AS_none:
+        llvm_unreachable("Unsupported access specifier");
       case AS_private:
         if (MD->isStatic())
           Out << 'C';
@@ -1858,36 +1860,70 @@ void MicrosoftMangleContextImpl::mangleN
   return Mangler.mangle(D);
 }
 
+static void mangleThunkThisAdjustment(const CXXMethodDecl *MD,
+                                      const ThisAdjustment &Adjustment,
+                                      MicrosoftCXXNameMangler &Mangler,
+                                      raw_ostream &Out) {
+  // FIXME: add support for vtordisp thunks.
+  if (Adjustment.NonVirtual != 0) {
+    switch (MD->getAccess()) {
+    case AS_none:
+      llvm_unreachable("Unsupported access specifier");
+    case AS_private:
+      Out << 'G';
+      break;
+    case AS_protected:
+      Out << 'O';
+      break;
+    case AS_public:
+      Out << 'W';
+    }
+    llvm::APSInt APSNumber(/*BitWidth=*/32, /*isUnsigned=*/true);
+    APSNumber = -Adjustment.NonVirtual;
+    Mangler.mangleNumber(APSNumber);
+  } else {
+    switch (MD->getAccess()) {
+    case AS_none:
+      llvm_unreachable("Unsupported access specifier");
+    case AS_private:
+      Out << 'A';
+      break;
+    case AS_protected:
+      Out << 'I';
+      break;
+    case AS_public:
+      Out << 'Q';
+    }
+  }
+}
+
 void MicrosoftMangleContextImpl::mangleThunk(const CXXMethodDecl *MD,
                                              const ThunkInfo &Thunk,
                                              raw_ostream &Out) {
-  // FIXME: this is not yet a complete implementation, but merely a
-  // reasonably-working stub to avoid crashing when required to emit a thunk.
   MicrosoftCXXNameMangler Mangler(*this, Out);
   Out << "\01?";
   Mangler.mangleName(MD);
-  if (Thunk.This.NonVirtual != 0) {
-    // FIXME: add support for protected/private or use mangleFunctionClass.
-    Out << "W";
-    llvm::APSInt APSNumber(/*BitWidth=*/32 /*FIXME: check on x64*/,
-                           /*isUnsigned=*/true);
-    APSNumber = -Thunk.This.NonVirtual;
-    Mangler.mangleNumber(APSNumber);
-  } else {
-    // FIXME: add support for protected/private or use mangleFunctionClass.
-    Out << "Q";
-  }
-  // FIXME: mangle return adjustment? Most likely includes using an overridee FPT?
-  Mangler.mangleFunctionType(MD->getType()->castAs<FunctionProtoType>(), MD);
-}
-
-void MicrosoftMangleContextImpl::mangleCXXDtorThunk(const CXXDestructorDecl *DD,
-                                                    CXXDtorType Type,
-                                                    const ThisAdjustment &,
-                                                    raw_ostream &) {
-  unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
-    "cannot mangle thunk for this destructor yet");
-  getDiags().Report(DD->getLocation(), DiagID);
+  mangleThunkThisAdjustment(MD, Thunk.This, Mangler, Out);
+  if (!Thunk.Return.isEmpty())
+    assert(Thunk.Method != 0 && "Thunk info should hold the overridee decl");
+
+  const CXXMethodDecl *DeclForFPT = Thunk.Method ? Thunk.Method : MD;
+  Mangler.mangleFunctionType(
+      DeclForFPT->getType()->castAs<FunctionProtoType>(), MD);
+}
+
+void MicrosoftMangleContextImpl::mangleCXXDtorThunk(
+    const CXXDestructorDecl *DD, CXXDtorType Type,
+    const ThisAdjustment &Adjustment, raw_ostream &Out) {
+  // FIXME: Actually, the dtor thunk should be emitted for vector deleting
+  // dtors rather than scalar deleting dtors. Just use the vector deleting dtor
+  // mangling manually until we support both deleting dtor types.
+  assert(Type == Dtor_Deleting);
+  MicrosoftCXXNameMangler Mangler(*this, Out, DD, Type);
+  Out << "\01??_E";
+  Mangler.mangleName(DD->getParent());
+  mangleThunkThisAdjustment(DD, Adjustment, Mangler, Out);
+  Mangler.mangleFunctionType(DD->getType()->castAs<FunctionProtoType>(), DD);
 }
 
 void MicrosoftMangleContextImpl::mangleCXXVFTable(

Modified: cfe/trunk/lib/AST/VTableBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/VTableBuilder.cpp?rev=192220&r1=192219&r2=192220&view=diff
==============================================================================
--- cfe/trunk/lib/AST/VTableBuilder.cpp (original)
+++ cfe/trunk/lib/AST/VTableBuilder.cpp Tue Oct  8 14:15:38 2013
@@ -992,6 +992,7 @@ public:
     MostDerivedClassIsVirtual(MostDerivedClassIsVirtual), 
     LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()), 
     Overriders(MostDerivedClass, MostDerivedClassOffset, LayoutClass) {
+    assert(!Context.getTargetInfo().getCXXABI().isMicrosoft());
 
     LayoutVTable();
 
@@ -1904,6 +1905,21 @@ VTableBuilder::LayoutVTablesForVirtualBa
   }
 }
 
+struct ItaniumThunkInfoComparator {
+  bool operator() (const ThunkInfo &LHS, const ThunkInfo &RHS) {
+    assert(LHS.Method == 0);
+    assert(RHS.Method == 0);
+
+    if (LHS.This != RHS.This)
+      return LHS.This < RHS.This;
+
+    if (LHS.Return != RHS.Return)
+      return LHS.Return < RHS.Return;
+
+    llvm_unreachable("Shouldn't observe two equal thunks");
+  }
+};
+
 /// dumpLayout - Dump the vtable layout.
 void VTableBuilder::dumpLayout(raw_ostream& Out) {
   // FIXME: write more tests that actually use the dumpLayout output to prevent
@@ -2146,7 +2162,8 @@ void VTableBuilder::dumpLayout(raw_ostre
       const CXXMethodDecl *MD = I->second;
 
       ThunkInfoVectorTy ThunksVector = Thunks[MD];
-      std::sort(ThunksVector.begin(), ThunksVector.end());
+      std::sort(ThunksVector.begin(), ThunksVector.end(),
+                ItaniumThunkInfoComparator());
 
       Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size();
       Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n";
@@ -2233,7 +2250,15 @@ void VTableBuilder::dumpLayout(raw_ostre
 
   Out << '\n';
 }
-  
+
+struct VTableThunksComparator {
+  bool operator()(const VTableLayout::VTableThunkTy &LHS,
+                  const VTableLayout::VTableThunkTy &RHS) {
+    assert(LHS.first != RHS.first &&
+            "All thunks should have unique indices!");
+    return LHS.first < RHS.first;
+  }
+};
 }
 
 VTableLayout::VTableLayout(uint64_t NumVTableComponents,
@@ -2252,6 +2277,9 @@ VTableLayout::VTableLayout(uint64_t NumV
             this->VTableComponents.get());
   std::copy(VTableThunks, VTableThunks+NumVTableThunks,
             this->VTableThunks.get());
+  std::sort(this->VTableThunks.get(),
+            this->VTableThunks.get() + NumVTableThunks,
+            VTableThunksComparator());
 }
 
 VTableLayout::~VTableLayout() { }
@@ -2312,7 +2340,6 @@ VTableContext::getVirtualBaseOffsetOffse
 static VTableLayout *CreateVTableLayout(const VTableBuilder &Builder) {
   SmallVector<VTableLayout::VTableThunkTy, 1>
     VTableThunks(Builder.vtable_thunks_begin(), Builder.vtable_thunks_end());
-  std::sort(VTableThunks.begin(), VTableThunks.end());
 
   return new VTableLayout(Builder.getNumVTableComponents(),
                           Builder.vtable_component_begin(),
@@ -2520,18 +2547,14 @@ private:
 
   /// AddMethod - Add a single virtual member function to the vftable
   /// components vector.
-  void AddMethod(const CXXMethodDecl *MD, ThisAdjustment ThisAdjustment,
-                 ReturnAdjustment ReturnAdjustment) {
+  void AddMethod(const CXXMethodDecl *MD, ThunkInfo TI) {
     if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
-      assert(ReturnAdjustment.isEmpty() &&
+      assert(TI.Return.isEmpty() &&
              "Destructor can't have return adjustment!");
       Components.push_back(VTableComponent::MakeDeletingDtor(DD));
     } else {
-      // Add the return adjustment if necessary.
-      if (!ReturnAdjustment.isEmpty() || !ThisAdjustment.isEmpty()) {
-        VTableThunks[Components.size()].Return = ReturnAdjustment;
-        VTableThunks[Components.size()].This = ThisAdjustment;
-      }
+      if (!TI.isEmpty())
+        VTableThunks[Components.size()] = TI;
       Components.push_back(VTableComponent::MakeFunction(MD));
     }
   }
@@ -2816,6 +2839,7 @@ void VFTableBuilder::AddMethods(BaseSubo
     FinalOverriders::OverriderInfo Overrider =
         Overriders.getOverrider(MD, Base.getBaseOffset());
     ThisAdjustment ThisAdjustmentOffset;
+    bool ForceThunk = false;
 
     // Check if this virtual member function overrides
     // a method in one of the visited bases.
@@ -2840,8 +2864,7 @@ void VFTableBuilder::AddMethods(BaseSubo
         AddThunk(MD, VTableThunks[OverriddenMethodInfo.VFTableIndex]);
       }
 
-      if (ComputeReturnAdjustmentBaseOffset(Context, MD, OverriddenMD)
-              .isEmpty()) {
+      if (MD->getResultType() == OverriddenMD->getResultType()) {
         // No return adjustment needed - just replace the overridden method info
         // with the current info.
         MethodInfo MI(OverriddenMethodInfo.VBTableIndex,
@@ -2859,6 +2882,7 @@ void VFTableBuilder::AddMethods(BaseSubo
         // method was in the vftable.
         // For now, just mark the overriden method as shadowed by a new slot.
         OverriddenMethodInfo.Shadowed = true;
+        ForceThunk = true;
 
         // Also apply this adjustment to the shadowed slots.
         if (!ThisAdjustmentOffset.isEmpty()) {
@@ -2907,6 +2931,7 @@ void VFTableBuilder::AddMethods(BaseSubo
           ComputeReturnAdjustmentBaseOffset(Context, OverriderMD, MD);
     }
     if (!ReturnAdjustmentOffset.isEmpty()) {
+      ForceThunk = true;
       ReturnAdjustment.NonVirtual =
           ReturnAdjustmentOffset.NonVirtualOffset.getQuantity();
       if (ReturnAdjustmentOffset.VirtualBase) {
@@ -2918,7 +2943,8 @@ void VFTableBuilder::AddMethods(BaseSubo
       }
     }
 
-    AddMethod(Overrider.Method, ThisAdjustmentOffset, ReturnAdjustment);
+    AddMethod(OverriderMD, ThunkInfo(ThisAdjustmentOffset, ReturnAdjustment,
+                                     ForceThunk ? MD : 0));
   }
 }
 
@@ -2929,6 +2955,20 @@ void PrintBasePath(const VFPtrInfo::Base
   }
 }
 
+struct MicrosoftThunkInfoStableSortComparator {
+  bool operator() (const ThunkInfo &LHS, const ThunkInfo &RHS) {
+    if (LHS.This != RHS.This)
+      return LHS.This < RHS.This;
+
+    if (LHS.Return != RHS.Return)
+      return LHS.Return < RHS.Return;
+
+    // Keep different thunks with the same adjustments in the order they
+    // were put into the vector.
+    return false;
+  }
+};
+
 void VFTableBuilder::dumpLayout(raw_ostream &Out) {
   Out << "VFTable for ";
   PrintBasePath(WhichVFPtr.PathToBaseWithVFPtr, Out);
@@ -3042,7 +3082,8 @@ void VFTableBuilder::dumpLayout(raw_ostr
       const CXXMethodDecl *MD = I->second;
 
       ThunkInfoVectorTy ThunksVector = Thunks[MD];
-      std::sort(ThunksVector.begin(), ThunksVector.end());
+      std::stable_sort(ThunksVector.begin(), ThunksVector.end(),
+                       MicrosoftThunkInfoStableSortComparator());
 
       Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size();
       Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n";
@@ -3218,7 +3259,6 @@ void MicrosoftVFTableContext::computeVTa
     assert(VFTableLayouts.count(id) == 0);
     SmallVector<VTableLayout::VTableThunkTy, 1> VTableThunks(
         Builder.vtable_thunks_begin(), Builder.vtable_thunks_end());
-    std::sort(VTableThunks.begin(), VTableThunks.end());
     VFTableLayouts[id] = new VTableLayout(
         Builder.getNumVTableComponents(), Builder.vtable_component_begin(),
         VTableThunks.size(), VTableThunks.data(), EmptyAddressPointsMap, true);

Modified: cfe/trunk/lib/CodeGen/CGCXXABI.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.h?rev=192220&r1=192219&r2=192220&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXXABI.h (original)
+++ cfe/trunk/lib/CodeGen/CGCXXABI.h Tue Oct  8 14:15:38 2013
@@ -339,11 +339,17 @@ public:
                                          SourceLocation CallLoc,
                                          llvm::Value *This) = 0;
 
+  virtual void adjustCallArgsForDestructorThunk(CodeGenFunction &CGF,
+                                                GlobalDecl GD,
+                                                CallArgList &CallArgs) {}
+
   /// Emit any tables needed to implement virtual inheritance.  For Itanium,
   /// this emits virtual table tables.  For the MSVC++ ABI, this emits virtual
   /// base tables.
   virtual void emitVirtualInheritanceTables(const CXXRecordDecl *RD) = 0;
 
+  virtual void setThunkLinkage(llvm::Function *Thunk, bool ForVTable) = 0;
+
   virtual void EmitReturnFromThunk(CodeGenFunction &CGF,
                                    RValue RV, QualType ResultType);
 

Modified: cfe/trunk/lib/CodeGen/CGVTables.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVTables.cpp?rev=192220&r1=192219&r2=192220&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGVTables.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGVTables.cpp Tue Oct  8 14:15:38 2013
@@ -333,6 +333,9 @@ void CodeGenFunction::GenerateThunk(llvm
   // Add our adjusted 'this' pointer.
   CallArgs.add(RValue::get(AdjustedThisPtr), ThisType);
 
+  if (isa<CXXDestructorDecl>(MD))
+    CGM.getCXXABI().adjustCallArgsForDestructorThunk(*this, GD, CallArgs);
+
   // Add the rest of the parameters.
   for (FunctionDecl::param_const_iterator I = MD->param_begin(),
        E = MD->param_end(); I != E; ++I) {
@@ -390,14 +393,8 @@ void CodeGenFunction::GenerateThunk(llvm
   setThunkVisibility(CGM, MD, Thunk, Fn);
 }
 
-void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk, 
-                               bool UseAvailableExternallyLinkage)
-{
-  if (CGM.getTarget().getCXXABI().isMicrosoft()) {
-    // Emission of thunks is not supported yet in Microsoft ABI.
-    return;
-  }
-
+void CodeGenVTables::emitThunk(GlobalDecl GD, const ThunkInfo &Thunk,
+                               bool ForVTable) {
   const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeGlobalDeclaration(GD);
 
   // FIXME: re-use FnInfo in this computation.
@@ -435,9 +432,11 @@ void CodeGenVTables::EmitThunk(GlobalDec
   }
 
   llvm::Function *ThunkFn = cast<llvm::Function>(Entry);
+  bool ABIHasKeyFunctions = CGM.getTarget().getCXXABI().hasKeyFunctions();
+  bool UseAvailableExternallyLinkage = ForVTable && ABIHasKeyFunctions;
 
   if (!ThunkFn->isDeclaration()) {
-    if (UseAvailableExternallyLinkage) {
+    if (!ABIHasKeyFunctions || UseAvailableExternallyLinkage) {
       // There is already a thunk emitted for this function, do nothing.
       return;
     }
@@ -466,14 +465,17 @@ void CodeGenVTables::EmitThunk(GlobalDec
     CodeGenFunction(CGM).GenerateThunk(ThunkFn, FnInfo, GD, Thunk);
   }
 
-  if (UseAvailableExternallyLinkage)
-    ThunkFn->setLinkage(llvm::GlobalValue::AvailableExternallyLinkage);
+  CGM.getCXXABI().setThunkLinkage(ThunkFn, ForVTable);
 }
 
-void CodeGenVTables::MaybeEmitThunkAvailableExternally(GlobalDecl GD,
-                                                       const ThunkInfo &Thunk) {
-  // We only want to do this when building with optimizations.
-  if (!CGM.getCodeGenOpts().OptimizationLevel)
+void CodeGenVTables::maybeEmitThunkForVTable(GlobalDecl GD,
+                                             const ThunkInfo &Thunk) {
+  // If the ABI has key functions, only the TU with the key function should emit
+  // the thunk. However, we can allow inlining of thunks if we emit them with
+  // available_externally linkage together with vtables when optimizations are
+  // enabled.
+  if (CGM.getTarget().getCXXABI().hasKeyFunctions() &&
+      !CGM.getCodeGenOpts().OptimizationLevel)
     return;
 
   // We can't emit thunks for member functions with incomplete types.
@@ -482,7 +484,7 @@ void CodeGenVTables::MaybeEmitThunkAvail
                                 cast<FunctionType>(MD->getType().getTypePtr())))
     return;
 
-  EmitThunk(GD, Thunk, /*UseAvailableExternallyLinkage=*/true);
+  emitThunk(GD, Thunk, /*ForVTable=*/true);
 }
 
 void CodeGenVTables::EmitThunks(GlobalDecl GD)
@@ -494,21 +496,18 @@ void CodeGenVTables::EmitThunks(GlobalDe
   if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base)
     return;
 
+  const VTableContext::ThunkInfoVectorTy *ThunkInfoVector;
   if (VFTContext.isValid()) {
-    // FIXME: This is a temporary solution to force generation of vftables in
-    // Microsoft ABI. Remove when we thread VFTableContext through CodeGen.
-    VFTContext->getVFPtrOffsets(MD->getParent());
-    return;
+    ThunkInfoVector = VFTContext->getThunkInfo(GD);
+  } else {
+    ThunkInfoVector = VTContext.getThunkInfo(GD);
   }
 
-  const VTableContext::ThunkInfoVectorTy *ThunkInfoVector =
-    VTContext.getThunkInfo(MD);
   if (!ThunkInfoVector)
     return;
 
   for (unsigned I = 0, E = ThunkInfoVector->size(); I != E; ++I)
-    EmitThunk(GD, (*ThunkInfoVector)[I],
-              /*UseAvailableExternallyLinkage=*/false);
+    emitThunk(GD, (*ThunkInfoVector)[I], /*ForVTable=*/false);
 }
 
 llvm::Constant *
@@ -603,7 +602,7 @@ CodeGenVTables::CreateVTableInitializer(
             VTableThunks[NextVTableThunkIndex].first == I) {
           const ThunkInfo &Thunk = VTableThunks[NextVTableThunkIndex].second;
         
-          MaybeEmitThunkAvailableExternally(GD, Thunk);
+          maybeEmitThunkForVTable(GD, Thunk);
           Init = CGM.GetAddrOfThunk(GD, Thunk);
 
           NextVTableThunkIndex++;

Modified: cfe/trunk/lib/CodeGen/CGVTables.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVTables.h?rev=192220&r1=192219&r2=192220&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGVTables.h (original)
+++ cfe/trunk/lib/CodeGen/CGVTables.h Tue Oct  8 14:15:38 2013
@@ -52,15 +52,12 @@ class CodeGenVTables {
   /// indices.
   SecondaryVirtualPointerIndicesMapTy SecondaryVirtualPointerIndices;
 
-  /// EmitThunk - Emit a single thunk.
-  void EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk, 
-                 bool UseAvailableExternallyLinkage);
+  /// emitThunk - Emit a single thunk.
+  void emitThunk(GlobalDecl GD, const ThunkInfo &Thunk, bool ForVTable);
 
-  /// MaybeEmitThunkAvailableExternally - Try to emit the given thunk with
-  /// available_externally linkage to allow for inlining of thunks.
-  /// This will be done iff optimizations are enabled and the member function
-  /// doesn't contain any incomplete types.
-  void MaybeEmitThunkAvailableExternally(GlobalDecl GD, const ThunkInfo &Thunk);
+  /// maybeEmitThunkForVTable - Emit the given thunk for the vtable if needed by
+  /// the ABI.
+  void maybeEmitThunkForVTable(GlobalDecl GD, const ThunkInfo &Thunk);
 
 public:
   /// CreateVTableInitializer - Create a vtable initializer for the given record

Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=192220&r1=192219&r2=192220&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Tue Oct  8 14:15:38 2013
@@ -173,6 +173,13 @@ public:
 
   void emitVirtualInheritanceTables(const CXXRecordDecl *RD);
 
+  void setThunkLinkage(llvm::Function *Thunk, bool ForVTable) {
+    // Allow inlining of thunks by emitting them with available_externally
+    // linkage together with vtables when needed.
+    if (ForVTable)
+      Thunk->setLinkage(llvm::GlobalValue::AvailableExternallyLinkage);
+  }
+
   StringRef GetPureVirtualCallName() { return "__cxa_pure_virtual"; }
   StringRef GetDeletedVirtualCallName() { return "__cxa_deleted_virtual"; }
 

Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=192220&r1=192219&r2=192220&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Tue Oct  8 14:15:38 2013
@@ -173,8 +173,20 @@ public:
                                  CXXDtorType DtorType, SourceLocation CallLoc,
                                  llvm::Value *This);
 
+  void adjustCallArgsForDestructorThunk(CodeGenFunction &CGF, GlobalDecl GD,
+                                        CallArgList &CallArgs) {
+    assert(GD.getDtorType() == Dtor_Deleting &&
+           "Only deleting destructor thunks are available in this ABI");
+    CallArgs.add(RValue::get(getStructorImplicitParamValue(CGF)),
+                             CGM.getContext().IntTy);
+  }
+
   void emitVirtualInheritanceTables(const CXXRecordDecl *RD);
 
+  void setThunkLinkage(llvm::Function *Thunk, bool ForVTable) {
+    Thunk->setLinkage(llvm::GlobalValue::WeakAnyLinkage);
+  }
+
   void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
                        llvm::GlobalVariable *DeclPtr,
                        bool PerformInit);

Added: cfe/trunk/test/CodeGenCXX/microsoft-abi-thunks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-thunks.cpp?rev=192220&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-thunks.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-thunks.cpp Tue Oct  8 14:15:38 2013
@@ -0,0 +1,118 @@
+// RUN: %clang_cc1 -fno-rtti -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 >%t 2>&1
+// RUN: FileCheck --check-prefix=MANGLING %s < %t
+// RUN: FileCheck --check-prefix=XMANGLING %s < %t
+// RUN: FileCheck --check-prefix=CODEGEN %s < %t
+// RUN: %clang_cc1 -fno-rtti -emit-llvm %s -o - -cxx-abi microsoft -triple=x86_64-pc-win32 2>&1 | FileCheck --check-prefix=MANGLING-X64 %s
+
+void foo(void *);
+
+struct A {
+  virtual ~A();
+  virtual void public_f();
+  // Make sure we don't emit unneeded thunks:
+  // XMANGLING-NOT: @"\01?public_f at A@@QAEXXZ"
+ protected:
+  virtual void protected_f();
+ private:
+  virtual void private_f();
+};
+
+struct B {
+  virtual ~B();
+  virtual void public_f();
+ protected:
+  virtual void protected_f();
+ private:
+  virtual void private_f();
+};
+
+
+struct C : A, B {
+  C();
+
+  virtual ~C();
+  // MANGLING-DAG: @"\01??1C@@UAE at XZ"
+  // MANGLING-DAG: @"\01??_GC@@UAEPAXI at Z"
+  // MANGLING-DAG: @"\01??_EC@@W3AEPAXI at Z"
+  // MANGLING-X64-DAG: @"\01??1C@@UEAA at XZ"
+  // MANGLING-X64-DAG: @"\01??_GC@@UEAAPEAXI at Z"
+  // MANGLING-X64-DAG: @"\01??_EC@@W7EAAPEAXI at Z"
+
+  // Overrides public_f() of two subobjects with distinct vfptrs, thus needs a thunk.
+  virtual void public_f();
+  // MANGLING-DAG: @"\01?public_f at C@@UAEXXZ"
+  // MANGLING-DAG: @"\01?public_f at C@@W3AEXXZ"
+  // MANGLING-X64-DAG: @"\01?public_f at C@@UEAAXXZ"
+  // MANGLING-X64-DAG: @"\01?public_f at C@@W7EAAXXZ"
+ protected:
+  virtual void protected_f();
+  // MANGLING-DAG: @"\01?protected_f at C@@MAEXXZ"
+  // MANGLING-DAG: @"\01?protected_f at C@@O3AEXXZ"
+  // MANGLING-X64-DAG: @"\01?protected_f at C@@MEAAXXZ"
+  // MANGLING-X64-DAG: @"\01?protected_f at C@@O7EAAXXZ"
+
+ private:
+  virtual void private_f();
+  // MANGLING-DAG: @"\01?private_f at C@@EAEXXZ"
+  // MANGLING-DAG: @"\01?private_f at C@@G3AEXXZ"
+  // MANGLING-X64-DAG: @"\01?private_f at C@@EEAAXXZ"
+  // MANGLING-X64-DAG: @"\01?private_f at C@@G7EAAXXZ"
+};
+
+C::C() {}  // Emits vftable and forces thunk generation.
+
+// CODEGEN: define weak x86_thiscallcc void @"\01??_EC@@W3AEPAXI at Z"(%struct.C* %this, i32 %should_call_delete)
+// CODEGEN:   getelementptr inbounds i8* {{.*}}, i64 -4
+// FIXME: should actually call _EC, not _GC.
+// CODEGEN:   call x86_thiscallcc void @"\01??_GC@@UAEPAXI at Z"
+// CODEGEN: ret
+
+// CODEGEN: define weak x86_thiscallcc void @"\01?public_f at C@@W3AEXXZ"(%struct.C*
+// CODEGEN:   getelementptr inbounds i8* {{.*}}, i64 -4
+// CODEGEN:   call x86_thiscallcc void @"\01?public_f at C@@UAEXXZ"(%struct.C*
+// CODEGEN: ret
+
+void zoo(C* obj) {
+  delete obj;
+}
+
+struct D {
+  virtual B* goo();
+};
+
+struct E : D {
+  virtual C* goo();
+  // MANGLING-DAG: @"\01?goo at E@@UAEPAUC@@XZ"
+  // MANGLING-DAG: @"\01?goo at E@@QAEPAUB@@XZ"
+  // MANGLING-X64-DAG: @"\01?goo at E@@UEAAPEAUC@@XZ"
+  // MANGLING-X64-DAG: @"\01?goo at E@@QEAAPEAUB@@XZ"
+};
+
+E e;  // Emits vftable and forces thunk generation.
+
+// CODEGEN: define weak x86_thiscallcc %struct.C* @"\01?goo at E@@QAEPAUB@@XZ"
+// CODEGEN:   call x86_thiscallcc %struct.C* @"\01?goo at E@@UAEPAUC@@XZ"
+// CODEGEN:   getelementptr inbounds i8* {{.*}}, i64 4
+// CODEGEN: ret
+
+struct F : virtual A, virtual B {
+  virtual ~F();
+};
+
+F f;  // Just make sure we don't crash, e.g. mangling the complete dtor.
+
+struct G : C { };
+
+struct H : E {
+  virtual G* goo();
+  // MANGLING-DAG: @"\01?goo at H@@UAEPAUG@@XZ"
+  // MANGLING-DAG: @"\01?goo at H@@QAEPAUB@@XZ"
+  // MANGLING-DAG: @"\01?goo at H@@QAEPAUC@@XZ"
+  // MANGLING-X64-DAG: @"\01?goo at H@@UEAAPEAUG@@XZ"
+  // MANGLING-X64-DAG: @"\01?goo at H@@QEAAPEAUB@@XZ"
+  // MANGLING-X64-DAG: @"\01?goo at H@@QEAAPEAUC@@XZ"
+};
+
+H h;
+
+// FIXME: Write vtordisp adjusting thunk tests

Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp?rev=192220&r1=192219&r2=192220&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp Tue Oct  8 14:15:38 2013
@@ -93,3 +93,11 @@ void call_vbase_bar(B *obj) {
 //
 // CHECK: ret void
 }
+
+struct C : B {
+  C();
+  // has an implicit vdtor.
+};
+
+// Used to crash on an assertion.
+C::C() {}

Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance.cpp?rev=192220&r1=192219&r2=192220&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance.cpp Tue Oct  8 14:15:38 2013
@@ -18,6 +18,7 @@
 // RUN: FileCheck --check-prefix=RET-THUNKS-Test3 %s < %t
 // RUN: FileCheck --check-prefix=RET-THUNKS-Test4 %s < %t
 // RUN: FileCheck --check-prefix=RET-THUNKS-Test5 %s < %t
+// RUN: FileCheck --check-prefix=RET-THUNKS-Test6 %s < %t
 
 // RUN: FileCheck --check-prefix=MANGLING %s < %t
 
@@ -458,4 +459,22 @@ struct Test5 : Ret1, Test1 {
 };
 
 Test5 t5;
+
+struct Ret3 : this_adjustment::Test1 { };
+
+struct Test6 : Test1 {
+  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: 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()
+
+  // RET-THUNKS-Test6: VFTable indices for 'return_adjustment::Test6' (1 entries).
+  // RET-THUNKS-Test6-NEXT: 3 | return_adjustment::Ret3 *return_adjustment::Test6::foo()
+};
+
+Test6 t6;
+
 }

Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp?rev=192220&r1=192219&r2=192220&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp Tue Oct  8 14:15:38 2013
@@ -154,6 +154,9 @@ struct X: virtual C {
   // TEST4-NOT: VFTable indices for 'Test4::X'
 
   // MANGLING-DAG: @"\01??_7X at Test4@@6B@"
+
+  // Also check the mangling of the thunk.
+  // MANGLING-DAG: define weak x86_thiscallcc void @"\01?f at C@@WPPPPPPPE at AEXXZ"
 };
 
 X x;





More information about the cfe-commits mailing list