From eb577d0df44df4df974e9b3a538575d92358a3b3 Mon Sep 17 00:00:00 2001 From: Anders Carlsson Date: Thu, 18 Feb 2010 17:26:40 +0000 Subject: [PATCH] More work on vcall offsets. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@96587 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGVtable.cpp | 65 +++++++++++++++++-- .../CodeGenCXX/vtable-layout-abi-examples.cpp | 25 +++++++ 2 files changed, 86 insertions(+), 4 deletions(-) diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp index 95bacec31b..176e9c3037 100644 --- a/lib/CodeGen/CGVtable.cpp +++ b/lib/CodeGen/CGVtable.cpp @@ -803,6 +803,11 @@ struct VCallOffsetMap { // FIXME: This should be a real map and not a vector. llvm::SmallVector Offsets; + /// MethodsCanShareVCallOffset - Returns whether two virtual member functions + /// can share the same vcall offset. + static bool MethodsCanShareVCallOffset(const CXXMethodDecl *LHS, + const CXXMethodDecl *RHS); + public: /// AddVCallOffset - Adds a vcall offset to the map. Returns true if the /// add was successful, or false if there was already a member function with @@ -817,14 +822,50 @@ public: void clear() { Offsets.clear(); } }; +bool VCallOffsetMap::MethodsCanShareVCallOffset(const CXXMethodDecl *LHS, + const CXXMethodDecl *RHS) { + assert(LHS->isVirtual() && "LHS must be virtual!"); + assert(RHS->isVirtual() && "LHS must be virtual!"); + + // FIXME: We need to check more things here. + + DeclarationName LHSName = LHS->getDeclName(); + DeclarationName RHSName = RHS->getDeclName(); + if (LHSName.getNameKind() != LHSName.getNameKind()) + return false; + + switch (LHSName.getNameKind()) { + default: + assert(false && "Unhandled name kind!"); + case DeclarationName::Identifier: + if (LHSName.getAsIdentifierInfo() != RHSName.getAsIdentifierInfo()) + return false; + } + + return true; +} + bool VCallOffsetMap::AddVCallOffset(const CXXMethodDecl *MD, int64_t OffsetOffset) { - /// FIXME: Implement this. + // Check if we can reuse an offset. + for (unsigned I = 0, E = Offsets.size(); I != E; ++I) { + if (MethodsCanShareVCallOffset(Offsets[I].first, MD)) + return false; + } + + // Add the offset. + Offsets.push_back(MethodAndOffsetPairTy(MD, OffsetOffset)); return true; } int64_t VCallOffsetMap::getVCallOffsetOffset(const CXXMethodDecl *MD) { - // FIXME: Implement this. + // Look for an offset. + for (unsigned I = 0, E = Offsets.size(); I != E; ++I) { + if (MethodsCanShareVCallOffset(Offsets[I].first, MD)) + return Offsets[I].second; + } + + assert(false && "Should always find a vcall offset offset!"); return 0; } @@ -1010,7 +1051,11 @@ VtableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD, ThisAdjustment Adjustment; if (!Offset.isEmpty()) { - assert(!Offset.VirtualBase && "FIXME: Handle virtual bases!"); + if (Offset.VirtualBase) { + // Get the vcall offset offset. + Adjustment.VCallOffsetOffset = VCallOffsets.getVCallOffsetOffset(MD); + } + Adjustment.NonVirtual = Offset.NonVirtualOffset; } @@ -1069,8 +1114,20 @@ void VtableBuilder::AddVCallOffsets(BaseSubobject Base) { if (!MD->isVirtual()) continue; - // FIXME: Check if we already have a vcall offset for this member function + // OffsetIndex is the index of this vcall offset, relative to the vtable + // address point. (We subtract 3 to account for the information just + // above the address point, the RTTI info, the offset to top, and the + // vcall offset itself). + int64_t OffsetIndex = -(3 + VCallAndVBaseOffsets.size()); + + // FIXME: We shouldn't use / 8 here. + int64_t OffsetOffset = OffsetIndex * + (int64_t)Context.Target.getPointerWidth(0) / 8; + + // Don't add a vcall offset if we already have one for this member function // signature. + if (!VCallOffsets.AddVCallOffset(MD, OffsetOffset)) + continue; // Get the 'this' pointer adjustment offset. FinalOverriders::BaseOffset ThisAdjustmentOffset = diff --git a/test/CodeGenCXX/vtable-layout-abi-examples.cpp b/test/CodeGenCXX/vtable-layout-abi-examples.cpp index c7008bbe4f..52c8bc6d8f 100644 --- a/test/CodeGenCXX/vtable-layout-abi-examples.cpp +++ b/test/CodeGenCXX/vtable-layout-abi-examples.cpp @@ -21,5 +21,30 @@ struct A { int ia; }; void A::f() {} + +// CHECK: Vtable for 'Test1::B' (13 entries). +// CHECK-NEXT: 0 | vbase_offset (16) +// CHECK-NEXT: 1 | offset_to_top (0) +// CHECK-NEXT: 2 | Test1::B RTTI +// CHECK-NEXT: -- (Test1::B, 0) vtable address -- +// CHECK-NEXT: 3 | void Test1::B::f() +// CHECK-NEXT: 4 | void Test1::B::h() +// CHECK-NEXT: 5 | vcall_offset (-16) +// CHECK-NEXT: 6 | vcall_offset (0) +// CHECK-NEXT: 7 | vcall_offset (-16) +// CHECK-NEXT: 8 | offset_to_top (-16) +// CHECK-NEXT: 9 | Test1::B RTTI +// CHECK-NEXT: -- (Test1::A, 16) vtable address -- +// CHECK-NEXT: 10 | void Test1::B::f() +// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +// CHECK-NEXT: 11 | void Test1::A::g() +// CHECK-NEXT: 12 | void Test1::B::h() +// CHECK-NEXT: [this adjustment: 0 non-virtual, -40 vcall offset offset] +struct B: public virtual A { + void f (); + void h (); + int ib; +}; +void B::f() {} }