[cfe-commits] r96114 - in /cfe/trunk: lib/CodeGen/CGVtable.cpp test/CodeGenCXX/vtable-layout.cpp
Anders Carlsson
andersca at mac.com
Sat Feb 13 12:11:51 PST 2010
Author: andersca
Date: Sat Feb 13 14:11:51 2010
New Revision: 96114
URL: http://llvm.org/viewvc/llvm-project?rev=96114&view=rev
Log:
More work on covariant return types. We now handle non-virtual adjustments fine.
Modified:
cfe/trunk/lib/CodeGen/CGVtable.cpp
cfe/trunk/test/CodeGenCXX/vtable-layout.cpp
Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVtable.cpp?rev=96114&r1=96113&r2=96114&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGVtable.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGVtable.cpp Sat Feb 13 14:11:51 2010
@@ -225,14 +225,19 @@
/// getOverrider - Get the final overrider for the given method declaration in
/// the given base subobject.
- const OverriderInfo getOverrider(BaseSubobject Base,
- const CXXMethodDecl *MD) const {
+ OverriderInfo getOverrider(BaseSubobject Base,
+ const CXXMethodDecl *MD) const {
assert(OverridersMap.count(std::make_pair(Base, MD)) &&
"Did not find overrider!");
return OverridersMap.lookup(std::make_pair(Base, MD));
}
+ BaseOffset getReturnAdjustmentOffset(BaseSubobject Base,
+ const CXXMethodDecl *MD) const {
+ return ReturnAdjustments.lookup(std::make_pair(Base, MD));
+ }
+
/// dump - dump the final overriders.
void dump() const {
dump(llvm::errs(), BaseSubobject(MostDerivedClass, 0));
@@ -469,7 +474,6 @@
}
void FinalOverriders::dump(llvm::raw_ostream &Out, BaseSubobject Base) const {
-
const CXXRecordDecl *RD = Base.getBase();
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
@@ -532,9 +536,6 @@
CK_DeletingDtorPointer
};
- /// dump - Dump the contents of this component to the given stream.
- void dump(llvm::raw_ostream &Out);
-
static VtableComponent MakeOffsetToTop(int64_t Offset) {
return VtableComponent(CK_OffsetToTop, Offset);
}
@@ -670,10 +671,27 @@
/// VBaseOffsetIndex - The index relative to the address point of the
/// virtual base class offset.
int64_t VBaseOffsetIndex;
- };
- void layoutVirtualMemberFunctions(BaseSubobject Base,
- PrimaryBasesSetTy &PrimaryBases);
+ ReturnAdjustment() : NonVirtual(0), VBaseOffsetIndex(0) { }
+
+ bool isEmpty() const { return !NonVirtual && !VBaseOffsetIndex; }
+ };
+
+ /// ReturnAdjustments - The return adjustments needed in this vtable.
+ llvm::SmallVector<std::pair<uint64_t, ReturnAdjustment>, 16>
+ ReturnAdjustments;
+
+ /// ComputeReturnAdjustment - Compute the return adjustment given return
+ /// adjustment base offset.
+ ReturnAdjustment ComputeReturnAdjustment(FinalOverriders::BaseOffset Offset);
+
+ /// AddMethod - Add a single virtual member function to the vtable
+ /// components vector.
+ void AddMethod(const CXXMethodDecl *MD, ReturnAdjustment ReturnAdjustment);
+
+ /// AddMethods - Add the methods of this base subobject and all its
+ /// primary bases to the vtable components vector.
+ void AddMethods(BaseSubobject Base, PrimaryBasesSetTy &PrimaryBases);
/// layoutSimpleVtable - A test function that will layout very simple vtables
/// without any bases. Just used for testing for now.
@@ -711,9 +729,41 @@
return 0;
}
+VtableBuilder::ReturnAdjustment
+VtableBuilder::ComputeReturnAdjustment(FinalOverriders::BaseOffset Offset) {
+ ReturnAdjustment Adjustment;
+
+ if (!Offset.isEmpty()) {
+ assert(!Offset.VirtualBase && "FIXME: Handle virtual bases!");
+
+ Adjustment.NonVirtual = Offset.NonVirtualOffset;
+ }
+
+ return Adjustment;
+}
+
void
-VtableBuilder::layoutVirtualMemberFunctions(BaseSubobject Base,
- PrimaryBasesSetTy &PrimaryBases) {
+VtableBuilder::AddMethod(const CXXMethodDecl *MD,
+ ReturnAdjustment ReturnAdjustment) {
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ assert(ReturnAdjustment.isEmpty() &&
+ "Destructor can't have return adjustment!");
+ // Add both the complete destructor and the deleting destructor.
+ Components.push_back(VtableComponent::MakeCompleteDtor(DD));
+ Components.push_back(VtableComponent::MakeDeletingDtor(DD));
+ } else {
+ // Add the return adjustment if necessary.
+ if (!ReturnAdjustment.isEmpty())
+ ReturnAdjustments.push_back(std::make_pair(Components.size(),
+ ReturnAdjustment));
+
+ // Add the function.
+ Components.push_back(VtableComponent::MakeFunction(MD));
+ }
+}
+
+void
+VtableBuilder::AddMethods(BaseSubobject Base, PrimaryBasesSetTy &PrimaryBases) {
const CXXRecordDecl *RD = Base.getBase();
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
@@ -725,7 +775,7 @@
assert(Layout.getBaseClassOffset(PrimaryBase) == 0 &&
"Primary base should have a zero offset!");
- layoutVirtualMemberFunctions(BaseSubobject(PrimaryBase, 0), PrimaryBases);
+ AddMethods(BaseSubobject(PrimaryBase, 0), PrimaryBases);
if (!PrimaryBases.insert(PrimaryBase))
assert(false && "Found a duplicate primary base!");
@@ -746,22 +796,20 @@
// Check if this virtual member function overrides a method in a primary
// base. If this is the case, and the return type doesn't require adjustment
// then we can just use the member function from the primary base.
- if (const CXXMethodDecl *OverriddenMD ATTRIBUTE_UNUSED =
- OverridesMethodInPrimaryBase(MD, PrimaryBases)) {
- assert(!ReturnTypeConversionRequiresAdjustment(MD, OverriddenMD)
- && "FIXME: Handle covariant thunks!");
-
- continue;
+ if (const CXXMethodDecl *OverriddenMD =
+ OverridesMethodInPrimaryBase(MD, PrimaryBases)) {
+ if (!ReturnTypeConversionRequiresAdjustment(MD, OverriddenMD))
+ continue;
}
+
+ // Check if this overrider needs a return adjustment.
+ FinalOverriders::BaseOffset ReturnAdjustmentOffset =
+ Overriders.getReturnAdjustmentOffset(Base, MD);
+
+ ReturnAdjustment ReturnAdjustment =
+ ComputeReturnAdjustment(ReturnAdjustmentOffset);
- if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
- // Add both the complete destructor and the deleting destructor.
- Components.push_back(VtableComponent::MakeCompleteDtor(DD));
- Components.push_back(VtableComponent::MakeDeletingDtor(DD));
- } else {
- // Add the function.
- Components.push_back(VtableComponent::MakeFunction(MD));
- }
+ AddMethod(Overrider.Method, ReturnAdjustment);
}
}
@@ -778,7 +826,7 @@
// Now go through all virtual member functions and add them.
PrimaryBasesSetTy PrimaryBases;
- layoutVirtualMemberFunctions(Base, PrimaryBases);
+ AddMethods(Base, PrimaryBases);
// Record the address point.
AddressPoints.insert(std::make_pair(Base, AddressPoint));
@@ -832,6 +880,7 @@
AddressPointsByIndex.insert(std::make_pair(Index, Base));
}
+ unsigned NextReturnAdjustmentIndex = 0;
for (unsigned I = 0, E = Components.size(); I != E; ++I) {
uint64_t Index = I;
@@ -895,6 +944,20 @@
if (MD->isPure())
Out << " [pure]";
+ // If this function pointer has a return adjustment thunk, dump it.
+ if (NextReturnAdjustmentIndex < ReturnAdjustments.size() &&
+ ReturnAdjustments[NextReturnAdjustmentIndex].first == I) {
+ const ReturnAdjustment Adjustment =
+ ReturnAdjustments[NextReturnAdjustmentIndex].second;
+
+ assert(!Adjustment.VBaseOffsetIndex && "FIXME: Handle virtual bases!");
+
+ Out << "\n [return adjustment: ";
+ Out << Adjustment.NonVirtual << " non-virtual]";
+
+ NextReturnAdjustmentIndex++;
+ }
+
break;
}
@@ -2186,6 +2249,12 @@
}
I = VirtualBaseClassIndicies.find(ClassPair);
+ // FIXME: The assertion below assertion currently fails with the old vtable
+ /// layout code if there is a non-virtual thunk adjustment in a vtable.
+ // Once the new layout is in place, this return should be removed.
+ if (I == VirtualBaseClassIndicies.end())
+ return 0;
+
assert(I != VirtualBaseClassIndicies.end() && "Did not find index!");
return I->second;
Modified: cfe/trunk/test/CodeGenCXX/vtable-layout.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/vtable-layout.cpp?rev=96114&r1=96113&r2=96114&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/vtable-layout.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/vtable-layout.cpp Sat Feb 13 14:11:51 2010
@@ -78,7 +78,7 @@
// CHECK-NEXT: 1 | Test3::B RTTI
// CHECK-NEXT: -- (Test3::A, 0) vtable address --
// CHECK-NEXT: -- (Test3::B, 0) vtable address --
-// CHECK-NEXT: 2 | void Test3::A::f()
+// CHECK-NEXT: 2 | void Test3::B::f()
// CHECK-NEXT: 3 | void Test3::B::g()
struct B : A {
virtual void f();
@@ -106,8 +106,8 @@
// CHECK-NEXT: -- (Test3::A, 0) vtable address --
// CHECK-NEXT: -- (Test3::B, 0) vtable address --
// CHECK-NEXT: -- (Test3::D, 0) vtable address --
-// CHECK-NEXT: 2 | void Test3::A::f()
-// CHECK-NEXT: 3 | void Test3::B::g()
+// CHECK-NEXT: 2 | void Test3::D::f()
+// CHECK-NEXT: 3 | void Test3::D::g()
// CHECK-NEXT: 4 | void Test3::D::h()
struct D : B {
virtual void f();
@@ -118,6 +118,35 @@
void D::f() { }
}
+namespace Test4 {
+
+// Test simple non-virtual result adjustments.
+
+struct R1 { int r1; };
+struct R2 { int r2; };
+struct R3 : R1, R2 { int r3; };
+
+struct A {
+ virtual R2 *f();
+};
+
+// CHECK: Vtable for 'Test4::B' (4 entries).
+// CHECK-NEXT: 0 | offset_to_top (0)
+// CHECK-NEXT: 1 | Test4::B RTTI
+// CHECK-NEXT: -- (Test4::A, 0) vtable address --
+// CHECK-NEXT: -- (Test4::B, 0) vtable address --
+// CHECK-NEXT: 2 | Test4::R3 *Test4::B::f()
+// CHECK-NEXT: [return adjustment: 4 non-virtual]
+// CHECK-NEXT: 3 | Test4::R3 *Test4::B::f()
+
+struct B : A {
+ virtual R3 *f();
+};
+
+R3 *B::f() { return 0; }
+
+}
+
// For now, just verify this doesn't crash.
namespace test0 {
struct Obj {};
More information about the cfe-commits
mailing list