]> granicus.if.org Git - clang/commitdiff
Support the tls_model attribute (PR9788)
authorHans Wennborg <hans@hanshq.net>
Sat, 23 Jun 2012 11:51:46 +0000 (11:51 +0000)
committerHans Wennborg <hans@hanshq.net>
Sat, 23 Jun 2012 11:51:46 +0000 (11:51 +0000)
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

docs/ReleaseNotes.html
include/clang/Basic/Attr.td
include/clang/Basic/DiagnosticSemaKinds.td
lib/CodeGen/CGDecl.cpp
lib/CodeGen/CGExprConstant.cpp
lib/CodeGen/CodeGenModule.cpp
lib/CodeGen/CodeGenModule.h
lib/Sema/SemaDeclAttr.cpp
test/CodeGen/thread-specifier.c
test/Sema/attr-tls_model.c [new file with mode: 0644]

index 294377318d5b4b54df4baeae80cd90c0270eff2d..7bca3bf218984ea5f7b79bf866de2ea8e62d0842 100644 (file)
@@ -123,6 +123,20 @@ int f(bool b) {
   flag.</li>
 </ul>
 
+<h4 id="tlsmodel">Support for <code>tls_model</code> attribute</h4>
+
+<p>Clang now supports the <code>tls_model</code> attribute, allowing code that
+uses thread-local storage to explicitly select which model to use. The available
+models are <code>"global-dynamic"</code>, <code>"local-dynamic"</code>,
+<code>"initial-exec"</code> and <code>"local-exec"</code>. See
+<a href="http://www.akkadia.org/drepper/tls.pdf">ELF Handling For Thread-Local
+ Storage</a> for more information.</p>
+
+<p>The compiler is free to choose a different model if the specified model is not
+supported by the target, or if the compiler determines that a more specific
+model can be used.
+</p>
+
 <!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
 <h3 id="newflags">New Compiler Flags</h3>
 <!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
index 988271ffbf248d0a7f264546125c12cd55230f5e..468d623eb7a896217a47882c3e9b54f62744d8a2 100644 (file)
@@ -160,6 +160,12 @@ def AlwaysInline : InheritableAttr {
   let Spellings = [GNU<"always_inline">];
 }
 
+def TLSModel : InheritableAttr {
+  let Spellings = [GNU<"tls_model">];
+  let Subjects = [Var];
+  let Args = [StringArgument<"Model">];
+}
+
 def AnalyzerNoReturn : InheritableAttr {
   let Spellings = [GNU<"analyzer_noreturn">];
 }
index 3a4c7feefc7b0f8d128dcba3a7063949b24169c1..32f9ba88bac9574a8d0b7b2540c9e597376f46bd 100644 (file)
@@ -1603,6 +1603,8 @@ def err_objc_literal_comparison : Error<
   "direct comparison of %select{a string literal|an array literal|"
   "a dictionary literal|a numeric literal|a boxed expression|}0 is not "
   "allowed%select{|; use -isEqual: instead}1">;
+def err_attr_tlsmodel_arg : Error<"tls_model must be \"global-dynamic\", "
+  "\"local-dynamic\", \"initial-exec\" or \"local-exec\"">;
 
 let CategoryName = "Cocoa API Issue" in {
 def warn_objc_redundant_literal_use : Warning<
@@ -1670,13 +1672,13 @@ def warn_attribute_wrong_decl_type : Warning<
   "functions, methods and blocks|functions, methods, and parameters|"
   "classes|variables|methods|variables, functions and labels|"
   "fields and global variables|structs|"
-  "variables, functions and tag types}1">;
+  "variables, functions and tag types|thread-local variables}1">;
 def err_attribute_wrong_decl_type : Error<
   "%0 attribute only applies to %select{functions|unions|"
   "variables and functions|functions and methods|parameters|"
   "functions, methods and blocks|functions, methods, and parameters|"
   "classes|variables|methods|variables, functions and labels|"
-  "fields and global variables|structs}1">;
+  "fields and global variables|structs|thread-local variables}1">;
 def warn_function_attribute_wrong_type : Warning<
   "'%0' only applies to function types; type here is %1">;
 def warn_pointer_attribute_wrong_type : Warning<
index ff803c612fb44399f3ea0056a1db54278da290f6..08a938254ba130a9002a3945c68503b4632f10a9 100644 (file)
@@ -183,12 +183,22 @@ CodeGenFunction::CreateStaticVarDecl(const VarDecl &D,
   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 @@ CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D,
                                   OldGV->isConstant(),
                                   OldGV->getLinkage(), Init, "",
                                   /*InsertBefore*/ OldGV,
-                                  D.isThreadSpecified(),
+                                  OldGV->getThreadLocalMode(),
                            CGM.getContext().getTargetAddressSpace(D.getType()));
     GV->setVisibility(OldGV->getVisibility());
 
@@ -1066,7 +1076,7 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
     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);
 
index 854810b310d871cabe680b90b2f8f75f65cf05a1..97512ad5307b6edc84126a5413a835e2373bcef7 100644 (file)
@@ -932,7 +932,8 @@ public:
         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;
     }
index 43d573689c96a6ec7e904d768c8096f86ee8b768..1d6ddd56de3d494c999519e0fddc9968d53ff68e 100644 (file)
@@ -1187,7 +1187,7 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
     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 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
     }
 
     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())
index 8f3bd78ac42c43af63e8d770cbaf9b905cb9d442..d1ecfec78a765a6ea5f7edb30ee197b0d4f420f8 100644 (file)
@@ -496,6 +496,15 @@ public:
     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()),
index b443911daf9b4023c6e372f3ad29b5f80a2a6dce..744d18bfd9fbda8fdc569e26b1852d3307b321b0 100644 (file)
@@ -43,7 +43,8 @@ enum AttributeDeclKind {
   ExpectedMethod,
   ExpectedVariableFunctionOrLabel,
   ExpectedFieldOrGlobalVar,
-  ExpectedStruct
+  ExpectedStruct,
+  ExpectedTLSVar
 };
 
 //===----------------------------------------------------------------------===//
@@ -1440,6 +1441,42 @@ static void handleAlwaysInlineAttr(Sema &S, Decl *D,
   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 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
     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:
index a1f3e168000e694d5fdea6653e7e92884d057957..a2d3e62c8c5d9d62a66ab55bb26e4b5cb915bd8d 100644 (file)
@@ -3,7 +3,13 @@
 // CHECK: @b = external thread_local global
 // CHECK: @d.e = internal thread_local global
 // CHECK: @d.f = internal thread_local global
+// CHECK: @f.a = internal thread_local(initialexec) global
 // CHECK: @a = thread_local global
+// CHECK: @g = thread_local global
+// CHECK: @h = thread_local(localdynamic) global
+// CHECK: @i = thread_local(initialexec) global
+// CHECK: @j = thread_local(localexec) global
+
 __thread int a;
 extern __thread int b;
 int c() { return *&b; }
@@ -13,3 +19,12 @@ int d() {
   return 0;
 }
 
+__thread int g __attribute__((tls_model("global-dynamic")));
+__thread int h __attribute__((tls_model("local-dynamic")));
+__thread int i __attribute__((tls_model("initial-exec")));
+__thread int j __attribute__((tls_model("local-exec")));
+
+int f() {
+  __thread static int a __attribute__((tls_model("initial-exec")));
+  return a++;
+}
diff --git a/test/Sema/attr-tls_model.c b/test/Sema/attr-tls_model.c
new file mode 100644 (file)
index 0000000..46f7d9b
--- /dev/null
@@ -0,0 +1,14 @@
+// RUN: %clang -Xclang -verify -fsyntax-only %s
+
+#if !__has_attribute(tls_model)
+#error "Should support tls_model attribute"
+#endif
+
+int f() __attribute((tls_model("global-dynamic"))); // expected-error {{'tls_model' attribute only applies to thread-local variables}}
+
+int x __attribute((tls_model("global-dynamic"))); // expected-error {{'tls_model' attribute only applies to thread-local variables}}
+static __thread int y __attribute((tls_model("global-dynamic"))); // no-warning
+
+static __thread int y __attribute((tls_model("local", "dynamic"))); // expected-error {{attribute takes one argument}}
+static __thread int y __attribute((tls_model(123))); // expected-error {{argument to tls_model attribute was not a string literal}}
+static __thread int y __attribute((tls_model("foobar"))); // expected-error {{tls_model must be "global-dynamic", "local-dynamic", "initial-exec" or "local-exec"}}