diff --git a/clang/lib/CodeGen/CGVtable.cpp b/clang/lib/CodeGen/CGVtable.cpp index 3962ecdc387d..398033067091 100644 --- a/clang/lib/CodeGen/CGVtable.cpp +++ b/clang/lib/CodeGen/CGVtable.cpp @@ -95,8 +95,10 @@ public: return llvm::ConstantExpr::getBitCast(m, Ptr8Ty); } - void GenerateVBaseOffsets(std::vector &offsets, - const CXXRecordDecl *RD, uint64_t Offset, +#define D1(x) +//#define D1(X) do { if (getenv("DEBUG")) { X; } } while (0) + + void GenerateVBaseOffsets(const CXXRecordDecl *RD, uint64_t Offset, bool updateVBIndex, Index_t current_vbindex) { for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), e = RD->bases_end(); i != e; ++i) { @@ -105,22 +107,24 @@ public: Index_t next_vbindex = current_vbindex; if (i->isVirtual() && !SeenVBase.count(Base)) { SeenVBase.insert(Base); - int64_t BaseOffset = -(Offset/8) + BLayout.getVBaseClassOffset(Base)/8; - llvm::Constant *m = wrap(BaseOffset); - m = wrap((0?700:0) + BaseOffset); if (updateVBIndex) { - next_vbindex = (ssize_t)(-(offsets.size()*LLVMPointerWidth/8) + next_vbindex = (ssize_t)(-(VCalls.size()*LLVMPointerWidth/8) - 3*LLVMPointerWidth/8); VBIndex[Base] = next_vbindex; } - offsets.push_back(m); + int64_t BaseOffset = -(Offset/8) + BLayout.getVBaseClassOffset(Base)/8; + VCalls.push_back((0?700:0) + BaseOffset); + D1(printf(" vbase for %s at %d delta %d most derived %s\n", + Base->getNameAsCString(), + (int)-VCalls.size()-3, (int)BaseOffset, + Class->getNameAsCString())); } // We also record offsets for non-virtual bases to closest enclosing // virtual base. We do this so that we don't have to search // for the nearst virtual base class when generating thunks. if (updateVBIndex && VBIndex.count(Base) == 0) VBIndex[Base] = next_vbindex; - GenerateVBaseOffsets(offsets, Base, Offset, updateVBIndex, next_vbindex); + GenerateVBaseOffsets(Base, Offset, updateVBIndex, next_vbindex); } } @@ -237,9 +241,17 @@ public: VCallOffset[MD] = OverrideOffset/8; idx = VCalls.size()+1; VCalls.push_back(0); + D1(printf(" vcall for %s at %d with delta %d most derived %s\n", + MD->getNameAsCString(), + (int)-VCalls.size()-3, (int)VCallOffset[MD], + Class->getNameAsCString())); } else { VCallOffset[MD] = VCallOffset[OMD]; VCalls[idx-1] = -VCallOffset[OMD] + OverrideOffset/8; + D1(printf(" vcall patch for %s at %d with delta %d most derived %s\n", + MD->getNameAsCString(), + (int)-VCalls.size()-3, (int)VCallOffset[MD], + Class->getNameAsCString())); } VCall[MD] = idx; CallOffset ThisOffset; @@ -340,7 +352,8 @@ public: } } - void AddMethod(const CXXMethodDecl *MD, bool MorallyVirtual, Index_t Offset) { + void AddMethod(const CXXMethodDecl *MD, bool MorallyVirtual, Index_t Offset, + bool ForVirtualBase) { llvm::Constant *m = WrapAddrOf(MD); // If we can find a previously allocated slot for this, reuse it. @@ -350,6 +363,7 @@ public: // else allocate a new slot. Index[MD] = submethods.size(); submethods.push_back(m); + D1(printf(" vfn for %s at %d\n", MD->getNameAsCString(), (int)Index[MD])); if (MD->isPure()) Pures[MD] = 1; if (MorallyVirtual) { @@ -359,16 +373,19 @@ public: if (idx == 0) { idx = VCalls.size()+1; VCalls.push_back(0); + D1(printf(" vcall for %s at %d with delta %d\n", + MD->getNameAsCString(), (int)-VCalls.size()-3, + (int)VCallOffset[MD])); } } } void AddMethods(const CXXRecordDecl *RD, bool MorallyVirtual, - Index_t Offset) { + Index_t Offset, bool RDisVirtualBase) { for (method_iter mi = RD->method_begin(), me = RD->method_end(); mi != me; ++mi) if (mi->isVirtual()) - AddMethod(*mi, MorallyVirtual, Offset); + AddMethod(*mi, MorallyVirtual, Offset, RDisVirtualBase); } void NonVirtualBases(const CXXRecordDecl *RD, const ASTRecordLayout &Layout, @@ -397,6 +414,7 @@ public: void insertVCalls(int InsertionPoint) { llvm::Constant *e = 0; + D1(printf("============= combining vbase/vcall\n")); D(VCalls.insert(VCalls.begin(), 673)); D(VCalls.push_back(672)); methods.insert(methods.begin() + InsertionPoint, VCalls.size(), e); @@ -408,11 +426,10 @@ public: VCalls.clear(); } - Index_t end(const CXXRecordDecl *RD, std::vector &offsets, - const ASTRecordLayout &Layout, - const CXXRecordDecl *PrimaryBase, - bool PrimaryBaseWasVirtual, bool MorallyVirtual, - int64_t Offset, bool ForVirtualBase, Path_t *Path) { + Index_t end(const CXXRecordDecl *RD, const ASTRecordLayout &Layout, + const CXXRecordDecl *PrimaryBase, bool PrimaryBaseWasVirtual, + bool MorallyVirtual, int64_t Offset, bool ForVirtualBase, + Path_t *Path) { bool alloc = false; if (Path == 0) { alloc = true; @@ -421,16 +438,6 @@ public: StartNewTable(); extra = 0; - // FIXME: Cleanup. - if (!ForVirtualBase) { - D(methods.push_back(wrap(666))); - // then virtual base offsets... - for (std::vector::reverse_iterator i = offsets.rbegin(), - e = offsets.rend(); i != e; ++i) - methods.push_back(*i); - D(methods.push_back(wrap(667))); - } - bool DeferVCalls = MorallyVirtual || ForVirtualBase; int VCallInsertionPoint = methods.size(); if (!DeferVCalls) { @@ -439,20 +446,12 @@ public: // FIXME: just for extra, or for all uses of VCalls.size post this? extra = -VCalls.size(); - if (ForVirtualBase) { - D(methods.push_back(wrap(668))); - // then virtual base offsets... - for (std::vector::reverse_iterator i = offsets.rbegin(), - e = offsets.rend(); i != e; ++i) - methods.push_back(*i); - D(methods.push_back(wrap(669))); - } - methods.push_back(wrap(-(Offset/8))); methods.push_back(rtti); Index_t AddressPoint = methods.size(); InstallThunks(); + D1(printf("============= combining methods\n")); methods.insert(methods.end(), submethods.begin(), submethods.end()); submethods.clear(); @@ -461,10 +460,8 @@ public: MorallyVirtual, Offset, Path); if (ForVirtualBase) { - D(methods.push_back(wrap(670))); insertVCalls(VCallInsertionPoint); AddressPoint += VCalls.size(); - D(methods.push_back(wrap(671))); } if (alloc) { @@ -473,7 +470,36 @@ public: return AddressPoint; } - void Primaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset) { + void Primaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset, + bool updateVBIndex, Index_t current_vbindex, + bool RDisVirtualBase) { + if (!RD->isDynamicClass()) + return; + + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual(); + + // vtables are composed from the chain of primaries. + if (PrimaryBase) { + D1(printf(" doing primaries for %s most derived %s\n", + RD->getNameAsCString(), Class->getNameAsCString())); + + if (!PrimaryBaseWasVirtual) + Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset, + updateVBIndex, current_vbindex, PrimaryBaseWasVirtual); + } + + D1(printf(" doing vcall entries for %s most derived %s\n", + RD->getNameAsCString(), Class->getNameAsCString())); + + // And add the virtuals for the class to the primary vtable. + AddMethods(RD, MorallyVirtual, Offset, RDisVirtualBase); + } + + void VBPrimaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset, + bool updateVBIndex, Index_t current_vbindex, + bool RDisVirtualBase, bool bottom=false) { if (!RD->isDynamicClass()) return; @@ -485,11 +511,22 @@ public: if (PrimaryBase) { if (PrimaryBaseWasVirtual) IndirectPrimary.insert(PrimaryBase); - Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset); + + D1(printf(" doing primaries for %s most derived %s\n", + RD->getNameAsCString(), Class->getNameAsCString())); + + VBPrimaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset, + updateVBIndex, current_vbindex, PrimaryBaseWasVirtual); } - // And add the virtuals for the class to the primary vtable. - AddMethods(RD, MorallyVirtual, Offset); + D1(printf(" doing vbase entries for %s most derived %s\n", + RD->getNameAsCString(), Class->getNameAsCString())); + GenerateVBaseOffsets(RD, Offset, updateVBIndex, current_vbindex); + + if (RDisVirtualBase || bottom) { + Primaries(RD, MorallyVirtual, Offset, updateVBIndex, current_vbindex, + RDisVirtualBase); + } } int64_t GenerateVtableForBase(const CXXRecordDecl *RD, @@ -503,19 +540,21 @@ public: const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual(); - std::vector offsets; extra = 0; - GenerateVBaseOffsets(offsets, RD, Offset, !ForVirtualBase, 0); - if (ForVirtualBase) - extra = offsets.size(); + D1(printf("building entries for base %s most derived %s\n", + RD->getNameAsCString(), Class->getNameAsCString())); - Primaries(RD, MorallyVirtual, Offset); + if (ForVirtualBase) + extra = VCalls.size(); + + VBPrimaries(RD, MorallyVirtual, Offset, !ForVirtualBase, 0, ForVirtualBase, + true); if (Path) OverrideMethods(Path, MorallyVirtual, Offset); - return end(RD, offsets, Layout, PrimaryBase, PrimaryBaseWasVirtual, - MorallyVirtual, Offset, ForVirtualBase, Path); + return end(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual, MorallyVirtual, + Offset, ForVirtualBase, Path); } void GenerateVtableForVBases(const CXXRecordDecl *RD, @@ -540,6 +579,8 @@ public: VCall.clear(); int64_t BaseOffset = BLayout.getVBaseClassOffset(Base); CurrentVBaseOffset = BaseOffset; + D1(printf("vtable %s virtual base %s\n", + Class->getNameAsCString(), Base->getNameAsCString())); GenerateVtableForBase(Base, true, BaseOffset, true, Path); } int64_t BaseOffset = Offset; @@ -575,6 +616,7 @@ int64_t CGVtableInfo::getMethodVtableIndex(const CXXMethodDecl *MD) { // FIXME: This seems expensive. Can we do a partial job to get // just this data. VtableBuilder b(methods, RD, CGM); + D1(printf("vtable %s\n", RD->getNameAsCString())); b.GenerateVtableForBase(RD); b.GenerateVtableForVBases(RD); @@ -599,6 +641,7 @@ int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, // FIXME: This seems expensive. Can we do a partial job to get // just this data. VtableBuilder b(methods, RD, CGM); + D1(printf("vtable %s\n", RD->getNameAsCString())); b.GenerateVtableForBase(RD); b.GenerateVtableForVBases(RD); @@ -629,6 +672,7 @@ llvm::Value *CodeGenFunction::GenerateVtable(const CXXRecordDecl *RD) { VtableBuilder b(methods, RD, CGM); + D1(printf("vtable %s\n", RD->getNameAsCString())); // First comes the vtables for all the non-virtual bases... AddressPoint = b.GenerateVtableForBase(RD); diff --git a/clang/test/CodeGenCXX/virt.cpp b/clang/test/CodeGenCXX/virt.cpp index ffd87bd967ba..e3b4526bb44c 100644 --- a/clang/test/CodeGenCXX/virt.cpp +++ b/clang/test/CodeGenCXX/virt.cpp @@ -306,10 +306,10 @@ struct test5_D : virtual test5_B1, virtual test5_B21, virtual test5_B31 { // CHECK-LP32-NEXT: .long __ZN9test5_B227funcB22Ev // CHECK-LP32-NEXT: .long __ZN9test5_B217funcB21Ev // CHECK-LP32-NEXT: .space 4 -// CHECK-LP32: .long 8 -// CHECK-LP32 .space 4 -// CHECK-LP32 .space 4 FIXME -// CHECK-LP32: .long 4 +// CHECK-LP32-NEXT: .long 8 +// CHECK-LP32-NEXT: .space 4 +// CHECK-LP32-NEXT: .space 4 +// CHECK-LP32-NEXT: .long 4 // CHECK-LP32-NEXT: .space 4 // CHECK-LP32-NEXT: .space 4 // CHECK-LP32-NEXT: .long 4294967288 @@ -358,10 +358,10 @@ struct test5_D : virtual test5_B1, virtual test5_B21, virtual test5_B31 { // CHECK-LP64-NEXT: .quad __ZN9test5_B227funcB22Ev // CHECK-LP64-NEXT: .quad __ZN9test5_B217funcB21Ev // CHECK-LP64-NEXT: .space 8 -// CHECK-LP64: .quad 16 -// CHECK-LP64 .space 8 -// CHECK-LP64 .space 8 -// CHECK-LP64: .quad 8 +// CHECK-LP64-NEXT: .quad 16 +// CHECK-LP64-NEXT: .space 8 +// CHECK-LP64-NEXT: .space 8 +// CHECK-LP64-NEXT: .quad 8 // CHECK-LP64-NEXT: .space 8 // CHECK-LP64-NEXT: .space 8 // CHECK-LP64-NEXT: .quad 18446744073709551600