mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 10:42:39 +01:00
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:
parent
a99a74391b
commit
6a96e17cac
@ -681,7 +681,7 @@ for each library name referenced.
|
||||
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:
|
||||
@ -761,12 +761,21 @@ 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:
|
||||
@ -828,10 +837,12 @@ 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
|
||||
@ -856,6 +867,8 @@ 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
|
||||
|
@ -527,6 +527,24 @@ the alias is accessed. It will not have any effect in the aliasee.
|
||||
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
|
||||
@ -650,6 +668,7 @@ iterate over them as an array, alignment padding would break this
|
||||
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>`.
|
||||
|
||||
@ -658,7 +677,8 @@ Variables and aliases can have a
|
||||
|
||||
Syntax::
|
||||
|
||||
@<GlobalVarName> = [Linkage] [Visibility] [DLLStorageClass] [ThreadLocal]
|
||||
@<GlobalVarName> = [Linkage] [PreemptionSpecifier] [Visibility]
|
||||
[DLLStorageClass] [ThreadLocal]
|
||||
[(unnamed_addr|local_unnamed_addr)] [AddrSpace]
|
||||
[ExternallyInitialized]
|
||||
<global | constant> <Type> [<InitializerConstant>]
|
||||
@ -691,7 +711,8 @@ Functions
|
||||
---------
|
||||
|
||||
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
|
||||
@ -750,7 +771,7 @@ not be significant within the module.
|
||||
|
||||
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"]
|
||||
@ -777,12 +798,13 @@ Aliases have a name and an aliasee that is either a global value or a
|
||||
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
|
||||
|
@ -80,13 +80,14 @@ protected:
|
||||
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.
|
||||
@ -103,11 +104,15 @@ protected:
|
||||
/// 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();
|
||||
@ -261,6 +266,12 @@ public:
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -494,6 +494,9 @@ lltok::Kind LLLexer::LexIdentifier() {
|
||||
KEYWORD(declare); KEYWORD(define);
|
||||
KEYWORD(global); KEYWORD(constant);
|
||||
|
||||
KEYWORD(dso_local);
|
||||
KEYWORD(dso_preemptable);
|
||||
|
||||
KEYWORD(private);
|
||||
KEYWORD(internal);
|
||||
KEYWORD(available_externally);
|
||||
|
@ -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);
|
||||
|
@ -240,7 +240,9 @@ namespace llvm {
|
||||
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);
|
||||
@ -284,12 +286,12 @@ namespace llvm {
|
||||
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();
|
||||
|
@ -45,6 +45,9 @@ enum Kind {
|
||||
kw_global,
|
||||
kw_constant,
|
||||
|
||||
kw_dso_local,
|
||||
kw_dso_preemptable,
|
||||
|
||||
kw_private,
|
||||
kw_internal,
|
||||
kw_linkonce,
|
||||
|
@ -911,6 +911,14 @@ getDecodedDLLStorageClass(unsigned Val) {
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
@ -2803,7 +2811,7 @@ Error BitcodeReader::parseComdatRecord(ArrayRef<uint64_t> Record) {
|
||||
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);
|
||||
@ -2888,13 +2896,18 @@ Error BitcodeReader::parseGlobalVarRecord(ArrayRef<uint64_t> 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);
|
||||
@ -2968,6 +2981,10 @@ Error BitcodeReader::parseFunctionRecord(ArrayRef<uint64_t> 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
|
||||
@ -2984,9 +3001,11 @@ Error BitcodeReader::parseGlobalIndirectSymbolRecord(
|
||||
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);
|
||||
@ -3036,6 +3055,8 @@ Error BitcodeReader::parseGlobalIndirectSymbolRecord(
|
||||
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();
|
||||
|
@ -1197,7 +1197,7 @@ void ModuleBitcodeWriter::writeModuleInfo() {
|
||||
// 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()));
|
||||
@ -1213,7 +1213,8 @@ void ModuleBitcodeWriter::writeModuleInfo() {
|
||||
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));
|
||||
@ -1223,6 +1224,8 @@ void ModuleBitcodeWriter::writeModuleInfo() {
|
||||
|
||||
auto AL = GV.getAttributesAsList(AttributeList::FunctionIndex);
|
||||
Vals.push_back(VE.getAttributeListID(AL));
|
||||
|
||||
Vals.push_back(GV.isDSOLocal());
|
||||
} else {
|
||||
AbbrevToUse = SimpleGVarAbbrev;
|
||||
}
|
||||
@ -1236,7 +1239,7 @@ void ModuleBitcodeWriter::writeModuleInfo() {
|
||||
// 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()));
|
||||
@ -1258,6 +1261,7 @@ void ModuleBitcodeWriter::writeModuleInfo() {
|
||||
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();
|
||||
@ -1266,7 +1270,8 @@ void ModuleBitcodeWriter::writeModuleInfo() {
|
||||
// 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()));
|
||||
@ -1277,6 +1282,8 @@ void ModuleBitcodeWriter::writeModuleInfo() {
|
||||
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();
|
||||
|
@ -2493,6 +2493,11 @@ static void PrintVisibility(GlobalValue::VisibilityTypes Vis,
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
@ -2563,6 +2568,7 @@ void AssemblyWriter::printGlobal(const GlobalVariable *GV) {
|
||||
Out << "external ";
|
||||
|
||||
Out << getLinkagePrintName(GV->getLinkage());
|
||||
PrintDSOLocation(GV->isDSOLocal(), Out);
|
||||
PrintVisibility(GV->getVisibility(), Out);
|
||||
PrintDLLStorageClass(GV->getDLLStorageClass(), Out);
|
||||
PrintThreadLocalModel(GV->getThreadLocalMode(), Out);
|
||||
@ -2609,6 +2615,7 @@ void AssemblyWriter::printIndirectSymbol(const GlobalIndirectSymbol *GIS) {
|
||||
Out << " = ";
|
||||
|
||||
Out << getLinkagePrintName(GIS->getLinkage());
|
||||
PrintDSOLocation(GIS->isDSOLocal(), Out);
|
||||
PrintVisibility(GIS->getVisibility(), Out);
|
||||
PrintDLLStorageClass(GIS->getDLLStorageClass(), Out);
|
||||
PrintThreadLocalModel(GIS->getThreadLocalMode(), Out);
|
||||
@ -2720,6 +2727,7 @@ void AssemblyWriter::printFunction(const Function *F) {
|
||||
Out << "define ";
|
||||
|
||||
Out << getLinkagePrintName(F->getLinkage());
|
||||
PrintDSOLocation(F->isDSOLocal(), Out);
|
||||
PrintVisibility(F->getVisibility(), Out);
|
||||
PrintDLLStorageClass(F->getDLLStorageClass(), Out);
|
||||
|
||||
|
@ -67,6 +67,7 @@ void GlobalValue::copyAttributesFrom(const GlobalValue *Src) {
|
||||
setVisibility(Src->getVisibility());
|
||||
setUnnamedAddr(Src->getUnnamedAddr());
|
||||
setDLLStorageClass(Src->getDLLStorageClass());
|
||||
setDSOLocal(Src->isDSOLocal());
|
||||
}
|
||||
|
||||
void GlobalValue::removeFromParent() {
|
||||
|
@ -568,6 +568,10 @@ void Verifier::visitGlobalValue(const GlobalValue &GV) {
|
||||
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())
|
||||
|
@ -128,7 +128,8 @@ bool TargetMachine::shouldAssumeDSOLocal(const Module &M,
|
||||
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()) {
|
||||
|
4
test/Assembler/dllimport-dsolocal-diag.ll
Normal file
4
test/Assembler/dllimport-dsolocal-diag.ll
Normal file
@ -0,0 +1,4 @@
|
||||
; 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
|
9
test/Assembler/ifunc-dsolocal-daig.ll
Normal file
9
test/Assembler/ifunc-dsolocal-daig.ll
Normal file
@ -0,0 +1,9 @@
|
||||
; 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
|
||||
}
|
47
test/Bitcode/dso_location.ll
Normal file
47
test/Bitcode/dso_location.ll
Normal file
@ -0,0 +1,47 @@
|
||||
; 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
|
||||
}
|
301
test/CodeGen/PowerPC/preemption.ll
Normal file
301
test/CodeGen/PowerPC/preemption.ll
Normal file
@ -0,0 +1,301 @@
|
||||
; 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
|
||||
}
|
||||
|
251
test/CodeGen/X86/darwin-preemption.ll
Normal file
251
test/CodeGen/X86/darwin-preemption.ll
Normal file
@ -0,0 +1,251 @@
|
||||
; 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
|
225
test/CodeGen/X86/linux-preemption.ll
Normal file
225
test/CodeGen/X86/linux-preemption.ll
Normal file
@ -0,0 +1,225 @@
|
||||
; 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
|
236
test/CodeGen/X86/win32-preemption.ll
Normal file
236
test/CodeGen/X86/win32-preemption.ll
Normal file
@ -0,0 +1,236 @@
|
||||
; 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
|
Loading…
Reference in New Issue
Block a user