More vtable improvements. We now compute and keep track of all vtable related information which avoids computing the same vtable layout over and over.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@99403 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp
index 3854c40..890b437 100644
--- a/lib/CodeGen/CGVtable.cpp
+++ b/lib/CodeGen/CGVtable.cpp
@@ -1091,6 +1091,9 @@
   typedef llvm::SmallSetVector<const CXXRecordDecl *, 8> 
     PrimaryBasesSetVectorTy;
   
+  typedef llvm::DenseMap<const CXXRecordDecl *, int64_t> 
+    VBaseOffsetOffsetsMapTy;
+
 private:
   /// VTables - Global vtable information.
   CodeGenVTables &VTables;
@@ -1122,9 +1125,6 @@
   /// bases in this vtable.
   llvm::DenseMap<const CXXRecordDecl *, VCallOffsetMap> VCallOffsetsForVBases;
 
-  typedef llvm::DenseMap<const CXXRecordDecl *, int64_t> 
-    VBaseOffsetOffsetsMapTy;
-  
   /// VBaseOffsetOffsets - Contains the offsets of the virtual base offsets for
   /// the most derived class.
   VBaseOffsetOffsetsMapTy VBaseOffsetOffsets;
@@ -1299,6 +1299,24 @@
     return Thunks.end();
   }
 
+  const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets() const {
+    return VBaseOffsetOffsets;
+  }
+
+  /// getNumVTableComponents - Return the number of components in the vtable
+  /// currently built.
+  uint64_t getNumVTableComponents() const {
+    return Components.size();
+  }
+
+  const uint64_t *vtable_components_data_begin() {
+    return reinterpret_cast<const uint64_t *>(Components.begin());
+  }
+  
+  const uint64_t *vtable_components_data_end() {
+    return reinterpret_cast<const uint64_t *>(Components.end());
+  }
+  
   /// dumpLayout - Dump the vtable layout.
   void dumpLayout(llvm::raw_ostream&);
 };
@@ -3874,34 +3892,67 @@
 
   const CXXRecordDecl *RD = MD->getParent();
   
+  // Compute VTable related info for this class.
+  ComputeVTableRelatedInformation(RD);
+  
   ThunksMapTy::const_iterator I = Thunks.find(MD);
   if (I == Thunks.end()) {
-    // We did not find a thunk for this method. Check if we've collected thunks
-    // for this record.
-    if (!ClassesWithKnownThunkStatus.insert(RD).second) {
-      // This member function doesn't have any associated thunks.
-      return;
-    }
-    
-    // Use the vtable builder to build thunks for this class.
-    VtableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD);
-
-    // Add the known thunks.
-    Thunks.insert(Builder.thunks_begin(), Builder.thunks_end());
-  
-    // Look for the thunk again.
-    I = Thunks.find(MD);
-    if (I == Thunks.end()) {
-      // Looks like this function doesn't have any associated thunks after all.
-      return;
-    }
+    // We did not find a thunk for this method.
+    return;
   }
-  
+
   const ThunkInfoVectorTy &ThunkInfoVector = I->second;
   for (unsigned I = 0, E = ThunkInfoVector.size(); I != E; ++I)
     EmitThunk(GD, ThunkInfoVector[I]);
 }
 
