diff options
author | Rafael Espindola <rafael.espindola@gmail.com> | 2014-09-16 15:18:21 +0000 |
---|---|---|
committer | Rafael Espindola <rafael.espindola@gmail.com> | 2014-09-16 15:18:21 +0000 |
commit | 1e4df92f4939a79a77be57ff145a252730749b11 (patch) | |
tree | 939202d44c99415dbf25610d58610db8a446f3fb /clang/lib/CodeGen | |
parent | 65f105719121ecddd8826f6d1f4f3b60d7d3a28d (diff) | |
download | bcm5719-llvm-1e4df92f4939a79a77be57ff145a252730749b11.tar.gz bcm5719-llvm-1e4df92f4939a79a77be57ff145a252730749b11.zip |
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.
llvm-svn: 217874
Diffstat (limited to 'clang/lib/CodeGen')
-rw-r--r-- | clang/lib/CodeGen/CGClass.cpp | 3 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenModule.cpp | 4 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenModule.h | 16 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenTypes.h | 6 | ||||
-rw-r--r-- | clang/lib/CodeGen/ItaniumCXXABI.cpp | 142 |
5 files changed, 126 insertions, 45 deletions
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index 72869d8ca9b..941e998bfd7 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -1292,6 +1292,9 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) { // 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: diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 9938c2401f9..5e87fc2799c 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -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(); diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 6012606e3de..b36d4a66cd8 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -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. diff --git a/clang/lib/CodeGen/CodeGenTypes.h b/clang/lib/CodeGen/CodeGenTypes.h index d422f554108..0ca274b8ff2 100644 --- a/clang/lib/CodeGen/CodeGenTypes.h +++ b/clang/lib/CodeGen/CodeGenTypes.h @@ -80,8 +80,8 @@ inline StructorType getFromCtorType(CXXCtorType T) { 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(CXXDtorType T) { return StructorType::Complete; case Dtor_Base: return StructorType::Base; + case Dtor_Comdat: + llvm_unreachable("not expecting a COMDAT"); } llvm_unreachable("not a CXXDtorType"); } diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 91e9d4d7a08..038d890c9d6 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -2999,35 +2999,102 @@ ItaniumCXXABI::RTTIUniquenessKind ItaniumCXXABI::classifyRTTIUniqueness( 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; + + if (llvm::GlobalValue::isWeakForLinker(Linkage)) + return StructorCodegen::COMDAT; + + return StructorCodegen::Alias; +} + +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); } - CGM.codegenCXXStructor(ctor, ctorType); -} - -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)); + // 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(CodeGenModule &CGM, const CXXDestructorDecl *dtor, // 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); } |