diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-04-06 05:00:46 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-04-06 05:00:46 +0000 |
commit | df931ce82ce9e002ec4d71f74a4bab3bf316b977 (patch) | |
tree | 22878fc50041049347ff35d069b139783fd1d86f /clang/lib/CodeGen/CodeGenModule.cpp | |
parent | c4bd84c1d5f192fae10a3526f6dc2d896b0b2683 (diff) | |
download | bcm5719-llvm-df931ce82ce9e002ec4d71f74a4bab3bf316b977.tar.gz bcm5719-llvm-df931ce82ce9e002ec4d71f74a4bab3bf316b977.zip |
When an internal-linkage function or variable is declared within an extern "C"
linkage specification, and is marked as __attribute__((used)), try to also give
it the unmangled name (by emitting an internal linkage alias) if nothing else
within the translation unit would use that name. This allows inline asm in that
translation unit to use the entity via its unmangled name, which people
apparently rely on.
llvm-svn: 178950
Diffstat (limited to 'clang/lib/CodeGen/CodeGenModule.cpp')
-rw-r--r-- | clang/lib/CodeGen/CodeGenModule.cpp | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index c518a5554e2..670f06620d2 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -186,6 +186,7 @@ void CodeGenModule::Release() { EmitCtorList(GlobalCtors, "llvm.global_ctors"); EmitCtorList(GlobalDtors, "llvm.global_dtors"); EmitGlobalAnnotations(); + EmitStaticExternCAliases(); EmitLLVMUsed(); if (CodeGenOpts.ModulesAutolink) { @@ -1707,6 +1708,39 @@ unsigned CodeGenModule::GetGlobalVarAddressSpace(const VarDecl *D, return AddrSpace; } +template<typename SomeDecl> +void CodeGenModule::MaybeHandleStaticInExternC(const SomeDecl *D, + llvm::GlobalValue *GV) { + if (!getLangOpts().CPlusPlus) + return; + + // Must have 'used' attribute, or else inline assembly can't rely on + // the name existing. + if (!D->template hasAttr<UsedAttr>()) + return; + + // Must have internal linkage and an ordinary name. + if (!D->getIdentifier() || D->getLinkage() != InternalLinkage) + return; + + // Must be in an extern "C" context. Entities declared directly within + // a record are not extern "C" even if the record is in such a context. + const DeclContext *DC = D->getFirstDeclaration()->getDeclContext(); + if (DC->isRecord() || !DC->isExternCContext()) + return; + + // OK, this is an internal linkage entity inside an extern "C" linkage + // specification. Make a note of that so we can give it the "expected" + // mangled name if nothing else is using that name. + StaticExternCMap::iterator I = + StaticExternCValues.insert(std::make_pair(D->getIdentifier(), GV)).first; + + // If we have multiple internal linkage entities with the same name + // in extern "C" regions, none of them gets that name. + if (I->second != GV) + I->second = 0; +} + void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { llvm::Constant *Init = 0; QualType ASTTy = D->getType(); @@ -1805,6 +1839,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { cast<llvm::GlobalValue>(Entry)->eraseFromParent(); } + MaybeHandleStaticInExternC(D, GV); + if (D->hasAttr<AnnotateAttr>()) AddGlobalAnnotations(D, GV); @@ -2083,6 +2119,8 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) { // FIXME: this is redundant with part of SetFunctionDefinitionAttributes setGlobalVisibility(Fn, D); + MaybeHandleStaticInExternC(D, Fn); + CodeGenFunction(*this).GenerateCode(D, Fn, FI); SetFunctionDefinitionAttributes(D, Fn); @@ -2903,6 +2941,21 @@ static void EmitGlobalDeclMetadata(CodeGenModule &CGM, GlobalMetadata->addOperand(llvm::MDNode::get(CGM.getLLVMContext(), Ops)); } +/// For each function which is declared within an extern "C" region and marked +/// as 'used', but has internal linkage, create an alias from the unmangled +/// name to the mangled name if possible. People expect to be able to refer +/// to such functions with an unmangled name from inline assembly within the +/// same translation unit. +void CodeGenModule::EmitStaticExternCAliases() { + for (StaticExternCMap::iterator I = StaticExternCValues.begin(), + E = StaticExternCValues.end(); + I != E; ++I) + if (I->second && !getModule().getNamedValue(I->first->getName())) + AddUsedGlobal( + new llvm::GlobalAlias(I->second->getType(), I->second->getLinkage(), + I->first->getName(), I->second, &getModule())); +} + /// Emits metadata nodes associating all the global values in the /// current module with the Decls they came from. This is useful for /// projects using IR gen as a subroutine. |