Add a new "available_externally" linkage type. This is intended

to support C99 inline, GNU extern inline, etc.  Related bugzilla's
include PR3517, PR3100, & PR2933.  Nothing uses this yet, but it
appears to work.

llvm-svn: 68940
This commit is contained in:
Chris Lattner 2009-04-13 05:44:34 +00:00
parent 57077413f1
commit c1bfdc9bb2
19 changed files with 120 additions and 29 deletions

View File

@ -509,6 +509,17 @@ All Global Variables and Functions have one of the following types of linkage:
'<tt>static</tt>' keyword in C.
</dd>
<dt><tt><b><a name="available_externally">available_externally</a></b></tt>:
</dt>
<dd>Globals with "<tt>available_externally</tt>" 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 <tt>available_externally</tt> linkage are allowed to be discarded
at will, and are otherwise the same as <tt>linkonce_odr</tt>. This linkage
type is only allowed on definitions, not declarations.</dd>
<dt><tt><b><a name="linkage_linkonce">linkonce</a></b></tt>: </dt>
<dd>Globals with "<tt>linkonce</tt>" linkage are merged with other globals of
@ -554,10 +565,10 @@ All Global Variables and Functions have one of the following types of linkage:
<dt><tt><b><a name="linkage_linkonce">linkonce_odr</a></b></tt>: </dt>
<dt><tt><b><a name="linkage_weak">weak_odr</a></b></tt>: </dt>
<dd>Some languages allow inequivalent globals to be merged, such as two
<dd>Some languages allow differing globals to be merged, such as two
functions with different semantics. Other languages, such as <tt>C++</tt>,
ensure that only equivalent globals are ever merged (the "one definition
rule" - <tt>odr</tt>). Such languages can use the <tt>linkonce_odr</tt>
rule" - "ODR"). Such languages can use the <tt>linkonce_odr</tt>
and <tt>weak_odr</tt> linkage types to indicate that the global will only
be merged with equivalent globals. These linkage types are otherwise the
same as their non-<tt>odr</tt> versions.

View File

@ -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

View File

@ -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 ||

View File

@ -487,6 +487,7 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(private);
KEYWORD(internal);
KEYWORD(available_externally);
KEYWORD(linkonce);
KEYWORD(linkonce_odr);
KEYWORD(weak);

View File

@ -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;

View File

@ -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,

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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());

View File

@ -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 {

View File

@ -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 {

View File

@ -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:

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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
}

View File

@ -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);
}