]> granicus.if.org Git - clang/commitdiff
Work-in-progess rewrite of thunks: move thunk generation outside of vtable
authorEli Friedman <eli.friedman@gmail.com>
Sun, 6 Dec 2009 22:01:30 +0000 (22:01 +0000)
committerEli Friedman <eli.friedman@gmail.com>
Sun, 6 Dec 2009 22:01:30 +0000 (22:01 +0000)
generation, and make sure we generate thunks when the function is defined
rather than when the vtable is defined.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@90722 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGCXX.cpp
lib/CodeGen/CGVtable.cpp
lib/CodeGen/CGVtable.h
lib/CodeGen/CodeGenModule.cpp
lib/CodeGen/CodeGenModule.h
test/CodeGenCXX/virt.cpp

index a2674b82d1b2b278039f34c721572b17681f4d3c..77bee48b58b66ade1999f364711eab31e08b15bd 100644 (file)
@@ -993,6 +993,102 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
   return Fn;
 }
 
+llvm::Constant *
+CodeGenModule::GetAddrOfThunk(GlobalDecl GD,
+                              const ThunkAdjustment &ThisAdjustment) {
+  const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+
+  // Compute mangled name
+  llvm::SmallString<256> OutName;
+  if (const CXXDestructorDecl* DD = dyn_cast<CXXDestructorDecl>(MD))
+    getMangleContext().mangleCXXDtorThunk(DD, GD.getDtorType(), ThisAdjustment,
+                                          OutName);
+  else
+    getMangleContext().mangleThunk(MD, ThisAdjustment, OutName);
+  OutName += '\0';
+  const char* Name = UniqueMangledName(OutName.begin(), OutName.end());
+
+  // Get function for mangled name
+  const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD);
+  return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl());
+}
+
+llvm::Constant *
+CodeGenModule::GetAddrOfCovariantThunk(GlobalDecl GD,
+                                   const CovariantThunkAdjustment &Adjustment) {
+  const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+
+  // Compute mangled name
+  llvm::SmallString<256> OutName;
+  getMangleContext().mangleCovariantThunk(MD, Adjustment, OutName);
+  OutName += '\0';
+  const char* Name = UniqueMangledName(OutName.begin(), OutName.end());
+
+  // Get function for mangled name
+  const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD);
+  return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl());
+}
+
+void CodeGenModule::BuildThunksForVirtual(GlobalDecl GD) {
+  BuildThunksForVirtualRecursive(GD, GD);
+}
+
+void
+CodeGenModule::BuildThunksForVirtualRecursive(GlobalDecl GD,
+                                              GlobalDecl BaseOGD) {
+  const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+  const CXXMethodDecl *BaseOMD = cast<CXXMethodDecl>(BaseOGD.getDecl());
+  for (CXXMethodDecl::method_iterator mi = BaseOMD->begin_overridden_methods(),
+         e = BaseOMD->end_overridden_methods();
+       mi != e; ++mi) {
+    GlobalDecl OGD;
+    const CXXMethodDecl *OMD = *mi;
+    if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(OMD))
+      OGD = GlobalDecl(DD, GD.getDtorType());
+    else
+      OGD = GlobalDecl(OMD);
+    QualType nc_oret = OMD->getType()->getAs<FunctionType>()->getResultType();
+    CanQualType oret = getContext().getCanonicalType(nc_oret);
+    QualType nc_ret = MD->getType()->getAs<FunctionType>()->getResultType();
+    CanQualType ret = getContext().getCanonicalType(nc_ret);
+    ThunkAdjustment ReturnAdjustment;
+    if (oret != ret) {
+      QualType qD = nc_ret->getPointeeType();
+      QualType qB = nc_oret->getPointeeType();
+      CXXRecordDecl *D = cast<CXXRecordDecl>(qD->getAs<RecordType>()->getDecl());
+      CXXRecordDecl *B = cast<CXXRecordDecl>(qB->getAs<RecordType>()->getDecl());
+      ReturnAdjustment = ComputeThunkAdjustment(D, B);
+    }
+    ThunkAdjustment ThisAdjustment =
+        getVtableInfo().getThisAdjustment(GD, OGD);
+    bool Extern = !cast<CXXRecordDecl>(OMD->getDeclContext())->isInAnonymousNamespace();
+    if (!ReturnAdjustment.isEmpty() || !ThisAdjustment.isEmpty()) {
+      CovariantThunkAdjustment CoAdj(ThisAdjustment, ReturnAdjustment);
+      llvm::Constant *FnConst;
+      if (!ReturnAdjustment.isEmpty())
+        FnConst = GetAddrOfCovariantThunk(GD, CoAdj);
+      else
+        FnConst = GetAddrOfThunk(GD, ThisAdjustment);
+      if (!isa<llvm::Function>(FnConst)) {
+        assert(0 && "Figure out how to handle incomplete-type cases!");
+      }
+      llvm::Function *Fn = cast<llvm::Function>(FnConst);
+      if (Fn->isDeclaration()) {
+        llvm::GlobalVariable::LinkageTypes linktype;
+        linktype = llvm::GlobalValue::WeakAnyLinkage;
+        if (!Extern)
+          linktype = llvm::GlobalValue::InternalLinkage;
+        Fn->setLinkage(linktype);
+        if (!Features.Exceptions && !Features.ObjCNonFragileABI)
+          Fn->addFnAttr(llvm::Attribute::NoUnwind);
+        Fn->setAlignment(2);
+        CodeGenFunction(*this).GenerateCovariantThunk(Fn, GD, Extern, CoAdj);
+      }
+    }
+    BuildThunksForVirtualRecursive(GD, OGD);
+  }
+}
+
 llvm::Constant *
 CodeGenModule::BuildThunk(GlobalDecl GD, bool Extern,
                           const ThunkAdjustment &ThisAdjustment) {
index 65c412e0b03b2d519de813c2c36e625115c90434..857e661254b594e5483c9fed9698e5b1803c6670 100644 (file)
@@ -73,6 +73,7 @@ private:
     /// Methods - The methods, in vtable order.
     typedef llvm::SmallVector<GlobalDecl, 16> MethodsVectorTy;
     MethodsVectorTy Methods;
+    MethodsVectorTy OrigMethods;
 
   public:
     /// AddMethod - Add a method to the vtable methods.
@@ -82,6 +83,7 @@ private:
       
       MethodToIndexMap[GD] = Methods.size();
       Methods.push_back(GD);
+      OrigMethods.push_back(GD);
     }
     
     /// OverrideMethod - Replace a method with another.
