Represent runtime preemption in the IR.

Currently we do not represent runtime preemption in the IR, which has several
drawbacks:

  1) The semantics of GlobalValues differ depending on the object file format
     you are targeting (as well as the relocation-model and -fPIE value).
  2) We have no way of disabling inlining of run time interposable functions,
     since in the IR we only know if a function is link-time interposable.
     Because of this llvm cannot support elf-interposition semantics.
  3) In LTO builds of executables we will have extra knowledge that a symbol
     resolved to a local definition and can't be preemptable, but have no way to
     propagate that knowledge through the compiler.

This patch adds preemptability specifiers to the IR with the following meaning:

dso_local --> means the compiler may assume the symbol will resolve to a
 definition within the current linkage unit and the symbol may be accessed
 directly even if the definition is not within this compilation unit.

dso_preemptable --> means that the compiler must assume the GlobalValue may be
replaced with a definition from outside the current linkage unit at runtime.

To ease transitioning dso_preemptable is treated as a 'default' in that
low-level codegen will still do the same checks it did previously to see if a
symbol should be accessed indirectly. Eventually when IR producers emit the
specifiers on all Globalvalues we can change dso_preemptable to mean 'always
access indirectly', and remove the current logic.

Differential Revision: https://reviews.llvm.org/D20217

llvm-svn: 316668
This commit is contained in:
Sean Fertile
2017-10-26 15:00:26 +00:00
parent 2232243863
commit c70d28bff5
20 changed files with 1262 additions and 49 deletions

View File

