Support the tls_model attribute (PR9788)
This adds support for the tls_model attribute. This allows the user to
choose a TLS model that is better than what LLVM would select by
default. For example, a variable might be declared as:
__thread int x __attribute__((tls_model("initial-exec")));
if it will not be used in a shared library that is dlopen'ed.
This depends on LLVM r159077.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@159078 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index ff803c6..08a9382 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -183,12 +183,22 @@
else
Name = GetStaticDeclName(*this, D, Separator);
+ llvm::GlobalVariable::ThreadLocalMode TLM;
+ TLM = D.isThreadSpecified() ? llvm::GlobalVariable::GeneralDynamicTLSModel
+ : llvm::GlobalVariable::NotThreadLocal;
+
+ // Set the TLS mode if it it's explicitly specified.
+ if (D.hasAttr<TLSModelAttr>()) {
+ assert(D.isThreadSpecified() && "Can't have TLS model on non-tls var.");
+ const TLSModelAttr *Attr = D.getAttr<TLSModelAttr>();
+ TLM = CodeGenModule::GetLLVMTLSModel(Attr->getModel());
+ }
+
llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(Ty);
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(CGM.getModule(), LTy,
Ty.isConstant(getContext()), Linkage,
- CGM.EmitNullConstant(D.getType()), Name, 0,
- D.isThreadSpecified(),
+ CGM.EmitNullConstant(D.getType()), Name, 0, TLM,
CGM.getContext().getTargetAddressSpace(Ty));
GV->setAlignment(getContext().getDeclAlign(&D).getQuantity());
if (Linkage != llvm::GlobalValue::InternalLinkage)
@@ -239,7 +249,7 @@
OldGV->isConstant(),
OldGV->getLinkage(), Init, "",
/*InsertBefore*/ OldGV,
- D.isThreadSpecified(),
+ OldGV->getThreadLocalMode(),
CGM.getContext().getTargetAddressSpace(D.getType()));
GV->setVisibility(OldGV->getVisibility());
@@ -1066,7 +1076,7 @@
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(CGM.getModule(), constant->getType(), true,
llvm::GlobalValue::PrivateLinkage,
- constant, Name, 0, false, 0);
+ constant, Name);
GV->setAlignment(alignment.getQuantity());
GV->setUnnamedAddr(true);
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index 854810b..97512ad 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -932,7 +932,8 @@
C = new llvm::GlobalVariable(CGM.getModule(), C->getType(),
E->getType().isConstant(CGM.getContext()),
llvm::GlobalValue::InternalLinkage,
- C, ".compoundliteral", 0, false,
+ C, ".compoundliteral", 0,
+ llvm::GlobalVariable::NotThreadLocal,
CGM.getContext().getTargetAddressSpace(E->getType()));
return C;
}
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 43d5736..1d6ddd5 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -1187,7 +1187,7 @@
new llvm::GlobalVariable(getModule(), Ty->getElementType(), false,
llvm::GlobalValue::ExternalLinkage,
0, MangledName, 0,
- false, AddrSpace);
+ llvm::GlobalVariable::NotThreadLocal, AddrSpace);
// Handle things which are present even on external declarations.
if (D) {
@@ -1211,6 +1211,12 @@
}
GV->setThreadLocal(D->isThreadSpecified());
+
+ // Set the TLS model if it it's explicitly specified.
+ if (D->hasAttr<TLSModelAttr>()) {
+ const TLSModelAttr *Attr = D->getAttr<TLSModelAttr>();
+ GV->setThreadLocalMode(GetLLVMTLSModel(Attr->getModel()));
+ }
}
if (AddrSpace != Ty->getAddressSpace())
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 8f3bd78..d1ecfec 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -496,6 +496,15 @@
llvm_unreachable("unknown visibility!");
}
+ static llvm::GlobalVariable::ThreadLocalMode GetLLVMTLSModel(StringRef S) {
+ return llvm::StringSwitch<llvm::GlobalVariable::ThreadLocalMode>(S)
+ .Case("global-dynamic", llvm::GlobalVariable::GeneralDynamicTLSModel)
+ .Case("local-dynamic", llvm::GlobalVariable::LocalDynamicTLSModel)
+ .Case("initial-exec", llvm::GlobalVariable::InitialExecTLSModel)
+ .Case("local-exec", llvm::GlobalVariable::LocalExecTLSModel)
+ .Default(llvm::GlobalVariable::NotThreadLocal);
+ }
+
llvm::Constant *GetAddrOfGlobal(GlobalDecl GD) {
if (isa<CXXConstructorDecl>(GD.getDecl()))
return GetAddrOfCXXConstructor(cast<CXXConstructorDecl>(GD.getDecl()),
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index b443911..744d18b 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -43,7 +43,8 @@
ExpectedMethod,
ExpectedVariableFunctionOrLabel,
ExpectedFieldOrGlobalVar,
- ExpectedStruct
+ ExpectedStruct,
+ ExpectedTLSVar
};
//===----------------------------------------------------------------------===//
@@ -1440,6 +1441,42 @@
D->addAttr(::new (S.Context) AlwaysInlineAttr(Attr.getRange(), S.Context));
}
+static void handleTLSModelAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ // Check the attribute arguments.
+ if (Attr.getNumArgs() != 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ return;
+ }
+
+ Expr *Arg = Attr.getArg(0);
+ Arg = Arg->IgnoreParenCasts();
+ StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
+
+ // Check that it is a string.
+ if (!Str) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_not_string) << "tls_model";
+ return;
+ }
+
+ if (!isa<VarDecl>(D) || !cast<VarDecl>(D)->isThreadSpecified()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedTLSVar;
+ return;
+ }
+
+ // Check that the value.
+ StringRef Model = Str->getString();
+ if (Model != "global-dynamic" && Model != "local-dynamic"
+ && Model != "initial-exec" && Model != "local-exec") {
+ S.Diag(Attr.getLoc(), diag::err_attr_tlsmodel_arg);
+ return;
+ }
+
+ D->addAttr(::new (S.Context) TLSModelAttr(Attr.getRange(), S.Context,
+ Model));
+}
+
static void handleMallocAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// Check the attribute arguments.
if (Attr.hasParameterOrArguments()) {
@@ -3939,6 +3976,7 @@
handleAlwaysInlineAttr (S, D, Attr); break;
case AttributeList::AT_AnalyzerNoReturn:
handleAnalyzerNoReturnAttr (S, D, Attr); break;
+ case AttributeList::AT_TLSModel: handleTLSModelAttr (S, D, Attr); break;
case AttributeList::AT_Annotate: handleAnnotateAttr (S, D, Attr); break;
case AttributeList::AT_Availability:handleAvailabilityAttr(S, D, Attr); break;
case AttributeList::AT_CarriesDependency: