* c-common.h (enum rid): Add RID_THREAD.
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 22 May 2002 01:11:29 +0000 (01:11 +0000)
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 22 May 2002 01:11:29 +0000 (01:11 +0000)
        * c-decl.c (start_decl): Do not set DECL_COMMON for tls variables.
        (grokdeclarator): Grok __thread.
        * c-parse.in (reswords): Add __thread.
        (rid_to_yy): Add RID_THREAD.
        * cp/lex.c (rid_to_yy): Add RID_THREAD.

        * tree.h (DECL_THREAD_LOCAL): New.
        (struct tree_decl): Add thread_local_flag.
        * print-tree.c (print_node): Dump DECL_THREAD_LOCAL.
        * tree.c (staticp): TLS variables are not static.

        * target-def.h (TARGET_HAVE_TLS): New.
        * target.h (have_tls): New.
        * output.h (SECTION_TLS): New.
        * varasm.c (assemble_variable): TLS variables can't be common for now.
        (default_section_type_flags): Handle .tdata and .tbss.
        (default_elf_asm_named_section): Handle SECTION_TLS.
        (categorize_decl_for_section): Handle DECL_THREAD_LOCAL.

        * flags.h (flag_tls_default): Declare.
        * toplev.c (flag_tls_default): Define.
        (display_help): Display help for it.
        (decode_f_option): Set it.

        * doc/extend.texi (Thread-Local): New node describing language-level
        thread-local storage.
        * doc/invoke.texi (-ftls-model): Document.

        * fixinc/inclhack.def (thread_keyword): New.
        * fixinc/fixincl.x: Rebuild.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@53715 138bc75d-0d04-0410-961f-82ee72b054a4

19 files changed:
gcc/ChangeLog
gcc/c-common.h
gcc/c-decl.c
gcc/c-parse.in
gcc/cp/ChangeLog
gcc/cp/lex.c
gcc/doc/extend.texi
gcc/doc/invoke.texi
gcc/fixinc/fixincl.x
gcc/fixinc/inclhack.def
gcc/flags.h
gcc/output.h
gcc/print-tree.c
gcc/target-def.h
gcc/target.h
gcc/toplev.c
gcc/tree.c
gcc/tree.h
gcc/varasm.c

index 34332fb..f6fc7d9 100644 (file)
@@ -1,3 +1,36 @@
+2002-05-21  Richard Henderson  <rth@redhat.com>
+
+       * c-common.h (enum rid): Add RID_THREAD.
+       * c-decl.c (start_decl): Do not set DECL_COMMON for tls variables.
+       (grokdeclarator): Grok __thread.
+       * c-parse.in (reswords): Add __thread.
+       (rid_to_yy): Add RID_THREAD.
+
+       * tree.h (DECL_THREAD_LOCAL): New.
+       (struct tree_decl): Add thread_local_flag.
+       * print-tree.c (print_node): Dump DECL_THREAD_LOCAL.
+       * tree.c (staticp): TLS variables are not static.
+
+       * target-def.h (TARGET_HAVE_TLS): New.
+       * target.h (have_tls): New.
+       * output.h (SECTION_TLS): New.
+       * varasm.c (assemble_variable): TLS variables can't be common for now.
+       (default_section_type_flags): Handle .tdata and .tbss.
+       (default_elf_asm_named_section): Handle SECTION_TLS.
+       (categorize_decl_for_section): Handle DECL_THREAD_LOCAL.
+
+       * flags.h (flag_tls_default): Declare.
+       * toplev.c (flag_tls_default): Define.
+       (display_help): Display help for it.
+       (decode_f_option): Set it.
+
+       * doc/extend.texi (Thread-Local): New node describing language-level
+       thread-local storage.
+       * doc/invoke.texi (-ftls-model): Document.
+
+       * fixinc/inclhack.def (thread_keyword): New.
+       * fixinc/fixincl.x: Rebuild.
+
 2002-05-21  Jeffrey A Law  <law@redhat.com>
 
        * i386.c (ix86_sched_reorder_ppro): Fix typo/thinko.
index 8666095..320d03d 100644 (file)
@@ -58,7 +58,7 @@ enum rid
   RID_VOLATILE, RID_SIGNED,  RID_AUTO,  RID_RESTRICT,
 
   /* C extensions */
