diff options
author | Anders Carlsson <andersca@mac.com> | 2010-02-18 17:26:40 +0000 |
---|---|---|
committer | Anders Carlsson <andersca@mac.com> | 2010-02-18 17:26:40 +0000 |
commit | eb577d0df44df4df974e9b3a538575d92358a3b3 (patch) | |
tree | 2921101c1ed50e5fbc413e424553ad2937bcd681 /lib/CodeGen/CGVtable.cpp | |
parent | be71e3b28a1440fe08c45ecbe25899d99235c309 (diff) |
More work on vcall offsets.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@96587 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CGVtable.cpp')
-rw-r--r-- | lib/CodeGen/CGVtable.cpp | 65 |
1 files changed, 61 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<MethodAndOffsetPairTy, 16> 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 = |