summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/LangRef.rst51
-rw-r--r--include/llvm/IR/GlobalValue.h33
-rw-r--r--include/llvm/IR/GlobalVariable.h21
-rw-r--r--lib/AsmParser/LLParser.cpp48
-rw-r--r--lib/AsmParser/LLParser.h6
-rw-r--r--lib/Bitcode/Reader/BitcodeReader.cpp2
-rw-r--r--lib/Bitcode/Writer/BitcodeWriter.cpp4
-rw-r--r--lib/CodeGen/SelectionDAG/SelectionDAG.cpp9
-rw-r--r--lib/IR/AsmWriter.cpp1
-rw-r--r--lib/IR/Globals.cpp6
-rw-r--r--lib/Target/AArch64/AArch64FastISel.cpp12
-rw-r--r--lib/Target/PowerPC/PPCFastISel.cpp8
-rw-r--r--lib/Target/TargetMachine.cpp15
-rw-r--r--lib/Target/X86/X86FastISel.cpp13
-rw-r--r--test/CodeGen/Mips/tls-alias.ll2
-rw-r--r--test/CodeGen/X86/2008-03-12-ThreadLocalAlias.ll2
-rw-r--r--test/CodeGen/X86/aliases.ll18
-rw-r--r--test/Feature/alias2.ll3
18 files changed, 143 insertions, 111 deletions
diff --git a/docs/LangRef.rst b/docs/LangRef.rst
index fa40363a75..650012e7f9 100644
--- a/docs/LangRef.rst
+++ b/docs/LangRef.rst
@@ -464,6 +464,34 @@ DLL storage class:
exists for defining a dll interface, the compiler, assembler and linker know
it is externally referenced and must refrain from deleting the symbol.
+.. _tls_model:
+
+Thread Local Storage Models
+---------------------------
+
+A variable may be defined as ``thread_local``, which means that it will
+not be shared by threads (each thread will have a separated copy of the
+variable). Not all targets support thread-local variables. Optionally, a
+TLS model may be specified:
+
+``localdynamic``
+ For variables that are only used within the current shared library.
+``initialexec``
+ For variables in modules that will not be loaded dynamically.
+``localexec``
+ For variables defined in the executable and only used within it.
+
+If no explicit model is given, the "general dynamic" model is used.
+
+The models correspond to the ELF TLS models; see `ELF Handling For
+Thread-Local Storage <http://people.redhat.com/drepper/tls.pdf>`_ 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.
+
+A model can also be specified in a alias, but then it only governs how
+the alias is accessed. It will not have any effect in the aliasee.
+
.. _namedtypes:
Structure Types
@@ -497,24 +525,6 @@ to be placed in, and may have an optional explicit alignment specified.
Global variables in other translation units can also be declared, in which
case they don't have an initializer.
-A variable may be defined as ``thread_local``, which means that it will
-not be shared by threads (each thread will have a separated copy of the
-variable). Not all targets support thread-local variables. Optionally, a
-TLS model may be specified:
-
-``localdynamic``
- For variables that are only used within the current shared library.
-``initialexec``
- For variables in modules that will not be loaded dynamically.
-``localexec``
- For variables defined in the executable and only used within it.
-
-The models correspond to the ELF TLS models; see `ELF Handling For
-Thread-Local Storage <http://people.redhat.com/drepper/tls.pdf>`_ 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.
-
A variable may be defined as a global ``constant``, which indicates that
the contents of the variable will **never** be modified (enabling better
optimization, allowing the global data to be placed in the read-only
@@ -572,6 +582,9 @@ iteration.
Globals can also have a :ref:`DLL storage class <dllstorageclass>`.
+Variables and aliasaes can have a
+:ref:`Thread Local Storage Model <tls_model>`.
+
Syntax::
[@<GlobalVarName> =] [Linkage] [Visibility] [DLLStorageClass] [ThreadLocal]
@@ -674,7 +687,7 @@ Aliases may have an optional :ref:`linkage type <linkage>`, an optional
Syntax::
- @<Name> = [Visibility] [DLLStorageClass] alias [Linkage] <AliaseeTy> @<Aliasee>
+ @<Name> = [Visibility] [DLLStorageClass] [ThreadLocal] alias [Linkage] <AliaseeTy> @<Aliasee>
The linkage must be one of ``private``, ``internal``, ``linkonce``, ``weak``,
``linkonce_odr``, ``weak_odr``, ``external``. Note that some system linkers
diff --git a/include/llvm/IR/GlobalValue.h b/include/llvm/IR/GlobalValue.h
index 10df372945..04c97a01d6 100644
--- a/include/llvm/IR/GlobalValue.h
+++ b/include/llvm/IR/GlobalValue.h
@@ -63,7 +63,8 @@ protected:
LinkageTypes Linkage, const Twine &Name)
: Constant(Ty, VTy, Ops, NumOps), Linkage(Linkage),
Visibility(DefaultVisibility), UnnamedAddr(0),
- DllStorageClass(DefaultStorageClass), Parent(nullptr) {
+ DllStorageClass(DefaultStorageClass),
+ ThreadLocal(NotThreadLocal), Parent(nullptr) {
setName(Name);
}
@@ -74,21 +75,32 @@ protected:
unsigned UnnamedAddr : 1; // This value's address is not significant
unsigned DllStorageClass : 2; // DLL storage class
+ unsigned ThreadLocal : 3; // Is this symbol "Thread Local", if so, what is
+ // the desired model?
+
private:
// Give subclasses access to what otherwise would be wasted padding.
- // (22 + 2 + 1 + 2 + 5) == 32.
- unsigned SubClassData : 22;
+ // (19 + 3 + 2 + 1 + 2 + 5) == 32.
+ unsigned SubClassData : 19;
protected:
unsigned getGlobalValueSubClassData() const {
return SubClassData;
}
void setGlobalValueSubClassData(unsigned V) {
- assert(V < (1 << 22) && "It will not fit");
+ assert(V < (1 << 19) && "It will not fit");
SubClassData = V;
}
Module *Parent; // The containing module.
public:
+ enum ThreadLocalMode {
+ NotThreadLocal = 0,
+ GeneralDynamicTLSModel,
+ LocalDynamicTLSModel,
+ InitialExecTLSModel,
+ LocalExecTLSModel
+ };
+
~GlobalValue() {
removeDeadConstantUsers(); // remove any dead constants using this.
}
@@ -110,6 +122,19 @@ public:
Visibility = V;
}
+ /// If the value is "Thread Local", its value isn't shared by the threads.
+ bool isThreadLocal() const { return getThreadLocalMode() != NotThreadLocal; }
+ void setThreadLocal(bool Val) {
+ setThreadLocalMode(Val ? GeneralDynamicTLSModel : NotThreadLocal);
+ }
+ void setThreadLocalMode(ThreadLocalMode Val) {
+ assert(Val == NotThreadLocal || getValueID() != Value::FunctionVal);
+ ThreadLocal = Val;
+ }
+ ThreadLocalMode getThreadLocalMode() const {
+ return static_cast<ThreadLocalMode>(ThreadLocal);
+ }
+
DLLStorageClassTypes getDLLStorageClass() const {
return DLLStorageClassTypes(DllStorageClass);
}
diff --git a/include/llvm/IR/GlobalVariable.h b/include/llvm/IR/GlobalVariable.h
index 8cd4332b1a..4189ccb90a 100644
--- a/include/llvm/IR/GlobalVariable.h
+++ b/include/llvm/IR/GlobalVariable.h
@@ -41,9 +41,6 @@ class GlobalVariable : public GlobalObject, public ilist_node<GlobalVariable> {
void setParent(Module *parent);
bool isConstantGlobal : 1; // Is this a global constant?
- unsigned threadLocalMode : 3; // Is this symbol "Thread Local",
- // if so, what is the desired
- // model?
bool isExternallyInitializedConstant : 1; // Is this a global whose value
// can change from its initial
// value before global
@@ -55,14 +52,6 @@ public:
return User::operator new(s, 1);
}
- enum ThreadLocalMode {
- NotThreadLocal = 0,
- GeneralDynamicTLSModel,
- LocalDynamicTLSModel,
- InitialExecTLSModel,
- LocalExecTLSModel
- };
-
/// GlobalVariable ctor - If a parent module is specified, the global is
/// automatically inserted into the end of the specified modules global list.
GlobalVariable(Type *Ty, bool isConstant, LinkageTypes Linkage,
@@ -155,16 +144,6 @@ public:
bool isConstant() const { return isConstantGlobal; }
void setConstant(bool Val) { isConstantGlobal = Val; }
- /// If the value is "Thread Local", its value isn't shared by the threads.
- bool isThreadLocal() const { return threadLocalMode != NotThreadLocal; }
- void setThreadLocal(bool Val) {
- threadLocalMode = Val ? GeneralDynamicTLSModel : NotThreadLocal;
- }
- void setThreadLocalMode(ThreadLocalMode Val) { threadLocalMode = Val; }
- ThreadLocalMode getThreadLocalMode() const {
- return static_cast<ThreadLocalMode>(threadLocalMode);
- }
-
bool isExternallyInitialized() const {
return isExternallyInitializedConstant;
}
diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp
index 3282e8a23b..f0efa9414d 100644
--- a/lib/AsmParser/LLParser.cpp
+++ b/lib/AsmParser/LLParser.cpp
@@ -259,10 +259,13 @@ bool LLParser::ParseTopLevelEntities() {
case lltok::kw_extern_weak: // OptionalLinkage
case lltok::kw_external: { // OptionalLinkage
unsigned Linkage, Visibility, DLLStorageClass;
+ GlobalVariable::ThreadLocalMode TLM;
if (ParseOptionalLinkage(Linkage) ||
ParseOptionalVisibility(Visibility) ||
ParseOptionalDLLStorageClass(DLLStorageClass) ||
- ParseGlobal("", SMLoc(), Linkage, true, Visibility, DLLStorageClass))
+ ParseOptionalThreadLocal(TLM) ||
+ ParseGlobal("", SMLoc(), Linkage, true, Visibility, DLLStorageClass,
+ TLM))
return true;
break;
}
@@ -270,18 +273,28 @@ bool LLParser::ParseTopLevelEntities() {
case lltok::kw_hidden: // OptionalVisibility
case lltok::kw_protected: { // OptionalVisibility
unsigned Visibility, DLLStorageClass;
+ GlobalVariable::ThreadLocalMode TLM;
if (ParseOptionalVisibility(Visibility) ||
ParseOptionalDLLStorageClass(DLLStorageClass) ||
- ParseGlobal("", SMLoc(), 0, false, Visibility, DLLStorageClass))
+ ParseOptionalThreadLocal(TLM) ||
+ ParseGlobal("", SMLoc(), 0, false, Visibility, DLLStorageClass, TLM))
+ return true;
+ break;
+ }
+
+ case lltok::kw_thread_local: { // OptionalThreadLocal
+ GlobalVariable::ThreadLocalMode TLM;
+ if (ParseOptionalThreadLocal(TLM) ||
+ ParseGlobal("", SMLoc(), 0, false, 0, 0, TLM))
return true;
break;
}
- case lltok::kw_thread_local: // OptionalThreadLocal
case lltok::kw_addrspace: // OptionalAddrSpace
case lltok::kw_constant: // GlobalType
case lltok::kw_global: // GlobalType
- if (ParseGlobal("", SMLoc(), 0, false, 0, 0)) return true;
+ if (ParseGlobal("", SMLoc(), 0, false, 0, 0, GlobalValue::NotThreadLocal))
+ return true;
break;
case lltok::kw_attributes: if (ParseUnnamedAttrGrp()) return true; break;
@@ -470,15 +483,17 @@ bool LLParser::ParseUnnamedGlobal() {
bool HasLinkage;
unsigned Linkage, Visibility, DLLStorageClass;
+ GlobalVariable::ThreadLocalMode TLM;
if (ParseOptionalLinkage(Linkage, HasLinkage) ||
ParseOptionalVisibility(Visibility) ||
- ParseOptionalDLLStorageClass(DLLStorageClass))
+ ParseOptionalDLLStorageClass(DLLStorageClass) ||
+ ParseOptionalThreadLocal(TLM))
return true;
if (HasLinkage || Lex.getKind() != lltok::kw_alias)
return ParseGlobal(Name, NameLoc, Linkage, HasLinkage, Visibility,
- DLLStorageClass);
- return ParseAlias(Name, NameLoc, Visibility, DLLStorageClass);
+ DLLStorageClass, TLM);
+ return ParseAlias(Name, NameLoc, Visibility, DLLStorageClass, TLM);
}
/// ParseNamedGlobal:
@@ -493,16 +508,18 @@ bool LLParser::ParseNamedGlobal() {
bool HasLinkage;
unsigned Linkage, Visibility, DLLStorageClass;
+ GlobalVariable::ThreadLocalMode TLM;
if (ParseToken(lltok::equal, "expected '=' in global variable") ||
ParseOptionalLinkage(Linkage, HasLinkage) ||
ParseOptionalVisibility(Visibility) ||
- ParseOptionalDLLStorageClass(DLLStorageClass))
+ ParseOptionalDLLStorageClass(DLLStorageClass) ||
+ ParseOptionalThreadLocal(TLM))
return true;
if (HasLinkage || Lex.getKind() != lltok::kw_alias)
return ParseGlobal(Name, NameLoc, Linkage, HasLinkage, Visibility,
- DLLStorageClass);
- return ParseAlias(Name, NameLoc, Visibility, DLLStorageClass);
+ DLLStorageClass, TLM);
+ return ParseAlias(Name, NameLoc, Visibility, DLLStorageClass, TLM);
}
// MDString:
@@ -639,7 +656,8 @@ static bool isValidVisibilityForLinkage(unsigned V, unsigned L) {
/// Everything through DLL storage class has already been parsed.
///
bool LLParser::ParseAlias(const std::string &Name, LocTy NameLoc,
- unsigned Visibility, unsigned DLLStorageClass) {
+ unsigned Visibility, unsigned DLLStorageClass,
+ GlobalVariable::ThreadLocalMode TLM) {
assert(Lex.getKind() == lltok::kw_alias);
Lex.Lex();
LocTy LinkageLoc = Lex.getLoc();
@@ -699,6 +717,7 @@ bool LLParser::ParseAlias(const std::string &Name, LocTy NameLoc,
std::unique_ptr<GlobalAlias> GA(
GlobalAlias::create(Ty, AddrSpace, (GlobalValue::LinkageTypes)Linkage,
Name, Aliasee, /*Parent*/ nullptr));
+ GA->setThreadLocalMode(TLM);
GA->setVisibility((GlobalValue::VisibilityTypes)Visibility);
GA->setDLLStorageClass((GlobalValue::DLLStorageClassTypes)DLLStorageClass);
@@ -753,21 +772,20 @@ bool LLParser::ParseAlias(const std::string &Name, LocTy NameLoc,
///
bool LLParser::ParseGlobal(const std::string &Name, LocTy NameLoc,
unsigned Linkage, bool HasLinkage,
- unsigned Visibility, unsigned DLLStorageClass) {
+ unsigned Visibility, unsigned DLLStorageClass,
+ GlobalVariable::ThreadLocalMode TLM) {
if (!isValidVisibilityForLinkage(Visibility, Linkage))
return Error(NameLoc,
"symbol with local linkage must have default visibility");
unsigned AddrSpace;
bool IsConstant, UnnamedAddr, IsExternallyInitialized;
- GlobalVariable::ThreadLocalMode TLM;
LocTy UnnamedAddrLoc;
LocTy IsExternallyInitializedLoc;
LocTy TyLoc;
Type *Ty = nullptr;
- if (ParseOptionalThreadLocal(TLM) ||
- ParseOptionalAddrSpace(AddrSpace) ||
+ if (ParseOptionalAddrSpace(AddrSpace) ||
ParseOptionalToken(lltok::kw_unnamed_addr, UnnamedAddr,
&UnnamedAddrLoc) ||
ParseOptionalToken(lltok::kw_externally_initialized,
diff --git a/lib/AsmParser/LLParser.h b/lib/AsmParser/LLParser.h
index e2bf46290b..1257b0aadc 100644
--- a/lib/AsmParser/LLParser.h
+++ b/lib/AsmParser/LLParser.h
@@ -239,9 +239,11 @@ namespace llvm {
bool ParseNamedGlobal();
bool ParseGlobal(const std::string &Name, LocTy Loc, unsigned Linkage,
bool HasLinkage, unsigned Visibility,
- unsigned DLLStorageClass);
+ unsigned DLLStorageClass,
+ GlobalVariable::ThreadLocalMode TLM);
bool ParseAlias(const std::string &Name, LocTy Loc, unsigned Visibility,
- unsigned DLLStorageClass);
+ unsigned DLLStorageClass,
+ GlobalVariable::ThreadLocalMode TLM);
bool ParseStandaloneMetadata();
bool ParseNamedMetadata();
bool ParseMDString(MDString *&Result);
diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp
index 4170f98567..a8fd8fab50 100644
--- a/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -2017,6 +2017,8 @@ error_code BitcodeReader::ParseModule(bool Resume) {
NewGA->setDLLStorageClass(GetDecodedDLLStorageClass(Record[4]));
else
UpgradeDLLImportExportLinkage(NewGA, Record[2]);
+ if (Record.size() > 5)
+ NewGA->setThreadLocalMode(GetDecodedThreadLocalMode(Record[5]));
ValueList.push_back(NewGA);
AliasInits.push_back(std::make_pair(NewGA, Record[1]));
break;
diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp
index cc73b842e3..dddcbc6f7e 100644
--- a/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -511,7 +511,7 @@ static unsigned getEncodedDLLStorageClass(const GlobalValue &GV) {
llvm_unreachable("Invalid DLL storage class");
}
-static unsigned getEncodedThreadLocalMode(const GlobalVariable &GV) {
+static unsigned getEncodedThreadLocalMode(const GlobalValue &GV) {
switch (GV.getThreadLocalMode()) {
case GlobalVariable::NotThreadLocal: return 0;
case GlobalVariable::GeneralDynamicTLSModel: return 1;
@@ -668,6 +668,8 @@ static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE,
Vals.push_back(getEncodedLinkage(A));
Vals.push_back(getEncodedVisibility(A));
Vals.push_back(getEncodedDLLStorageClass(A));
+ if (A.isThreadLocal())
+ Vals.push_back(getEncodedThreadLocalMode(A));
unsigned AbbrevToUse = 0;
Stream.EmitRecord(bitc::MODULE_CODE_ALIAS, Vals, AbbrevToUse);
Vals.clear();
diff --git a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index b1b8035a7d..51ae11dea2 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -1190,15 +1190,8 @@ SDValue SelectionDAG::getGlobalAddress(const GlobalValue *GV, SDLoc DL,
if (BitWidth < 64)
Offset = SignExtend64(Offset, BitWidth);
- const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GV);
- if (!GVar) {
- // If GV is an alias then use the aliasee for determining thread-localness.
- if (const GlobalAlias *GA = dyn_cast<GlobalAlias>(GV))
- GVar = dyn_cast_or_null<GlobalVariable>(GA->getAliasee());
- }
-
unsigned Opc;
- if (GVar && GVar->isThreadLocal())
+ if (GV->isThreadLocal())
Opc = isTargetGA ? ISD::TargetGlobalTLSAddress : ISD::GlobalTLSAddress;
else
Opc = isTargetGA ? ISD::TargetGlobalAddress : ISD::GlobalAddress;
diff --git a/lib/IR/AsmWriter.cpp b/lib/IR/AsmWriter.cpp
index 0fef0d0a18..8aee77ac07 100644
--- a/lib/IR/AsmWriter.cpp
+++ b/lib/IR/AsmWriter.cpp
@@ -1488,6 +1488,7 @@ void AssemblyWriter::printAlias(const GlobalAlias *GA) {
}
PrintVisibility(GA->getVisibility(), Out);
PrintDLLStorageClass(GA->getDLLStorageClass(), Out);
+ PrintThreadLocalModel(GA->getThreadLocalMode(), Out);
Out << "alias ";
diff --git a/lib/IR/Globals.cpp b/lib/IR/Globals.cpp
index c905cfe31e..344a08d8f3 100644
--- a/lib/IR/Globals.cpp
+++ b/lib/IR/Globals.cpp
@@ -113,8 +113,9 @@ GlobalVariable::GlobalVariable(Type *Ty, bool constant, LinkageTypes Link,
: GlobalObject(PointerType::get(Ty, AddressSpace), Value::GlobalVariableVal,
OperandTraits<GlobalVariable>::op_begin(this),
InitVal != nullptr, Link, Name),
- isConstantGlobal(constant), threadLocalMode(TLMode),
+ isConstantGlobal(constant),
isExternallyInitializedConstant(isExternallyInitialized) {
+ setThreadLocalMode(TLMode);
if (InitVal) {
assert(InitVal->getType() == Ty &&
"Initializer should be the same type as the GlobalVariable!");
@@ -132,8 +133,9 @@ GlobalVariable::GlobalVariable(Module &M, Type *Ty, bool constant,
: GlobalObject(PointerType::get(Ty, AddressSpace), Value::GlobalVariableVal,
OperandTraits<GlobalVariable>::op_begin(this),
InitVal != nullptr, Link, Name),
- isConstantGlobal(constant), threadLocalMode(TLMode),
+ isConstantGlobal(constant),
isExternallyInitializedConstant(isExternallyInitialized) {
+ setThreadLocalMode(TLMode);
if (InitVal) {
assert(InitVal->getType() == Ty &&
"Initializer should be the same type as the GlobalVariable!");
diff --git a/lib/Target/AArch64/AArch64FastISel.cpp b/lib/Target/AArch64/AArch64FastISel.cpp
index c3b53692fb..f97cfb943d 100644
--- a/lib/Target/AArch64/AArch64FastISel.cpp
+++ b/lib/Target/AArch64/AArch64FastISel.cpp
@@ -240,21 +240,15 @@ unsigned AArch64FastISel::AArch64MaterializeFP(const ConstantFP *CFP, MVT VT) {
}
unsigned AArch64FastISel::AArch64MaterializeGV(const GlobalValue *GV) {
- // We can't handle thread-local variables quickly yet. Unfortunately we have
- // to peer through any aliases to find out if that rule applies.
- const GlobalValue *TLSGV = GV;
- if (const GlobalAlias *GA = dyn_cast<GlobalAlias>(GV))
- TLSGV = GA->getAliasee();
+ // We can't handle thread-local variables quickly yet.
+ if (GV->isThreadLocal())
+ return 0;
// MachO still uses GOT for large code-model accesses, but ELF requires
// movz/movk sequences, which FastISel doesn't handle yet.
if (TM.getCodeModel() != CodeModel::Small && !Subtarget->isTargetMachO())
return 0;
- if (const GlobalVariable *GVar = dyn_cast<GlobalVariable>(TLSGV))
- if (GVar->isThreadLocal())
- return 0;
-
unsigned char OpFlags = Subtarget->ClassifyGlobalReference(GV, TM);
EVT DestEVT = TLI.getValueType(GV->getType(), true);
diff --git a/lib/Target/PowerPC/PPCFastISel.cpp b/lib/Target/PowerPC/PPCFastISel.cpp
index ed3cb4d329..f55984ea9d 100644
--- a/lib/Target/PowerPC/PPCFastISel.cpp
+++ b/lib/Target/PowerPC/PPCFastISel.cpp
@@ -1859,15 +1859,9 @@ unsigned PPCFastISel::PPCMaterializeGV(const GlobalValue *GV, MVT VT) {
// handle switches; if that changes, we need them as well. For now,
// what follows assumes everything's a generic (or TLS) global address.
const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GV);
- if (!GVar) {
- // If GV is an alias, use the aliasee for determining thread-locality.
- if (const GlobalAlias *GA = dyn_cast<GlobalAlias>(GV))
- GVar = dyn_cast_or_null<GlobalVariable>(GA->getAliasee());
- }
// FIXME: We don't yet handle the complexity of TLS.
- bool IsTLS = GVar && GVar->isThreadLocal();
- if (IsTLS)
+ if (GV->isThreadLocal())
return 0;
// For small code model, generate a simple TOC load.
diff --git a/lib/Target/TargetMachine.cpp b/lib/Target/TargetMachine.cpp
index 8365f64dc5..95c8cb66f4 100644
--- a/lib/Target/TargetMachine.cpp
+++ b/lib/Target/TargetMachine.cpp
@@ -88,8 +88,8 @@ CodeModel::Model TargetMachine::getCodeModel() const {
}
/// Get the IR-specified TLS model for Var.
-static TLSModel::Model getSelectedTLSModel(const GlobalVariable *Var) {
- switch (Var->getThreadLocalMode()) {
+static TLSModel::Model getSelectedTLSModel(const GlobalValue *GV) {
+ switch (GV->getThreadLocalMode()) {
case GlobalVariable::NotThreadLocal:
llvm_unreachable("getSelectedTLSModel for non-TLS variable");
break;
@@ -127,13 +127,10 @@ TLSModel::Model TargetMachine::getTLSModel(const GlobalValue *GV) const {
Model = TLSModel::InitialExec;
}
- const GlobalVariable *Var = dyn_cast<GlobalVariable>(GV);
- if (Var) {
- // If the user specified a more specific model, use that.
- TLSModel::Model SelectedModel = getSelectedTLSModel(Var);
- if (SelectedModel > Model)
- return SelectedModel;
- }
+ // If the user specified a more specific model, use that.
+ TLSModel::Model SelectedModel = getSelectedTLSModel(GV);
+ if (SelectedModel > Model)
+ return SelectedModel;
return Model;
}
diff --git a/lib/Target/X86/X86FastISel.cpp b/lib/Target/X86/X86FastISel.cpp
index 56bcfa30ff..2ef4bf29cc 100644
--- a/lib/Target/X86/X86FastISel.cpp
+++ b/lib/Target/X86/X86FastISel.cpp
@@ -355,17 +355,8 @@ bool X86FastISel::handleConstantAddresses(const Value *V, X86AddressMode &AM) {
return false;
// Can't handle TLS yet.
- if (const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GV))
- if (GVar->isThreadLocal())
- return false;
-
- // Can't handle TLS yet, part 2 (this is slightly crazy, but this is how
- // it works...).
- if (const GlobalAlias *GA = dyn_cast<GlobalAlias>(GV))
- if (const GlobalVariable *GVar =
- dyn_cast_or_null<GlobalVariable>(GA->getAliasee()))
- if (GVar->isThreadLocal())
- return false;
+ if (GV->isThreadLocal())
+ return false;
// RIP-relative addresses can't have additional register operands, so if
// we've already folded stuff into the addressing mode, just force the
diff --git a/test/CodeGen/Mips/tls-alias.ll b/test/CodeGen/Mips/tls-alias.ll
index 80fbe87a8d..b61f84e037 100644
--- a/test/CodeGen/Mips/tls-alias.ll
+++ b/test/CodeGen/Mips/tls-alias.ll
@@ -1,7 +1,7 @@
; RUN: llc -march=mipsel -relocation-model=pic -disable-mips-delay-filler < %s | FileCheck %s
@foo = thread_local global i32 42
-@bar = hidden alias i32* @foo
+@bar = hidden thread_local alias i32* @foo
define i32* @zed() {
; CHECK-DAG: __tls_get_addr
diff --git a/test/CodeGen/X86/2008-03-12-ThreadLocalAlias.ll b/test/CodeGen/X86/2008-03-12-ThreadLocalAlias.ll
index e64375a2b3..a0106d7798 100644
--- a/test/CodeGen/X86/2008-03-12-ThreadLocalAlias.ll
+++ b/test/CodeGen/X86/2008-03-12-ThreadLocalAlias.ll
@@ -8,7 +8,7 @@ target triple = "i386-pc-linux-gnu"
@__resp = thread_local global %struct.__res_state* @_res ; <%struct.__res_state**> [#uses=1]
@_res = global %struct.__res_state zeroinitializer, section ".bss" ; <%struct.__res_state*> [#uses=1]
-@__libc_resp = hidden alias %struct.__res_state** @__resp ; <%struct.__res_state**> [#uses=2]
+@__libc_resp = hidden thread_local alias %struct.__res_state** @__resp ; <%struct.__res_state**> [#uses=2]
define i32 @foo() {
; CHECK-LABEL: foo:
diff --git a/test/CodeGen/X86/aliases.ll b/test/CodeGen/X86/aliases.ll
index 8487c6082b..d207880d66 100644
--- a/test/CodeGen/X86/aliases.ll
+++ b/test/CodeGen/X86/aliases.ll
@@ -1,4 +1,20 @@
-; RUN: llc < %s -mtriple=i686-pc-linux-gnu -asm-verbose=false | FileCheck %s
+; RUN: llc < %s -mtriple=i686-pc-linux-gnu -asm-verbose=false \
+; RUN: -relocation-model=pic | FileCheck %s
+
+@thread_var = thread_local global i32 42, align 4
+@thread_alias = thread_local(localdynamic) alias i32* @thread_var
+
+; CHECK-LABEL: get_thread_var
+define i32* @get_thread_var() {
+; CHECK: leal thread_var@TLSGD
+ ret i32* @thread_var
+}
+
+; CHECK-LABEL: get_thread_alias
+define i32* @get_thread_alias() {
+; CHECK: leal thread_alias@TLSLD
+ ret i32* @thread_alias
+}
@bar = global i32 42
diff --git a/test/Feature/alias2.ll b/test/Feature/alias2.ll
index 693ef7c9be..4334a62017 100644
--- a/test/Feature/alias2.ll
+++ b/test/Feature/alias2.ll
@@ -17,3 +17,6 @@
@v6 = alias i16, i32* @v1
; CHECK: @v6 = alias i16, i32* @v1
+
+@v7 = thread_local(localdynamic) alias i32* @v1
+; CHECK: @v7 = thread_local(localdynamic) alias i32* @v1