aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnders Carlsson <andersca@mac.com>2010-03-24 16:42:11 +0000
committerAnders Carlsson <andersca@mac.com>2010-03-24 16:42:11 +0000
commitccd83d748c82c5255100f38e3f07537b949853b3 (patch)
tree0054679842e8b966f4ad9b486ea3b6d323b69908
parentc1b621daf98d83075a466c6f4ad9904dc845dd09 (diff)
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
-rw-r--r--lib/CodeGen/CGVtable.cpp102
-rw-r--r--lib/CodeGen/CGVtable.h23
-rw-r--r--test/CodeGenCXX/copy-constructor-synthesis-2.cpp2
-rw-r--r--test/CodeGenCXX/vtable-pointer-initialization.cpp8
4 files changed, 102 insertions, 33 deletions
diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp
index 3854c404c2..890b437c4b 100644
--- a/lib/CodeGen/CGVtable.cpp
+++ b/lib/CodeGen/CGVtable.cpp
@@ -1091,6 +1091,9 @@ public:
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 @@ private:
/// 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 @@ public:
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 @@ void CodeGenVTables::EmitThunks(GlobalDecl GD)
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 @@ llvm::Constant *CodeGenVTables::GetAddrOfVTable(const CXXRecordDecl *RD) {
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 4a924431af..6670b4ed72 100644
--- a/lib/CodeGen/CGVtable.h
+++ b/lib/CodeGen/CGVtable.h
@@ -260,11 +260,21 @@ private:
/// 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 @@ private:
/// 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 4d40372a56..2f7c79b903 100644
--- a/test/CodeGenCXX/copy-constructor-synthesis-2.cpp
+++ b/test/CodeGenCXX/copy-constructor-synthesis-2.cpp
@@ -4,4 +4,4 @@ struct A { virtual void a(); };
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 bf8575a268..75620ab8e6 100644
--- a/test/CodeGenCXX/vtable-pointer-initialization.cpp
+++ b/test/CodeGenCXX/vtable-pointer-initialization.cpp
@@ -21,13 +21,13 @@ struct A : Base {
// 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 @@ void f() { B b; }
// 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