@@ -483,10 +483,12 @@ bool LLParser::ParseOptionalUnnamedAddr(
/// ParseUnnamedGlobal:
/// OptionalVisibility (ALIAS | IFUNC) ...
/// OptionalLinkage OptionalVisibility OptionalDLLStorageClass
/// OptionalLinkage OptionalPreemptionSpecifier OptionalVisibility
/// OptionalDLLStorageClass
/// ... -> global variable
/// GlobalID '=' OptionalVisibility (ALIAS | IFUNC) ...
/// GlobalID '=' OptionalLinkage OptionalVisibility OptionalDLLStorageClass
/// GlobalID '=' OptionalLinkage OptionalPreemptionSpecifier OptionalVisibility
/// OptionalDLLStorageClass
/// ... -> global variable
bool LLParser::ParseUnnamedGlobal() {
unsigned VarID = NumberedVals.size();
@@ -506,23 +508,26 @@ bool LLParser::ParseUnnamedGlobal() {
bool HasLinkage;
unsigned Linkage, Visibility, DLLStorageClass;
bool DSOLocal;
GlobalVariable::ThreadLocalMode TLM;
GlobalVariable::UnnamedAddr UnnamedAddr;
if (ParseOptionalLinkage(Linkage, HasLinkage, Visibility, DLLStorageClass) ||
if (ParseOptionalLinkage(Linkage, HasLinkage, Visibility, DLLStorageClass,
DSOLocal) ||
ParseOptionalThreadLocal(TLM) || ParseOptionalUnnamedAddr(UnnamedAddr))
return true;
if (Lex.getKind() != lltok::kw_alias && Lex.getKind() != lltok::kw_ifunc)
return ParseGlobal(Name, NameLoc, Linkage, HasLinkage, Visibility,
DLLStorageClass, TLM, UnnamedAddr);
DLLStorageClass, DSOLocal, TLM, UnnamedAddr);
return parseIndirectSymbol(Name, NameLoc, Linkage, Visibility,
DLLStorageClass, TLM, UnnamedAddr);
DLLStorageClass, DSOLocal, TLM, UnnamedAddr);
}
/// ParseNamedGlobal:
/// GlobalVar '=' OptionalVisibility (ALIAS | IFUNC) ...
/// GlobalVar '=' OptionalLinkage OptionalVisibility OptionalDLLStorageClass
/// GlobalVar '=' OptionalLinkage OptionalPreemptionSpecifier
/// OptionalVisibility OptionalDLLStorageClass
/// ... -> global variable
bool LLParser::ParseNamedGlobal() {
assert(Lex.getKind() == lltok::GlobalVar);
@@ -532,19 +537,21 @@ bool LLParser::ParseNamedGlobal() {
bool HasLinkage;
unsigned Linkage, Visibility, DLLStorageClass;
bool DSOLocal;
GlobalVariable::ThreadLocalMode TLM;
GlobalVariable::UnnamedAddr UnnamedAddr;
if (ParseToken(lltok::equal, "expected '=' in global variable") ||
ParseOptionalLinkage(Linkage, HasLinkage, Visibility, DLLStorageClass) ||
ParseOptionalLinkage(Linkage, HasLinkage, Visibility, DLLStorageClass,
DSOLocal) ||
ParseOptionalThreadLocal(TLM) || ParseOptionalUnnamedAddr(UnnamedAddr))
return true;
if (Lex.getKind() != lltok::kw_alias && Lex.getKind() != lltok::kw_ifunc)
return ParseGlobal(Name, NameLoc, Linkage, HasLinkage, Visibility,
DLLStorageClass, TLM, UnnamedAddr);
DLLStorageClass, DSOLocal, TLM, UnnamedAddr);
return parseIndirectSymbol(Name, NameLoc, Linkage, Visibility,
DLLStorageClass, TLM, UnnamedAddr);
DLLStorageClass, DSOLocal, TLM, UnnamedAddr);
}
bool LLParser::parseComdat() {
@@ -709,19 +716,21 @@ static bool isValidVisibilityForLinkage(unsigned V, unsigned L) {
}
/// parseIndirectSymbol:
/// ::= GlobalVar '=' OptionalLinkage OptionalVisibility
/// OptionalDLLStorageClass OptionalThreadLocal
/// OptionalUnnamedAddr 'alias|ifunc' IndirectSymbol
/// ::= GlobalVar '=' OptionalLinkage OptionalPreemptionSpecifier
/// OptionalVisibility OptionalDLLStorageClass
/// OptionalThreadLocal OptionalUnnamedAddr
// 'alias|ifunc' IndirectSymbol
///
/// IndirectSymbol
/// ::= TypeAndValue
///
/// Everything through OptionalUnnamedAddr has already been parsed.
///
bool LLParser::parseIndirectSymbol(
const std::string &Name, LocTy NameLoc, unsigned L, unsigned Visibility,
unsigned DLLStorageClass, GlobalVariable::ThreadLocalMode TLM,
GlobalVariable::UnnamedAddr UnnamedAddr) {
bool LLParser::parseIndirectSymbol(const std::string &Name, LocTy NameLoc,
unsigned L, unsigned Visibility,
unsigned DLLStorageClass, bool DSOLocal,
GlobalVariable::ThreadLocalMode TLM,
GlobalVariable::UnnamedAddr UnnamedAddr) {
bool IsAlias;
if (Lex.getKind() == lltok::kw_alias)
IsAlias = true;
@@ -740,6 +749,11 @@ bool LLParser::parseIndirectSymbol(
return Error(NameLoc,
"symbol with local linkage must have default visibility");
if (DSOLocal && !IsAlias) {
return Error(NameLoc,
"dso_local is invalid on ifunc");
}
Type *Ty;
LocTy ExplicitTypeLoc = Lex.getLoc();
if (ParseType(Ty) ||
@@ -812,6 +826,7 @@ bool LLParser::parseIndirectSymbol(
GA->setVisibility((GlobalValue::VisibilityTypes)Visibility);
GA->setDLLStorageClass((GlobalValue::DLLStorageClassTypes)DLLStorageClass);
GA->setUnnamedAddr(UnnamedAddr);
GA->setDSOLocal(DSOLocal);
if (Name.empty())
NumberedVals.push_back(GA.get());
@@ -843,12 +858,14 @@ bool LLParser::parseIndirectSymbol(
}
/// ParseGlobal
/// ::= GlobalVar '=' OptionalLinkage OptionalVisibility OptionalDLLStorageClass
/// OptionalThreadLocal OptionalUnnamedAddr OptionalAddrSpace
/// OptionalExternallyInitialized GlobalType Type Const OptionalAttrs
/// ::= OptionalLinkage OptionalVisibility OptionalDLLStorageClass
/// ::= GlobalVar '=' OptionalLinkage OptionalPreemptionSpecifier
/// OptionalVisibility OptionalDLLStorageClass
/// OptionalThreadLocal OptionalUnnamedAddr OptionalAddrSpace
/// OptionalExternallyInitialized GlobalType Type Const OptionalAttrs
/// ::= OptionalLinkage OptionalPreemptionSpecifier OptionalVisibility
/// OptionalDLLStorageClass OptionalThreadLocal OptionalUnnamedAddr
/// OptionalAddrSpace OptionalExternallyInitialized GlobalType Type
/// Const OptionalAttrs
///
/// Everything up to and including OptionalUnnamedAddr has been parsed
/// already.
@@ -856,7 +873,7 @@ bool LLParser::parseIndirectSymbol(
bool LLParser::ParseGlobal(const std::string &Name, LocTy NameLoc,
unsigned Linkage, bool HasLinkage,
unsigned Visibility, unsigned DLLStorageClass,
GlobalVariable::ThreadLocalMode TLM,
bool DSOLocal, GlobalVariable::ThreadLocalMode TLM,
GlobalVariable::UnnamedAddr UnnamedAddr) {
if (!isValidVisibilityForLinkage(Visibility, Linkage))
return Error(NameLoc,
@@ -930,6 +947,7 @@ bool LLParser::ParseGlobal(const std::string &Name, LocTy NameLoc,
GV->setInitializer(Init);
GV->setConstant(IsConstant);
GV->setLinkage((GlobalValue::LinkageTypes)Linkage);
GV->setDSOLocal(DSOLocal);
GV->setVisibility((GlobalValue::VisibilityTypes)Visibility);
GV->setDLLStorageClass((GlobalValue::DLLStorageClassTypes)DLLStorageClass);
GV->setExternallyInitialized(IsExternallyInitialized);
@@ -1608,15 +1626,38 @@ static unsigned parseOptionalLinkageAux(lltok::Kind Kind, bool &HasLinkage) {
/// ::= 'external'
bool LLParser::ParseOptionalLinkage(unsigned &Res, bool &HasLinkage,
unsigned &Visibility,
unsigned &DLLStorageClass) {
unsigned &DLLStorageClass,
bool &DSOLocal) {
Res = parseOptionalLinkageAux(Lex.getKind(), HasLinkage);
if (HasLinkage)
Lex.Lex();
ParseOptionalDSOLocal(DSOLocal);
ParseOptionalVisibility(Visibility);
ParseOptionalDLLStorageClass(DLLStorageClass);
if (DSOLocal && DLLStorageClass == GlobalValue::DLLImportStorageClass) {
return Error(Lex.getLoc(), "dso_location and DLL-StorageClass mismatch");
}
return false;
}
void LLParser::ParseOptionalDSOLocal(bool &DSOLocal) {
switch (Lex.getKind()) {
default:
DSOLocal = false;
break;
case lltok::kw_dso_local:
DSOLocal = true;
Lex.Lex();
break;
case lltok::kw_dso_preemptable:
DSOLocal = false;
Lex.Lex();
break;
}
}
/// ParseOptionalVisibility
/// ::= /*empty*/
/// ::= 'default'
@@ -4699,22 +4740,24 @@ bool LLParser::ParseTypeAndBasicBlock(BasicBlock *&BB, LocTy &Loc,
}
/// FunctionHeader
/// ::= OptionalLinkage OptionalVisibility OptionalCallingConv OptRetAttrs
/// OptUnnamedAddr Type GlobalName '(' ArgList ')' OptFuncAttrs OptSection
/// OptionalAlign OptGC OptionalPrefix OptionalPrologue OptPersonalityFn
/// ::= OptionalLinkage OptionalPreemptionSpecifier OptionalVisibility
/// OptionalCallingConv OptRetAttrs OptUnnamedAddr Type GlobalName
/// '(' ArgList ')' OptFuncAttrs OptSection OptionalAlign OptGC
/// OptionalPrefix OptionalPrologue OptPersonalityFn
bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
// Parse the linkage.
LocTy LinkageLoc = Lex.getLoc();
unsigned Linkage;
unsigned Visibility;
unsigned DLLStorageClass;
bool DSOLocal;
AttrBuilder RetAttrs;
unsigned CC;
bool HasLinkage;
Type *RetType = nullptr;
LocTy RetTypeLoc = Lex.getLoc();
if (ParseOptionalLinkage(Linkage, HasLinkage, Visibility, DLLStorageClass) ||
if (ParseOptionalLinkage(Linkage, HasLinkage, Visibility, DLLStorageClass,
DSOLocal) ||
ParseOptionalCallingConv(CC) || ParseOptionalReturnAttrs(RetAttrs) ||
ParseType(RetType, RetTypeLoc, true /*void allowed*/))
return true;
@@ -4876,6 +4919,7 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
NumberedVals.push_back(Fn);
Fn->setLinkage((GlobalValue::LinkageTypes)Linkage);
Fn->setDSOLocal(DSOLocal);
Fn->setVisibility((GlobalValue::VisibilityTypes)Visibility);
Fn->setDLLStorageClass((GlobalValue::DLLStorageClassTypes)DLLStorageClass);
Fn->setCallingConv(CC);