-  RID_BOUNDED, RID_UNBOUNDED, RID_COMPLEX,
+  RID_BOUNDED, RID_UNBOUNDED, RID_COMPLEX, RID_THREAD,
 
   /* C++ */
   RID_FRIEND, RID_VIRTUAL, RID_EXPLICIT, RID_EXPORT, RID_MUTABLE,
index 8825db1..0890a2a 100644 (file)
@@ -3350,9 +3350,19 @@ start_decl (declarator, declspecs, initialized, attributes)
   /* ANSI specifies that a tentative definition which is not merged with
      a non-tentative definition behaves exactly like a definition with an
      initializer equal to zero.  (Section 3.7.2)
-     -fno-common gives strict ANSI behavior.  Usually you don't want it.
-     This matters only for variables with external linkage.  */
-  if (!initialized && (! flag_no_common || ! TREE_PUBLIC (decl)))
+
+     -fno-common gives strict ANSI behavior, though this tends to break
+     a large body of code that grew up without this rule.
+
+     Thread-local variables are never common, since there's no entrenched
+     body of code to break, and it allows more efficient variable references
+     in the presense of dynamic linking.  */
+
+  if (TREE_CODE (decl) == VAR_DECL
+      && !initialized
+      && TREE_PUBLIC (decl)
+      && !DECL_THREAD_LOCAL (decl)
+      && !flag_no_common)
     DECL_COMMON (decl) = 1;
 
   /* Set attributes here so if duplicate decl, will have proper attributes.  */
@@ -3933,7 +3943,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
          enum rid i = C_RID_CODE (id);
          if ((int) i <= (int) RID_LAST_MODIFIER)
            {
-             if (i == RID_LONG && (specbits & (1 << (int) i)))
+             if (i == RID_LONG && (specbits & (1 << (int) RID_LONG)))
                {
                  if (longlong)
                    error ("`long long long' is too long for GCC");
@@ -3947,6 +3957,19 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
                }
              else if (specbits & (1 << (int) i))
                pedwarn ("duplicate `%s'", IDENTIFIER_POINTER (id));
+
+             /* Diagnose "__thread extern".  Recall that this list
+                is in the reverse order seen in the text.  */
+             if (i == RID_THREAD
+                 && (specbits & (1 << (int) RID_EXTERN
+                                 | 1 << (int) RID_STATIC)))
+               {
+                 if (specbits & 1 << (int) RID_EXTERN)
+                   error ("`__thread' before `extern'");
+                 else
+                   error ("`__thread' before `static'");
+               }
+
              specbits |= 1 << (int) i;
              goto found;
            }
@@ -4196,6 +4219,12 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
     if (specbits & 1 << (int) RID_REGISTER) nclasses++;
     if (specbits & 1 << (int) RID_TYPEDEF) nclasses++;
 
+    /* "static __thread" and "extern __thread" are allowed.  */
+    if ((specbits & (1 << (int) RID_THREAD
+                    | 1 << (int) RID_STATIC
+                    | 1 << (int) RID_EXTERN)) == (1 << (int) RID_THREAD))
+      nclasses++;
+
     /* Warn about storage classes that are invalid for certain
        kinds of declarations (parameters, typenames, etc.).  */
 
@@ -4205,7 +4234,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
             && (specbits
                 & ((1 << (int) RID_REGISTER)
                    | (1 << (int) RID_AUTO)
-                   | (1 << (int) RID_TYPEDEF))))
+                   | (1 << (int) RID_TYPEDEF)
+                   | (1 << (int) RID_THREAD))))
       {
        if (specbits & 1 << (int) RID_AUTO
            && (pedantic || current_binding_level == global_binding_level))
@@ -4214,8 +4244,10 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
          error ("function definition declared `register'");
        if (specbits & 1 << (int) RID_TYPEDEF)
          error ("function definition declared `typedef'");
+       if (specbits & 1 << (int) RID_THREAD)
+         error ("function definition declared `__thread'");
        specbits &= ~((1 << (int) RID_TYPEDEF) | (1 << (int) RID_REGISTER)
-                     | (1 << (int) RID_AUTO));
+                     | (1 << (int) RID_AUTO) | (1 << (int) RID_THREAD));
       }
     else if (decl_context != NORMAL && nclasses > 0)
       {
@@ -4238,7 +4270,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
              }
            specbits &= ~((1 << (int) RID_TYPEDEF) | (1 << (int) RID_REGISTER)
                          | (1 << (int) RID_AUTO) | (1 << (int) RID_STATIC)
-                         | (1 << (int) RID_EXTERN));
+                         | (1 << (int) RID_EXTERN) | (1 << (int) RID_THREAD));
          }
       }
     else if (specbits & 1 << (int) RID_EXTERN && initialized && ! funcdef_flag)
