diff --git a/docs/LangRef.html b/docs/LangRef.html index 457a56ab0cb..8ec11235dc2 100644 --- a/docs/LangRef.html +++ b/docs/LangRef.html @@ -509,6 +509,17 @@ All Global Variables and Functions have one of the following types of linkage: 'static' keyword in C. +
available_externally: +
+ +
Globals with "available_externally" linkage are never emitted + into the object file corresponding to the LLVM module. They exist to + allow inlining and other optimizations to take place given knowledge of the + definition of the global, which is known to be somewhere outside the module. + Globals with available_externally linkage are allowed to be discarded + at will, and are otherwise the same as linkonce_odr. This linkage + type is only allowed on definitions, not declarations.
+
linkonce:
Globals with "linkonce" linkage are merged with other globals of @@ -554,10 +565,10 @@ All Global Variables and Functions have one of the following types of linkage:
linkonce_odr:
weak_odr:
-
Some languages allow inequivalent globals to be merged, such as two +
Some languages allow differing globals to be merged, such as two functions with different semantics. Other languages, such as C++, ensure that only equivalent globals are ever merged (the "one definition - rule" - odr). Such languages can use the linkonce_odr + rule" - "ODR"). Such languages can use the linkonce_odr and weak_odr linkage types to indicate that the global will only be merged with equivalent globals. These linkage types are otherwise the same as their non-odr versions. diff --git a/include/llvm/CodeGen/MachineFunctionPass.h b/include/llvm/CodeGen/MachineFunctionPass.h index 95bb2bf510d..6b5e64abc46 100644 --- a/include/llvm/CodeGen/MachineFunctionPass.h +++ b/include/llvm/CodeGen/MachineFunctionPass.h @@ -24,8 +24,9 @@ namespace llvm { + // FIXME: This pass should declare that the pass does not invalidate any LLVM + // passes. struct MachineFunctionPass : public FunctionPass { - explicit MachineFunctionPass(intptr_t ID) : FunctionPass(ID) {} explicit MachineFunctionPass(void *ID) : FunctionPass(ID) {} @@ -36,14 +37,7 @@ protected: virtual bool runOnMachineFunction(MachineFunction &MF) = 0; public: - // FIXME: This pass should declare that the pass does not invalidate any LLVM - // passes. - bool runOnFunction(Function &F) { - return runOnMachineFunction(MachineFunction::get(&F)); - } - -private: - virtual void virtfn(); // out of line virtual fn to give class a home. + bool runOnFunction(Function &F); }; } // End llvm namespace diff --git a/include/llvm/GlobalValue.h b/include/llvm/GlobalValue.h index e6a82ef22e9..50c613ef6a2 100644 --- a/include/llvm/GlobalValue.h +++ b/include/llvm/GlobalValue.h @@ -31,6 +31,7 @@ public: /// @brief An enumeration for the kinds of linkage for global values. enum LinkageTypes { ExternalLinkage = 0,///< Externally visible function + AvailableExternallyLinkage, ///< Available for inspection, not emission. LinkOnceAnyLinkage, ///< Keep one copy of function when linking (inline) LinkOnceODRLinkage, ///< Same, but only replaced by something equivalent. WeakAnyLinkage, ///< Keep one copy of named function when linking (weak) @@ -109,6 +110,9 @@ public: } bool hasExternalLinkage() const { return Linkage == ExternalLinkage; } + bool hasAvailableExternallyLinkage() const { + return Linkage == AvailableExternallyLinkage; + } bool hasLinkOnceLinkage() const { return Linkage == LinkOnceAnyLinkage || Linkage == LinkOnceODRLinkage; } @@ -119,7 +123,8 @@ public: bool hasInternalLinkage() const { return Linkage == InternalLinkage; } bool hasPrivateLinkage() const { return Linkage == PrivateLinkage; } bool hasLocalLinkage() const { - return Linkage == InternalLinkage || Linkage == PrivateLinkage; + return Linkage == InternalLinkage || Linkage == PrivateLinkage || + Linkage == AvailableExternallyLinkage; } bool hasDLLImportLinkage() const { return Linkage == DLLImportLinkage; } bool hasDLLExportLinkage() const { return Linkage == DLLExportLinkage; } @@ -141,9 +146,10 @@ public: } /// isWeakForLinker - Whether the definition of this global may be replaced at - /// link time, whether the replacement is equivalent to the original or not. + /// link time. bool isWeakForLinker() const { - return (Linkage == WeakAnyLinkage || + return (Linkage == AvailableExternallyLinkage || + Linkage == WeakAnyLinkage || Linkage == WeakODRLinkage || Linkage == LinkOnceAnyLinkage || Linkage == LinkOnceODRLinkage || diff --git a/lib/AsmParser/LLLexer.cpp b/lib/AsmParser/LLLexer.cpp index d4815d83d68..b227af259f0 100644 --- a/lib/AsmParser/LLLexer.cpp +++ b/lib/AsmParser/LLLexer.cpp @@ -487,6 +487,7 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(private); KEYWORD(internal); + KEYWORD(available_externally); KEYWORD(linkonce); KEYWORD(linkonce_odr); KEYWORD(weak); diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp index 177161e3a61..d92957a6eff 100644 --- a/lib/AsmParser/LLParser.cpp +++ b/lib/AsmParser/LLParser.cpp @@ -764,6 +764,9 @@ bool LLParser::ParseOptionalLinkage(unsigned &Res, bool &HasLinkage) { case lltok::kw_weak_odr: Res = GlobalValue::WeakODRLinkage; break; case lltok::kw_linkonce: Res = GlobalValue::LinkOnceAnyLinkage; break; case lltok::kw_linkonce_odr: Res = GlobalValue::LinkOnceODRLinkage; break; + case lltok::kw_available_externally: + Res = GlobalValue::AvailableExternallyLinkage; + break; case lltok::kw_appending: Res = GlobalValue::AppendingLinkage; break; case lltok::kw_dllexport: Res = GlobalValue::DLLExportLinkage; break; case lltok::kw_common: Res = GlobalValue::CommonLinkage; break; diff --git a/lib/AsmParser/LLToken.h b/lib/AsmParser/LLToken.h index 35cb4dbaa74..d8bd38a4a61 100644 --- a/lib/AsmParser/LLToken.h +++ b/lib/AsmParser/LLToken.h @@ -37,7 +37,7 @@ namespace lltok { kw_global, kw_constant, kw_private, kw_internal, kw_linkonce, kw_linkonce_odr, kw_weak, kw_weak_odr, - kw_appending, kw_dllimport, kw_dllexport, kw_common, + kw_appending, kw_dllimport, kw_dllexport, kw_common,kw_available_externally, kw_default, kw_hidden, kw_protected, kw_extern_weak, kw_external, kw_thread_local, diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp index 6f91dda5012..8079acddb06 100644 --- a/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/lib/Bitcode/Reader/BitcodeReader.cpp @@ -70,6 +70,7 @@ static GlobalValue::LinkageTypes GetDecodedLinkage(unsigned Val) { case 9: return GlobalValue::PrivateLinkage; case 10: return GlobalValue::WeakODRLinkage; case 11: return GlobalValue::LinkOnceODRLinkage; + case 12: return GlobalValue::AvailableExternallyLinkage; } } diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp index c836d39d259..1937c7e26f1 100644 --- a/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -287,6 +287,7 @@ static unsigned getEncodedLinkage(const GlobalValue *GV) { case GlobalValue::PrivateLinkage: return 9; case GlobalValue::WeakODRLinkage: return 10; case GlobalValue::LinkOnceODRLinkage: return 11; + case GlobalValue::AvailableExternallyLinkage: return 12; } } diff --git a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index d19e9afaf02..0979ced89a3 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -443,7 +443,9 @@ bool AsmPrinter::EmitSpecialLLVMGlobal(const GlobalVariable *GV) { } // Ignore debug and non-emitted data. - if (GV->getSection() == "llvm.metadata") return true; + if (GV->getSection() == "llvm.metadata" || + GV->hasAvailableExternallyLinkage()) + return true; if (!GV->hasAppendingLinkage()) return false; diff --git a/lib/CodeGen/AsmPrinter/DwarfWriter.cpp b/lib/CodeGen/AsmPrinter/DwarfWriter.cpp index d59609b371e..4582f4a447f 100644 --- a/lib/CodeGen/AsmPrinter/DwarfWriter.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfWriter.cpp @@ -3519,6 +3519,9 @@ class DwarfException : public Dwarf { /// void EmitEHFrame(const FunctionEHFrameInfo &EHFrameInfo) { Function::LinkageTypes linkage = EHFrameInfo.function->getLinkage(); + + assert(!EHFrameInfo.function->hasAvailableExternallyLinkage() && + "Should not emit 'available externally' functions at all"); Asm->SwitchToTextSection(TAI->getDwarfEHFrameSection()); diff --git a/lib/CodeGen/MachineFunction.cpp b/lib/CodeGen/MachineFunction.cpp index bd7105fd285..18a040e5540 100644 --- a/lib/CodeGen/MachineFunction.cpp +++ b/lib/CodeGen/MachineFunction.cpp @@ -38,8 +38,14 @@ using namespace llvm; static AnnotationID MF_AID( AnnotationManager::getID("CodeGen::MachineCodeForFunction")); -// Out of line virtual function to home classes. -void MachineFunctionPass::virtfn() {} +bool MachineFunctionPass::runOnFunction(Function &F) { + // Do not codegen any 'available_externally' functions at all, they have + // definitions outside the translation unit. + if (F.hasAvailableExternallyLinkage()) + return false; + + return runOnMachineFunction(MachineFunction::get(&F)); +} namespace { struct VISIBILITY_HIDDEN Printer : public MachineFunctionPass { diff --git a/lib/Linker/LinkModules.cpp b/lib/Linker/LinkModules.cpp index 0ca4e10f5bf..4a15d88d8f3 100644 --- a/lib/Linker/LinkModules.cpp +++ b/lib/Linker/LinkModules.cpp @@ -480,9 +480,10 @@ static bool GetLinkageResult(GlobalValue *Dest, const GlobalValue *Src, } else if (Src->isWeakForLinker()) { // At this point we know that Dest has LinkOnce, External*, Weak, Common, // or DLL* linkage. - if ((Dest->hasLinkOnceLinkage() && - (Src->hasWeakLinkage() || Src->hasCommonLinkage())) || - Dest->hasExternalWeakLinkage()) { + if (Dest->hasExternalWeakLinkage() || + Dest->hasAvailableExternallyLinkage() || + (Dest->hasLinkOnceLinkage() && + (Src->hasWeakLinkage() || Src->hasCommonLinkage()))) { LinkFromSrc = true; LT = Src->getLinkage(); } else { diff --git a/lib/Target/CppBackend/CPPBackend.cpp b/lib/Target/CppBackend/CPPBackend.cpp index 8262408d15c..e89d5f9ddd1 100644 --- a/lib/Target/CppBackend/CPPBackend.cpp +++ b/lib/Target/CppBackend/CPPBackend.cpp @@ -294,6 +294,8 @@ namespace { Out << "GlobalValue::InternalLinkage"; break; case GlobalValue::PrivateLinkage: Out << "GlobalValue::PrivateLinkage"; break; + case GlobalValue::AvailableExternallyLinkage: + Out << "GlobalValue::AvailableExternallyLinkage "; break; case GlobalValue::LinkOnceAnyLinkage: Out << "GlobalValue::LinkOnceAnyLinkage "; break; case GlobalValue::LinkOnceODRLinkage: diff --git a/lib/VMCore/AsmWriter.cpp b/lib/VMCore/AsmWriter.cpp index b1bf42ea835..e4dd9d6b83e 100644 --- a/lib/VMCore/AsmWriter.cpp +++ b/lib/VMCore/AsmWriter.cpp @@ -1225,6 +1225,9 @@ static void PrintLinkage(GlobalValue::LinkageTypes LT, raw_ostream &Out) { switch (LT) { case GlobalValue::PrivateLinkage: Out << "private "; break; case GlobalValue::InternalLinkage: Out << "internal "; break; + case GlobalValue::AvailableExternallyLinkage: + Out << "available_externally "; + break; case GlobalValue::LinkOnceAnyLinkage: Out << "linkonce "; break; case GlobalValue::LinkOnceODRLinkage: Out << "linkonce_odr "; break; case GlobalValue::WeakAnyLinkage: Out << "weak "; break; diff --git a/test/CodeGen/Generic/externally_available.ll b/test/CodeGen/Generic/externally_available.ll new file mode 100644 index 00000000000..73b6b9825d2 --- /dev/null +++ b/test/CodeGen/Generic/externally_available.ll @@ -0,0 +1,10 @@ +; RUN: llvm-as < %s | llc | not grep test_ + +; test_function should not be emitted to the .s file. +define available_externally i32 @test_function() { + ret i32 4 +} + +; test_global should not be emitted to the .s file. +@test_global = available_externally global i32 4 + diff --git a/test/Transforms/GlobalDCE/externally_available.ll b/test/Transforms/GlobalDCE/externally_available.ll new file mode 100644 index 00000000000..ccdf7e198fa --- /dev/null +++ b/test/Transforms/GlobalDCE/externally_available.ll @@ -0,0 +1,10 @@ +; RUN: llvm-as < %s | opt -globaldce | llvm-dis | not grep test_ + +; test_function should not be emitted to the .s file. +define available_externally i32 @test_function() { + ret i32 4 +} + +; test_global should not be emitted to the .s file. +@test_global = available_externally global i32 4 + diff --git a/test/Transforms/Inline/externally_available.ll b/test/Transforms/Inline/externally_available.ll new file mode 100644 index 00000000000..68f7d65d659 --- /dev/null +++ b/test/Transforms/Inline/externally_available.ll @@ -0,0 +1,16 @@ +; RUN: llvm-as < %s | opt -inline -constprop | llvm-dis > %t +; RUN: not grep test_function %t +; RUN: grep {ret i32 5} %t + + +; test_function should not be emitted to the .s file. +define available_externally i32 @test_function() { + ret i32 4 +} + + +define i32 @result() { + %A = call i32 @test_function() + %B = add i32 %A, 1 + ret i32 %B +} \ No newline at end of file diff --git a/test/Transforms/InstCombine/odr-linkage.ll b/test/Transforms/InstCombine/odr-linkage.ll new file mode 100644 index 00000000000..96f883335bc --- /dev/null +++ b/test/Transforms/InstCombine/odr-linkage.ll @@ -0,0 +1,19 @@ +; RUN: llvm-as < %s | opt -instcombine | llvm-dis | grep {ret i32 10} + +@g1 = available_externally constant i32 1 +@g2 = linkonce_odr constant i32 2 +@g3 = weak_odr constant i32 3 +@g4 = internal constant i32 4 + +define i32 @test() { + %A = load i32* @g1 + %B = load i32* @g2 + %C = load i32* @g3 + %D = load i32* @g4 + + %a = add i32 %A, %B + %b = add i32 %a, %C + %c = add i32 %b, %D + ret i32 %c +} + \ No newline at end of file diff --git a/tools/llvm-nm/llvm-nm.cpp b/tools/llvm-nm/llvm-nm.cpp index 344951051e8..324e0f67035 100644 --- a/tools/llvm-nm/llvm-nm.cpp +++ b/tools/llvm-nm/llvm-nm.cpp @@ -69,7 +69,6 @@ namespace { } static char TypeCharForSymbol(GlobalValue &GV) { - /* FIXME: what to do with private linkage? */ if (GV.isDeclaration()) return 'U'; if (GV.hasLinkOnceLinkage()) return 'C'; if (GV.hasCommonLinkage()) return 'C'; @@ -87,8 +86,11 @@ static char TypeCharForSymbol(GlobalValue &GV) { } static void DumpSymbolNameForGlobalValue(GlobalValue &GV) { + // Private linkage and available_externally linkage don't exist in symtab. + if (GV.hasPrivateLinkage() || GV.hasAvailableExternallyLinkage()) return; + const std::string SymbolAddrStr = " "; // Not used yet... - char TypeChar = TypeCharForSymbol (GV); + char TypeChar = TypeCharForSymbol(GV); if ((TypeChar != 'U') && UndefinedOnly) return; if ((TypeChar == 'U') && DefinedOnly) @@ -96,17 +98,17 @@ static void DumpSymbolNameForGlobalValue(GlobalValue &GV) { if (GV.hasLocalLinkage () && ExternalOnly) return; if (OutputFormat == posix) { - std::cout << GV.getName () << " " << TypeCharForSymbol (GV) << " " + std::cout << GV.getName () << " " << TypeCharForSymbol(GV) << " " << SymbolAddrStr << "\n"; } else if (OutputFormat == bsd) { - std::cout << SymbolAddrStr << " " << TypeCharForSymbol (GV) << " " + std::cout << SymbolAddrStr << " " << TypeCharForSymbol(GV) << " " << GV.getName () << "\n"; } else if (OutputFormat == sysv) { std::string PaddedName (GV.getName ()); while (PaddedName.length () < 20) PaddedName += " "; std::cout << PaddedName << "|" << SymbolAddrStr << "| " - << TypeCharForSymbol (GV) + << TypeCharForSymbol(GV) << " | | | |\n"; } } @@ -122,10 +124,10 @@ static void DumpSymbolNamesFromModule(Module *M) { << "Name Value Class Type" << " Size Line Section\n"; } - std::for_each (M->begin (), M->end (), DumpSymbolNameForGlobalValue); - std::for_each (M->global_begin (), M->global_end (), + std::for_each (M->begin(), M->end(), DumpSymbolNameForGlobalValue); + std::for_each (M->global_begin(), M->global_end(), DumpSymbolNameForGlobalValue); - std::for_each (M->alias_begin (), M->alias_end (), + std::for_each (M->alias_begin(), M->alias_end(), DumpSymbolNameForGlobalValue); }