@@ -113,6 +115,10 @@ private:
       return true;
     }
 
+    GlobalDecl getOrigMethod(uint64_t Index) const {
+      return OrigMethods[Index];
+    }
+
     MethodsVectorTy::size_type size() const {
       return Methods.size();
     }
@@ -120,6 +126,7 @@ private:
     void clear() {
       MethodToIndexMap.clear();
       Methods.clear();
+      OrigMethods.clear();
     }
     
     GlobalDecl operator[](uint64_t Index) const {
@@ -135,6 +142,10 @@ private:
   typedef llvm::DenseMap<uint64_t, ThunkAdjustment> ThisAdjustmentsMapTy;
   ThisAdjustmentsMapTy ThisAdjustments;
 
+  typedef std::vector<std::pair<std::pair<GlobalDecl, GlobalDecl>,
+                                ThunkAdjustment> > SavedThisAdjustmentsVectorTy;
+  SavedThisAdjustmentsVectorTy SavedThisAdjustments;
+
   /// BaseReturnTypes - Contains the base return types of methods who have been
   /// overridden with methods whose return types require adjustment. Used for
   /// generating covariant thunk information.
@@ -202,6 +213,9 @@ public:
   llvm::DenseMap<const CXXRecordDecl *, Index_t> &getVBIndex()
     { return VBIndex; }
 
+  SavedThisAdjustmentsVectorTy &getSavedThisAdjustments()
+    { return SavedThisAdjustments; }
+
   llvm::Constant *wrap(Index_t i) {
     llvm::Constant *m;
     m = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), i);
@@ -762,11 +776,17 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual,
     else
       OGD = OMD;
 
-    // FIXME: Explain why this is necessary!
+    // Check whether this is the method being overridden in this section of
+    // the vtable.
     uint64_t Index;
     if (!Methods.getIndex(OGD, Index))
       continue;
 
+    // Get the original method, which we should be computing thunks, etc,
+    // against.
+    OGD = Methods.getOrigMethod(Index);
+    OMD = cast<CXXMethodDecl>(OGD.getDecl());
+
     QualType ReturnType = 
       MD->getType()->getAs<FunctionType>()->getResultType();
     QualType OverriddenReturnType = 