@@ -4249,12 +4281,25 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
        else
          error ("`%s' has both `extern' and initializer", name);
       }
-    else if (specbits & 1 << (int) RID_EXTERN && funcdef_flag
-            && current_binding_level != global_binding_level)
-      error ("nested function `%s' declared `extern'", name);
-    else if (current_binding_level == global_binding_level
-            && specbits & (1 << (int) RID_AUTO))
-      error ("top-level declaration of `%s' specifies `auto'", name);
+    else if (current_binding_level == global_binding_level)
+      {
+       if (specbits & 1 << (int) RID_AUTO)
+         error ("top-level declaration of `%s' specifies `auto'", name);
+      }
+    else
+      {
+       if (specbits & 1 << (int) RID_EXTERN && funcdef_flag)
+         error ("nested function `%s' declared `extern'", name);
+       else if ((specbits & (1 << (int) RID_THREAD
+                              | 1 << (int) RID_EXTERN
+                              | 1 << (int) RID_STATIC))
+                == (1 << (int) RID_THREAD))
+         {
+           error ("function-scope `%s' implicitly auto and declared `__thread'",
+                  name);
+           specbits &= ~(1 << (int) RID_THREAD);
+         }
+      }
   }
 
   /* Now figure out the structure of the declarator proper.
@@ -4842,6 +4887,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
          pedwarn ("invalid storage class for function `%s'", name);
        if (specbits & (1 << (int) RID_REGISTER))
          error ("invalid storage class for function `%s'", name);
+       if (specbits & (1 << (int) RID_THREAD))
+         error ("invalid storage class for function `%s'", name);
        /* Function declaration not at top level.
           Storage classes other than `extern' are not allowed
           and `extern' makes no difference.  */
@@ -4934,22 +4981,32 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
          pedwarn_with_decl (decl, "variable `%s' declared `inline'");
 
        DECL_EXTERNAL (decl) = extern_ref;
+
        /* At top level, the presence of a `static' or `register' storage
           class specifier, or the absence of all storage class specifiers
           makes this declaration a definition (perhaps tentative).  Also,
           the absence of both `static' and `register' makes it public.  */
        if (current_binding_level == global_binding_level)
          {
-           TREE_PUBLIC (decl)
-             = !(specbits
-                 & ((1 << (int) RID_STATIC) | (1 << (int) RID_REGISTER)));
-           TREE_STATIC (decl) = ! DECL_EXTERNAL (decl);
+           TREE_PUBLIC (decl) = !(specbits & ((1 << (int) RID_STATIC)
+                                              | (1 << (int) RID_REGISTER)));
+           TREE_STATIC (decl) = !extern_ref;
          }
        /* Not at top level, only `static' makes a static definition.  */
        else
          {
            TREE_STATIC (decl) = (specbits & (1 << (int) RID_STATIC)) != 0;
-           TREE_PUBLIC (decl) = DECL_EXTERNAL (decl);
+           TREE_PUBLIC (decl) = extern_ref;
+         }
+
+       if (specbits & 1 << (int) RID_THREAD)
+         {
+           if (targetm.have_tls)
+             DECL_THREAD_LOCAL (decl) = 1;
+           else
+             /* A mere warning is sure to result in improper semantics
+                at runtime.  Don't bother to allow this to compile.  */
+             error ("thread-local storage not supported for this target");
          }
       }
 
index 679d42d..70bcb0c 100644 (file)
@@ -3343,6 +3343,7 @@ static const struct resword reswords[] =
   { "__restrict__",    RID_RESTRICT,   0 },
   { "__signed",                RID_SIGNED,     0 },
   { "__signed__",      RID_SIGNED,     0 },
