MODULE_CODE_GLOBALVAR Record
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-``[GLOBALVAR, strtab offset, strtab size, pointer type, isconst, initid, linkage, alignment, section, visibility, threadlocal, unnamed_addr, externally_initialized, dllstorageclass, comdat]``
+``[GLOBALVAR, strtab offset, strtab size, pointer type, isconst, initid, linkage, alignment, section, visibility, threadlocal, unnamed_addr, externally_initialized, dllstorageclass, comdat, attributes, preemptionspecifier]``
The ``GLOBALVAR`` record (code 7) marks the declaration or definition of a
global variable. The operand fields are:
* *comdat*: An encoding of the COMDAT of this function
+* *attributes*: If nonzero, the 1-based index into the table of AttributeLists.
+
+.. _bcpreemptionspecifier:
+
+* *preemptionspecifier*: If present, an encoding of the runtime preemption specifier of this variable:
+
+ * ``dso_preemptable``: code 0
+ * ``dso_local``: code 1
+
.. _FUNCTION:
MODULE_CODE_FUNCTION Record
^^^^^^^^^^^^^^^^^^^^^^^^^^^
-``[FUNCTION, strtab offset, strtab size, type, callingconv, isproto, linkage, paramattr, alignment, section, visibility, gc, prologuedata, dllstorageclass, comdat, prefixdata, personalityfn]``
+``[FUNCTION, strtab offset, strtab size, type, callingconv, isproto, linkage, paramattr, alignment, section, visibility, gc, prologuedata, dllstorageclass, comdat, prefixdata, personalityfn, preemptionspecifier]``
The ``FUNCTION`` record (code 8) marks the declaration or definition of a
function. The operand fields are:
* *personalityfn*: If non-zero, the value index of the personality function for this function,
plus 1.
+* *preemptionspecifier*: If present, an encoding of the :ref:`runtime preemption specifier<bcpreemptionspecifier>` of this function.
+
MODULE_CODE_ALIAS Record
^^^^^^^^^^^^^^^^^^^^^^^^
-``[ALIAS, strtab offset, strtab size, alias type, aliasee val#, linkage, visibility, dllstorageclass, threadlocal, unnamed_addr]``
+``[ALIAS, strtab offset, strtab size, alias type, aliasee val#, linkage, visibility, dllstorageclass, threadlocal, unnamed_addr, preemptionspecifier]``
The ``ALIAS`` record (code 9) marks the definition of an alias. The operand
fields are
* *unnamed_addr*: If present, an encoding of the
:ref:`unnamed_addr<bcunnamedaddr>` attribute of this alias
+* *preemptionspecifier*: If present, an encoding of the :ref:`runtime preemption specifier<bcpreemptionspecifier>` of this alias.
+
.. _MODULE_CODE_GCNAME:
MODULE_CODE_GCNAME Record
For platforms without linker support of ELF TLS model, the -femulated-tls
flag can be used to generate GCC compatible emulated TLS code.
+.. _runtime_preemption_model:
+
+Runtime Preemption Specifiers
+-----------------------------
+
+Global variables, functions and aliases may have an optional runtime preemption
+specifier. If a preemption specifier isn't given explicitly, then a
+symbol is assumed to be ``dso_preemptable``.
+
+``dso_preemptable``
+ Indicates that the function or variable may be replaced by a symbol from
+ outside the linkage unit at runtime.
+
+``dso_local``
+ The compiler may assume that a function or variable marked as ``dso_local``
+ will resolve to a symbol within the same linkage unit. Direct access will
+ be generated even if the definition is not within this compilation unit.
+
.. _namedtypes:
Structure Types
iteration. The maximum alignment is ``1 << 29``.
Globals can also have a :ref:`DLL storage class <dllstorageclass>`,
+an optional :ref:`runtime preemption specifier <runtime_preemption_model>`,
an optional :ref:`global attributes <glattrs>` and
an optional list of attached :ref:`metadata <metadata>`.
Syntax::
- @<GlobalVarName> = [Linkage] [Visibility] [DLLStorageClass] [ThreadLocal]
+ @<GlobalVarName> = [Linkage] [PreemptionSpecifier] [Visibility]
+ [DLLStorageClass] [ThreadLocal]
[(unnamed_addr|local_unnamed_addr)] [AddrSpace]
[ExternallyInitialized]
<global | constant> <Type> [<InitializerConstant>]
---------
LLVM function definitions consist of the "``define``" keyword, an
-optional :ref:`linkage type <linkage>`, an optional :ref:`visibility
+optional :ref:`linkage type <linkage>`, an optional :ref:`runtime preemption
+specifier <runtime_preemption_model>`, an optional :ref:`visibility
style <visibility>`, an optional :ref:`DLL storage class <dllstorageclass>`,
an optional :ref:`calling convention <callingconv>`,
an optional ``unnamed_addr`` attribute, a return type, an optional
Syntax::
- define [linkage] [visibility] [DLLStorageClass]
+ define [linkage] [PreemptionSpecifier] [visibility] [DLLStorageClass]
[cconv] [ret attrs]
<ResultType> @<FunctionName> ([argument list])
[(unnamed_addr|local_unnamed_addr)] [fn Attrs] [section "name"]
constant expression.
Aliases may have an optional :ref:`linkage type <linkage>`, an optional
+:ref:`runtime preemption specifier <runtime_preemption_model>`, an optional
:ref:`visibility style <visibility>`, an optional :ref:`DLL storage class
<dllstorageclass>` and an optional :ref:`tls model <tls_model>`.
Syntax::
- @<Name> = [Linkage] [Visibility] [DLLStorageClass] [ThreadLocal] [(unnamed_addr|local_unnamed_addr)] alias <AliaseeTy>, <AliaseeTy>* @<Aliasee>
+ @<Name> = [Linkage] [PreemptionSpecifier] [Visibility] [DLLStorageClass] [ThreadLocal] [(unnamed_addr|local_unnamed_addr)] alias <AliaseeTy>, <AliaseeTy>* @<Aliasee>
The linkage must be one of ``private``, ``internal``, ``linkonce``, ``weak``,
``linkonce_odr``, ``weak_odr``, ``external``. Note that some system linkers
ValueType(Ty), Linkage(Linkage), Visibility(DefaultVisibility),
UnnamedAddrVal(unsigned(UnnamedAddr::None)),
DllStorageClass(DefaultStorageClass), ThreadLocal(NotThreadLocal),
- HasLLVMReservedName(false), IntID((Intrinsic::ID)0U), Parent(nullptr) {
+ HasLLVMReservedName(false), IsDSOLocal(false),
+ IntID((Intrinsic::ID)0U), Parent(nullptr) {
setName(Name);
}
Type *ValueType;
- static const unsigned GlobalValueSubClassDataBits = 18;
+ static const unsigned GlobalValueSubClassDataBits = 17;
// All bitfields use unsigned as the underlying type so that MSVC will pack
// them.
/// Function::intrinsicID() returns Intrinsic::not_intrinsic.
unsigned HasLLVMReservedName : 1;
+ /// If true then there is a definition within the same linkage unit and that
+ /// definition cannot be runtime preempted.
+ unsigned IsDSOLocal : 1;
+
private:
friend class Constant;
// Give subclasses access to what otherwise would be wasted padding.
- // (18 + 4 + 2 + 2 + 2 + 3 + 1) == 32.
+ // (17 + 4 + 2 + 2 + 2 + 3 + 1 + 1) == 32.
unsigned SubClassData : GlobalValueSubClassDataBits;
void destroyConstantImpl();
Type *getValueType() const { return ValueType; }
+ void setDSOLocal(bool Local) { IsDSOLocal = Local; }
+
+ bool isDSOLocal() const {
+ return IsDSOLocal;
+ }
+
static LinkageTypes getLinkOnceLinkage(bool ODR) {
return ODR ? LinkOnceODRLinkage : LinkOnceAnyLinkage;
}
KEYWORD(declare); KEYWORD(define);
KEYWORD(global); KEYWORD(constant);
+ KEYWORD(dso_local);
+ KEYWORD(dso_preemptable);
+
KEYWORD(private);
KEYWORD(internal);
KEYWORD(available_externally);
/// 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();
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);
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() {
}
/// 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;
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) ||
GA->setVisibility((GlobalValue::VisibilityTypes)Visibility);
GA->setDLLStorageClass((GlobalValue::DLLStorageClassTypes)DLLStorageClass);
GA->setUnnamedAddr(UnnamedAddr);
+ GA->setDSOLocal(DSOLocal);
if (Name.empty())
NumberedVals.push_back(GA.get());
}
/// 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.
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,
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);
/// ::= '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'
}
/// 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;
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);
bool ParseOptionalParamAttrs(AttrBuilder &B);
bool ParseOptionalReturnAttrs(AttrBuilder &B);
bool ParseOptionalLinkage(unsigned &Linkage, bool &HasLinkage,
- unsigned &Visibility, unsigned &DLLStorageClass);
+ unsigned &Visibility, unsigned &DLLStorageClass,
+ bool &DSOLocal);
+ void ParseOptionalDSOLocal(bool &DSOLocal);
void ParseOptionalVisibility(unsigned &Visibility);
void ParseOptionalDLLStorageClass(unsigned &DLLStorageClass);
bool ParseOptionalCallingConv(unsigned &CC);
bool ParseNamedGlobal();
bool ParseGlobal(const std::string &Name, LocTy Loc, unsigned Linkage,
bool HasLinkage, unsigned Visibility,
- unsigned DLLStorageClass,
+ unsigned DLLStorageClass, bool DSOLocal,
GlobalVariable::ThreadLocalMode TLM,
GlobalVariable::UnnamedAddr UnnamedAddr);
bool parseIndirectSymbol(const std::string &Name, LocTy Loc,
unsigned Linkage, unsigned Visibility,
- unsigned DLLStorageClass,
+ unsigned DLLStorageClass, bool DSOLocal,
GlobalVariable::ThreadLocalMode TLM,
GlobalVariable::UnnamedAddr UnnamedAddr);
bool parseComdat();
kw_global,
kw_constant,
+ kw_dso_local,
+ kw_dso_preemptable,
+
kw_private,
kw_internal,
kw_linkonce,
}
}
+static bool getDecodedDSOLocal(unsigned Val) {
+ switch(Val) {
+ default: // Map unknown values to preemptable.
+ case 0: return false;
+ case 1: return true;
+ }
+}
+
static GlobalVariable::ThreadLocalMode getDecodedThreadLocalMode(unsigned Val) {
switch (Val) {
case 0: return GlobalVariable::NotThreadLocal;
Error BitcodeReader::parseGlobalVarRecord(ArrayRef<uint64_t> Record) {
// v1: [pointer type, isconst, initid, linkage, alignment, section,
// visibility, threadlocal, unnamed_addr, externally_initialized,
- // dllstorageclass, comdat, attributes] (name in VST)
+ // dllstorageclass, comdat, attributes, preemption specifier] (name in VST)
// v2: [strtab_offset, strtab_size, v1]
StringRef Name;
std::tie(Name, Record) = readNameFromStrtab(Record);
auto AS = getAttributes(Record[12]).getFnAttributes();
NewGV->setAttributes(AS);
}
+
+ if (Record.size() > 13) {
+ NewGV->setDSOLocal(getDecodedDSOLocal(Record[13]));
+ }
+
return Error::success();
}
Error BitcodeReader::parseFunctionRecord(ArrayRef<uint64_t> Record) {
// v1: [type, callingconv, isproto, linkage, paramattr, alignment, section,
// visibility, gc, unnamed_addr, prologuedata, dllstorageclass, comdat,
- // prefixdata] (name in VST)
+ // prefixdata, personalityfn, preemption specifier] (name in VST)
// v2: [strtab_offset, strtab_size, v1]
StringRef Name;
std::tie(Name, Record) = readNameFromStrtab(Record);
if (Record.size() > 14 && Record[14] != 0)
FunctionPersonalityFns.push_back(std::make_pair(Func, Record[14] - 1));
+ if (Record.size() > 15) {
+ Func->setDSOLocal(getDecodedDSOLocal(Record[15]));
+ }
+
ValueList.push_back(Func);
// If this is a function with a body, remember the prototype we are
unsigned BitCode, ArrayRef<uint64_t> Record) {
// v1 ALIAS_OLD: [alias type, aliasee val#, linkage] (name in VST)
// v1 ALIAS: [alias type, addrspace, aliasee val#, linkage, visibility,
- // dllstorageclass] (name in VST)
+ // dllstorageclass, threadlocal, unnamed_addr,
+ // preemption specifier] (name in VST)
// v1 IFUNC: [alias type, addrspace, aliasee val#, linkage,
- // visibility, dllstorageclass] (name in VST)
+ // visibility, dllstorageclass, threadlocal, unnamed_addr,
+ // preemption specifier] (name in VST)
// v2: [strtab_offset, strtab_size, v1]
StringRef Name;
std::tie(Name, Record) = readNameFromStrtab(Record);
NewGA->setThreadLocalMode(getDecodedThreadLocalMode(Record[OpNum++]));
if (OpNum != Record.size())
NewGA->setUnnamedAddr(getDecodedUnnamedAddrType(Record[OpNum++]));
+ if (OpNum != Record.size())
+ NewGA->setDSOLocal(getDecodedDSOLocal(Record[OpNum++]));
ValueList.push_back(NewGA);
IndirectSymbolInits.push_back(std::make_pair(NewGA, Val));
return Error::success();
// GLOBALVAR: [strtab offset, strtab size, type, isconst, initid,
// linkage, alignment, section, visibility, threadlocal,
// unnamed_addr, externally_initialized, dllstorageclass,
- // comdat, attributes]
+ // comdat, attributes, DSO_Local]
Vals.push_back(addToStrtab(GV.getName()));
Vals.push_back(GV.getName().size());
Vals.push_back(VE.getTypeID(GV.getValueType()));
GV.isExternallyInitialized() ||
GV.getDLLStorageClass() != GlobalValue::DefaultStorageClass ||
GV.hasComdat() ||
- GV.hasAttributes()) {
+ GV.hasAttributes() ||
+ GV.isDSOLocal()) {
Vals.push_back(getEncodedVisibility(GV));
Vals.push_back(getEncodedThreadLocalMode(GV));
Vals.push_back(getEncodedUnnamedAddr(GV));
auto AL = GV.getAttributesAsList(AttributeList::FunctionIndex);
Vals.push_back(VE.getAttributeListID(AL));
+
+ Vals.push_back(GV.isDSOLocal());
} else {
AbbrevToUse = SimpleGVarAbbrev;
}
// FUNCTION: [strtab offset, strtab size, type, callingconv, isproto,
// linkage, paramattrs, alignment, section, visibility, gc,
// unnamed_addr, prologuedata, dllstorageclass, comdat,
- // prefixdata, personalityfn]
+ // prefixdata, personalityfn, DSO_Local]
Vals.push_back(addToStrtab(F.getName()));
Vals.push_back(F.getName().size());
Vals.push_back(VE.getTypeID(F.getFunctionType()));
Vals.push_back(
F.hasPersonalityFn() ? (VE.getValueID(F.getPersonalityFn()) + 1) : 0);
+ Vals.push_back(F.isDSOLocal());
unsigned AbbrevToUse = 0;
Stream.EmitRecord(bitc::MODULE_CODE_FUNCTION, Vals, AbbrevToUse);
Vals.clear();
// Emit the alias information.
for (const GlobalAlias &A : M.aliases()) {
// ALIAS: [strtab offset, strtab size, alias type, aliasee val#, linkage,
- // visibility, dllstorageclass, threadlocal, unnamed_addr]
+ // visibility, dllstorageclass, threadlocal, unnamed_addr,
+ // DSO_Local]
Vals.push_back(addToStrtab(A.getName()));
Vals.push_back(A.getName().size());
Vals.push_back(VE.getTypeID(A.getValueType()));
Vals.push_back(getEncodedDLLStorageClass(A));
Vals.push_back(getEncodedThreadLocalMode(A));
Vals.push_back(getEncodedUnnamedAddr(A));
+ Vals.push_back(A.isDSOLocal());
+
unsigned AbbrevToUse = 0;
Stream.EmitRecord(bitc::MODULE_CODE_ALIAS, Vals, AbbrevToUse);
Vals.clear();
}
}
+static void PrintDSOLocation(bool IsDSOLocal, formatted_raw_ostream &Out){
+ if (IsDSOLocal)
+ Out << "dso_local ";
+}
+
static void PrintDLLStorageClass(GlobalValue::DLLStorageClassTypes SCT,
formatted_raw_ostream &Out) {
switch (SCT) {
Out << "external ";
Out << getLinkagePrintName(GV->getLinkage());
+ PrintDSOLocation(GV->isDSOLocal(), Out);
PrintVisibility(GV->getVisibility(), Out);
PrintDLLStorageClass(GV->getDLLStorageClass(), Out);
PrintThreadLocalModel(GV->getThreadLocalMode(), Out);
Out << " = ";
Out << getLinkagePrintName(GIS->getLinkage());
+ PrintDSOLocation(GIS->isDSOLocal(), Out);
PrintVisibility(GIS->getVisibility(), Out);
PrintDLLStorageClass(GIS->getDLLStorageClass(), Out);
PrintThreadLocalModel(GIS->getThreadLocalMode(), Out);
Out << "define ";
Out << getLinkagePrintName(F->getLinkage());
+ PrintDSOLocation(F->isDSOLocal(), Out);
PrintVisibility(F->getVisibility(), Out);
PrintDLLStorageClass(F->getDLLStorageClass(), Out);
setVisibility(Src->getVisibility());
setUnnamedAddr(Src->getUnnamedAddr());
setDLLStorageClass(Src->getDLLStorageClass());
+ setDSOLocal(Src->isDSOLocal());
}
void GlobalValue::removeFromParent() {
if (GV.isDeclarationForLinker())
Assert(!GV.hasComdat(), "Declaration may not be in a Comdat!", &GV);
+ if (GV.hasDLLImportStorageClass())
+ Assert(!GV.isDSOLocal(),
+ "GlobalValue with DLLImport Storage is dso_local!", &GV);
+
forEachUser(&GV, GlobalValueVisited, [&](const Value *V) -> bool {
if (const Instruction *I = dyn_cast<Instruction>(V)) {
if (!I->getParent() || !I->getParent()->getParent())
if (TT.isOSBinFormatCOFF() || (TT.isOSWindows() && TT.isOSBinFormatMachO()))
return true;
- if (GV && (GV->hasLocalLinkage() || !GV->hasDefaultVisibility()))
+ if (GV && (GV->hasLocalLinkage() || !GV->hasDefaultVisibility() ||
+ GV->isDSOLocal()))
return true;
if (TT.isOSBinFormatMachO()) {
--- /dev/null
+; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
+
+declare dso_local dllimport void @fun()
+; CHECK: error: dso_location and DLL-StorageClass mismatch
--- /dev/null
+; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
+
+@foo = dso_local ifunc i32 (i32), i64 ()* @foo_ifunc
+; CHECK: error: dso_local is invalid on ifunc
+
+define internal i64 @foo_ifunc() {
+entry:
+ ret i64 0
+}
--- /dev/null
+; RUN: llvm-as < %s | llvm-dis | FileCheck %s
+
+; Tests parsing for the dso_local keyword as well as the serialization/
+; deserialization of the dso_local value on GlobalValues.
+
+@local_global = dso_local global i32 0
+; CHECK: @local_global = dso_local global i32 0
+
+@weak_local_global = weak dso_local global i32 0
+; CHECK: @weak_local_global = weak dso_local global i32 0
+
+@external_local_global = external dso_local global i32
+; CHECK: @external_local_global = external dso_local global i32
+
+@default_local_global = dso_local default global i32 0
+; CHECK: @default_local_global = dso_local global i32 0
+
+@hidden_local_global = dso_local hidden global i32 0
+; CHECK: @hidden_local_global = dso_local hidden global i32 0
+
+@protected_local_global = dso_local protected global i32 0
+; CHECK: @protected_local_global = dso_local protected global i32 0
+
+@local_alias = dso_local alias i32, i32* @local_global
+; CHECK-DAG: @local_alias = dso_local alias i32, i32* @local_global
+
+@preemptable_alias = dso_preemptable alias i32, i32* @hidden_local_global
+; CHECK-DAG: @preemptable_alias = alias i32, i32* @hidden_local_global
+
+@preemptable_ifunc = dso_preemptable ifunc void (), i8* ()* @ifunc_resolver
+; CHECK-DAG: @preemptable_ifunc = ifunc void (), i8* ()* @ifunc_resolver
+declare dso_local default void @default_local()
+; CHECK: declare dso_local void @default_local()
+
+declare dso_local hidden void @hidden_local()
+; CHECK: declare dso_local hidden void @hidden_local()
+
+define dso_local protected void @protected_local() {
+; CHECK: define dso_local protected void @protected_local()
+entry:
+ ret void
+}
+
+define i8* @ifunc_resolver() {
+entry:
+ ret i8* null
+}
--- /dev/null
+; RUN: llc -mtriple powerpc64le-unkown-gnu-linux < %s | FileCheck %s
+; RUN: llc -mtriple powerpc64le-unkown-gnu-linux -relocation-model=static \
+; RUN: < %s | FileCheck --check-prefix=STATIC %s
+; RUN: llc -mtriple powerpc64le-unkown-gnu-linux -relocation-model=pic \
+; RUN: < %s | FileCheck %s
+
+; globals
+
+@strong_default = global i32 55
+define i32* @get_strong_default() #0 {
+ ret i32* @strong_default
+
+; STATIC-LABEL: @get_strong_default
+; STATIC: addis 3, 2, strong_default@toc@ha
+; STATIC: addi 3, 3, strong_default@toc@l
+; STATIC: blr
+
+; CHECK-LABEL: @get_strong_default
+; CHECK: addis 3, 2, .LC0@toc@ha
+; CHECK: ld 3, .LC0@toc@l(3)
+; CHECK: blr
+}
+
+@weak_default = weak global i32 55
+define i32* @get_weak_default() #0 {
+ ret i32* @weak_default
+
+; STATIC-LABEL: @get_weak_default
+; STATIC: addis 3, 2, weak_default@toc@ha
+; STATIC: addi 3, 3, weak_default@toc@l
+; STATIC: blr
+
+; CHECK-LABEL: @get_weak_default
+; CHECK: addis 3, 2, .LC1@toc@ha
+; CHECK: ld 3, .LC1@toc@l(3)
+; CHECK: blr
+}
+
+@external_default_global = external global i32
+define i32* @get_external_default_global() {
+ ret i32* @external_default_global
+
+; STATIC-LABEL: @get_external_default_global
+; STATIC: addis 3, 2, .LC0@toc@ha
+; STATIC: ld 3, .LC0@toc@l(3)
+; STATIC: blr
+
+; CHECK-LABEL: @get_external_default_global
+; CHECK: addis 3, 2, .LC2@toc@ha
+; CHECK: ld 3, .LC2@toc@l(3)
+; CHECK: blr
+}
+
+
+@strong_local_global = dso_local global i32 55
+define i32* @get_strong_local_global() {
+ ret i32* @strong_local_global
+
+; STATIC-LABEL: @get_strong_local_global
+; STATIC: addis 3, 2, strong_local_global@toc@ha
+; STATIC: addi 3, 3, strong_local_global@toc@l
+; STATIC: blr
+
+; CHECK-LABEL: @get_strong_local_global
+; CHECK: addis 3, 2, strong_local_global@toc@ha
+; CHECK: addi 3, 3, strong_local_global@toc@l
+; CHECK: blr
+}
+
+@weak_local_global = weak dso_local global i32 42
+define i32* @get_weak_local_global() {
+ ret i32* @weak_local_global
+
+; STATIC-LABEL: @get_weak_local_global
+; STATIC: addis 3, 2, weak_local_global@toc@ha
+; STATIC: addi 3, 3, weak_local_global@toc@l
+; STATIC: blr
+
+; CHECK-LABEL: @get_weak_local_global
+; CHECK: addis 3, 2, weak_local_global@toc@ha
+; CHECK: addi 3, 3, weak_local_global@toc@l
+; CHECK: blr
+}
+
+@external_local_global = external dso_local global i32
+define i32* @get_external_local_global() {
+ ret i32* @external_local_global
+; STATIC-LABEL: @get_external_local_global
+; STATIC: addis 3, 2, external_local_global@toc@ha
+; STATIC: addi 3, 3, external_local_global@toc@l
+; STATIC: blr
+
+; CHECK-LABEL: @get_external_local_global
+; CHECK: addis 3, 2, external_local_global@toc@ha
+; CHECK: addi 3, 3, external_local_global@toc@l
+; CHECK: blr
+}
+
+@strong_preemptable_global = dso_preemptable global i32 42
+define i32* @get_strong_preemptable_global() {
+ ret i32* @strong_preemptable_global
+
+; STATIC-LABEL: @get_strong_preemptable_global
+; STATIC: addis 3, 2, strong_preemptable_global@toc@ha
+; STATIC: addi 3, 3, strong_preemptable_global@toc@l
+; STATIC: blr
+
+; CHECK-LABEL: @get_strong_preemptable_global
+; CHECK: addis 3, 2, .LC3@toc@ha
+; CHECK: ld 3, .LC3@toc@l(3)
+; CHECK: blr
+}
+
+@weak_preemptable_global = weak dso_preemptable global i32 42
+define i32* @get_weak_preemptable_global() {
+ ret i32* @weak_preemptable_global
+
+; STATIC-LABEL: @get_weak_preemptable_global
+; STATIC: addis 3, 2, weak_preemptable_global@toc@ha
+; STATIC: addi 3, 3, weak_preemptable_global@toc@l
+; STATIC: blr
+
+; CHECK-LABEL: @get_weak_preemptable_global
+; CHECK: addis 3, 2, .LC4@toc@ha
+; CHECK: ld 3, .LC4@toc@l(3)
+; CHECK: blr
+}
+
+@external_preemptable_global = external dso_preemptable global i32
+define i32* @get_external_preemptable_global() {
+ ret i32* @external_preemptable_global
+
+; STATIC-LABEL: @get_external_preemptable_global
+; STATIC: addis 3, 2, .LC1@toc@ha
+; STATIC: ld 3, .LC1@toc@l(3)
+; STATIC: blr
+
+; CHECK-LABEL: @get_external_preemptable_global
+; CHECK: addis 3, 2, .LC5@toc@ha
+; CHECK: ld 3, .LC5@toc@l(3)
+; CHECK: blr
+}
+
+; functions
+define signext i32 @strong_default_function(i32 %i) {
+ ret i32 %i
+}
+define signext i32 @strong_default_function_caller(i32 %i) {
+ %call = notail call signext i32 @strong_default_function(i32 signext %i)
+ ret i32 %call
+
+; STATIC-LABEL: @strong_default_function_caller
+; STATIC: bl strong_default_function
+; STATIC-NOT: nop
+; STATIC: blr
+
+; CHECK-LABEL: @strong_default_function_caller
+; CHECK: bl strong_default_function
+; CHECK-NEXT: nop
+; CHECK: blr
+}
+
+define weak signext i32 @weak_default_function(i32 %i) {
+ ret i32 %i
+}
+define signext i32 @weak_default_function_caller(i32 %i) {
+ %call = notail call signext i32 @weak_default_function(i32 signext %i)
+ ret i32 %call
+
+; STATIC-LABEL: @weak_default_function_caller
+; STATIC: bl weak_default_function
+; STATIC-NOT: nop
+; STATIC: blr
+
+; CHECK-LABEL: @weak_default_function_caller
+; CHECK: bl weak_default_function
+; CHECK-NEXT: nop
+; CHECK: blr
+}
+
+
+declare i32 @external_default_function(i32 %i)
+define i32 @external_default_function_caller(i32 %i) {
+ %call = notail call signext i32 @external_default_function(i32 signext %i)
+ ret i32 %call
+
+; STATIC-LABEL: @external_default_function_caller
+; STATIC: bl external_default_function
+; STATIC-NEXT: nop
+; STATIC: blr
+
+; CHECK-LABEL: @external_default_function_caller
+; CHECK: bl external_default_function
+; CHECK-NEXT: nop
+; CHECK: blr
+}
+
+define dso_local signext i32 @strong_local_function(i32 %i) {
+ ret i32 %i
+}
+define signext i32 @strong_local_function_caller(i32 %i) {
+ %call = notail call signext i32 @strong_local_function(i32 signext %i)
+ ret i32 %call
+
+; STATIC-LABEL: @strong_local_function_caller
+; STATIC: bl strong_local_function
+; STATIC-NOT: nop
+; STATIC: blr
+
+; CHECK-LABEL: @strong_local_function_caller
+; CHECK: bl strong_local_function
+; CHECK-NOT: nop
+; CHECK: blr
+}
+
+define weak dso_local signext i32 @weak_local_function(i32 %i) {
+ ret i32 %i
+}
+define signext i32 @weak_local_function_caller(i32 %i) {
+ %call = notail call signext i32 @weak_local_function(i32 signext %i)
+ ret i32 %call
+
+; STATIC-LABEL: @weak_local_function_caller
+; STATIC: bl weak_local_function
+; STATIC-NOT: nop
+; STATIC: blr
+
+; CHECK-LABEL: @weak_local_function_caller
+; CHECK: bl weak_local_function
+; CHECK-NOT: nop
+; CHECK: blr
+}
+
+declare dso_local i32 @external_local_function(i32 %i)
+define i32 @external_local_function_caller(i32 %i) {
+ %call = notail call signext i32 @external_local_function(i32 signext %i)
+ ret i32 %call
+
+; STATIC-LABEL: @external_local_function_caller
+; STATIC: bl external_local_function
+; STATIC-NOT: nop
+; STATIC: blr
+
+; CHECK-LABEL: @external_local_function_caller
+; CHECK: bl external_local_function
+; CHECK-NOT: nop
+; CHECK: blr
+}
+
+define dso_preemptable signext i32 @strong_preemptable_function(i32 %i) {
+ ret i32 %i
+}
+define signext i32 @strong_preemptable_function_caller(i32 %i) {
+ %call = notail call signext i32 @strong_preemptable_function(i32 signext %i)
+ ret i32 %call
+
+; STATIC-LABEL: @strong_preemptable_function_caller
+; STATIC: bl strong_preemptable_function
+; STATIC-NOT: nop
+; STATIC: blr
+
+; CHECK-LABEL: @strong_preemptable_function_caller
+; CHECK: bl strong_preemptable_function
+; CHECK-NEXT: nop
+; CHECK: blr
+}
+
+define weak dso_preemptable signext i32 @weak_preemptable_function(i32 %i) {
+ ret i32 %i
+}
+define signext i32 @weak_preemptable_function_caller(i32 %i) {
+ %call = notail call signext i32 @weak_preemptable_function(i32 signext %i)
+ ret i32 %call
+
+; STATIC-LABEL: @weak_preemptable_function_caller
+; STATIC: bl weak_preemptable_function
+; STATIC-NOT: nop
+; STATIC: blr
+
+; CHECK-LABEL: @weak_preemptable_function_caller
+; CHECK: bl weak_preemptable_function
+; CHECK-NEXT: nop
+; CHECK: blr
+}
+
+declare dso_preemptable i32 @external_preemptable_function(i32 %i)
+define i32 @external_preemptable_function_caller(i32 %i) {
+ %call = notail call signext i32 @external_preemptable_function(i32 signext %i)
+ ret i32 %call
+
+; STATIC-LABEL: @external_preemptable_function_caller
+; STATIC: bl external_preemptable_function
+; STATIC-NEXT: nop
+; STATIC: blr
+
+; CHECK-LABEL: @external_preemptable_function_caller
+; CHECK: bl external_preemptable_function
+; CHECK-NEXT: nop
+; CHECK: blr
+}
+
--- /dev/null
+; RUN: llc -mtriple x86_64-apple-darwin \
+; RUN: -relocation-model=static < %s | FileCheck %s
+; RUN: llc -mtriple x86_64-apple-darwin \
+; RUN: -relocation-model=pic < %s | FileCheck %s
+; RUN: llc -mtriple x86_64-apple-darwin \
+; RUN: -relocation-model=dynamic-no-pic < %s | FileCheck %s
+
+; 32 bits
+
+; RUN: llc -mtriple i386-apple-darwin \
+; RUN: -relocation-model=static < %s | FileCheck --check-prefix=DARWIN32_S %s
+; RUN: llc -mtriple i386-apple-darwin \
+; RUN: -relocation-model=pic < %s | FileCheck --check-prefix=DARWIN32 %s
+; RUN: llc -mtriple i386-apple-darwin \
+; RUN: -relocation-model=dynamic-no-pic < %s | \
+; RUN: FileCheck --check-prefix=DARWIN32_DNP %s
+
+; globals
+
+@strong_default_global = global i32 42
+define i32* @get_strong_default_global() {
+ ret i32* @strong_default_global
+}
+; CHECK: leaq _strong_default_global(%rip), %rax
+; DARWIN32: leal _strong_default_global-L{{.*}}$pb(%eax), %eax
+; DARWIN32_S: movl $_strong_default_global, %eax
+; DARWIN32_DNP: movl $_strong_default_global, %eax
+
+@weak_default_global = weak global i32 42
+define i32* @get_weak_default_global() {
+ ret i32* @weak_default_global
+}
+; CHECK: movq _weak_default_global@GOTPCREL(%rip), %rax
+; DARWIN32: movl L_weak_default_global$non_lazy_ptr-L{{.*}}$pb(%eax), %eax
+; DARWIN32_S: movl $_weak_default_global, %eax
+; DARWIN32_DNP: movl L_weak_default_global$non_lazy_ptr, %eax
+
+@external_default_global = external global i32
+define i32* @get_external_default_global() {
+ ret i32* @external_default_global
+}
+; CHECK: movq _external_default_global@GOTPCREL(%rip), %rax
+; DARWIN32: movl L_external_default_global$non_lazy_ptr-L{{.*}}$pb(%eax), %eax
+; DARWIN32_S: movl $_external_default_global, %eax
+; DARWIN32_DNP: movl L_external_default_global$non_lazy_ptr, %eax
+
+@strong_local_global = dso_local global i32 42
+define i32* @get_strong_local_global() {
+ ret i32* @strong_local_global
+}
+; CHECK: leaq _strong_local_global(%rip), %rax
+; DARWIN32: leal _strong_local_global-L{{.*}}$pb(%eax), %eax
+; DARWIN32_S: movl $_strong_local_global, %eax
+; DARWIN32_DNP: movl $_strong_local_global, %eax
+
+@weak_local_global = weak dso_local global i32 42
+define i32* @get_weak_local_global() {
+ ret i32* @weak_local_global
+}
+; CHECK: leaq _weak_local_global(%rip), %rax
+; DARWIN32: leal _weak_local_global-L{{.}}$pb(%eax), %eax
+; DARWIN32_S: movl $_weak_local_global, %eax
+; DARWIN32_DNP: movl $_weak_local_global, %eax
+
+@external_local_global = external dso_local global i32
+define i32* @get_external_local_global() {
+ ret i32* @external_local_global
+}
+; CHECK: leaq _external_local_global(%rip), %rax
+; DARWIN32: movl L_external_local_global$non_lazy_ptr-L{{.*}}$pb(%eax), %eax
+; DARWIN32_S: movl $_external_local_global, %eax
+; DARWIN32_DNP: movl $_external_local_global, %eax
+
+@strong_preemptable_global = dso_preemptable global i32 42
+define i32* @get_strong_preemptable_global() {
+ ret i32* @strong_preemptable_global
+}
+; CHECK: leaq _strong_preemptable_global(%rip), %rax
+; DARWIN32: leal _strong_preemptable_global-L{{.*}}$pb(%eax), %eax
+; DARWIN32_S: movl $_strong_preemptable_global, %eax
+; DARWIN32_DNP: movl $_strong_preemptable_global, %eax
+
+@weak_preemptable_global = weak dso_preemptable global i32 42
+define i32* @get_weak_preemptable_global() {
+ ret i32* @weak_preemptable_global
+}
+; CHECK: movq _weak_preemptable_global@GOTPCREL(%rip), %rax
+; DARWIN32: movl L_weak_preemptable_global$non_lazy_ptr-L{{.*}}$pb(%eax), %eax
+; DARWIN32_S: movl $_weak_preemptable_global, %eax
+; DARWIN32_DNP: movl L_weak_preemptable_global$non_lazy_ptr, %eax
+
+@external_preemptable_global = external dso_preemptable global i32
+define i32* @get_external_preemptable_global() {
+ ret i32* @external_preemptable_global
+}
+; CHECK: movq _external_preemptable_global@GOTPCREL(%rip), %rax
+; DARWIN32: movl L_external_preemptable_global$non_lazy_ptr-L{{.*}}$pb(%eax), %eax
+; DARWIN32_S: movl $_external_preemptable_global, %eax
+; DARWIN32_DNP: movl L_external_preemptable_global$non_lazy_ptr, %eax
+
+; aliases
+@aliasee = global i32 42
+
+@strong_default_alias = alias i32, i32* @aliasee
+define i32* @get_strong_default_alias() {
+ ret i32* @strong_default_alias
+}
+; CHECK: leaq _strong_default_alias(%rip), %rax
+; DARWIN32: leal _strong_default_alias-L{{.*}}$pb(%eax), %eax
+; DARWIN32_S: movl $_strong_default_alias, %eax
+; DARWIN32_DNP: movl $_strong_default_alias, %eax
+
+@weak_default_alias = weak alias i32, i32* @aliasee
+define i32* @get_weak_default_alias() {
+ ret i32* @weak_default_alias
+}
+; CHECK: movq _weak_default_alias@GOTPCREL(%rip), %rax
+; DARWIN32: movl L_weak_default_alias$non_lazy_ptr-L{{.*}}$pb(%eax), %eax
+; DARWIN32_S: movl $_weak_default_alias, %eax
+; DARWIN32_DNP: movl L_weak_default_alias$non_lazy_ptr, %eax
+
+@strong_local_alias = dso_local alias i32, i32* @aliasee
+define i32* @get_strong_local_alias() {
+ ret i32* @strong_local_alias
+}
+; CHECK: leaq _strong_local_alias(%rip), %rax
+; DARWIN32: leal _strong_local_alias-L{{.*}}$pb(%eax), %eax
+; DARWIN32_S: movl $_strong_local_alias, %eax
+; DARWIN32_DNP: movl $_strong_local_alias, %eax
+
+@weak_local_alias = weak dso_local alias i32, i32* @aliasee
+define i32* @get_weak_local_alias() {
+ ret i32* @weak_local_alias
+}
+; CHECK: leaq _weak_local_alias(%rip), %rax
+; DARWIN32: leal _weak_local_alias-L{{.*}}$pb(%eax), %eax
+; DARWIN32_S: movl $_weak_local_alias, %eax
+; DARWIN32_DNP: movl $_weak_local_alias, %eax
+
+@strong_preemptable_alias = dso_preemptable alias i32, i32* @aliasee
+define i32* @get_strong_preemptable_alias() {
+ ret i32* @strong_preemptable_alias
+}
+; CHECK: leaq _strong_preemptable_alias(%rip), %rax
+; DARWIN32: leal _strong_preemptable_alias-L{{.*}}$pb(%eax), %eax
+; DARWIN32_S: movl $_strong_preemptable_alias, %eax
+; DARWIN32_DNP: movl $_strong_preemptable_alias, %eax
+
+@weak_preemptable_alias = weak dso_preemptable alias i32, i32* @aliasee
+define i32* @get_weak_preemptable_alias() {
+ ret i32* @weak_preemptable_alias
+}
+; CHECK: movq _weak_preemptable_alias@GOTPCREL(%rip), %rax
+; DARWIN32: movl L_weak_preemptable_alias$non_lazy_ptr-L{{.*}}$pb(%eax), %eax
+; DARWIN32_S: movl $_weak_preemptable_alias, %eax
+; DARWIN32_DNP: movl L_weak_preemptable_alias$non_lazy_ptr, %eax
+
+; functions
+
+define void @strong_default_function() {
+ ret void
+}
+define void()* @get_strong_default_function() {
+ ret void()* @strong_default_function
+}
+; CHECK: leaq _strong_default_function(%rip), %rax
+; DARWIN32: leal _strong_default_function-L{{.*}}$pb(%eax), %eax
+; DARWIN32_S: movl $_strong_default_function, %eax
+; DARWIN32_DNP: movl $_strong_default_function, %eax
+
+define weak void @weak_default_function() {
+ ret void
+}
+define void()* @get_weak_default_function() {
+ ret void()* @weak_default_function
+}
+; CHECK: movq _weak_default_function@GOTPCREL(%rip), %rax
+; DARWIN32: movl L_weak_default_function$non_lazy_ptr-L{{.*}}$pb(%eax), %eax
+; DARWIN32_S: movl $_weak_default_function, %eax
+; DARWIN32_DNP: movl L_weak_default_function$non_lazy_ptr, %eax
+
+declare void @external_default_function()
+define void()* @get_external_default_function() {
+ ret void()* @external_default_function
+}
+; CHECK: movq _external_default_function@GOTPCREL(%rip), %rax
+; DARWIN32: movl L_external_default_function$non_lazy_ptr-L{{.*}}$pb(%eax), %eax
+; DARWIN32_S: movl $_external_default_function, %eax
+; DARWIN32_DNP: movl L_external_default_function$non_lazy_ptr, %eax
+
+define dso_local void @strong_local_function() {
+ ret void
+}
+define void()* @get_strong_local_function() {
+ ret void()* @strong_local_function
+}
+; CHECK: leaq _strong_local_function(%rip), %rax
+; DARWIN32: leal _strong_local_function-L{{.*}}$pb(%eax), %eax
+; DARWIN32_S: movl $_strong_local_function, %eax
+; DARWIN32_DNP: movl $_strong_local_function, %eax
+
+define weak dso_local void @weak_local_function() {
+ ret void
+}
+define void()* @get_weak_local_function() {
+ ret void()* @weak_local_function
+}
+; CHECK: leaq _weak_local_function(%rip), %rax
+; DARWIN32: leal _weak_local_function-L{{.*}}$pb(%eax), %eax
+; DARWIN32_S: movl $_weak_local_function, %eax
+; DARWIN32_DNP: movl $_weak_local_function, %eax
+
+declare dso_local void @external_local_function()
+define void()* @get_external_local_function() {
+ ret void()* @external_local_function
+}
+; CHECK: leaq _external_local_function(%rip), %rax
+; DARWIN32: movl L_external_local_function$non_lazy_ptr-L{{.*}}$pb(%eax), %eax
+; DARWIN32_S: movl $_external_local_function, %eax
+; DARWIN32_DNP: movl $_external_local_function, %eax
+
+define dso_preemptable void @strong_preemptable_function() {
+ ret void
+}
+define void()* @get_strong_preemptable_function() {
+ ret void()* @strong_preemptable_function
+}
+; CHECK: leaq _strong_preemptable_function(%rip), %rax
+; DARWIN32: leal _strong_preemptable_function-L{{.*}}$pb(%eax), %eax
+; DARWIN32_S: movl $_strong_preemptable_function, %eax
+; DARWIN32_DNP: movl $_strong_preemptable_function, %eax
+
+define weak dso_preemptable void @weak_preemptable_function() {
+ ret void
+}
+define void()* @get_weak_preemptable_function() {
+ ret void()* @weak_preemptable_function
+}
+; CHECK: movq _weak_preemptable_function@GOTPCREL(%rip), %rax
+; DARWIN32: movl L_weak_preemptable_function$non_lazy_ptr-L{{.*}}$pb(%eax), %eax
+; DARWIN32_S: movl $_weak_preemptable_function, %eax
+; DARWIN32_DNP: movl L_weak_preemptable_function$non_lazy_ptr, %eax
+
+declare dso_preemptable void @external_preemptable_function()
+define void()* @get_external_preemptable_function() {
+ ret void()* @external_preemptable_function
+}
+; CHECK: movq _external_preemptable_function@GOTPCREL(%rip), %rax
+; DARWIN32: movl L_external_preemptable_function$non_lazy_ptr-L{{.*}}$pb(%eax), %eax
+; DARWIN32_S: movl $_external_preemptable_function, %eax
+; DARWIN32_DNP: movl L_external_preemptable_function$non_lazy_ptr, %eax
--- /dev/null
+; RUN: llc -mtriple x86_64-pc-linux \
+; RUN: -relocation-model=static < %s | FileCheck --check-prefix=STATIC %s
+; RUN: llc -mtriple x86_64-pc-linux \
+; RUN: -relocation-model=pic < %s | FileCheck %s
+; RUN: llc -mtriple x86_64-pc-linux \
+; RUN: -relocation-model=dynamic-no-pic < %s | FileCheck %s
+
+; 32 bits
+
+; RUN: llc -mtriple i386-pc-linux \
+; RUN: -relocation-model=pic < %s | FileCheck --check-prefix=CHECK32 %s
+
+; globals
+
+@strong_default_global = global i32 42
+define i32* @get_strong_default_global() {
+ ret i32* @strong_default_global
+}
+; CHECK: movq strong_default_global@GOTPCREL(%rip), %rax
+; STATIC: movl $strong_default_global, %eax
+; CHECK32: movl strong_default_global@GOT(%eax), %eax
+
+@weak_default_global = weak global i32 42
+define i32* @get_weak_default_global() {
+ ret i32* @weak_default_global
+}
+; CHECK: movq weak_default_global@GOTPCREL(%rip), %rax
+; STATIC: movl $weak_default_global, %eax
+; CHECK32: movl weak_default_global@GOT(%eax), %eax
+
+@external_default_global = external global i32
+define i32* @get_external_default_global() {
+ ret i32* @external_default_global
+}
+; CHECK: movq external_default_global@GOTPCREL(%rip), %rax
+; STATIC: movl $external_default_global, %eax
+; CHECK32: movl external_default_global@GOT(%eax), %eax
+
+@strong_local_global = dso_local global i32 42
+define i32* @get_strong_local_global() {
+ ret i32* @strong_local_global
+}
+; CHECK: leaq strong_local_global(%rip), %rax
+; STATIC: movl $strong_local_global, %eax
+; CHECK32: leal strong_local_global@GOTOFF(%eax), %eax
+
+@weak_local_global = weak dso_local global i32 42
+define i32* @get_weak_local_global() {
+ ret i32* @weak_local_global
+}
+; CHECK: leaq weak_local_global(%rip), %rax
+; STATIC: movl $weak_local_global, %eax
+; CHECK32: leal weak_local_global@GOTOFF(%eax), %eax
+
+@external_local_global = external dso_local global i32
+define i32* @get_external_local_global() {
+ ret i32* @external_local_global
+}
+; CHECK: leaq external_local_global(%rip), %rax
+; STATIC: movl $external_local_global, %eax
+; CHECK32: leal external_local_global@GOTOFF(%eax), %eax
+
+
+@strong_preemptable_global = dso_preemptable global i32 42
+define i32* @get_strong_preemptable_global() {
+ ret i32* @strong_preemptable_global
+}
+; CHECK: movq strong_preemptable_global@GOTPCREL(%rip), %rax
+; STATIC: movl $strong_preemptable_global, %eax
+; CHECK32: movl strong_preemptable_global@GOT(%eax), %eax
+
+@weak_preemptable_global = weak dso_preemptable global i32 42
+define i32* @get_weak_preemptable_global() {
+ ret i32* @weak_preemptable_global
+}
+; CHECK ;ADD_LABEL_BACK; movq weak_preemptable_global@GOTPCREL(%rip), %rax
+; STATIC ;ADD_LABEL_BACK; movq weak_preemptable_global@GOTPCREL, %rax
+; CHECK32 ;ADD_LABEL_BACK; movl weak_preemptable_global@GOT(%eax), %eax
+
+@external_preemptable_global = external dso_preemptable global i32
+define i32* @get_external_preemptable_global() {
+ ret i32* @external_preemptable_global
+}
+; CHECK: movq external_preemptable_global@GOTPCREL(%rip), %rax
+; STATIC: movl $external_preemptable_global, %eax
+; CHECK32: movl external_preemptable_global@GOT(%eax), %eax
+
+; aliases
+@aliasee = global i32 42
+
+@strong_default_alias = alias i32, i32* @aliasee
+define i32* @get_strong_default_alias() {
+ ret i32* @strong_default_alias
+}
+; CHECK: movq strong_default_alias@GOTPCREL(%rip), %rax
+; STATIC: movl $strong_default_alias, %eax
+; CHECK32: movl strong_default_alias@GOT(%eax), %eax
+
+@weak_default_alias = weak alias i32, i32* @aliasee
+define i32* @get_weak_default_alias() {
+ ret i32* @weak_default_alias
+}
+; CHECK: movq weak_default_alias@GOTPCREL(%rip), %rax
+; STATIC: movl $weak_default_alias, %eax
+; CHECK32: movl weak_default_alias@GOT(%eax), %eax
+
+@strong_local_alias = dso_local alias i32, i32* @aliasee
+define i32* @get_strong_local_alias() {
+ ret i32* @strong_local_alias
+}
+; CHECK: leaq strong_local_alias(%rip), %rax
+; STATIC: movl $strong_local_alias, %eax
+; CHECK32: leal strong_local_alias@GOTOFF(%eax), %eax
+
+@weak_local_alias = weak dso_local alias i32, i32* @aliasee
+define i32* @get_weak_local_alias() {
+ ret i32* @weak_local_alias
+}
+; CHECK: leaq weak_local_alias(%rip), %rax
+; STATIC: movl $weak_local_alias, %eax
+; CHECK32: leal weak_local_alias@GOTOFF(%eax), %eax
+
+
+@strong_preemptable_alias = dso_preemptable alias i32, i32* @aliasee
+define i32* @get_strong_preemptable_alias() {
+ ret i32* @strong_preemptable_alias
+}
+; CHECK: movq strong_preemptable_alias@GOTPCREL(%rip), %rax
+; STATIC: movl $strong_preemptable_alias, %eax
+; CHECK32: movl strong_preemptable_alias@GOT(%eax), %eax
+
+@weak_preemptable_alias = weak dso_preemptable alias i32, i32* @aliasee
+define i32* @get_weak_preemptable_alias() {
+ ret i32* @weak_preemptable_alias
+}
+; CHECK: movq weak_preemptable_alias@GOTPCREL(%rip), %rax
+; STATIC: movl $weak_preemptable_alias, %eax
+; CHECK32: movl weak_preemptable_alias@GOT(%eax), %eax
+
+; functions
+
+define void @strong_default_function() {
+ ret void
+}
+define void()* @get_strong_default_function() {
+ ret void()* @strong_default_function
+}
+; CHECK: movq strong_default_function@GOTPCREL(%rip), %rax
+; STATIC: movl $strong_default_function, %eax
+; CHECK32: movl strong_default_function@GOT(%eax), %eax
+
+define weak void @weak_default_function() {
+ ret void
+}
+define void()* @get_weak_default_function() {
+ ret void()* @weak_default_function
+}
+; CHECK: movq weak_default_function@GOTPCREL(%rip), %rax
+; STATIC: movl $weak_default_function, %eax
+; CHECK32: movl weak_default_function@GOT(%eax), %eax
+
+declare void @external_default_function()
+define void()* @get_external_default_function() {
+ ret void()* @external_default_function
+}
+; CHECK: movq external_default_function@GOTPCREL(%rip), %rax
+; STATIC: movl $external_default_function, %eax
+; CHECK32: movl external_default_function@GOT(%eax), %eax
+
+define dso_local void @strong_local_function() {
+ ret void
+}
+define void()* @get_strong_local_function() {
+ ret void()* @strong_local_function
+}
+; CHECK: leaq strong_local_function(%rip), %rax
+; STATIC: movl $strong_local_function, %eax
+; CHECK32: leal strong_local_function@GOTOFF(%eax), %eax
+
+define weak dso_local void @weak_local_function() {
+ ret void
+}
+define void()* @get_weak_local_function() {
+ ret void()* @weak_local_function
+}
+; CHECK: leaq weak_local_function(%rip), %rax
+; STATIC: movl $weak_local_function, %eax
+; CHECK32: leal weak_local_function@GOTOFF(%eax), %eax
+
+declare dso_local void @external_local_function()
+define void()* @get_external_local_function() {
+ ret void()* @external_local_function
+}
+; CHECK: leaq external_local_function(%rip), %rax
+; STATIC: movl $external_local_function, %eax
+; CHECK32: leal external_local_function@GOTOFF(%eax), %eax
+
+
+define dso_preemptable void @strong_preemptable_function() {
+ ret void
+}
+define void()* @get_strong_preemptable_function() {
+ ret void()* @strong_preemptable_function
+}
+; CHECK: movq strong_preemptable_function@GOTPCREL(%rip), %rax
+; STATIC: movl $strong_preemptable_function, %eax
+; CHECK32: movl strong_preemptable_function@GOT(%eax), %eax
+
+define weak dso_preemptable void @weak_preemptable_function() {
+ ret void
+}
+define void()* @get_weak_preemptable_function() {
+ ret void()* @weak_preemptable_function
+}
+; CHECK: movq weak_preemptable_function@GOTPCREL(%rip), %rax
+; STATIC: movl $weak_preemptable_function, %eax
+; CHECK32: movl weak_preemptable_function@GOT(%eax), %eax
+
+declare dso_preemptable void @external_preemptable_function()
+define void()* @get_external_preemptable_function() {
+ ret void()* @external_preemptable_function
+}
+; CHECK: movq external_preemptable_function@GOTPCREL(%rip), %rax
+; STATIC: movl $external_preemptable_function, %eax
+; CHECK32: movl external_preemptable_function@GOT(%eax), %eax
--- /dev/null
+; RUN: llc -mtriple x86_64-pc-win32 \
+; RUN: -relocation-model=static < %s | FileCheck --check-prefix=COFF_S %s
+; RUN: llc -mtriple x86_64-pc-win32 \
+; RUN: -relocation-model=pic < %s | FileCheck --check-prefix=COFF %s
+; RUN: llc -mtriple x86_64-pc-win32 \
+; RUN: -relocation-model=dynamic-no-pic < %s | FileCheck --check-prefix=COFF %s
+
+
+; 32 bits
+
+; RUN: llc -mtriple i386-pc-win32 \
+; RUN: -relocation-model=static < %s | FileCheck --check-prefix=COFF32 %s
+; RUN: llc -mtriple i386-pc-win32 \
+; RUN: -relocation-model=pic < %s | FileCheck --check-prefix=COFF32 %s
+; RUN: llc -mtriple i386-pc-win32 \
+; RUN: -relocation-model=dynamic-no-pic < %s | \
+; RUN: FileCheck --check-prefix=COFF32 %s
+
+; globals
+
+@strong_default_global = global i32 42
+define i32* @get_strong_default_global() {
+ ret i32* @strong_default_global
+}
+; COFF: leaq strong_default_global(%rip), %rax
+; COFF_S: movl $strong_default_global, %eax
+; COFF32: movl $_strong_default_global, %eax
+
+@weak_default_global = weak global i32 42
+define i32* @get_weak_default_global() {
+ ret i32* @weak_default_global
+}
+; COFF: leaq weak_default_global(%rip), %rax
+; COFF_S: movl $weak_default_global, %eax
+; COFF32: movl $_weak_default_global, %eax
+
+@external_default_global = external global i32
+define i32* @get_external_default_global() {
+ ret i32* @external_default_global
+}
+; COFF: leaq external_default_global(%rip), %rax
+; COFF_S: movl $external_default_global, %eax
+; COFF32: movl $_external_default_global, %eax
+
+
+@strong_local_global = dso_local global i32 42
+define i32* @get_strong_local_global() {
+ ret i32* @strong_local_global
+}
+; COFF: leaq strong_local_global(%rip), %rax
+; COFF_S: movl $strong_local_global, %eax
+; COFF32: movl $_strong_local_global, %eax
+
+@weak_local_global = weak dso_local global i32 42
+define i32* @get_weak_local_global() {
+ ret i32* @weak_local_global
+}
+; COFF: leaq weak_local_global(%rip), %rax
+; COFF_S: movl $weak_local_global, %eax
+; COFF32: movl $_weak_local_global, %eax
+
+@external_local_global = external dso_local global i32
+define i32* @get_external_local_global() {
+ ret i32* @external_local_global
+}
+; COFF: leaq external_local_global(%rip), %rax
+; COFF_S: movl $external_local_global, %eax
+; COFF32: movl $_external_local_global, %eax
+
+
+@strong_preemptable_global = dso_preemptable global i32 42
+define i32* @get_strong_preemptable_global() {
+ ret i32* @strong_preemptable_global
+}
+; COFF: leaq strong_preemptable_global(%rip), %rax
+; COFF_S: movl $strong_preemptable_global, %eax
+; COFF32: movl $_strong_preemptable_global, %eax
+
+@weak_preemptable_global = weak dso_preemptable global i32 42
+define i32* @get_weak_preemptable_global() {
+ ret i32* @weak_preemptable_global
+}
+; COFF: leaq weak_preemptable_global(%rip), %rax
+; COFF_S: movl $weak_preemptable_global, %eax
+; COFF32: movl $_weak_preemptable_global, %eax
+
+@external_preemptable_global = external dso_preemptable global i32
+define i32* @get_external_preemptable_global() {
+ ret i32* @external_preemptable_global
+}
+; COFF: leaq external_preemptable_global(%rip), %rax
+; COFF_S: movl $external_preemptable_global, %eax
+; COFF32: movl $_external_preemptable_global, %eax
+
+
+; aliases
+@aliasee = global i32 42
+
+@strong_default_alias = alias i32, i32* @aliasee
+define i32* @get_strong_default_alias() {
+ ret i32* @strong_default_alias
+}
+; COFF: leaq strong_default_alias(%rip), %rax
+; COFF_S: movl $strong_default_alias, %eax
+; COFF32: movl $_strong_default_alias, %eax
+
+@weak_default_alias = weak alias i32, i32* @aliasee
+define i32* @get_weak_default_alias() {
+ ret i32* @weak_default_alias
+}
+; COFF: leaq weak_default_alias(%rip), %rax
+; COFF_S: movl $weak_default_alias, %eax
+; COFF32: movl $_weak_default_alias, %eax
+
+
+@strong_local_alias = dso_local alias i32, i32* @aliasee
+define i32* @get_strong_local_alias() {
+ ret i32* @strong_local_alias
+}
+; COFF: leaq strong_local_alias(%rip), %rax
+; COFF_S: movl $strong_local_alias, %eax
+; COFF32: movl $_strong_local_alias, %eax
+
+@weak_local_alias = weak dso_local alias i32, i32* @aliasee
+define i32* @get_weak_local_alias() {
+ ret i32* @weak_local_alias
+}
+; COFF: leaq weak_local_alias(%rip), %rax
+; COFF_S: movl $weak_local_alias, %eax
+; COFF32: movl $_weak_local_alias, %eax
+
+
+@strong_preemptable_alias = dso_preemptable alias i32, i32* @aliasee
+define i32* @get_strong_preemptable_alias() {
+ ret i32* @strong_preemptable_alias
+}
+; COFF: leaq strong_preemptable_alias(%rip), %rax
+; COFF_S: movl $strong_preemptable_alias, %eax
+; COFF32: movl $_strong_preemptable_alias, %eax
+
+@weak_preemptable_alias = weak dso_preemptable alias i32, i32* @aliasee
+define i32* @get_weak_preemptable_alias() {
+ ret i32* @weak_preemptable_alias
+}
+; COFF: leaq weak_preemptable_alias(%rip), %rax
+; COFF_S: movl $weak_preemptable_alias, %eax
+; COFF32: movl $_weak_preemptable_alias, %eax
+
+
+; functions
+
+define void @strong_default_function() {
+ ret void
+}
+define void()* @get_strong_default_function() {
+ ret void()* @strong_default_function
+}
+; COFF: leaq strong_default_function(%rip), %rax
+; COFF_S: movl $strong_default_function, %eax
+; COFF32: movl $_strong_default_function, %eax
+
+define weak void @weak_default_function() {
+ ret void
+}
+define void()* @get_weak_default_function() {
+ ret void()* @weak_default_function
+}
+; COFF: leaq weak_default_function(%rip), %rax
+; COFF_S: movl $weak_default_function, %eax
+; COFF32: movl $_weak_default_function, %eax
+
+declare void @external_default_function()
+define void()* @get_external_default_function() {
+ ret void()* @external_default_function
+}
+; COFF: leaq external_default_function(%rip), %rax
+; COFF_S: movl $external_default_function, %eax
+; COFF32: movl $_external_default_function, %eax
+
+
+define dso_local void @strong_local_function() {
+ ret void
+}
+define void()* @get_strong_local_function() {
+ ret void()* @strong_local_function
+}
+; COFF: leaq strong_local_function(%rip), %rax
+; COFF_S: movl $strong_local_function, %eax
+; COFF32: movl $_strong_local_function, %eax
+
+define weak dso_local void @weak_local_function() {
+ ret void
+}
+define void()* @get_weak_local_function() {
+ ret void()* @weak_local_function
+}
+; COFF: leaq weak_local_function(%rip), %rax
+; COFF_S: movl $weak_local_function, %eax
+; COFF32: movl $_weak_local_function, %eax
+
+declare dso_local void @external_local_function()
+define void()* @get_external_local_function() {
+ ret void()* @external_local_function
+}
+; COFF: leaq external_local_function(%rip), %rax
+; COFF_S: movl $external_local_function, %eax
+; COFF32: movl $_external_local_function, %eax
+
+
+define dso_preemptable void @strong_preemptable_function() {
+ ret void
+}
+define void()* @get_strong_preemptable_function() {
+ ret void()* @strong_preemptable_function
+}
+; COFF: leaq strong_preemptable_function(%rip), %rax
+; COFF_S: movl $strong_preemptable_function, %eax
+; COFF32: movl $_strong_preemptable_function, %eax
+
+define weak dso_preemptable void @weak_preemptable_function() {
+ ret void
+}
+define void()* @get_weak_preemptable_function() {
+ ret void()* @weak_preemptable_function
+}
+; COFF: leaq weak_preemptable_function(%rip), %rax
+; COFF_S: movl $weak_preemptable_function, %eax
+; COFF32: movl $_weak_preemptable_function, %eax
+
+declare dso_preemptable void @external_preemptable_function()
+define void()* @get_external_preemptable_function() {
+ ret void()* @external_preemptable_function
+}
+; COFF: leaq external_preemptable_function(%rip), %rax
+; COFF_S: movl $external_preemptable_function, %eax
+; COFF32: movl $_external_preemptable_function, %eax