+void CodeGenVTables::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) {
+  uint64_t *&LayoutData = VTableLayoutMap[RD];
+  
+  // Check if we've computed this information before.
+  if (LayoutData)
+    return;
+      
+  VtableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD);
+
+  // Add the VTable layout.
+  uint64_t NumVTableComponents = Builder.getNumVTableComponents();
+  LayoutData = new uint64_t[NumVTableComponents + 1];
+
+  // Store the number of components.
+  LayoutData[0] = NumVTableComponents;
+
+  // Store the components.
+  std::copy(Builder.vtable_components_data_begin(),
+            Builder.vtable_components_data_end(),
+            &LayoutData[1]);
+
+  // Add the known thunks.
+  Thunks.insert(Builder.thunks_begin(), Builder.thunks_end());
+  
+  // If we don't have the vbase information for this class, insert it.
+  // getVirtualBaseOffsetOffset will compute it separately without computing
+  // the rest of the vtable related information.
+  if (!RD->getNumVBases())
+    return;
+  
+  const RecordType *VBaseRT = 
+    RD->vbases_begin()->getType()->getAs<RecordType>();
+  const CXXRecordDecl *VBase = cast<CXXRecordDecl>(VBaseRT->getDecl());
+  
+  if (VirtualBaseClassOffsetOffsets.count(std::make_pair(RD, VBase)))
+    return;
+  
+  for (VtableBuilder::VBaseOffsetOffsetsMapTy::const_iterator I =
+       Builder.getVBaseOffsetOffsets().begin(), 
+       E = Builder.getVBaseOffsetOffsets().end(); I != E; ++I) {
+    // Insert all types.
+    ClassPairTy ClassPair(RD, I->first);
+    
+    VirtualBaseClassOffsetOffsets.insert(std::make_pair(ClassPair, I->second));
+  }
+}
+
 void 
 CodeGenVTables::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage,
                                   const CXXRecordDecl *RD) {
@@ -3923,8 +3974,11 @@
   CGM.getMangleContext().mangleCXXVtable(RD, OutName);
   llvm::StringRef Name = OutName.str();
 
+  ComputeVTableRelatedInformation(RD);
+  
   const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
-  llvm::ArrayType *ArrayType = llvm::ArrayType::get(Int8PtrTy, 0);
+  llvm::ArrayType *ArrayType = 
+    llvm::ArrayType::get(Int8PtrTy, getNumVTableComponents(RD));
   
   llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(Name);
   if (GV) {
diff --git a/lib/CodeGen/CGVtable.h b/lib/CodeGen/CGVtable.h
index 4a92443..6670b4e 100644
--- a/lib/CodeGen/CGVtable.h
+++ b/lib/CodeGen/CGVtable.h
@@ -260,11 +260,21 @@
   
   /// Thunks - Contains all thunks that a given method decl will need.
   ThunksMapTy Thunks;
-
-  /// ClassesWithKnownThunkStatus - Contains all the classes for which we know
-  /// whether their virtual member functions have thunks or not.
-  llvm::DenseSet<const CXXRecordDecl *> ClassesWithKnownThunkStatus;
   
+  typedef llvm::DenseMap<const CXXRecordDecl *, uint64_t *> VTableLayoutMapTy;
+  
+  /// VTableLayoutMap - Stores the vtable layout for all record decls.
+  /// The layout is stored as an array of 64-bit integers, where the first
+  /// integer is the number of vtable entries in the layout, and the subsequent
+  /// integers are the vtable components.
+  VTableLayoutMapTy VTableLayoutMap;
+
+  uint64_t getNumVTableComponents(const CXXRecordDecl *RD) const {
+    assert(VTableLayoutMap.count(RD) && "No vtable layout for this class!");
+    
+    return VTableLayoutMap.lookup(RD)[0];
+  }
+
   typedef llvm::DenseMap<ClassPairTy, uint64_t> SubVTTIndiciesTy;
   SubVTTIndiciesTy SubVTTIndicies;
 
@@ -290,6 +300,11 @@
   /// EmitThunks - Emit the associated thunks for the given global decl.
   void EmitThunks(GlobalDecl GD);
   
+  /// ComputeVTableRelatedInformation - Compute and store all vtable related
+  /// information (vtable layout, vbase offset offsets, thunks etc) for the
+  /// given record decl.
+  void ComputeVTableRelatedInformation(const CXXRecordDecl *RD);
+
 public:
   CodeGenVTables(CodeGenModule &CGM)
     : CGM(CGM) { }
diff --git a/test/CodeGenCXX/copy-constructor-synthesis-2.cpp b/test/CodeGenCXX/copy-constructor-synthesis-2.cpp
index 4d40372..2f7c79b 100644
--- a/test/CodeGenCXX/copy-constructor-synthesis-2.cpp
+++ b/test/CodeGenCXX/copy-constructor-synthesis-2.cpp
@@ -4,4 +4,4 @@
 A x(A& y) { return y; }
 
 // CHECK: define linkonce_odr void @_ZN1AC1ERKS_(
-// CHECK: store i8** getelementptr inbounds ([0 x i8*]* @_ZTV1A, i64 0, i64 2)
+// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2)
diff --git a/test/CodeGenCXX/vtable-pointer-initialization.cpp b/test/CodeGenCXX/vtable-pointer-initialization.cpp
index bf8575a..75620ab 100644
--- a/test/CodeGenCXX/vtable-pointer-initialization.cpp
+++ b/test/CodeGenCXX/vtable-pointer-initialization.cpp
@@ -21,13 +21,13 @@
 
 // CHECK: define void @_ZN1AC2Ev(
 // CHECK: call void @_ZN4BaseC2Ev(
-// CHECK: store i8** getelementptr inbounds ([0 x i8*]* @_ZTV1A, i64 0, i64 2)
+// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2)
 // CHECK: call void @_ZN5FieldC1Ev(
 // CHECK: ret void
 A::A() { }
 
 // CHECK: define void @_ZN1AD2Ev(
-// CHECK: store i8** getelementptr inbounds ([0 x i8*]* @_ZTV1A, i64 0, i64 2)
+// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2)
 // CHECK: call void @_ZN5FieldD1Ev(
 // CHECK: call void @_ZN4BaseD2Ev(
 // CHECK: ret void
@@ -45,13 +45,13 @@
 // CHECK: call void @_ZN1BC2Ev(
 
 // CHECK: define linkonce_odr void @_ZN1BD1Ev(
-// CHECK: store i8** getelementptr inbounds ([0 x i8*]* @_ZTV1B, i64 0, i64 2)
+// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1B, i64 0, i64 2)
 // CHECK: call void @_ZN5FieldD1Ev(
 // CHECK: call void @_ZN4BaseD2Ev(
 // CHECK: ret void
 
 // CHECK: define linkonce_odr void @_ZN1BC2Ev(
 // CHECK: call void @_ZN4BaseC2Ev(
-// CHECK: store i8** getelementptr inbounds ([0 x i8*]* @_ZTV1B, i64 0, i64 2)
+// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1B, i64 0, i64 2)
 // CHECK: call void @_ZN5FieldC1Ev
 // CHECK: ret void