+  { "__thread",                RID_THREAD,     0 },
   { "__typeof",                RID_TYPEOF,     0 },
   { "__typeof__",      RID_TYPEOF,     0 },
   { "__unbounded",     RID_UNBOUNDED,  0 },
@@ -3438,6 +3439,7 @@ static const short rid_to_yy[RID_MAX] =
   /* RID_BOUNDED */    TYPE_QUAL,
   /* RID_UNBOUNDED */  TYPE_QUAL,
   /* RID_COMPLEX */    TYPESPEC,
+  /* RID_THREAD */     SCSPEC,
 
   /* C++ */
   /* RID_FRIEND */     0,
index cd76ef2..638154a 100644 (file)
@@ -1,3 +1,7 @@
+2002-05-21  Richard Henderson  <rth@redhat.com>
+
+       * lex.c (rid_to_yy): Add RID_THREAD.
+
 2002-05-21  Alexandre Oliva  <aoliva@redhat.com>
 
        * init.c (build_vec_init): Test for trivial copy-assignment when
index 7e4657c..a1f35d4 100644 (file)
@@ -474,6 +474,7 @@ const short rid_to_yy[RID_MAX] =
   /* RID_BOUNDED */    0,
   /* RID_UNBOUNDED */  0,
   /* RID_COMPLEX */    TYPESPEC,
+  /* RID_THREAD */     0,
 
   /* C++ */
   /* RID_FRIEND */     SCSPEC,
index b27bec4..e37a66b 100644 (file)
@@ -432,6 +432,7 @@ extensions, accepted by GCC in C89 mode and in C++.
 * Target Builtins::     Built-in functions specific to particular targets.
 * Pragmas::             Pragmas accepted by GCC.
 * Unnamed Fields::      Unnamed struct/union fields within structs/unions.
+* Thread-Local::        Per-thread variables.
 @end menu
 
 @node Statement Exprs
@@ -6165,6 +6166,55 @@ It is ambiguous which @code{a} is being referred to with @samp{foo.a}.
 Such constructs are not supported and must be avoided.  In the future,
 such constructs may be detected and treated as compilation errors.
 
+@node Thread-Local
+@section Thread-Local Storage
+@cindex Thread-Local Storage
+@cindex TLS
+@cindex __thread
+
+Thread-local storage (TLS) is a mechanism by which variables are
+allocated such that there is one instance of the variable per extant
+thread.  The run-time model GCC uses to implement this originates
+in the IA-64 processor-specific ABI, but has since been migrated
+to other processors as well.  It requires significant support from
+the linker (@command{ld}), dynamic linker (@command{ld.so}), and
+system libraries (@file{libc.so} and @file{libpthread.so}), so it
+is not supported everywhere.
+
+At the user level, the extension is visible with a new storage
+class keyword: @code{__thread}.  For example:
+
+@example
+__thread int i;
+extern __thread struct state s;
+static __thread char *p;
+@end example
+
+The @code{__thread} specifier may be used alone, with the @code{extern}
+or @code{static} specifiers, but with no other storage class specifier.
+When used with @code{extern} or @code{static}, @code{__thread} must appear
+immediately after the other storage class specifier.
+
+The @code{__thread} specifier may be applied to any global, file-scoped
+static, function-scoped static, or class-scoped static variable.  It may
+not be applied to function-scoped automatic or class-scoped member variables.
+
+When the address-of operator is applied to a thread-local variable, it is
+evaluated at run-time and returns the address of the current thread's
+instance of that variable.  An address so obtained may be used by any
+thread.  When a thread terminates, any pointers to thread-local variables
+in that thread become invalid.
+
+No static initialization may refer to the address of a thread-local variable.
+
+In C++, a thread-local variable may not be initialized by a static
+constructor.
+
+See @uref{http://people.redhat.com/drepper/tls.pdf,
+ELF Handling For Thread-Local Storage} for a detailed explanation of
+the four thread-local storage addressing models, and how the run-time
+is expected to function.
+
 @node C++ Extensions
 @chapter Extensions to the C++ Language
 @cindex extensions, C++ language