@@ -777,10 +797,6 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual,
                                           OverriddenReturnType)) {
       CanQualType &BaseReturnType = BaseReturnTypes[Index];
 
-      // Get the canonical return type.
-      CanQualType CanReturnType = 
-        CGM.getContext().getCanonicalType(ReturnType);
-
       // Insert the base return type.
       if (BaseReturnType.isNull())
         BaseReturnType =
@@ -820,8 +836,12 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual,
       ThunkAdjustment ThisAdjustment(NonVirtualAdjustment,
                                       VirtualAdjustment);
 
-      if (!isPure && !ThisAdjustment.isEmpty())
+      if (!isPure && !ThisAdjustment.isEmpty()) {
         ThisAdjustments[Index] = ThisAdjustment;
+        // FIXME: Might this end up inserting some false adjustments?
+        SavedThisAdjustments.push_back(std::make_pair(std::make_pair(GD, OGD),
+                                                      ThisAdjustment));
+      }
       return true;
     }
 
@@ -882,10 +902,10 @@ void VtableBuilder::AppendMethodsToVtable() {
     if (!ReturnAdjustment.isEmpty()) {
       // Build a covariant thunk.
       CovariantThunkAdjustment Adjustment(ThisAdjustment, ReturnAdjustment);
-      Method = CGM.BuildCovariantThunk(MD, Extern, Adjustment);
+      Method = wrap(CGM.GetAddrOfCovariantThunk(GD, Adjustment));
     } else if (!ThisAdjustment.isEmpty()) {
       // Build a "regular" thunk.
-      Method = CGM.BuildThunk(GD, Extern, ThisAdjustment);
+      Method = wrap(CGM.GetAddrOfThunk(GD, ThisAdjustment));
     } else if (MD->isPure()) {
       // We have a pure virtual method.
       Method = getPureVirtualFn();
@@ -1048,6 +1068,32 @@ uint64_t CGVtableInfo::getMethodVtableIndex(GlobalDecl GD) {
   return I->second;
 }
 
+ThunkAdjustment CGVtableInfo::getThisAdjustment(GlobalDecl GD,
+                                                GlobalDecl OGD) {
+  SavedThisAdjustmentsTy::iterator I =
+    SavedThisAdjustments.find(std::make_pair(GD, OGD));
+  if (I != SavedThisAdjustments.end())
+    return I->second;
+
+  const CXXRecordDecl *RD = cast<CXXRecordDecl>(GD.getDecl()->getDeclContext());
+  if (!SavedThisAdjustmentRecords.insert(RD).second)
+    return ThunkAdjustment();
+
+  VtableBuilder b(RD, RD, 0, CGM, false);
+  D1(printf("vtable %s\n", RD->getNameAsCString()));
+  b.GenerateVtableForBase(RD);
+  b.GenerateVtableForVBases(RD);
+  
+  SavedThisAdjustments.insert(b.getSavedThisAdjustments().begin(),
+                              b.getSavedThisAdjustments().end());
+
+  I = SavedThisAdjustments.find(std::make_pair(GD, OGD));
+  if (I != SavedThisAdjustments.end())
+    return I->second;
+
+  return ThunkAdjustment();
+}
+
 int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, 
                                                 const CXXRecordDecl *VBase) {
   ClassPairTy ClassPair(RD, VBase);
@@ -1416,5 +1462,17 @@ void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) {
   
   // Emit the data.
   GenerateClassData(Linkage, RD);
+
+  for (CXXRecordDecl::method_iterator i = RD->method_begin(),
+       e = RD->method_end(); i != e; ++i) {
+    if ((*i)->isVirtual() && (*i)->hasInlineBody()) {
+      if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(*i)) {
+        CGM.BuildThunksForVirtual(GlobalDecl(DD, Dtor_Complete));
+        CGM.BuildThunksForVirtual(GlobalDecl(DD, Dtor_Deleting));
+      } else {
+        CGM.BuildThunksForVirtual(GlobalDecl(*i));
+      }
+    }
+  }
 }
 
index fd7a4865b6415076426424f7723ba786c3c2b4b3..1507725f0fbd15f64f8c48fc171d9c4c73202122 100644 (file)
@@ -15,6 +15,7 @@
 #define CLANG_CODEGEN_CGVTABLE_H
 
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
 #include "llvm/GlobalVariable.h"
 #include "GlobalDecl.h"
 
