mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-12 17:32:19 +00:00
Extend the IL for selecting TLS models (PR9788)
This allows the user/front-end to specify a model that is better than what LLVM would choose by default. For example, a variable might be declared as @x = thread_local(initialexec) global i32 42 if it will not be used in a shared library that is dlopen'ed. If the specified model isn't supported by the target, or if LLVM can make a better choice, a different model may be used. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@159077 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
47cbc4e0ee
commit
ce718ff9f4
@ -864,7 +864,7 @@ library name referenced.</p>
|
|||||||
<h4><a name="MODULE_CODE_GLOBALVAR">MODULE_CODE_GLOBALVAR Record</a></h4>
|
<h4><a name="MODULE_CODE_GLOBALVAR">MODULE_CODE_GLOBALVAR Record</a></h4>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<p><tt>[GLOBALVAR, pointer type, isconst, initid, linkage, alignment, section, visibility, threadlocal]</tt></p>
|
<p><tt>[GLOBALVAR, pointer type, isconst, initid, linkage, alignment, section, visibility, threadlocal, unnamed_addr]</tt></p>
|
||||||
|
|
||||||
<p>The <tt>GLOBALVAR</tt> record (code 7) marks the declaration or
|
<p>The <tt>GLOBALVAR</tt> record (code 7) marks the declaration or
|
||||||
definition of a global variable. The operand fields are:</p>
|
definition of a global variable. The operand fields are:</p>
|
||||||
@ -915,8 +915,16 @@ encoding of the visibility of this variable:
|
|||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li><i>threadlocal</i>: If present and non-zero, indicates that the variable
|
<li><i>threadlocal</i>: If present, an encoding of the thread local storage
|
||||||
is <tt>thread_local</tt></li>
|
mode of the variable:
|
||||||
|
<ul>
|
||||||
|
<li><tt>not thread local</tt>: code 0</li>
|
||||||
|
<li><tt>thread local; default TLS model</tt>: code 1</li>
|
||||||
|
<li><tt>localdynamic</tt>: code 2</li>
|
||||||
|
<li><tt>initialexec</tt>: code 3</li>
|
||||||
|
<li><tt>localexec</tt>: code 4</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li><i>unnamed_addr</i>: If present and non-zero, indicates that the variable
|
<li><i>unnamed_addr</i>: If present and non-zero, indicates that the variable
|
||||||
has <tt>unnamed_addr</tt></li>
|
has <tt>unnamed_addr</tt></li>
|
||||||
|
@ -838,9 +838,32 @@ define i32 @main() { <i>; i32()* </i>
|
|||||||
<p>Global variables define regions of memory allocated at compilation time
|
<p>Global variables define regions of memory allocated at compilation time
|
||||||
instead of run-time. Global variables may optionally be initialized, may
|
instead of run-time. Global variables may optionally be initialized, may
|
||||||
have an explicit section to be placed in, and may have an optional explicit
|
have an explicit section to be placed in, and may have an optional explicit
|
||||||
alignment specified. A variable may be defined as "thread_local", which
|
alignment specified.</p>
|
||||||
|
|
||||||
|
<p>A variable may be defined as <tt>thread_local</tt>, which
|
||||||
means that it will not be shared by threads (each thread will have a
|
means that it will not be shared by threads (each thread will have a
|
||||||
separated copy of the variable). A variable may be defined as a global
|
separated copy of the variable). Not all targets support thread-local
|
||||||
|
variables. Optionally, a TLS model may be specified:</p>
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt><b><tt>localdynamic</tt></b>:</dt>
|
||||||
|
<dd>For variables that are only used within the current shared library.</dd>
|
||||||
|
|
||||||
|
<dt><b><tt>initialexec</tt></b>:</dt>
|
||||||
|
<dd>For variables in modules that will not be loaded dynamically.</dd>
|
||||||
|
|
||||||
|
<dt><b><tt>localexec</tt></b>:</dt>
|
||||||
|
<dd>For variables defined in the executable and only used within it.</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<p>The models correspond to the ELF TLS models; see
|
||||||
|
<a href="http://people.redhat.com/drepper/tls.pdf">ELF
|
||||||
|
Handling For Thread-Local Storage</a> for more information on under which
|
||||||
|
circumstances the different models may be used. The target may choose a
|
||||||
|
different TLS model if the specified model is not supported, or if a better
|
||||||
|
choice of model can be made.</p>
|
||||||
|
|
||||||
|
<p>A variable may be defined as a global
|
||||||
"constant," which indicates that the contents of the variable
|
"constant," which indicates that the contents of the variable
|
||||||
will <b>never</b> be modified (enabling better optimization, allowing the
|
will <b>never</b> be modified (enabling better optimization, allowing the
|
||||||
global data to be placed in the read-only section of an executable, etc).
|
global data to be placed in the read-only section of an executable, etc).
|
||||||
@ -893,6 +916,13 @@ define i32 @main() { <i>; i32()* </i>
|
|||||||
@G = addrspace(5) constant float 1.0, section "foo", align 4
|
@G = addrspace(5) constant float 1.0, section "foo", align 4
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
<p>The following example defines a thread-local global with
|
||||||
|
the <tt>initialexec</tt> TLS model:</p>
|
||||||
|
|
||||||
|
<pre class="doc_code">
|
||||||
|
@G = thread_local(initialexec) global i32 0, align 4
|
||||||
|
</pre>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
@ -41,24 +41,47 @@ class GlobalVariable : public GlobalValue, public ilist_node<GlobalVariable> {
|
|||||||
void setParent(Module *parent);
|
void setParent(Module *parent);
|
||||||
|
|
||||||
bool isConstantGlobal : 1; // Is this a global constant?
|
bool isConstantGlobal : 1; // Is this a global constant?
|
||||||
bool isThreadLocalSymbol : 1; // Is this symbol "Thread Local"?
|
unsigned threadLocalMode : 3; // Is this symbol "Thread Local",
|
||||||
|
// if so, what is the desired model?
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// allocate space for exactly one operand
|
// allocate space for exactly one operand
|
||||||
void *operator new(size_t s) {
|
void *operator new(size_t s) {
|
||||||
return User::operator new(s, 1);
|
return User::operator new(s, 1);
|
||||||
}
|
}
|
||||||
/// GlobalVariable ctor - If a parent module is specified, the global is
|
|
||||||
/// automatically inserted into the end of the specified modules global list.
|
enum ThreadLocalMode {
|
||||||
|
NotThreadLocal = 0,
|
||||||
|
GeneralDynamicTLSModel,
|
||||||
|
LocalDynamicTLSModel,
|
||||||
|
InitialExecTLSModel,
|
||||||
|
LocalExecTLSModel
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Remove these once Clang is updated.
|
||||||
GlobalVariable(Type *Ty, bool isConstant, LinkageTypes Linkage,
|
GlobalVariable(Type *Ty, bool isConstant, LinkageTypes Linkage,
|
||||||
Constant *Initializer = 0, const Twine &Name = "",
|
Constant *Initializer = 0, const Twine &Name = "",
|
||||||
bool ThreadLocal = false, unsigned AddressSpace = 0);
|
bool ThreadLocal = false, unsigned AddressSpace = 0);
|
||||||
|
GlobalVariable(Module &M, Type *Ty, bool isConstant,
|
||||||
|
LinkageTypes Linkage, Constant *Initializer,
|
||||||
|
const Twine &Name = "",
|
||||||
|
GlobalVariable *InsertBefore = 0, bool ThreadLocal = false,
|
||||||
|
unsigned AddressSpace = 0);
|
||||||
|
|
||||||
|
/// GlobalVariable ctor - If a parent module is specified, the global is
|
||||||
|
/// automatically inserted into the end of the specified modules global list.
|
||||||
|
// TODO: Put default param values back when ctors above are removed.
|
||||||
|
GlobalVariable(Type *Ty, bool isConstant, LinkageTypes Linkage,
|
||||||
|
Constant *Initializer, const Twine &Name,
|
||||||
|
ThreadLocalMode, unsigned AddressSpace = 0);
|
||||||
/// GlobalVariable ctor - This creates a global and inserts it before the
|
/// GlobalVariable ctor - This creates a global and inserts it before the
|
||||||
/// specified other global.
|
/// specified other global.
|
||||||
|
// TODO: Put default param values back when ctors above are removed.
|
||||||
GlobalVariable(Module &M, Type *Ty, bool isConstant,
|
GlobalVariable(Module &M, Type *Ty, bool isConstant,
|
||||||
LinkageTypes Linkage, Constant *Initializer,
|
LinkageTypes Linkage, Constant *Initializer,
|
||||||
const Twine &Name,
|
const Twine &Name,
|
||||||
GlobalVariable *InsertBefore = 0, bool ThreadLocal = false,
|
GlobalVariable *InsertBefore,
|
||||||
|
ThreadLocalMode,
|
||||||
unsigned AddressSpace = 0);
|
unsigned AddressSpace = 0);
|
||||||
|
|
||||||
~GlobalVariable() {
|
~GlobalVariable() {
|
||||||
@ -135,8 +158,14 @@ public:
|
|||||||
void setConstant(bool Val) { isConstantGlobal = Val; }
|
void setConstant(bool Val) { isConstantGlobal = Val; }
|
||||||
|
|
||||||
/// If the value is "Thread Local", its value isn't shared by the threads.
|
/// If the value is "Thread Local", its value isn't shared by the threads.
|
||||||
bool isThreadLocal() const { return isThreadLocalSymbol; }
|
bool isThreadLocal() const { return threadLocalMode != NotThreadLocal; }
|
||||||
void setThreadLocal(bool Val) { isThreadLocalSymbol = Val; }
|
void setThreadLocal(bool Val) {
|
||||||
|
threadLocalMode = Val ? GeneralDynamicTLSModel : NotThreadLocal;
|
||||||
|
}
|
||||||
|
void setThreadLocalMode(ThreadLocalMode Val) { threadLocalMode = Val; }
|
||||||
|
ThreadLocalMode getThreadLocalMode() const {
|
||||||
|
return static_cast<ThreadLocalMode>(threadLocalMode);
|
||||||
|
}
|
||||||
|
|
||||||
/// copyAttributesFrom - copy all additional attributes (those not needed to
|
/// copyAttributesFrom - copy all additional attributes (those not needed to
|
||||||
/// create a GlobalVariable) from the GlobalVariable Src to this one.
|
/// create a GlobalVariable) from the GlobalVariable Src to this one.
|
||||||
|
@ -474,6 +474,9 @@ lltok::Kind LLLexer::LexIdentifier() {
|
|||||||
KEYWORD(extern_weak);
|
KEYWORD(extern_weak);
|
||||||
KEYWORD(external);
|
KEYWORD(external);
|
||||||
KEYWORD(thread_local);
|
KEYWORD(thread_local);
|
||||||
|
KEYWORD(localdynamic);
|
||||||
|
KEYWORD(initialexec);
|
||||||
|
KEYWORD(localexec);
|
||||||
KEYWORD(zeroinitializer);
|
KEYWORD(zeroinitializer);
|
||||||
KEYWORD(undef);
|
KEYWORD(undef);
|
||||||
KEYWORD(null);
|
KEYWORD(null);
|
||||||
|
@ -645,12 +645,13 @@ bool LLParser::ParseGlobal(const std::string &Name, LocTy NameLoc,
|
|||||||
unsigned Linkage, bool HasLinkage,
|
unsigned Linkage, bool HasLinkage,
|
||||||
unsigned Visibility) {
|
unsigned Visibility) {
|
||||||
unsigned AddrSpace;
|
unsigned AddrSpace;
|
||||||
bool ThreadLocal, IsConstant, UnnamedAddr;
|
bool IsConstant, UnnamedAddr;
|
||||||
|
GlobalVariable::ThreadLocalMode TLM;
|
||||||
LocTy UnnamedAddrLoc;
|
LocTy UnnamedAddrLoc;
|
||||||
LocTy TyLoc;
|
LocTy TyLoc;
|
||||||
|
|
||||||
Type *Ty = 0;
|
Type *Ty = 0;
|
||||||
if (ParseOptionalToken(lltok::kw_thread_local, ThreadLocal) ||
|
if (ParseOptionalThreadLocal(TLM) ||
|
||||||
ParseOptionalAddrSpace(AddrSpace) ||
|
ParseOptionalAddrSpace(AddrSpace) ||
|
||||||
ParseOptionalToken(lltok::kw_unnamed_addr, UnnamedAddr,
|
ParseOptionalToken(lltok::kw_unnamed_addr, UnnamedAddr,
|
||||||
&UnnamedAddrLoc) ||
|
&UnnamedAddrLoc) ||
|
||||||
@ -691,7 +692,8 @@ bool LLParser::ParseGlobal(const std::string &Name, LocTy NameLoc,
|
|||||||
|
|
||||||
if (GV == 0) {
|
if (GV == 0) {
|
||||||
GV = new GlobalVariable(*M, Ty, false, GlobalValue::ExternalLinkage, 0,
|
GV = new GlobalVariable(*M, Ty, false, GlobalValue::ExternalLinkage, 0,
|
||||||
Name, 0, false, AddrSpace);
|
Name, 0, GlobalVariable::NotThreadLocal,
|
||||||
|
AddrSpace);
|
||||||
} else {
|
} else {
|
||||||
if (GV->getType()->getElementType() != Ty)
|
if (GV->getType()->getElementType() != Ty)
|
||||||
return Error(TyLoc,
|
return Error(TyLoc,
|
||||||
@ -710,7 +712,7 @@ bool LLParser::ParseGlobal(const std::string &Name, LocTy NameLoc,
|
|||||||
GV->setConstant(IsConstant);
|
GV->setConstant(IsConstant);
|
||||||
GV->setLinkage((GlobalValue::LinkageTypes)Linkage);
|
GV->setLinkage((GlobalValue::LinkageTypes)Linkage);
|
||||||
GV->setVisibility((GlobalValue::VisibilityTypes)Visibility);
|
GV->setVisibility((GlobalValue::VisibilityTypes)Visibility);
|
||||||
GV->setThreadLocal(ThreadLocal);
|
GV->setThreadLocalMode(TLM);
|
||||||
GV->setUnnamedAddr(UnnamedAddr);
|
GV->setUnnamedAddr(UnnamedAddr);
|
||||||
|
|
||||||
// Parse attributes on the global.
|
// Parse attributes on the global.
|
||||||
@ -858,6 +860,46 @@ bool LLParser::ParseUInt32(unsigned &Val) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// ParseTLSModel
|
||||||
|
/// := 'localdynamic'
|
||||||
|
/// := 'initialexec'
|
||||||
|
/// := 'localexec'
|
||||||
|
bool LLParser::ParseTLSModel(GlobalVariable::ThreadLocalMode &TLM) {
|
||||||
|
switch (Lex.getKind()) {
|
||||||
|
default:
|
||||||
|
return TokError("expected localdynamic, initialexec or localexec");
|
||||||
|
case lltok::kw_localdynamic:
|
||||||
|
TLM = GlobalVariable::LocalDynamicTLSModel;
|
||||||
|
break;
|
||||||
|
case lltok::kw_initialexec:
|
||||||
|
TLM = GlobalVariable::InitialExecTLSModel;
|
||||||
|
break;
|
||||||
|
case lltok::kw_localexec:
|
||||||
|
TLM = GlobalVariable::LocalExecTLSModel;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Lex.Lex();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ParseOptionalThreadLocal
|
||||||
|
/// := /*empty*/
|
||||||
|
/// := 'thread_local'
|
||||||
|
/// := 'thread_local' '(' tlsmodel ')'
|
||||||
|
bool LLParser::ParseOptionalThreadLocal(GlobalVariable::ThreadLocalMode &TLM) {
|
||||||
|
TLM = GlobalVariable::NotThreadLocal;
|
||||||
|
if (!EatIfPresent(lltok::kw_thread_local))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
TLM = GlobalVariable::GeneralDynamicTLSModel;
|
||||||
|
if (Lex.getKind() == lltok::lparen) {
|
||||||
|
Lex.Lex();
|
||||||
|
return ParseTLSModel(TLM) ||
|
||||||
|
ParseToken(lltok::rparen, "expected ')' after thread local model");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// ParseOptionalAddrSpace
|
/// ParseOptionalAddrSpace
|
||||||
/// := /*empty*/
|
/// := /*empty*/
|
||||||
|
@ -171,6 +171,9 @@ namespace llvm {
|
|||||||
Loc = Lex.getLoc();
|
Loc = Lex.getLoc();
|
||||||
return ParseUInt32(Val);
|
return ParseUInt32(Val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ParseTLSModel(GlobalVariable::ThreadLocalMode &TLM);
|
||||||
|
bool ParseOptionalThreadLocal(GlobalVariable::ThreadLocalMode &TLM);
|
||||||
bool ParseOptionalAddrSpace(unsigned &AddrSpace);
|
bool ParseOptionalAddrSpace(unsigned &AddrSpace);
|
||||||
bool ParseOptionalAttrs(Attributes &Attrs, unsigned AttrKind);
|
bool ParseOptionalAttrs(Attributes &Attrs, unsigned AttrKind);
|
||||||
bool ParseOptionalLinkage(unsigned &Linkage, bool &HasLinkage);
|
bool ParseOptionalLinkage(unsigned &Linkage, bool &HasLinkage);
|
||||||
|
@ -44,6 +44,7 @@ namespace lltok {
|
|||||||
kw_unnamed_addr,
|
kw_unnamed_addr,
|
||||||
kw_extern_weak,
|
kw_extern_weak,
|
||||||
kw_external, kw_thread_local,
|
kw_external, kw_thread_local,
|
||||||
|
kw_localdynamic, kw_initialexec, kw_localexec,
|
||||||
kw_zeroinitializer,
|
kw_zeroinitializer,
|
||||||
kw_undef, kw_null,
|
kw_undef, kw_null,
|
||||||
kw_to,
|
kw_to,
|
||||||
|
@ -102,6 +102,17 @@ static GlobalValue::VisibilityTypes GetDecodedVisibility(unsigned Val) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GlobalVariable::ThreadLocalMode GetDecodedThreadLocalMode(unsigned Val) {
|
||||||
|
switch (Val) {
|
||||||
|
case 0: return GlobalVariable::NotThreadLocal;
|
||||||
|
default: // Map unknown non-zero value to general dynamic.
|
||||||
|
case 1: return GlobalVariable::GeneralDynamicTLSModel;
|
||||||
|
case 2: return GlobalVariable::LocalDynamicTLSModel;
|
||||||
|
case 3: return GlobalVariable::InitialExecTLSModel;
|
||||||
|
case 4: return GlobalVariable::LocalExecTLSModel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int GetDecodedCastOpcode(unsigned Val) {
|
static int GetDecodedCastOpcode(unsigned Val) {
|
||||||
switch (Val) {
|
switch (Val) {
|
||||||
default: return -1;
|
default: return -1;
|
||||||
@ -1544,9 +1555,10 @@ bool BitcodeReader::ParseModule(bool Resume) {
|
|||||||
GlobalValue::VisibilityTypes Visibility = GlobalValue::DefaultVisibility;
|
GlobalValue::VisibilityTypes Visibility = GlobalValue::DefaultVisibility;
|
||||||
if (Record.size() > 6)
|
if (Record.size() > 6)
|
||||||
Visibility = GetDecodedVisibility(Record[6]);
|
Visibility = GetDecodedVisibility(Record[6]);
|
||||||
bool isThreadLocal = false;
|
|
||||||
|
GlobalVariable::ThreadLocalMode TLM = GlobalVariable::NotThreadLocal;
|
||||||
if (Record.size() > 7)
|
if (Record.size() > 7)
|
||||||
isThreadLocal = Record[7];
|
TLM = GetDecodedThreadLocalMode(Record[7]);
|
||||||
|
|
||||||
bool UnnamedAddr = false;
|
bool UnnamedAddr = false;
|
||||||
if (Record.size() > 8)
|
if (Record.size() > 8)
|
||||||
@ -1554,12 +1566,11 @@ bool BitcodeReader::ParseModule(bool Resume) {
|
|||||||
|
|
||||||
GlobalVariable *NewGV =
|
GlobalVariable *NewGV =
|
||||||
new GlobalVariable(*TheModule, Ty, isConstant, Linkage, 0, "", 0,
|
new GlobalVariable(*TheModule, Ty, isConstant, Linkage, 0, "", 0,
|
||||||
isThreadLocal, AddressSpace);
|
TLM, AddressSpace);
|
||||||
NewGV->setAlignment(Alignment);
|
NewGV->setAlignment(Alignment);
|
||||||
if (!Section.empty())
|
if (!Section.empty())
|
||||||
NewGV->setSection(Section);
|
NewGV->setSection(Section);
|
||||||
NewGV->setVisibility(Visibility);
|
NewGV->setVisibility(Visibility);
|
||||||
NewGV->setThreadLocal(isThreadLocal);
|
|
||||||
NewGV->setUnnamedAddr(UnnamedAddr);
|
NewGV->setUnnamedAddr(UnnamedAddr);
|
||||||
|
|
||||||
ValueList.push_back(NewGV);
|
ValueList.push_back(NewGV);
|
||||||
|
@ -379,6 +379,17 @@ static unsigned getEncodedVisibility(const GlobalValue *GV) {
|
|||||||
llvm_unreachable("Invalid visibility");
|
llvm_unreachable("Invalid visibility");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned getEncodedThreadLocalMode(const GlobalVariable *GV) {
|
||||||
|
switch (GV->getThreadLocalMode()) {
|
||||||
|
case GlobalVariable::NotThreadLocal: return 0;
|
||||||
|
case GlobalVariable::GeneralDynamicTLSModel: return 1;
|
||||||
|
case GlobalVariable::LocalDynamicTLSModel: return 2;
|
||||||
|
case GlobalVariable::InitialExecTLSModel: return 3;
|
||||||
|
case GlobalVariable::LocalExecTLSModel: return 4;
|
||||||
|
}
|
||||||
|
llvm_unreachable("Invalid TLS model");
|
||||||
|
}
|
||||||
|
|
||||||
// Emit top-level description of module, including target triple, inline asm,
|
// Emit top-level description of module, including target triple, inline asm,
|
||||||
// descriptors for global variables, and function prototype info.
|
// descriptors for global variables, and function prototype info.
|
||||||
static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE,
|
static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE,
|
||||||
@ -487,7 +498,7 @@ static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE,
|
|||||||
GV->getVisibility() != GlobalValue::DefaultVisibility ||
|
GV->getVisibility() != GlobalValue::DefaultVisibility ||
|
||||||
GV->hasUnnamedAddr()) {
|
GV->hasUnnamedAddr()) {
|
||||||
Vals.push_back(getEncodedVisibility(GV));
|
Vals.push_back(getEncodedVisibility(GV));
|
||||||
Vals.push_back(GV->isThreadLocal());
|
Vals.push_back(getEncodedThreadLocalMode(GV));
|
||||||
Vals.push_back(GV->hasUnnamedAddr());
|
Vals.push_back(GV->hasUnnamedAddr());
|
||||||
} else {
|
} else {
|
||||||
AbbrevToUse = SimpleGVarAbbrev;
|
AbbrevToUse = SimpleGVarAbbrev;
|
||||||
|
@ -684,7 +684,7 @@ bool ModuleLinker::linkAppendingVarProto(GlobalVariable *DstGV,
|
|||||||
GlobalVariable *NG =
|
GlobalVariable *NG =
|
||||||
new GlobalVariable(*DstGV->getParent(), NewType, SrcGV->isConstant(),
|
new GlobalVariable(*DstGV->getParent(), NewType, SrcGV->isConstant(),
|
||||||
DstGV->getLinkage(), /*init*/0, /*name*/"", DstGV,
|
DstGV->getLinkage(), /*init*/0, /*name*/"", DstGV,
|
||||||
DstGV->isThreadLocal(),
|
DstGV->getThreadLocalMode(),
|
||||||
DstGV->getType()->getAddressSpace());
|
DstGV->getType()->getAddressSpace());
|
||||||
|
|
||||||
// Propagate alignment, visibility and section info.
|
// Propagate alignment, visibility and section info.
|
||||||
@ -759,7 +759,7 @@ bool ModuleLinker::linkGlobalProto(GlobalVariable *SGV) {
|
|||||||
new GlobalVariable(*DstM, TypeMap.get(SGV->getType()->getElementType()),
|
new GlobalVariable(*DstM, TypeMap.get(SGV->getType()->getElementType()),
|
||||||
SGV->isConstant(), SGV->getLinkage(), /*init*/0,
|
SGV->isConstant(), SGV->getLinkage(), /*init*/0,
|
||||||
SGV->getName(), /*insertbefore*/0,
|
SGV->getName(), /*insertbefore*/0,
|
||||||
SGV->isThreadLocal(),
|
SGV->getThreadLocalMode(),
|
||||||
SGV->getType()->getAddressSpace());
|
SGV->getType()->getAddressSpace());
|
||||||
// Propagate alignment, visibility and section info.
|
// Propagate alignment, visibility and section info.
|
||||||
copyGVAttributes(NewDGV, SGV);
|
copyGVAttributes(NewDGV, SGV);
|
||||||
|
@ -130,6 +130,7 @@ namespace {
|
|||||||
private:
|
private:
|
||||||
void printLinkageType(GlobalValue::LinkageTypes LT);
|
void printLinkageType(GlobalValue::LinkageTypes LT);
|
||||||
void printVisibilityType(GlobalValue::VisibilityTypes VisTypes);
|
void printVisibilityType(GlobalValue::VisibilityTypes VisTypes);
|
||||||
|
void printThreadLocalMode(GlobalVariable::ThreadLocalMode TLM);
|
||||||
void printCallingConv(CallingConv::ID cc);
|
void printCallingConv(CallingConv::ID cc);
|
||||||
void printEscapedString(const std::string& str);
|
void printEscapedString(const std::string& str);
|
||||||
void printCFP(const ConstantFP* CFP);
|
void printCFP(const ConstantFP* CFP);
|
||||||
@ -325,6 +326,26 @@ void CppWriter::printVisibilityType(GlobalValue::VisibilityTypes VisType) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CppWriter::printThreadLocalMode(GlobalVariable::ThreadLocalMode TLM) {
|
||||||
|
switch (TLM) {
|
||||||
|
case GlobalVariable::NotThreadLocal:
|
||||||
|
Out << "GlobalVariable::NotThreadLocal";
|
||||||
|
break;
|
||||||
|
case GlobalVariable::GeneralDynamicTLSModel:
|
||||||
|
Out << "GlobalVariable::GeneralDynamicTLSModel";
|
||||||
|
break;
|
||||||
|
case GlobalVariable::LocalDynamicTLSModel:
|
||||||
|
Out << "GlobalVariable::LocalDynamicTLSModel";
|
||||||
|
break;
|
||||||
|
case GlobalVariable::InitialExecTLSModel:
|
||||||
|
Out << "GlobalVariable::InitialExecTLSModel";
|
||||||
|
break;
|
||||||
|
case GlobalVariable::LocalExecTLSModel:
|
||||||
|
Out << "GlobalVariable::LocalExecTLSModel";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// printEscapedString - Print each character of the specified string, escaping
|
// printEscapedString - Print each character of the specified string, escaping
|
||||||
// it if it is not printable or if it is an escape char.
|
// it if it is not printable or if it is an escape char.
|
||||||
void CppWriter::printEscapedString(const std::string &Str) {
|
void CppWriter::printEscapedString(const std::string &Str) {
|
||||||
@ -996,7 +1017,9 @@ void CppWriter::printVariableHead(const GlobalVariable *GV) {
|
|||||||
}
|
}
|
||||||
if (GV->isThreadLocal()) {
|
if (GV->isThreadLocal()) {
|
||||||
printCppName(GV);
|
printCppName(GV);
|
||||||
Out << "->setThreadLocal(true);";
|
Out << "->setThreadLocalMode(";
|
||||||
|
printThreadLocalMode(GV->getThreadLocalMode());
|
||||||
|
Out << ");";
|
||||||
nl(Out);
|
nl(Out);
|
||||||
}
|
}
|
||||||
if (is_inline) {
|
if (is_inline) {
|
||||||
|
@ -77,6 +77,24 @@ CodeModel::Model TargetMachine::getCodeModel() const {
|
|||||||
return CodeGenInfo->getCodeModel();
|
return CodeGenInfo->getCodeModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the IR-specified TLS model for Var.
|
||||||
|
static TLSModel::Model getSelectedTLSModel(const GlobalVariable *Var) {
|
||||||
|
switch (Var->getThreadLocalMode()) {
|
||||||
|
case GlobalVariable::NotThreadLocal:
|
||||||
|
llvm_unreachable("getSelectedTLSModel for non-TLS variable");
|
||||||
|
break;
|
||||||
|
case GlobalVariable::GeneralDynamicTLSModel:
|
||||||
|
return TLSModel::GeneralDynamic;
|
||||||
|
case GlobalVariable::LocalDynamicTLSModel:
|
||||||
|
return TLSModel::LocalDynamic;
|
||||||
|
case GlobalVariable::InitialExecTLSModel:
|
||||||
|
return TLSModel::InitialExec;
|
||||||
|
case GlobalVariable::LocalExecTLSModel:
|
||||||
|
return TLSModel::LocalExec;
|
||||||
|
}
|
||||||
|
llvm_unreachable("invalid TLS model");
|
||||||
|
}
|
||||||
|
|
||||||
TLSModel::Model TargetMachine::getTLSModel(const GlobalValue *GV) const {
|
TLSModel::Model TargetMachine::getTLSModel(const GlobalValue *GV) const {
|
||||||
// If GV is an alias then use the aliasee for determining
|
// If GV is an alias then use the aliasee for determining
|
||||||
// thread-localness.
|
// thread-localness.
|
||||||
@ -86,22 +104,31 @@ TLSModel::Model TargetMachine::getTLSModel(const GlobalValue *GV) const {
|
|||||||
|
|
||||||
bool isLocal = Var->hasLocalLinkage();
|
bool isLocal = Var->hasLocalLinkage();
|
||||||
bool isDeclaration = Var->isDeclaration();
|
bool isDeclaration = Var->isDeclaration();
|
||||||
|
bool isPIC = getRelocationModel() == Reloc::PIC_;
|
||||||
|
bool isPIE = Options.PositionIndependentExecutable;
|
||||||
// FIXME: what should we do for protected and internal visibility?
|
// FIXME: what should we do for protected and internal visibility?
|
||||||
// For variables, is internal different from hidden?
|
// For variables, is internal different from hidden?
|
||||||
bool isHidden = Var->hasHiddenVisibility();
|
bool isHidden = Var->hasHiddenVisibility();
|
||||||
|
|
||||||
if (getRelocationModel() == Reloc::PIC_ &&
|
TLSModel::Model Model;
|
||||||
!Options.PositionIndependentExecutable) {
|
if (isPIC && !isPIE) {
|
||||||
if (isLocal || isHidden)
|
if (isLocal || isHidden)
|
||||||
return TLSModel::LocalDynamic;
|
Model = TLSModel::LocalDynamic;
|
||||||
else
|
else
|
||||||
return TLSModel::GeneralDynamic;
|
Model = TLSModel::GeneralDynamic;
|
||||||
} else {
|
} else {
|
||||||
if (!isDeclaration || isHidden)
|
if (!isDeclaration || isHidden)
|
||||||
return TLSModel::LocalExec;
|
Model = TLSModel::LocalExec;
|
||||||
else
|
else
|
||||||
return TLSModel::InitialExec;
|
Model = TLSModel::InitialExec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the user specified a more specific model, use that.
|
||||||
|
TLSModel::Model SelectedModel = getSelectedTLSModel(Var);
|
||||||
|
if (SelectedModel > Model)
|
||||||
|
return SelectedModel;
|
||||||
|
|
||||||
|
return Model;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// getOptLevel - Returns the optimization level: None, Less,
|
/// getOptLevel - Returns the optimization level: None, Less,
|
||||||
@ -135,4 +162,3 @@ void TargetMachine::setFunctionSections(bool V) {
|
|||||||
void TargetMachine::setDataSections(bool V) {
|
void TargetMachine::setDataSections(bool V) {
|
||||||
DataSections = V;
|
DataSections = V;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -517,7 +517,7 @@ static GlobalVariable *SRAGlobal(GlobalVariable *GV, const TargetData &TD) {
|
|||||||
GlobalVariable *NGV = new GlobalVariable(STy->getElementType(i), false,
|
GlobalVariable *NGV = new GlobalVariable(STy->getElementType(i), false,
|
||||||
GlobalVariable::InternalLinkage,
|
GlobalVariable::InternalLinkage,
|
||||||
In, GV->getName()+"."+Twine(i),
|
In, GV->getName()+"."+Twine(i),
|
||||||
GV->isThreadLocal(),
|
GV->getThreadLocalMode(),
|
||||||
GV->getType()->getAddressSpace());
|
GV->getType()->getAddressSpace());
|
||||||
Globals.insert(GV, NGV);
|
Globals.insert(GV, NGV);
|
||||||
NewGlobals.push_back(NGV);
|
NewGlobals.push_back(NGV);
|
||||||
@ -550,7 +550,7 @@ static GlobalVariable *SRAGlobal(GlobalVariable *GV, const TargetData &TD) {
|
|||||||
GlobalVariable *NGV = new GlobalVariable(STy->getElementType(), false,
|
GlobalVariable *NGV = new GlobalVariable(STy->getElementType(), false,
|
||||||
GlobalVariable::InternalLinkage,
|
GlobalVariable::InternalLinkage,
|
||||||
In, GV->getName()+"."+Twine(i),
|
In, GV->getName()+"."+Twine(i),
|
||||||
GV->isThreadLocal(),
|
GV->getThreadLocalMode(),
|
||||||
GV->getType()->getAddressSpace());
|
GV->getType()->getAddressSpace());
|
||||||
Globals.insert(GV, NGV);
|
Globals.insert(GV, NGV);
|
||||||
NewGlobals.push_back(NGV);
|
NewGlobals.push_back(NGV);
|
||||||
@ -866,7 +866,7 @@ static GlobalVariable *OptimizeGlobalAddressOfMalloc(GlobalVariable *GV,
|
|||||||
UndefValue::get(GlobalType),
|
UndefValue::get(GlobalType),
|
||||||
GV->getName()+".body",
|
GV->getName()+".body",
|
||||||
GV,
|
GV,
|
||||||
GV->isThreadLocal());
|
GV->getThreadLocalMode());
|
||||||
|
|
||||||
// If there are bitcast users of the malloc (which is typical, usually we have
|
// If there are bitcast users of the malloc (which is typical, usually we have
|
||||||
// a malloc + bitcast) then replace them with uses of the new global. Update
|
// a malloc + bitcast) then replace them with uses of the new global. Update
|
||||||
@ -899,7 +899,7 @@ static GlobalVariable *OptimizeGlobalAddressOfMalloc(GlobalVariable *GV,
|
|||||||
new GlobalVariable(Type::getInt1Ty(GV->getContext()), false,
|
new GlobalVariable(Type::getInt1Ty(GV->getContext()), false,
|
||||||
GlobalValue::InternalLinkage,
|
GlobalValue::InternalLinkage,
|
||||||
ConstantInt::getFalse(GV->getContext()),
|
ConstantInt::getFalse(GV->getContext()),
|
||||||
GV->getName()+".init", GV->isThreadLocal());
|
GV->getName()+".init", GV->getThreadLocalMode());
|
||||||
bool InitBoolUsed = false;
|
bool InitBoolUsed = false;
|
||||||
|
|
||||||
// Loop over all uses of GV, processing them in turn.
|
// Loop over all uses of GV, processing them in turn.
|
||||||
@ -1321,7 +1321,7 @@ static GlobalVariable *PerformHeapAllocSRoA(GlobalVariable *GV, CallInst *CI,
|
|||||||
PFieldTy, false, GlobalValue::InternalLinkage,
|
PFieldTy, false, GlobalValue::InternalLinkage,
|
||||||
Constant::getNullValue(PFieldTy),
|
Constant::getNullValue(PFieldTy),
|
||||||
GV->getName() + ".f" + Twine(FieldNo), GV,
|
GV->getName() + ".f" + Twine(FieldNo), GV,
|
||||||
GV->isThreadLocal());
|
GV->getThreadLocalMode());
|
||||||
FieldGlobals.push_back(NGV);
|
FieldGlobals.push_back(NGV);
|
||||||
|
|
||||||
unsigned TypeSize = TD->getTypeAllocSize(FieldTy);
|
unsigned TypeSize = TD->getTypeAllocSize(FieldTy);
|
||||||
@ -1647,7 +1647,7 @@ static bool TryToShrinkGlobalToBoolean(GlobalVariable *GV, Constant *OtherVal) {
|
|||||||
GlobalValue::InternalLinkage,
|
GlobalValue::InternalLinkage,
|
||||||
ConstantInt::getFalse(GV->getContext()),
|
ConstantInt::getFalse(GV->getContext()),
|
||||||
GV->getName()+".b",
|
GV->getName()+".b",
|
||||||
GV->isThreadLocal());
|
GV->getThreadLocalMode());
|
||||||
GV->getParent()->getGlobalList().insert(GV, NewGV);
|
GV->getParent()->getGlobalList().insert(GV, NewGV);
|
||||||
|
|
||||||
Constant *InitVal = GV->getInitializer();
|
Constant *InitVal = GV->getInitializer();
|
||||||
@ -2054,7 +2054,7 @@ static GlobalVariable *InstallGlobalCtors(GlobalVariable *GCL,
|
|||||||
// Create the new global and insert it next to the existing list.
|
// Create the new global and insert it next to the existing list.
|
||||||
GlobalVariable *NGV = new GlobalVariable(CA->getType(), GCL->isConstant(),
|
GlobalVariable *NGV = new GlobalVariable(CA->getType(), GCL->isConstant(),
|
||||||
GCL->getLinkage(), CA, "",
|
GCL->getLinkage(), CA, "",
|
||||||
GCL->isThreadLocal());
|
GCL->getThreadLocalMode());
|
||||||
GCL->getParent()->getGlobalList().insert(GCL, NGV);
|
GCL->getParent()->getGlobalList().insert(GCL, NGV);
|
||||||
NGV->takeName(GCL);
|
NGV->takeName(GCL);
|
||||||
|
|
||||||
|
@ -511,7 +511,7 @@ bool AddressSanitizer::insertGlobalRedzones(Module &M) {
|
|||||||
// Create a new global variable with enough space for a redzone.
|
// Create a new global variable with enough space for a redzone.
|
||||||
GlobalVariable *NewGlobal = new GlobalVariable(
|
GlobalVariable *NewGlobal = new GlobalVariable(
|
||||||
M, NewTy, G->isConstant(), G->getLinkage(),
|
M, NewTy, G->isConstant(), G->getLinkage(),
|
||||||
NewInitializer, "", G, G->isThreadLocal());
|
NewInitializer, "", G, G->getThreadLocalMode());
|
||||||
NewGlobal->copyAttributesFrom(G);
|
NewGlobal->copyAttributesFrom(G);
|
||||||
NewGlobal->setAlignment(RedzoneSize);
|
NewGlobal->setAlignment(RedzoneSize);
|
||||||
|
|
||||||
|
@ -448,7 +448,7 @@ bool GCOVProfiler::emitProfileArcs() {
|
|||||||
new GlobalVariable(*M, CounterTy, false,
|
new GlobalVariable(*M, CounterTy, false,
|
||||||
GlobalValue::InternalLinkage,
|
GlobalValue::InternalLinkage,
|
||||||
Constant::getNullValue(CounterTy),
|
Constant::getNullValue(CounterTy),
|
||||||
"__llvm_gcov_ctr", 0, false, 0);
|
"__llvm_gcov_ctr");
|
||||||
CountersBySP.push_back(std::make_pair(Counters, (MDNode*)SP));
|
CountersBySP.push_back(std::make_pair(Counters, (MDNode*)SP));
|
||||||
|
|
||||||
UniqueVector<BasicBlock *> ComplexEdgePreds;
|
UniqueVector<BasicBlock *> ComplexEdgePreds;
|
||||||
|
@ -53,7 +53,7 @@ Module *llvm::CloneModule(const Module *M, ValueToValueMapTy &VMap) {
|
|||||||
I->isConstant(), I->getLinkage(),
|
I->isConstant(), I->getLinkage(),
|
||||||
(Constant*) 0, I->getName(),
|
(Constant*) 0, I->getName(),
|
||||||
(GlobalVariable*) 0,
|
(GlobalVariable*) 0,
|
||||||
I->isThreadLocal(),
|
I->getThreadLocalMode(),
|
||||||
I->getType()->getAddressSpace());
|
I->getType()->getAddressSpace());
|
||||||
GV->copyAttributesFrom(I);
|
GV->copyAttributesFrom(I);
|
||||||
VMap[I] = GV;
|
VMap[I] = GV;
|
||||||
|
@ -1376,6 +1376,26 @@ static void PrintVisibility(GlobalValue::VisibilityTypes Vis,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void PrintThreadLocalModel(GlobalVariable::ThreadLocalMode TLM,
|
||||||
|
formatted_raw_ostream &Out) {
|
||||||
|
switch (TLM) {
|
||||||
|
case GlobalVariable::NotThreadLocal:
|
||||||
|
break;
|
||||||
|
case GlobalVariable::GeneralDynamicTLSModel:
|
||||||
|
Out << "thread_local ";
|
||||||
|
break;
|
||||||
|
case GlobalVariable::LocalDynamicTLSModel:
|
||||||
|
Out << "thread_local(localdynamic) ";
|
||||||
|
break;
|
||||||
|
case GlobalVariable::InitialExecTLSModel:
|
||||||
|
Out << "thread_local(initialexec) ";
|
||||||
|
break;
|
||||||
|
case GlobalVariable::LocalExecTLSModel:
|
||||||
|
Out << "thread_local(localexec) ";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AssemblyWriter::printGlobal(const GlobalVariable *GV) {
|
void AssemblyWriter::printGlobal(const GlobalVariable *GV) {
|
||||||
if (GV->isMaterializable())
|
if (GV->isMaterializable())
|
||||||
Out << "; Materializable\n";
|
Out << "; Materializable\n";
|
||||||
@ -1388,8 +1408,8 @@ void AssemblyWriter::printGlobal(const GlobalVariable *GV) {
|
|||||||
|
|
||||||
PrintLinkage(GV->getLinkage(), Out);
|
PrintLinkage(GV->getLinkage(), Out);
|
||||||
PrintVisibility(GV->getVisibility(), Out);
|
PrintVisibility(GV->getVisibility(), Out);
|
||||||
|
PrintThreadLocalModel(GV->getThreadLocalMode(), Out);
|
||||||
|
|
||||||
if (GV->isThreadLocal()) Out << "thread_local ";
|
|
||||||
if (unsigned AddressSpace = GV->getType()->getAddressSpace())
|
if (unsigned AddressSpace = GV->getType()->getAddressSpace())
|
||||||
Out << "addrspace(" << AddressSpace << ") ";
|
Out << "addrspace(" << AddressSpace << ") ";
|
||||||
if (GV->hasUnnamedAddr()) Out << "unnamed_addr ";
|
if (GV->hasUnnamedAddr()) Out << "unnamed_addr ";
|
||||||
|
@ -1210,7 +1210,7 @@ LLVMValueRef LLVMAddGlobalInAddressSpace(LLVMModuleRef M, LLVMTypeRef Ty,
|
|||||||
unsigned AddressSpace) {
|
unsigned AddressSpace) {
|
||||||
return wrap(new GlobalVariable(*unwrap(M), unwrap(Ty), false,
|
return wrap(new GlobalVariable(*unwrap(M), unwrap(Ty), false,
|
||||||
GlobalValue::ExternalLinkage, 0, Name, 0,
|
GlobalValue::ExternalLinkage, 0, Name, 0,
|
||||||
false, AddressSpace));
|
GlobalVariable::NotThreadLocal, AddressSpace));
|
||||||
}
|
}
|
||||||
|
|
||||||
LLVMValueRef LLVMGetNamedGlobal(LLVMModuleRef M, const char *Name) {
|
LLVMValueRef LLVMGetNamedGlobal(LLVMModuleRef M, const char *Name) {
|
||||||
|
@ -80,6 +80,7 @@ bool GlobalValue::isDeclaration() const {
|
|||||||
// GlobalVariable Implementation
|
// GlobalVariable Implementation
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// TODO: Remove once clang is updated.
|
||||||
GlobalVariable::GlobalVariable(Type *Ty, bool constant, LinkageTypes Link,
|
GlobalVariable::GlobalVariable(Type *Ty, bool constant, LinkageTypes Link,
|
||||||
Constant *InitVal, const Twine &Name,
|
Constant *InitVal, const Twine &Name,
|
||||||
bool ThreadLocal, unsigned AddressSpace)
|
bool ThreadLocal, unsigned AddressSpace)
|
||||||
@ -87,7 +88,51 @@ GlobalVariable::GlobalVariable(Type *Ty, bool constant, LinkageTypes Link,
|
|||||||
Value::GlobalVariableVal,
|
Value::GlobalVariableVal,
|
||||||
OperandTraits<GlobalVariable>::op_begin(this),
|
OperandTraits<GlobalVariable>::op_begin(this),
|
||||||
InitVal != 0, Link, Name),
|
InitVal != 0, Link, Name),
|
||||||
isConstantGlobal(constant), isThreadLocalSymbol(ThreadLocal) {
|
isConstantGlobal(constant),
|
||||||
|
threadLocalMode(ThreadLocal ? GeneralDynamicTLSModel : NotThreadLocal) {
|
||||||
|
if (InitVal) {
|
||||||
|
assert(InitVal->getType() == Ty &&
|
||||||
|
"Initializer should be the same type as the GlobalVariable!");
|
||||||
|
Op<0>() = InitVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
LeakDetector::addGarbageObject(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Remove once clang is updated.
|
||||||
|
GlobalVariable::GlobalVariable(Module &M, Type *Ty, bool constant,
|
||||||
|
LinkageTypes Link, Constant *InitVal,
|
||||||
|
const Twine &Name,
|
||||||
|
GlobalVariable *Before, bool ThreadLocal,
|
||||||
|
unsigned AddressSpace)
|
||||||
|
: GlobalValue(PointerType::get(Ty, AddressSpace),
|
||||||
|
Value::GlobalVariableVal,
|
||||||
|
OperandTraits<GlobalVariable>::op_begin(this),
|
||||||
|
InitVal != 0, Link, Name),
|
||||||
|
isConstantGlobal(constant),
|
||||||
|
threadLocalMode(ThreadLocal ? GeneralDynamicTLSModel : NotThreadLocal) {
|
||||||
|
if (InitVal) {
|
||||||
|
assert(InitVal->getType() == Ty &&
|
||||||
|
"Initializer should be the same type as the GlobalVariable!");
|
||||||
|
Op<0>() = InitVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
LeakDetector::addGarbageObject(this);
|
||||||
|
|
||||||
|
if (Before)
|
||||||
|
Before->getParent()->getGlobalList().insert(Before, this);
|
||||||
|
else
|
||||||
|
M.getGlobalList().push_back(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalVariable::GlobalVariable(Type *Ty, bool constant, LinkageTypes Link,
|
||||||
|
Constant *InitVal, const Twine &Name,
|
||||||
|
ThreadLocalMode TLMode, unsigned AddressSpace)
|
||||||
|
: GlobalValue(PointerType::get(Ty, AddressSpace),
|
||||||
|
Value::GlobalVariableVal,
|
||||||
|
OperandTraits<GlobalVariable>::op_begin(this),
|
||||||
|
InitVal != 0, Link, Name),
|
||||||
|
isConstantGlobal(constant), threadLocalMode(TLMode) {
|
||||||
if (InitVal) {
|
if (InitVal) {
|
||||||
assert(InitVal->getType() == Ty &&
|
assert(InitVal->getType() == Ty &&
|
||||||
"Initializer should be the same type as the GlobalVariable!");
|
"Initializer should be the same type as the GlobalVariable!");
|
||||||
@ -100,13 +145,13 @@ GlobalVariable::GlobalVariable(Type *Ty, bool constant, LinkageTypes Link,
|
|||||||
GlobalVariable::GlobalVariable(Module &M, Type *Ty, bool constant,
|
GlobalVariable::GlobalVariable(Module &M, Type *Ty, bool constant,
|
||||||
LinkageTypes Link, Constant *InitVal,
|
LinkageTypes Link, Constant *InitVal,
|
||||||
const Twine &Name,
|
const Twine &Name,
|
||||||
GlobalVariable *Before, bool ThreadLocal,
|
GlobalVariable *Before, ThreadLocalMode TLMode,
|
||||||
unsigned AddressSpace)
|
unsigned AddressSpace)
|
||||||
: GlobalValue(PointerType::get(Ty, AddressSpace),
|
: GlobalValue(PointerType::get(Ty, AddressSpace),
|
||||||
Value::GlobalVariableVal,
|
Value::GlobalVariableVal,
|
||||||
OperandTraits<GlobalVariable>::op_begin(this),
|
OperandTraits<GlobalVariable>::op_begin(this),
|
||||||
InitVal != 0, Link, Name),
|
InitVal != 0, Link, Name),
|
||||||
isConstantGlobal(constant), isThreadLocalSymbol(ThreadLocal) {
|
isConstantGlobal(constant), threadLocalMode(TLMode) {
|
||||||
if (InitVal) {
|
if (InitVal) {
|
||||||
assert(InitVal->getType() == Ty &&
|
assert(InitVal->getType() == Ty &&
|
||||||
"Initializer should be the same type as the GlobalVariable!");
|
"Initializer should be the same type as the GlobalVariable!");
|
||||||
|
@ -28,7 +28,7 @@ Value *IRBuilderBase::CreateGlobalString(StringRef Str, const Twine &Name) {
|
|||||||
Module &M = *BB->getParent()->getParent();
|
Module &M = *BB->getParent()->getParent();
|
||||||
GlobalVariable *GV = new GlobalVariable(M, StrConstant->getType(),
|
GlobalVariable *GV = new GlobalVariable(M, StrConstant->getType(),
|
||||||
true, GlobalValue::PrivateLinkage,
|
true, GlobalValue::PrivateLinkage,
|
||||||
StrConstant, "", 0, false);
|
StrConstant);
|
||||||
GV->setName(Name);
|
GV->setName(Name);
|
||||||
GV->setUnnamedAddr(true);
|
GV->setUnnamedAddr(true);
|
||||||
return GV;
|
return GV;
|
||||||
|
11
test/Assembler/tls-models.ll
Normal file
11
test/Assembler/tls-models.ll
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s
|
||||||
|
|
||||||
|
; CHECK: @a = thread_local global i32 0
|
||||||
|
; CHECK: @b = thread_local(localdynamic) global i32 0
|
||||||
|
; CHECK: @c = thread_local(initialexec) global i32 0
|
||||||
|
; CHECK: @d = thread_local(localexec) global i32 0
|
||||||
|
|
||||||
|
@a = thread_local global i32 0
|
||||||
|
@b = thread_local(localdynamic) global i32 0
|
||||||
|
@c = thread_local(initialexec) global i32 0
|
||||||
|
@d = thread_local(localexec) global i32 0
|
117
test/CodeGen/ARM/tls-models.ll
Normal file
117
test/CodeGen/ARM/tls-models.ll
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
; RUN: llc -march=arm -mtriple=arm-linux-gnueabi < %s | FileCheck -check-prefix=CHECK-NONPIC %s
|
||||||
|
; RUN: llc -march=arm -mtriple=arm-linux-gnueabi -relocation-model=pic < %s | FileCheck -check-prefix=CHECK-PIC %s
|
||||||
|
|
||||||
|
|
||||||
|
@external_gd = external thread_local global i32
|
||||||
|
@internal_gd = internal thread_local global i32 42
|
||||||
|
|
||||||
|
@external_ld = external thread_local(localdynamic) global i32
|
||||||
|
@internal_ld = internal thread_local(localdynamic) global i32 42
|
||||||
|
|
||||||
|
@external_ie = external thread_local(initialexec) global i32
|
||||||
|
@internal_ie = internal thread_local(initialexec) global i32 42
|
||||||
|
|
||||||
|
@external_le = external thread_local(localexec) global i32
|
||||||
|
@internal_le = internal thread_local(localexec) global i32 42
|
||||||
|
|
||||||
|
; ----- no model specified -----
|
||||||
|
|
||||||
|
define i32* @f1() {
|
||||||
|
entry:
|
||||||
|
ret i32* @external_gd
|
||||||
|
|
||||||
|
; Non-PIC code can use initial-exec, PIC code has to use general dynamic.
|
||||||
|
; CHECK-NONPIC: f1:
|
||||||
|
; CHECK-NONPIC: external_gd(gottpoff)
|
||||||
|
; CHECK-PIC: f1:
|
||||||
|
; CHECK-PIC: external_gd(tlsgd)
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32* @f2() {
|
||||||
|
entry:
|
||||||
|
ret i32* @internal_gd
|
||||||
|
|
||||||
|
; Non-PIC code can use local exec, PIC code can use local dynamic,
|
||||||
|
; but that is not implemented, so falls back to general dynamic.
|
||||||
|
; CHECK-NONPIC: f2:
|
||||||
|
; CHECK-NONPIC: internal_gd(tpoff)
|
||||||
|
; CHECK-PIC: f2:
|
||||||
|
; CHECK-PIC: internal_gd(tlsgd)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
; ----- localdynamic specified -----
|
||||||
|
|
||||||
|
define i32* @f3() {
|
||||||
|
entry:
|
||||||
|
ret i32* @external_ld
|
||||||
|
|
||||||
|
; Non-PIC code can use initial exec, PIC should use local dynamic,
|
||||||
|
; but that is not implemented, so falls back to general dynamic.
|
||||||
|
; CHECK-NONPIC: f3:
|
||||||
|
; CHECK-NONPIC: external_ld(gottpoff)
|
||||||
|
; CHECK-PIC: f3:
|
||||||
|
; CHECK-PIC: external_ld(tlsgd)
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32* @f4() {
|
||||||
|
entry:
|
||||||
|
ret i32* @internal_ld
|
||||||
|
|
||||||
|
; Non-PIC code can use local exec, PIC code can use local dynamic,
|
||||||
|
; but that is not implemented, so it falls back to general dynamic.
|
||||||
|
; CHECK-NONPIC: f4:
|
||||||
|
; CHECK-NONPIC: internal_ld(tpoff)
|
||||||
|
; CHECK-PIC: f4:
|
||||||
|
; CHECK-PIC: internal_ld(tlsgd)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
; ----- initialexec specified -----
|
||||||
|
|
||||||
|
define i32* @f5() {
|
||||||
|
entry:
|
||||||
|
ret i32* @external_ie
|
||||||
|
|
||||||
|
; Non-PIC and PIC code will use initial exec as specified.
|
||||||
|
; CHECK-NONPIC: f5:
|
||||||
|
; CHECK-NONPIC: external_ie(gottpoff)
|
||||||
|
; CHECK-PIC: f5:
|
||||||
|
; CHECK-PIC: external_ie(gottpoff)
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32* @f6() {
|
||||||
|
entry:
|
||||||
|
ret i32* @internal_ie
|
||||||
|
|
||||||
|
; Non-PIC code can use local exec, PIC code use initial exec as specified.
|
||||||
|
; CHECK-NONPIC: f6:
|
||||||
|
; CHECK-NONPIC: internal_ie(tpoff)
|
||||||
|
; CHECK-PIC: f6:
|
||||||
|
; CHECK-PIC: internal_ie(gottpoff)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
; ----- localexec specified -----
|
||||||
|
|
||||||
|
define i32* @f7() {
|
||||||
|
entry:
|
||||||
|
ret i32* @external_le
|
||||||
|
|
||||||
|
; Non-PIC and PIC code will use local exec as specified.
|
||||||
|
; CHECK-NONPIC: f7:
|
||||||
|
; CHECK-NONPIC: external_le(tpoff)
|
||||||
|
; CHECK-PIC: f7:
|
||||||
|
; CHECK-PIC: external_le(tpoff)
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32* @f8() {
|
||||||
|
entry:
|
||||||
|
ret i32* @internal_le
|
||||||
|
|
||||||
|
; Non-PIC and PIC code will use local exec as specified.
|
||||||
|
; CHECK-NONPIC: f8:
|
||||||
|
; CHECK-NONPIC: internal_le(tpoff)
|
||||||
|
; CHECK-PIC: f8:
|
||||||
|
; CHECK-PIC: internal_le(tpoff)
|
||||||
|
}
|
113
test/CodeGen/Mips/tls-models.ll
Normal file
113
test/CodeGen/Mips/tls-models.ll
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
; RUN: llc -march=mipsel < %s | FileCheck -check-prefix=CHECK-PIC %s
|
||||||
|
; RUN: llc -march=mipsel -relocation-model=static < %s | FileCheck -check-prefix=CHECK-NONPIC %s
|
||||||
|
|
||||||
|
@external_gd = external thread_local global i32
|
||||||
|
@internal_gd = internal thread_local global i32 42
|
||||||
|
|
||||||
|
@external_ld = external thread_local(localdynamic) global i32
|
||||||
|
@internal_ld = internal thread_local(localdynamic) global i32 42
|
||||||
|
|
||||||
|
@external_ie = external thread_local(initialexec) global i32
|
||||||
|
@internal_ie = internal thread_local(initialexec) global i32 42
|
||||||
|
|
||||||
|
@external_le = external thread_local(localexec) global i32
|
||||||
|
@internal_le = internal thread_local(localexec) global i32 42
|
||||||
|
|
||||||
|
; ----- no model specified -----
|
||||||
|
|
||||||
|
define i32* @f1() {
|
||||||
|
entry:
|
||||||
|
ret i32* @external_gd
|
||||||
|
|
||||||
|
; Non-PIC code can use initial-exec, PIC code has to use general dynamic.
|
||||||
|
; CHECK-NONPIC: f1:
|
||||||
|
; CHECK-NONPIC: %gottprel
|
||||||
|
; CHECK-PIC: f1:
|
||||||
|
; CHECK-PIC: %tlsgd
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32* @f2() {
|
||||||
|
entry:
|
||||||
|
ret i32* @internal_gd
|
||||||
|
|
||||||
|
; Non-PIC code can use local exec, PIC code can use local dynamic.
|
||||||
|
; CHECK-NONPIC: f2:
|
||||||
|
; CHECK-NONPIC: %tprel_hi
|
||||||
|
; CHECK-PIC: f2:
|
||||||
|
; CHECK-PIC: %tlsldm
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
; ----- localdynamic specified -----
|
||||||
|
|
||||||
|
define i32* @f3() {
|
||||||
|
entry:
|
||||||
|
ret i32* @external_ld
|
||||||
|
|
||||||
|
; Non-PIC code can use initial exec, PIC should use local dynamic.
|
||||||
|
; CHECK-NONPIC: f3:
|
||||||
|
; CHECK-NONPIC: %gottprel
|
||||||
|
; CHECK-PIC: f3:
|
||||||
|
; CHECK-PIC: %tlsldm
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32* @f4() {
|
||||||
|
entry:
|
||||||
|
ret i32* @internal_ld
|
||||||
|
|
||||||
|
; Non-PIC code can use local exec, PIC code can use local dynamic.
|
||||||
|
; CHECK-NONPIC: f4:
|
||||||
|
; CHECK-NONPIC: %tprel_hi
|
||||||
|
; CHECK-PIC: f4:
|
||||||
|
; CHECK-PIC: %tlsldm
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
; ----- initialexec specified -----
|
||||||
|
|
||||||
|
define i32* @f5() {
|
||||||
|
entry:
|
||||||
|
ret i32* @external_ie
|
||||||
|
|
||||||
|
; Non-PIC and PIC code will use initial exec as specified.
|
||||||
|
; CHECK-NONPIC: f5:
|
||||||
|
; CHECK-NONPIC: %gottprel
|
||||||
|
; CHECK-PIC: f5:
|
||||||
|
; CHECK-PIC: %gottprel
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32* @f6() {
|
||||||
|
entry:
|
||||||
|
ret i32* @internal_ie
|
||||||
|
|
||||||
|
; Non-PIC code can use local exec, PIC code use initial exec as specified.
|
||||||
|
; CHECK-NONPIC: f6:
|
||||||
|
; CHECK-NONPIC: %tprel_hi
|
||||||
|
; CHECK-PIC: f6:
|
||||||
|
; CHECK-PIC: %gottprel
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
; ----- localexec specified -----
|
||||||
|
|
||||||
|
define i32* @f7() {
|
||||||
|
entry:
|
||||||
|
ret i32* @external_le
|
||||||
|
|
||||||
|
; Non-PIC and PIC code will use local exec as specified.
|
||||||
|
; CHECK-NONPIC: f7:
|
||||||
|
; CHECK-NONPIC: %tprel_hi
|
||||||
|
; CHECK-PIC: f7:
|
||||||
|
; CHECK-PIC: %tprel_hi
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32* @f8() {
|
||||||
|
entry:
|
||||||
|
ret i32* @internal_le
|
||||||
|
|
||||||
|
; Non-PIC and PIC code will use local exec as specified.
|
||||||
|
; CHECK-NONPIC: f8:
|
||||||
|
; CHECK-NONPIC: %tprel_hi
|
||||||
|
; CHECK-PIC: f8:
|
||||||
|
; CHECK-PIC: %tprel_hi
|
||||||
|
}
|
166
test/CodeGen/X86/tls-models.ll
Normal file
166
test/CodeGen/X86/tls-models.ll
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
; RUN: llc < %s -march=x86-64 -mtriple=x86_64-linux-gnu | FileCheck -check-prefix=X64 %s
|
||||||
|
; RUN: llc < %s -march=x86-64 -mtriple=x86_64-linux-gnu -relocation-model=pic | FileCheck -check-prefix=X64_PIC %s
|
||||||
|
; RUN: llc < %s -march=x86 -mtriple=i386-linux-gnu | FileCheck -check-prefix=X32 %s
|
||||||
|
; RUN: llc < %s -march=x86 -mtriple=i386-linux-gnu -relocation-model=pic | FileCheck -check-prefix=X32_PIC %s
|
||||||
|
|
||||||
|
; Darwin always uses the same model.
|
||||||
|
; RUN: llc < %s -march=x86-64 -mtriple=x86_64-apple-darwin | FileCheck -check-prefix=DARWIN %s
|
||||||
|
|
||||||
|
@external_gd = external thread_local global i32
|
||||||
|
@internal_gd = internal thread_local global i32 42
|
||||||
|
|
||||||
|
@external_ld = external thread_local(localdynamic) global i32
|
||||||
|
@internal_ld = internal thread_local(localdynamic) global i32 42
|
||||||
|
|
||||||
|
@external_ie = external thread_local(initialexec) global i32
|
||||||
|
@internal_ie = internal thread_local(initialexec) global i32 42
|
||||||
|
|
||||||
|
@external_le = external thread_local(localexec) global i32
|
||||||
|
@internal_le = internal thread_local(localexec) global i32 42
|
||||||
|
|
||||||
|
; ----- no model specified -----
|
||||||
|
|
||||||
|
define i32* @f1() {
|
||||||
|
entry:
|
||||||
|
ret i32* @external_gd
|
||||||
|
|
||||||
|
; Non-PIC code can use initial-exec, PIC code has to use general dynamic.
|
||||||
|
; X64: f1:
|
||||||
|
; X64: external_gd@GOTTPOFF
|
||||||
|
; X32: f1:
|
||||||
|
; X32: external_gd@INDNTPOFF
|
||||||
|
; X64_PIC: f1:
|
||||||
|
; X64_PIC: external_gd@TLSGD
|
||||||
|
; X32_PIC: f1:
|
||||||
|
; X32_PIC: external_gd@TLSGD
|
||||||
|
; DARWIN: f1:
|
||||||
|
; DARWIN: _external_gd@TLVP
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32* @f2() {
|
||||||
|
entry:
|
||||||
|
ret i32* @internal_gd
|
||||||
|
|
||||||
|
; Non-PIC code can use local exec, PIC code can use local dynamic.
|
||||||
|
; X64: f2:
|
||||||
|
; X64: internal_gd@TPOFF
|
||||||
|
; X32: f2:
|
||||||
|
; X32: internal_gd@NTPOFF
|
||||||
|
; X64_PIC: f2:
|
||||||
|
; X64_PIC: internal_gd@TLSLD
|
||||||
|
; X32_PIC: f2:
|
||||||
|
; X32_PIC: internal_gd@TLSLDM
|
||||||
|
; DARWIN: f2:
|
||||||
|
; DARWIN: _internal_gd@TLVP
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
; ----- localdynamic specified -----
|
||||||
|
|
||||||
|
define i32* @f3() {
|
||||||
|
entry:
|
||||||
|
ret i32* @external_ld
|
||||||
|
|
||||||
|
; Non-PIC code can use initial exec, PIC code use local dynamic as specified.
|
||||||
|
; X64: f3:
|
||||||
|
; X64: external_ld@GOTTPOFF
|
||||||
|
; X32: f3:
|
||||||
|
; X32: external_ld@INDNTPOFF
|
||||||
|
; X64_PIC: f3:
|
||||||
|
; X64_PIC: external_ld@TLSLD
|
||||||
|
; X32_PIC: f3:
|
||||||
|
; X32_PIC: external_ld@TLSLDM
|
||||||
|
; DARWIN: f3:
|
||||||
|
; DARWIN: _external_ld@TLVP
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32* @f4() {
|
||||||
|
entry:
|
||||||
|
ret i32* @internal_ld
|
||||||
|
|
||||||
|
; Non-PIC code can use local exec, PIC code can use local dynamic.
|
||||||
|
; X64: f4:
|
||||||
|
; X64: internal_ld@TPOFF
|
||||||
|
; X32: f4:
|
||||||
|
; X32: internal_ld@NTPOFF
|
||||||
|
; X64_PIC: f4:
|
||||||
|
; X64_PIC: internal_ld@TLSLD
|
||||||
|
; X32_PIC: f4:
|
||||||
|
; X32_PIC: internal_ld@TLSLDM
|
||||||
|
; DARWIN: f4:
|
||||||
|
; DARWIN: _internal_ld@TLVP
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
; ----- initialexec specified -----
|
||||||
|
|
||||||
|
define i32* @f5() {
|
||||||
|
entry:
|
||||||
|
ret i32* @external_ie
|
||||||
|
|
||||||
|
; Non-PIC and PIC code will use initial exec as specified.
|
||||||
|
; X64: f5:
|
||||||
|
; X64: external_ie@GOTTPOFF
|
||||||
|
; X32: f5:
|
||||||
|
; X32: external_ie@INDNTPOFF
|
||||||
|
; X64_PIC: f5:
|
||||||
|
; X64_PIC: external_ie@GOTTPOFF
|
||||||
|
; X32_PIC: f5:
|
||||||
|
; X32_PIC: external_ie@GOTNTPOFF
|
||||||
|
; DARWIN: f5:
|
||||||
|
; DARWIN: _external_ie@TLVP
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32* @f6() {
|
||||||
|
entry:
|
||||||
|
ret i32* @internal_ie
|
||||||
|
|
||||||
|
; Non-PIC code can use local exec, PIC code use initial exec as specified.
|
||||||
|
; X64: f6:
|
||||||
|
; X64: internal_ie@TPOFF
|
||||||
|
; X32: f6:
|
||||||
|
; X32: internal_ie@NTPOFF
|
||||||
|
; X64_PIC: f6:
|
||||||
|
; X64_PIC: internal_ie@GOTTPOFF
|
||||||
|
; X32_PIC: f6:
|
||||||
|
; X32_PIC: internal_ie@GOTNTPOFF
|
||||||
|
; DARWIN: f6:
|
||||||
|
; DARWIN: _internal_ie@TLVP
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
; ----- localexec specified -----
|
||||||
|
|
||||||
|
define i32* @f7() {
|
||||||
|
entry:
|
||||||
|
ret i32* @external_le
|
||||||
|
|
||||||
|
; Non-PIC and PIC code will use local exec as specified.
|
||||||
|
; X64: f7:
|
||||||
|
; X64: external_le@TPOFF
|
||||||
|
; X32: f7:
|
||||||
|
; X32: external_le@NTPOFF
|
||||||
|
; X64_PIC: f7:
|
||||||
|
; X64_PIC: external_le@TPOFF
|
||||||
|
; X32_PIC: f7:
|
||||||
|
; X32_PIC: external_le@NTPOFF
|
||||||
|
; DARWIN: f7:
|
||||||
|
; DARWIN: _external_le@TLVP
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32* @f8() {
|
||||||
|
entry:
|
||||||
|
ret i32* @internal_le
|
||||||
|
|
||||||
|
; Non-PIC and PIC code will use local exec as specified.
|
||||||
|
; X64: f8:
|
||||||
|
; X64: internal_le@TPOFF
|
||||||
|
; X32: f8:
|
||||||
|
; X32: internal_le@NTPOFF
|
||||||
|
; X64_PIC: f8:
|
||||||
|
; X64_PIC: internal_le@TPOFF
|
||||||
|
; X32_PIC: f8:
|
||||||
|
; X32_PIC: internal_le@NTPOFF
|
||||||
|
; DARWIN: f8:
|
||||||
|
; DARWIN: _internal_le@TLVP
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user