index 855fcd9..cedabdf 100644 (file)
@@ -677,7 +677,7 @@ in the following sections.
 -fverbose-asm  -fpack-struct  -fstack-check @gol
 -fstack-limit-register=@var{reg}  -fstack-limit-symbol=@var{sym} @gol
 -fargument-alias  -fargument-noalias @gol
--fargument-noalias-global  -fleading-underscore}
+-fargument-noalias-global  -fleading-underscore -ftls-model=@var{model}}
 @end table
 
 @menu
@@ -9915,6 +9915,14 @@ is to help link with legacy assembly code.
 
 Be warned that you should know what you are doing when invoking this
 option, and that not all targets provide complete support for it.
+
+@item -ftls-model=@var{model}
+Alter the thread-local storage model to be used (@pxref{Thread-Local}).
+The @var{model} argument should be one of @code{global-dynamic},
+@code{local-dynamic}, @code{initial-exec} or @code{local-exec}.
+
+The default without @option{-fpic} is @code{initial-exec}; with
+@option{-fpic} the default is @code{global-dynamic}.
 @end table
 
 @c man end
index 589687f..b927146 100644 (file)
@@ -5,7 +5,7 @@
  * files which are fixed to work correctly with ANSI C and placed in a
  * directory that GNU C will search.
  *
- * This file contains 145 fixup descriptions.
+ * This file contains 146 fixup descriptions.
  *
  * See README for more information.
  *
