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
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 565b1a2..5b661ce 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -483,10 +483,12 @@
/// 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 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 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 @@
}
/// 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 @@
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 @@
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 @@
}
/// ParseGlobal
-/// ::= GlobalVar '=' OptionalLinkage OptionalVisibility OptionalDLLStorageClass
+/// ::= GlobalVar '=' OptionalLinkage OptionalPreemptionSpecifier
+/// OptionalVisibility OptionalDLLStorageClass
/// OptionalThreadLocal OptionalUnnamedAddr OptionalAddrSpace
/// OptionalExternallyInitialized GlobalType Type Const OptionalAttrs
-/// ::= OptionalLinkage 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::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 @@
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 @@
/// ::= '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 @@
}
/// 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 @@
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);