On Tue, Sep 16, 2014 at 8:18 AM, Rafael Espindola < [email protected]> wrote:
> Author: rafael > Date: Tue Sep 16 10:18:21 2014 > New Revision: 217874 > > URL: http://llvm.org/viewvc/llvm-project?rev=217874&view=rev > Log: > Add support for putting constructors and destructos in explicit comdats. > > There are situations when clang knows that the C1 and C2 constructors > or the D1 and D2 destructors are identical. We already optimize some > of these cases, but cannot optimize it when the GlobalValue is > weak_odr. > > The problem with weak_odr is that an old TU seeing the same code will > have a C1 and a C2 comdat with the corresponding symbols. We cannot > suddenly start putting the C2 symbol in the C1 comdat as we cannot > guarantee that the linker will not pick a .o with only C1 in it. > > The solution implemented by GCC is to expand the ABI to have a comdat > whose name uses a C5/D5 suffix and always has both symbols. That is > what this patch implements. > I was sort of hoping this would happen - this change caused an XPASS on the GDB buildbot ( http://lab.llvm.org:8011/builders/clang-x86_64-ubuntu-gdb-75/builds/17323 ) as it resolves PR14473. I've updated the test case in r217882 & marked the bug as resolved. Thanks! > > Modified: > cfe/trunk/include/clang/AST/Mangle.h > cfe/trunk/include/clang/Basic/ABI.h > cfe/trunk/lib/AST/ItaniumMangle.cpp > cfe/trunk/lib/AST/MicrosoftMangle.cpp > cfe/trunk/lib/CodeGen/CGClass.cpp > cfe/trunk/lib/CodeGen/CodeGenModule.cpp > cfe/trunk/lib/CodeGen/CodeGenModule.h > cfe/trunk/lib/CodeGen/CodeGenTypes.h > cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp > cfe/trunk/test/CodeGenCXX/ctor-dtor-alias.cpp > cfe/trunk/test/CodeGenCXX/destructors.cpp > cfe/trunk/test/CodeGenCXX/virtual-destructor-calls.cpp > > Modified: cfe/trunk/include/clang/AST/Mangle.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Mangle.h?rev=217874&r1=217873&r2=217874&view=diff > > ============================================================================== > --- cfe/trunk/include/clang/AST/Mangle.h (original) > +++ cfe/trunk/include/clang/AST/Mangle.h Tue Sep 16 10:18:21 2014 > @@ -156,6 +156,11 @@ public: > virtual void mangleItaniumThreadLocalWrapper(const VarDecl *D, > raw_ostream &) = 0; > > + virtual void mangleCXXCtorComdat(const CXXConstructorDecl *D, > + raw_ostream &) = 0; > + virtual void mangleCXXDtorComdat(const CXXDestructorDecl *D, > + raw_ostream &) = 0; > + > static bool classof(const MangleContext *C) { > return C->getKind() == MK_Itanium; > } > > Modified: cfe/trunk/include/clang/Basic/ABI.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/ABI.h?rev=217874&r1=217873&r2=217874&view=diff > > ============================================================================== > --- cfe/trunk/include/clang/Basic/ABI.h (original) > +++ cfe/trunk/include/clang/Basic/ABI.h Tue Sep 16 10:18:21 2014 > @@ -24,14 +24,15 @@ namespace clang { > enum CXXCtorType { > Ctor_Complete, ///< Complete object ctor > Ctor_Base, ///< Base object ctor > - Ctor_CompleteAllocating ///< Complete object allocating ctor > + Ctor_Comdat ///< The COMDAT used for ctors > }; > > /// \brief C++ destructor types. > enum CXXDtorType { > Dtor_Deleting, ///< Deleting dtor > Dtor_Complete, ///< Complete object dtor > - Dtor_Base ///< Base object dtor > + Dtor_Base, ///< Base object dtor > + Dtor_Comdat ///< The COMDAT used for dtors > }; > > /// \brief A return adjustment. > > Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=217874&r1=217873&r2=217874&view=diff > > ============================================================================== > --- cfe/trunk/lib/AST/ItaniumMangle.cpp (original) > +++ cfe/trunk/lib/AST/ItaniumMangle.cpp Tue Sep 16 10:18:21 2014 > @@ -150,6 +150,8 @@ public: > void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, > raw_ostream &) override; > > + void mangleCXXCtorComdat(const CXXConstructorDecl *D, raw_ostream &) > override; > + void mangleCXXDtorComdat(const CXXDestructorDecl *D, raw_ostream &) > override; > void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &) > override; > void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out) > override; > void mangleDynamicAtExitDestructor(const VarDecl *D, > @@ -3249,8 +3251,8 @@ void CXXNameMangler::mangleFunctionParam > void CXXNameMangler::mangleCXXCtorType(CXXCtorType T) { > // <ctor-dtor-name> ::= C1 # complete object constructor > // ::= C2 # base object constructor > - // ::= C3 # complete object allocating constructor > // > + // In addition, C5 is a comdat name with C1 and C2 in it. > switch (T) { > case Ctor_Complete: > Out << "C1"; > @@ -3258,8 +3260,8 @@ void CXXNameMangler::mangleCXXCtorType(C > case Ctor_Base: > Out << "C2"; > break; > - case Ctor_CompleteAllocating: > - Out << "C3"; > + case Ctor_Comdat: > + Out << "C5"; > break; > } > } > @@ -3269,6 +3271,7 @@ void CXXNameMangler::mangleCXXDtorType(C > // ::= D1 # complete object destructor > // ::= D2 # base object destructor > // > + // In addition, D5 is a comdat name with D1, D2 and, if virtual, D0 in > it. > switch (T) { > case Dtor_Deleting: > Out << "D0"; > @@ -3279,6 +3282,9 @@ void CXXNameMangler::mangleCXXDtorType(C > case Dtor_Base: > Out << "D2"; > break; > + case Dtor_Comdat: > + Out << "D5"; > + break; > } > } > > @@ -3689,6 +3695,18 @@ void ItaniumMangleContextImpl::mangleCXX > Mangler.mangle(D); > } > > +void ItaniumMangleContextImpl::mangleCXXCtorComdat(const > CXXConstructorDecl *D, > + raw_ostream &Out) { > + CXXNameMangler Mangler(*this, Out, D, Ctor_Comdat); > + Mangler.mangle(D); > +} > + > +void ItaniumMangleContextImpl::mangleCXXDtorComdat(const > CXXDestructorDecl *D, > + raw_ostream &Out) { > + CXXNameMangler Mangler(*this, Out, D, Dtor_Comdat); > + Mangler.mangle(D); > +} > + > void ItaniumMangleContextImpl::mangleThunk(const CXXMethodDecl *MD, > const ThunkInfo &Thunk, > raw_ostream &Out) { > > Modified: cfe/trunk/lib/AST/MicrosoftMangle.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/MicrosoftMangle.cpp?rev=217874&r1=217873&r2=217874&view=diff > > ============================================================================== > --- cfe/trunk/lib/AST/MicrosoftMangle.cpp (original) > +++ cfe/trunk/lib/AST/MicrosoftMangle.cpp Tue Sep 16 10:18:21 2014 > @@ -854,6 +854,8 @@ void MicrosoftCXXNameMangler::mangleCXXD > // <operator-name> ::= ?_E # vector deleting destructor > // FIXME: Add a vector deleting dtor type. It goes in the vtable, so > we need > // it. > + case Dtor_Comdat: > + llvm_unreachable("not expecting a COMDAT"); > } > llvm_unreachable("Unsupported dtor type?"); > } > > Modified: cfe/trunk/lib/CodeGen/CGClass.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=217874&r1=217873&r2=217874&view=diff > > ============================================================================== > --- cfe/trunk/lib/CodeGen/CGClass.cpp (original) > +++ cfe/trunk/lib/CodeGen/CGClass.cpp Tue Sep 16 10:18:21 2014 > @@ -1292,6 +1292,9 @@ void CodeGenFunction::EmitDestructorBody > // we'd introduce *two* handler blocks. In the Microsoft ABI, we > // always delegate because we might not have a definition in this TU. > switch (DtorType) { > + case Dtor_Comdat: > + llvm_unreachable("not expecting a COMDAT"); > + > case Dtor_Deleting: llvm_unreachable("already handled deleting case"); > > case Dtor_Complete: > > Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=217874&r1=217873&r2=217874&view=diff > > ============================================================================== > --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original) > +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Tue Sep 16 10:18:21 2014 > @@ -198,6 +198,10 @@ void CodeGenModule::createCUDARuntime() > CUDARuntime = CreateNVCUDARuntime(*this); > } > > +void CodeGenModule::addReplacement(StringRef Name, llvm::Constant *C) { > + Replacements[Name] = C; > +} > + > void CodeGenModule::applyReplacements() { > for (ReplacementsTy::iterator I = Replacements.begin(), > E = Replacements.end(); > > Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=217874&r1=217873&r2=217874&view=diff > > ============================================================================== > --- cfe/trunk/lib/CodeGen/CodeGenModule.h (original) > +++ cfe/trunk/lib/CodeGen/CodeGenModule.h Tue Sep 16 10:18:21 2014 > @@ -1058,9 +1058,17 @@ public: > void setFunctionDefinitionAttributes(const FunctionDecl *D, > llvm::Function *F); > > -private: > llvm::GlobalValue *GetGlobalValue(StringRef Ref); > > + /// Set attributes which are common to any form of a global definition > (alias, > + /// Objective-C method, function, global variable). > + /// > + /// NOTE: This should only be called for definitions. > + void SetCommonAttributes(const Decl *D, llvm::GlobalValue *GV); > + > + void addReplacement(StringRef Name, llvm::Constant *C); > +private: > + > llvm::Constant * > GetOrCreateLLVMFunction(StringRef MangledName, llvm::Type *Ty, > GlobalDecl D, > bool ForVTable, bool DontDefer = false, > @@ -1070,12 +1078,6 @@ private: > llvm::PointerType *PTy, > const VarDecl *D); > > - /// Set attributes which are common to any form of a global definition > (alias, > - /// Objective-C method, function, global variable). > - /// > - /// NOTE: This should only be called for definitions. > - void SetCommonAttributes(const Decl *D, llvm::GlobalValue *GV); > - > void setNonAliasAttributes(const Decl *D, llvm::GlobalObject *GO); > > /// Set function attributes for a function declaration. > > Modified: cfe/trunk/lib/CodeGen/CodeGenTypes.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenTypes.h?rev=217874&r1=217873&r2=217874&view=diff > > ============================================================================== > --- cfe/trunk/lib/CodeGen/CodeGenTypes.h (original) > +++ cfe/trunk/lib/CodeGen/CodeGenTypes.h Tue Sep 16 10:18:21 2014 > @@ -80,8 +80,8 @@ inline StructorType getFromCtorType(CXXC > return StructorType::Complete; > case Ctor_Base: > return StructorType::Base; > - case Ctor_CompleteAllocating: > - llvm_unreachable("invalid enum"); > + case Ctor_Comdat: > + llvm_unreachable("not expecting a COMDAT"); > } > llvm_unreachable("not a CXXCtorType"); > } > @@ -106,6 +106,8 @@ inline StructorType getFromDtorType(CXXD > return StructorType::Complete; > case Dtor_Base: > return StructorType::Base; > + case Dtor_Comdat: > + llvm_unreachable("not expecting a COMDAT"); > } > llvm_unreachable("not a CXXDtorType"); > } > > Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=217874&r1=217873&r2=217874&view=diff > > ============================================================================== > --- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original) > +++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Tue Sep 16 10:18:21 2014 > @@ -2999,35 +2999,102 @@ ItaniumCXXABI::RTTIUniquenessKind Itaniu > return RUK_NonUniqueVisible; > } > > -static void emitCXXConstructor(CodeGenModule &CGM, > - const CXXConstructorDecl *ctor, > - StructorType ctorType) { > - if (!ctor->getParent()->getNumVBases() && > - (ctorType == StructorType::Complete || ctorType == > StructorType::Base)) { > - // The complete constructor is equivalent to the base constructor > - // for classes with no virtual bases. Try to emit it as an alias. > - bool ProducedAlias = !CGM.TryEmitDefinitionAsAlias( > - GlobalDecl(ctor, Ctor_Complete), GlobalDecl(ctor, Ctor_Base), > true); > - if (ctorType == StructorType::Complete && ProducedAlias) > - return; > +// Find out how to codegen the complete destructor and constructor > +namespace { > +enum class StructorCodegen { Emit, RAUW, Alias, COMDAT }; > +} > +static StructorCodegen getCodegenToUse(CodeGenModule &CGM, > + const CXXMethodDecl *MD) { > + if (!CGM.getCodeGenOpts().CXXCtorDtorAliases) > + return StructorCodegen::Emit; > + > + // The complete and base structors are not equivalent if there are any > virtual > + // bases, so emit separate functions. > + if (MD->getParent()->getNumVBases()) > + return StructorCodegen::Emit; > + > + GlobalDecl AliasDecl; > + if (const auto *DD = dyn_cast<CXXDestructorDecl>(MD)) { > + AliasDecl = GlobalDecl(DD, Dtor_Complete); > + } else { > + const auto *CD = cast<CXXConstructorDecl>(MD); > + AliasDecl = GlobalDecl(CD, Ctor_Complete); > } > + llvm::GlobalValue::LinkageTypes Linkage = > CGM.getFunctionLinkage(AliasDecl); > + > + if (llvm::GlobalValue::isDiscardableIfUnused(Linkage)) > + return StructorCodegen::RAUW; > + > + // FIXME: Should we allow available_externally aliases? > + if (!llvm::GlobalAlias::isValidLinkage(Linkage)) > + return StructorCodegen::RAUW; > > - CGM.codegenCXXStructor(ctor, ctorType); > + if (llvm::GlobalValue::isWeakForLinker(Linkage)) > + return StructorCodegen::COMDAT; > + > + return StructorCodegen::Alias; > } > > -static void emitCXXDestructor(CodeGenModule &CGM, const CXXDestructorDecl > *dtor, > - StructorType dtorType) { > - // The complete destructor is equivalent to the base destructor for > - // classes with no virtual bases, so try to emit it as an alias. > - if (!dtor->getParent()->getNumVBases() && > - (dtorType == StructorType::Complete || dtorType == > StructorType::Base)) { > - bool ProducedAlias = !CGM.TryEmitDefinitionAsAlias( > - GlobalDecl(dtor, Dtor_Complete), GlobalDecl(dtor, Dtor_Base), > true); > - if (ProducedAlias) { > - if (dtorType == StructorType::Complete) > - return; > - if (dtor->isVirtual()) > - CGM.getVTables().EmitThunks(GlobalDecl(dtor, Dtor_Complete)); > +static void emitConstructorDestructorAlias(CodeGenModule &CGM, > + GlobalDecl AliasDecl, > + GlobalDecl TargetDecl) { > + llvm::GlobalValue::LinkageTypes Linkage = > CGM.getFunctionLinkage(AliasDecl); > + > + StringRef MangledName = CGM.getMangledName(AliasDecl); > + llvm::GlobalValue *Entry = CGM.GetGlobalValue(MangledName); > + if (Entry && !Entry->isDeclaration()) > + return; > + > + auto *Aliasee = > cast<llvm::GlobalValue>(CGM.GetAddrOfGlobal(TargetDecl)); > + llvm::PointerType *AliasType = Aliasee->getType(); > + > + // Create the alias with no name. > + auto *Alias = llvm::GlobalAlias::create( > + AliasType->getElementType(), 0, Linkage, "", Aliasee, > &CGM.getModule()); > + > + // Switch any previous uses to the alias. > + if (Entry) { > + assert(Entry->getType() == AliasType && > + "declaration exists with different type"); > + Alias->takeName(Entry); > + Entry->replaceAllUsesWith(Alias); > + Entry->eraseFromParent(); > + } else { > + Alias->setName(MangledName); > + } > + > + // Finally, set up the alias with its proper name and attributes. > + CGM.SetCommonAttributes(cast<NamedDecl>(AliasDecl.getDecl()), Alias); > +} > + > +void ItaniumCXXABI::emitCXXStructor(const CXXMethodDecl *MD, > + StructorType Type) { > + auto *CD = dyn_cast<CXXConstructorDecl>(MD); > + const CXXDestructorDecl *DD = CD ? nullptr : > cast<CXXDestructorDecl>(MD); > + > + StructorCodegen CGType = getCodegenToUse(CGM, MD); > + > + if (Type == StructorType::Complete) { > + GlobalDecl CompleteDecl; > + GlobalDecl BaseDecl; > + if (CD) { > + CompleteDecl = GlobalDecl(CD, Ctor_Complete); > + BaseDecl = GlobalDecl(CD, Ctor_Base); > + } else { > + CompleteDecl = GlobalDecl(DD, Dtor_Complete); > + BaseDecl = GlobalDecl(DD, Dtor_Base); > + } > + > + if (CGType == StructorCodegen::Alias || CGType == > StructorCodegen::COMDAT) { > + emitConstructorDestructorAlias(CGM, CompleteDecl, BaseDecl); > + return; > + } > + > + if (CGType == StructorCodegen::RAUW) { > + StringRef MangledName = CGM.getMangledName(CompleteDecl); > + auto *Aliasee = > cast<llvm::GlobalValue>(CGM.GetAddrOfGlobal(BaseDecl)); > + CGM.addReplacement(MangledName, Aliasee); > + return; > } > } > > @@ -3035,17 +3102,20 @@ static void emitCXXDestructor(CodeGenMod > // base class if there is exactly one non-virtual base class with a > // non-trivial destructor, there are no fields with a non-trivial > // destructor, and the body of the destructor is trivial. > - if (dtorType == StructorType::Base && > !CGM.TryEmitBaseDestructorAsAlias(dtor)) > + if (DD && Type == StructorType::Base && CGType != > StructorCodegen::COMDAT && > + !CGM.TryEmitBaseDestructorAsAlias(DD)) > return; > > - CGM.codegenCXXStructor(dtor, dtorType); > -} > + llvm::Function *Fn = CGM.codegenCXXStructor(MD, Type); > > -void ItaniumCXXABI::emitCXXStructor(const CXXMethodDecl *MD, > - StructorType Type) { > - if (auto *CD = dyn_cast<CXXConstructorDecl>(MD)) { > - emitCXXConstructor(CGM, CD, Type); > - return; > + if (CGType == StructorCodegen::COMDAT) { > + SmallString<256> Buffer; > + llvm::raw_svector_ostream Out(Buffer); > + if (DD) > + getMangleContext().mangleCXXDtorComdat(DD, Out); > + else > + getMangleContext().mangleCXXCtorComdat(CD, Out); > + llvm::Comdat *C = CGM.getModule().getOrInsertComdat(Out.str()); > + Fn->setComdat(C); > } > - emitCXXDestructor(CGM, cast<CXXDestructorDecl>(MD), Type); > } > > Modified: cfe/trunk/test/CodeGenCXX/ctor-dtor-alias.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/ctor-dtor-alias.cpp?rev=217874&r1=217873&r2=217874&view=diff > > ============================================================================== > --- cfe/trunk/test/CodeGenCXX/ctor-dtor-alias.cpp (original) > +++ cfe/trunk/test/CodeGenCXX/ctor-dtor-alias.cpp Tue Sep 16 10:18:21 2014 > @@ -6,18 +6,23 @@ > // RUN: FileCheck --check-prefix=CHECK3 --input-file=%t %s > // RUN: FileCheck --check-prefix=CHECK4 --input-file=%t %s > // RUN: FileCheck --check-prefix=CHECK5 --input-file=%t %s > +// RUN: FileCheck --check-prefix=CHECK6 --input-file=%t %s > > namespace test1 { > -// test that we don't produce an alias when the destructor is weak_odr. > The > -// reason to avoid it that another TU might have no explicit template > -// instantiation definition or declaration, causing it to to output only > -// one of the destructors as linkonce_odr, producing a different comdat. > +// Test that we produce the apropriate comdats when creating aliases to > +// weak_odr constructors and destructors. > > -// CHECK1: define weak_odr void @_ZN5test16foobarIvEC2Ev > -// CHECK1: define weak_odr void @_ZN5test16foobarIvEC1Ev > +// CHECK1: @_ZN5test16foobarIvEC1Ev = weak_odr alias void {{.*}} > @_ZN5test16foobarIvEC2Ev > +// CHECK1: @_ZN5test16foobarIvED1Ev = weak_odr alias void > (%"struct.test1::foobar"*)* @_ZN5test16foobarIvED2Ev > +// CHECK1: define weak_odr void @_ZN5test16foobarIvEC2Ev({{.*}} comdat > $_ZN5test16foobarIvEC5Ev > +// CHECK1: define weak_odr void @_ZN5test16foobarIvED2Ev({{.*}} comdat > $_ZN5test16foobarIvED5Ev > +// CHECK1: define weak_odr void @_ZN5test16foobarIvED0Ev({{.*}} comdat > $_ZN5test16foobarIvED5Ev > +// CHECK1-NOT: comdat > > -template <typename T> struct foobar { > +template <typename T> > +struct foobar { > foobar() {} > + virtual ~foobar() {} > }; > > template struct foobar<void>; > @@ -187,3 +192,38 @@ void > fn1() { > new C; > } > + > +namespace test10 { > +// Test that if a destructor is in a comdat, we don't try to emit is as an > +// alias to a base class destructor. > +struct bar { > + ~bar(); > +}; > +bar::~bar() { > +} > +} // closing the namespace causes ~bar to be sent to CodeGen > +namespace test10 { > +template <typename T> > +struct foo : public bar { > + ~foo(); > +}; > +template <typename T> > +foo<T>::~foo() {} > +template class foo<int>; > +// CHECK5: define weak_odr void @_ZN6test103fooIiED2Ev({{.*}} comdat > $_ZN6test103fooIiED5Ev > +} > + > +namespace test11 { > +// Test that when we don't have to worry about COMDATs we produce an alias > +// from complate to base and from base to base class base. > +struct bar { > + ~bar(); > +}; > +bar::~bar() {} > +struct foo : public bar { > + ~foo(); > +}; > +foo::~foo() {} > +// CHECK6: @_ZN6test113fooD2Ev = alias {{.*}} @_ZN6test113barD2Ev > +// CHECK6: @_ZN6test113fooD1Ev = alias {{.*}} @_ZN6test113fooD2Ev > +} > > Modified: cfe/trunk/test/CodeGenCXX/destructors.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/destructors.cpp?rev=217874&r1=217873&r2=217874&view=diff > > ============================================================================== > --- cfe/trunk/test/CodeGenCXX/destructors.cpp (original) > +++ cfe/trunk/test/CodeGenCXX/destructors.cpp Tue Sep 16 10:18:21 2014 > @@ -204,18 +204,14 @@ namespace test3 { > // CHECK4: call void @_ZN5test312_GLOBAL__N_11DD0Ev( > // CHECK4: ret void > > - // CHECK4-LABEL: define internal void > @_ZThn8_N5test312_GLOBAL__N_11CD1Ev( > - // CHECK4: getelementptr inbounds i8* {{.*}}, i64 -8 > - // CHECK4: call void @_ZN5test312_GLOBAL__N_11CD2Ev( > - // CHECK4: ret void > + // CHECK4-LABEL: declare void @_ZN5test31BD2Ev( > + // CHECK4-LABEL: declare void @_ZN5test31AD2Ev( > > // CHECK4-LABEL: define internal void > @_ZN5test312_GLOBAL__N_11CD2Ev(%"struct.test3::(anonymous namespace)::C"* > %this) unnamed_addr > // CHECK4: invoke void @_ZN5test31BD2Ev( > // CHECK4: call void @_ZN5test31AD2Ev( > // CHECK4: ret void > > - // CHECK4: declare void @_ZN5test31BD2Ev( > - // CHECK4: declare void @_ZN5test31AD2Ev( > > // CHECK4-LABEL: define internal void > @_ZN5test312_GLOBAL__N_11CD0Ev(%"struct.test3::(anonymous namespace)::C"* > %this) unnamed_addr > // CHECK4: invoke void @_ZN5test312_GLOBAL__N_11CD2Ev( > @@ -226,6 +222,11 @@ namespace test3 { > // CHECK4: call void @_ZdlPv({{.*}}) [[NUW]] > // CHECK4: resume { i8*, i32 } > > + // CHECK4-LABEL: define internal void > @_ZThn8_N5test312_GLOBAL__N_11CD1Ev( > + // CHECK4: getelementptr inbounds i8* {{.*}}, i64 -8 > + // CHECK4: call void @_ZN5test312_GLOBAL__N_11CD2Ev( > + // CHECK4: ret void > + > // CHECK4-LABEL: define internal void > @_ZThn8_N5test312_GLOBAL__N_11CD0Ev( > // CHECK4: getelementptr inbounds i8* {{.*}}, i64 -8 > // CHECK4: call void @_ZN5test312_GLOBAL__N_11CD0Ev( > > Modified: cfe/trunk/test/CodeGenCXX/virtual-destructor-calls.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/virtual-destructor-calls.cpp?rev=217874&r1=217873&r2=217874&view=diff > > ============================================================================== > --- cfe/trunk/test/CodeGenCXX/virtual-destructor-calls.cpp (original) > +++ cfe/trunk/test/CodeGenCXX/virtual-destructor-calls.cpp Tue Sep 16 > 10:18:21 2014 > @@ -17,8 +17,8 @@ struct B : A { > // CHECK: @_ZN1BD1Ev = alias {{.*}} @_ZN1BD2Ev > > // (aliases from C) > -// CHECK: @_ZN1CD1Ev = alias {{.*}} @_ZN1CD2Ev > // CHECK: @_ZN1CD2Ev = alias bitcast {{.*}} @_ZN1BD2Ev > +// CHECK: @_ZN1CD1Ev = alias {{.*}} @_ZN1CD2Ev > > // Base dtor: actually calls A's base dtor. > // CHECK-LABEL: define void @_ZN1BD2Ev(%struct.B* %this) unnamed_addr > > > _______________________________________________ > cfe-commits mailing list > [email protected] > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits >
_______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