@@ -4568,6 +4568,40 @@ static const char* apzSysz_Stdlib_For_SunPatch[] = {
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * *
  *
+ *  Description of Thread_Keyword fix
+ */
+tSCC zThread_KeywordName[] =
+     "thread_keyword";
+
+/*
+ *  File name selection pattern
+ */
+tSCC zThread_KeywordList[] =
+  "|bits/sigthread.h|pthread.h|";
+/*
+ *  Machine/OS name selection pattern
+ */
+#define apzThread_KeywordMachs (const char**)NULL
+
+/*
+ *  content selection pattern - do fix if pattern found
+ */
+tSCC zThread_KeywordSelect0[] =
+       "__thread";
+
+#define    THREAD_KEYWORD_TEST_CT  1
+static tTestDesc aThread_KeywordTests[] = {
+  { TT_EGREP,    zThread_KeywordSelect0, (regex_t*)NULL }, };
+
+/*
+ *  Fix Command Arguments for Thread_Keyword
+ */
+static const char* apzThread_KeywordPatch[] = { "sed",
+    "-e", "s/\\([^a-z0-9_]\\)__thread\\([^a-z0-9_]\\)/\\1__thr\\2/g",
+    (char*)NULL };
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
  *  Description of Tinfo_Cplusplus fix
  */
 tSCC zTinfo_CplusplusName[] =
@@ -5672,9 +5706,9 @@ static const char* apzX11_SprintfPatch[] = {
  *
  *  List of all fixes
  */
-#define REGEX_COUNT          152
+#define REGEX_COUNT          153
 #define MACH_LIST_SIZE_LIMIT 279
-#define FIX_COUNT            145
+#define FIX_COUNT            146
 
 /*
  *  Enumerate the fixes
@@ -5796,6 +5830,7 @@ typedef enum {
     SVR4_PROFIL_FIXIDX,
     SYSV68_STRING_FIXIDX,
     SYSZ_STDLIB_FOR_SUN_FIXIDX,
+    THREAD_KEYWORD_FIXIDX,
     TINFO_CPLUSPLUS_FIXIDX,
     ULTRIX_ATEXIT_PARAM_FIXIDX,
     ULTRIX_ATOF_PARAM_FIXIDX,
@@ -6408,6 +6443,11 @@ tFixDesc fixDescList[ FIX_COUNT ] = {
      SYSZ_STDLIB_FOR_SUN_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
      aSysz_Stdlib_For_SunTests,   apzSysz_Stdlib_For_SunPatch, 0 },
 
+  {  zThread_KeywordName,    zThread_KeywordList,
+     apzThread_KeywordMachs,
+     THREAD_KEYWORD_TEST_CT, FD_MACH_ONLY,
+     aThread_KeywordTests,   apzThread_KeywordPatch, 0 },
+
   {  zTinfo_CplusplusName,    zTinfo_CplusplusList,
      apzTinfo_CplusplusMachs,
      TINFO_CPLUSPLUS_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
index d5b5eec..322a79d 100644 (file)
@@ -1,4 +1,3 @@
-
 /* -*- Mode: C -*-  */
 
 autogen definitions fixincl;
@@ -2887,6 +2886,20 @@ fix = {
 
 
 /*
+ * __thread is now a keyword.
+ */
+fix = {
+    hackname   = thread_keyword;
+    files      = "pthread.h";
+    files      = "bits/sigthread.h";
+    select     = "pthread_t __thread";
+
+    sed                = "s/pthread_t __thread\\([^a-z0-9_]\\)/pthread_t __thr\\1/";
+
+    test_text  = "extern int pthread_kill (pthread_t __thread, int __signo);";
+};
+
+/*
  *  if the #if says _cplusplus, not the double underscore __cplusplus
  *  that it should be
  */
index efcc771..37f54d2 100644 (file)
@@ -458,11 +458,22 @@ extern int flag_dump_unnumbered;
 
 extern int flag_pedantic_errors;
 
-/* Nonzero means generate position-independent code.
-   This is not fully implemented yet.  */
+/* Nonzero means generate position-independent code.  1 vs 2 for a 
+   target-dependent "small" or "large" mode.  */
 
 extern int flag_pic;
 
+/* Set to the default thread-local storage (tls) model to use.  */
+
+enum tls_model {
+  TLS_MODEL_GLOBAL_DYNAMIC,
+  TLS_MODEL_LOCAL_DYNAMIC,
+  TLS_MODEL_INITIAL_EXEC,
+  TLS_MODEL_LOCAL_EXEC
+};
+
+extern enum tls_model flag_tls_default;
+
 /* Nonzero means generate extra code for exception handling and enable
    exception handling.  */
 
index 7a87b82..35229c3 100644 (file)
@@ -507,7 +507,8 @@ extern void no_asm_to_stream PARAMS ((FILE *));
 #define SECTION_STRINGS  0x10000       /* contains zero terminated strings without
                                           embedded zeros */
 #define SECTION_OVERRIDE 0x20000       /* allow override of default flags */
-#define SECTION_MACH_DEP 0x40000       /* subsequent bits reserved for target */
+#define SECTION_TLS     0x40000        /* contains thread-local storage */
+#define SECTION_MACH_DEP 0x80000       /* subsequent bits reserved for target */
 
 extern unsigned int get_named_section_flags PARAMS ((const char *));
 extern bool set_named_section_flags    PARAMS ((const char *, unsigned int));
index 40ee816..d9a5e41 100644 (file)
@@ -352,6 +352,8 @@ print_node (file, prefix, node, indent)
 
       if (TREE_CODE (node) == VAR_DECL && DECL_IN_TEXT_SECTION (node))
        fputs (" in-text-section", file);
+      if (TREE_CODE (node) == VAR_DECL && DECL_THREAD_LOCAL (node))
+       fputs (" thread-local", file);
 
       if (TREE_CODE (node) == PARM_DECL && DECL_TRANSPARENT_UNION (node))
        fputs (" transparent-union", file);
index c3438b5..63fbead 100644 (file)
@@ -110,6 +110,10 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 #define TARGET_HAVE_NAMED_SECTIONS false
 #endif
 
+#ifndef TARGET_HAVE_TLS
+#define TARGET_HAVE_TLS false
+#endif
+
 #ifndef TARGET_ASM_EXCEPTION_SECTION
 #define TARGET_ASM_EXCEPTION_SECTION default_exception_section
 #endif
@@ -244,6 +248,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
   TARGET_STRIP_NAME_ENCODING,                  \
   TARGET_HAVE_NAMED_SECTIONS,                  \
   TARGET_HAVE_CTORS_DTORS,                     \
+  TARGET_HAVE_TLS                              \
 }
 
 #include "hooks.h"
index f8648d5..3d3b8db 100644 (file)
@@ -256,6 +256,9 @@ struct gcc_target
   /* True if "native" constructors and destructors are supported,
      false if we're using collect2 for the job.  */
   bool have_ctors_dtors;
+
+  /* True if thread-local storage is supported.  */
+  bool have_tls;
 };
 
 extern struct gcc_target targetm;
index 878cdca..a7e856b 100644 (file)
@@ -685,12 +685,15 @@ int flag_shared_data;
 int flag_delayed_branch;
 
 /* Nonzero if we are compiling pure (sharable) code.
-   Value is 1 if we are doing reasonable (i.e. simple
-   offset into offset table) pic.  Value is 2 if we can
-   only perform register offsets.  */
+   Value is 1 if we are doing "small" pic; value is 2 if we're doing
+   "large" pic.  */
 
 int flag_pic;
 
+/* Set to the default thread-local storage (tls) model to use.  */
+
+enum tls_model flag_tls_default;
+
 /* Nonzero means generate extra code for exception handling and enable
    exception handling.  */
 
@@ -3547,6 +3550,7 @@ display_help ()
   printf (_("  -finline-limit=<number> Limits the size of inlined functions to <number>\n"));
   printf (_("  -fmessage-length=<number> Limits diagnostics messages lengths to <number> characters per line.  0 suppresses line-wrapping\n"));
   printf (_("  -fdiagnostics-show-location=[once | every-line] Indicates how often source location information should be emitted, as prefix, at the beginning of diagnostics when line-wrapping\n"));
+  printf (_("  -ftls-model=[global-dynamic | local-dynamic | initial-exec | local-exec] Indicates the default thread-local storage code generation model\n"));
 
   for (i = ARRAY_SIZE (f_options); i--;)
     {
@@ -3825,6 +3829,19 @@ decode_f_option (arg)
                                 MAX_INLINE_INSNS);
       set_param_value ("max-inline-insns", val);
     }