@@ -83,6 +84,11 @@ class CGVtableInfo {
   /// pointers in the vtable for a given record decl.
   llvm::DenseMap<const CXXRecordDecl *, uint64_t> NumVirtualFunctionPointers;
 
+  typedef llvm::DenseMap<std::pair<GlobalDecl, GlobalDecl>,
+                         ThunkAdjustment> SavedThisAdjustmentsTy;
+  SavedThisAdjustmentsTy SavedThisAdjustments;
+  llvm::DenseSet<const CXXRecordDecl*> SavedThisAdjustmentRecords;
+
   /// getNumVirtualFunctionPointers - Return the number of virtual function
   /// pointers in the vtable for a given record decl.
   uint64_t getNumVirtualFunctionPointers(const CXXRecordDecl *RD);
@@ -122,6 +128,8 @@ public:
   int64_t getVirtualBaseOffsetIndex(const CXXRecordDecl *RD,
                                     const CXXRecordDecl *VBase);
 
+  ThunkAdjustment getThisAdjustment(GlobalDecl GD, GlobalDecl OGD);
+
   /// getVtableAddressPoint - returns the address point of the vtable for the
   /// given record decl.
   /// FIXME: This should return a list of address points.
index 8fb03b2d19c4818f779a8b196c253f56ac7a5d30..5f822f509f81e18cdfd076418c478e7fadce6902 100644 (file)
@@ -621,8 +621,13 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) {
                                  Context.getSourceManager(),
                                  "Generating code for declaration");
   
-  if (isa<CXXMethodDecl>(D))
+  if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
     getVtableInfo().MaybeEmitVtable(GD);
+    if (MD->isVirtual() && MD->isOutOfLine() &&
+        (!isa<CXXDestructorDecl>(D) || GD.getDtorType() != Dtor_Base)) {
+      BuildThunksForVirtual(GD);
+    }
+  }
   
   if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(D))
     EmitCXXConstructor(CD, GD.getCtorType());
index cf36bcf9a0291b2c00f627d94f7be4b3a5f82b32..466aaa67cc038c2841808d9589f9060a4a5d57fe 100644 (file)
@@ -223,6 +223,13 @@ public:
   /// non-class type.
   llvm::Constant *GenerateRTTI(QualType Ty);
   
+  llvm::Constant *GetAddrOfThunk(GlobalDecl GD,
+                                 const ThunkAdjustment &ThisAdjustment);
+  llvm::Constant *GetAddrOfCovariantThunk(GlobalDecl GD,
+                                const CovariantThunkAdjustment &ThisAdjustment);
+  void BuildThunksForVirtual(GlobalDecl GD);
+  void BuildThunksForVirtualRecursive(GlobalDecl GD, GlobalDecl BaseOGD);
+
   /// BuildThunk - Build a thunk for the given method.
   llvm::Constant *BuildThunk(GlobalDecl GD, bool Extern, 
                              const ThunkAdjustment &ThisAdjustment);
index 7135aaf81ec7f2a7d711babaabe60d5c18dc1f92..e3b2afe2f770db647e6e86c94510133290463525 100644 (file)
@@ -768,7 +768,7 @@ struct test16_D : test16_NV1, virtual test16_B2 {
 
 // FIXME: This is the wrong thunk, but until these issues are fixed, better
 // than nothing.
-// CHECK-LPLL64:define weak %class.test8_D* @_ZTcvn16_n72_v16_n32_N8test16_D4foo1Ev(%class.test8_D*) {
+// CHECK-LPLL64:define weak %class.test8_D* @_ZTcvn16_n72_v16_n32_N8test16_D4foo1Ev(%class.test8_D*)
 // CHECK-LPLL64:entry:
 // CHECK-LPLL64:  %retval = alloca %class.test8_D*
 // CHECK-LPLL64:  %.addr = alloca %class.test8_D*
@@ -790,7 +790,7 @@ struct test16_D : test16_NV1, virtual test16_B2 {
 // CHECK-LPLL64:  ret %class.test8_D* %10
 // CHECK-LPLL64:}
 
-// CHECK-LPLL64:define weak %class.test8_D* @_ZTch0_v16_n32_N8test16_D4foo1Ev(%class.test8_D*) {
+// CHECK-LPLL64:define weak %class.test8_D* @_ZTch0_v16_n32_N8test16_D4foo1Ev(%class.test8_D*)
 // CHECK-LPLL64:entry:
 // CHECK-LPLL64:  %retval = alloca %class.test8_D*
 // CHECK-LPLL64:  %.addr = alloca %class.test8_D*