aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog33
-rw-r--r--gcc/c-common.h2
-rw-r--r--gcc/c-decl.c93
-rw-r--r--gcc/c-parse.in2
-rw-r--r--gcc/cp/ChangeLog4
-rw-r--r--gcc/cp/lex.c1
-rw-r--r--gcc/doc/extend.texi50
-rw-r--r--gcc/doc/invoke.texi10
-rw-r--r--gcc/fixinc/fixincl.x46
-rw-r--r--gcc/fixinc/inclhack.def15
-rw-r--r--gcc/flags.h15
-rw-r--r--gcc/output.h3
-rw-r--r--gcc/print-tree.c2
-rw-r--r--gcc/target-def.h5
-rw-r--r--gcc/target.h3
-rw-r--r--gcc/toplev.c23
-rw-r--r--gcc/tree.c9
-rw-r--r--gcc/tree.h7
-rw-r--r--gcc/varasm.c53
19 files changed, 327 insertions, 49 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 34332fb..f6fc7d9 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/c-common.h b/gcc/c-common.h
index 8666095..320d03d 100644
--- a/gcc/c-common.h
+++ b/gcc/c-common.h
@@ -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,
diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index 8825db1..0890a2a 100644
--- a/gcc/c-decl.c
+++ b/gcc/c-decl.c
@@ -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");
}
}
diff --git a/gcc/c-parse.in b/gcc/c-parse.in
index 679d42d..70bcb0c 100644
--- a/gcc/c-parse.in
+++ b/gcc/c-parse.in
@@ -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,
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index cd76ef2..638154a 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c
index 7e4657c..a1f35d4 100644
--- a/gcc/cp/lex.c
+++ b/gcc/cp/lex.c
@@ -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,
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index b27bec4..e37a66b 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -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
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 855fcd9..cedabdf 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -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
diff --git a/gcc/fixinc/fixincl.x b/gcc/fixinc/fixincl.x
index 589687f..b927146 100644
--- a/gcc/fixinc/fixincl.x
+++ b/gcc/fixinc/fixincl.x
@@ -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,
diff --git a/gcc/fixinc/inclhack.def b/gcc/fixinc/inclhack.def
index d5b5eec..322a79d 100644
--- a/gcc/fixinc/inclhack.def
+++ b/gcc/fixinc/inclhack.def
@@ -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
*/
diff --git a/gcc/flags.h b/gcc/flags.h
index efcc771..37f54d2 100644
--- a/gcc/flags.h
+++ b/gcc/flags.h
@@ -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. */
diff --git a/gcc/output.h b/gcc/output.h
index 7a87b82..35229c3 100644
--- a/gcc/output.h
+++ b/gcc/output.h
@@ -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));
diff --git a/gcc/print-tree.c b/gcc/print-tree.c
index 40ee816..d9a5e41 100644
--- a/gcc/print-tree.c
+++ b/gcc/print-tree.c
@@ -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);
diff --git a/gcc/target-def.h b/gcc/target-def.h
index c3438b5..63fbead 100644
--- a/gcc/target-def.h
+++ b/gcc/target-def.h
@@ -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"
diff --git a/gcc/target.h b/gcc/target.h
index f8648d5..3d3b8db 100644
--- a/gcc/target.h
+++ b/gcc/target.h
@@ -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;
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 878cdca..a7e856b 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -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);
diff --git a/gcc/tree.c b/gcc/tree.c
index 945f3a1..17731c8 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -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);
diff --git a/gcc/tree.h b/gcc/tree.h
index 3e5ef3a..e7163ea 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -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;
diff --git a/gcc/varasm.c b/gcc/varasm.c
index 47e652e..3165b92 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -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;