+  else if ((option_value = skip_leading_substring (arg, "tls-model=")))
+    {
+      if (strcmp (option_value, "global-dynamic") == 0)
+       flag_tls_default = TLS_MODEL_GLOBAL_DYNAMIC;
+      else if (strcmp (option_value, "local-dynamic") == 0)
+       flag_tls_default = TLS_MODEL_LOCAL_DYNAMIC;
+      else if (strcmp (option_value, "initial-exec") == 0)
+       flag_tls_default = TLS_MODEL_INITIAL_EXEC;
+      else if (strcmp (option_value, "local-exec") == 0)
+       flag_tls_default = TLS_MODEL_LOCAL_EXEC;
+      else
+       warning ("`%s': unknown tls-model option", arg - 2);
+    }
 #ifdef INSN_SCHEDULING
   else if ((option_value = skip_leading_substring (arg, "sched-verbose=")))
     fix_sched_param ("verbose", option_value);
index 945f3a1..17731c8 100644 (file)
@@ -1349,12 +1349,13 @@ staticp (arg)
     case FUNCTION_DECL:
       /* Nested functions aren't static, since taking their address
         involves a trampoline.  */
-      return (decl_function_context (arg) == 0 || DECL_NO_STATIC_CHAIN (arg))
-       && ! DECL_NON_ADDR_CONST_P (arg);
+      return ((decl_function_context (arg) == 0 || DECL_NO_STATIC_CHAIN (arg))
+             && ! DECL_NON_ADDR_CONST_P (arg));
 
     case VAR_DECL:
-      return (TREE_STATIC (arg) || DECL_EXTERNAL (arg))
-       && ! DECL_NON_ADDR_CONST_P (arg);
+      return ((TREE_STATIC (arg) || DECL_EXTERNAL (arg))
+             && ! DECL_THREAD_LOCAL (arg)
+             && ! DECL_NON_ADDR_CONST_P (arg));
 
     case CONSTRUCTOR:
       return TREE_STATIC (arg);
index 3e5ef3a..e7163ea 100644 (file)
@@ -1615,6 +1615,10 @@ struct tree_type
 /* In a FUNCTION_DECL, nonzero if the function cannot be inlined.  */
 #define DECL_UNINLINABLE(NODE) (FUNCTION_DECL_CHECK (NODE)->decl.uninlinable)
 
+/* In a VAR_DECL, nonzero if the data should be allocated from 
+   thread-local storage.  */
+#define DECL_THREAD_LOCAL(NODE) (VAR_DECL_CHECK (NODE)->decl.thread_local_flag)
+
 /* In a FUNCTION_DECL, the saved representation of the body of the
    entire function.  Usually a COMPOUND_STMT, but in C++ this may also
    be a RETURN_INIT, CTOR_INITIALIZER, or TRY_BLOCK.  */
@@ -1793,7 +1797,8 @@ struct tree_decl
   unsigned non_addressable : 1;
   unsigned user_align : 1;
   unsigned uninlinable : 1;
-  /* Three unused bits.  */
+  unsigned thread_local_flag : 1;
+  /* Two unused bits.  */
 
   unsigned lang_flag_0 : 1;
   unsigned lang_flag_1 : 1;
index 47e652e..3165b92 100644 (file)
@@ -1586,19 +1586,28 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
 
   /* Handle uninitialized definitions.  */
 
-  if ((DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node
-#if defined ASM_EMIT_BSS
-       || (flag_zero_initialized_in_bss
-          && initializer_zerop (DECL_INITIAL (decl)))
-#endif
-       )
-      /* If the target can't output uninitialized but not common global data
-        in .bss, then we have to use .data.  */
-#if ! defined ASM_EMIT_BSS
-      && DECL_COMMON (decl)
+  /* If the decl has been given an explicit section name, then it
+     isn't common, and shouldn't be handled as such.  */
+  if (DECL_SECTION_NAME (decl) || dont_output_data)
+    ;
+  /* We don't implement common thread-local data at present.  */
+  else if (DECL_THREAD_LOCAL (decl))
+    {
+      if (DECL_COMMON (decl))
+       sorry ("thread-local COMMON data not implemented");
+    }
+#ifndef ASM_EMIT_BSS
+  /* If the target can't output uninitialized but not common global data
+     in .bss, then we have to use .data.  */
+  /* ??? We should handle .bss via select_section mechanisms rather than
+     via special target hooks.  That would eliminate this special case.  */
+  else if (!DECL_COMMON (decl))
+    ;
 #endif
-      && DECL_SECTION_NAME (decl) == NULL_TREE
-      && ! dont_output_data)
+  else if (DECL_INITIAL (decl) == 0
+          || DECL_INITIAL (decl) == error_mark_node
+           || (flag_zero_initialized_in_bss
+              && initializer_zerop (DECL_INITIAL (decl))))
     {
       unsigned HOST_WIDE_INT size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
       unsigned HOST_WIDE_INT rounded = size;
@@ -5101,9 +5110,14 @@ default_section_type_flags (decl, name, reloc)
       || strncmp (name, ".gnu.linkonce.b.", 16) == 0
       || strcmp (name, ".sbss") == 0
       || strncmp (name, ".sbss.", 6) == 0
-      || strncmp (name, ".gnu.linkonce.sb.", 17) == 0)
+      || strncmp (name, ".gnu.linkonce.sb.", 17) == 0
+      || strcmp (name, ".tbss") == 0)
     flags |= SECTION_BSS;
 
+  if (strcmp (name, ".tdata") == 0
+      || strcmp (name, ".tbss") == 0)
+    flags |= SECTION_TLS;
+
   return flags;
 }
 
@@ -5146,6 +5160,8 @@ default_elf_asm_named_section (name, flags)
     *f++ = 'M';
   if (flags & SECTION_STRINGS)
     *f++ = 'S';
+  if (flags & SECTION_TLS)
+    *f++ = 'T';
   *f = '\0';
 
   if (flags & SECTION_BSS)
@@ -5353,8 +5369,17 @@ categorize_decl_for_section (decl, reloc)
   else
     ret = SECCAT_RODATA;
 
+  /* There are no read-only thread-local sections.  */
+  if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
+    {
+      if (ret == SECCAT_BSS)
+       ret = SECCAT_TBSS;
+      else
+       ret = SECCAT_TDATA;
+    }
+
   /* If the target uses small data sections, select it.  */
-  if ((*targetm.in_small_data_p) (decl))
+  else if ((*targetm.in_small_data_p) (decl))
     {
       if (ret == SECCAT_BSS)
        ret = SECCAT_SBSS;