Commit 3d78f2e9 by Richard Henderson Committed by Richard Henderson

c-common.h (enum rid): Add RID_THREAD.

        * 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.
        * 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.

From-SVN: r53715
parent f5eb2fc8
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> 2002-05-21 Jeffrey A Law <law@redhat.com>
* i386.c (ix86_sched_reorder_ppro): Fix typo/thinko. * i386.c (ix86_sched_reorder_ppro): Fix typo/thinko.
......
...@@ -58,7 +58,7 @@ enum rid ...@@ -58,7 +58,7 @@ enum rid
RID_VOLATILE, RID_SIGNED, RID_AUTO, RID_RESTRICT, RID_VOLATILE, RID_SIGNED, RID_AUTO, RID_RESTRICT,
/* C extensions */ /* C extensions */
RID_BOUNDED, RID_UNBOUNDED, RID_COMPLEX, RID_BOUNDED, RID_UNBOUNDED, RID_COMPLEX, RID_THREAD,
/* C++ */ /* C++ */
RID_FRIEND, RID_VIRTUAL, RID_EXPLICIT, RID_EXPORT, RID_MUTABLE, RID_FRIEND, RID_VIRTUAL, RID_EXPLICIT, RID_EXPORT, RID_MUTABLE,
......
...@@ -3350,9 +3350,19 @@ start_decl (declarator, declspecs, initialized, attributes) ...@@ -3350,9 +3350,19 @@ start_decl (declarator, declspecs, initialized, attributes)
/* ANSI specifies that a tentative definition which is not merged with /* ANSI specifies that a tentative definition which is not merged with
a non-tentative definition behaves exactly like a definition with an a non-tentative definition behaves exactly like a definition with an
initializer equal to zero. (Section 3.7.2) 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. */ -fno-common gives strict ANSI behavior, though this tends to break
if (!initialized && (! flag_no_common || ! TREE_PUBLIC (decl))) 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; DECL_COMMON (decl) = 1;
/* Set attributes here so if duplicate decl, will have proper attributes. */ /* Set attributes here so if duplicate decl, will have proper attributes. */
...@@ -3933,7 +3943,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) ...@@ -3933,7 +3943,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
enum rid i = C_RID_CODE (id); enum rid i = C_RID_CODE (id);
if ((int) i <= (int) RID_LAST_MODIFIER) 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) if (longlong)
error ("`long long long' is too long for GCC"); error ("`long long long' is too long for GCC");
...@@ -3947,6 +3957,19 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) ...@@ -3947,6 +3957,19 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
} }
else if (specbits & (1 << (int) i)) else if (specbits & (1 << (int) i))
pedwarn ("duplicate `%s'", IDENTIFIER_POINTER (id)); 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; specbits |= 1 << (int) i;
goto found; goto found;
} }
...@@ -4196,6 +4219,12 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) ...@@ -4196,6 +4219,12 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
if (specbits & 1 << (int) RID_REGISTER) nclasses++; if (specbits & 1 << (int) RID_REGISTER) nclasses++;
if (specbits & 1 << (int) RID_TYPEDEF) 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 /* Warn about storage classes that are invalid for certain
kinds of declarations (parameters, typenames, etc.). */ kinds of declarations (parameters, typenames, etc.). */
...@@ -4205,7 +4234,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) ...@@ -4205,7 +4234,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
&& (specbits && (specbits
& ((1 << (int) RID_REGISTER) & ((1 << (int) RID_REGISTER)
| (1 << (int) RID_AUTO) | (1 << (int) RID_AUTO)
| (1 << (int) RID_TYPEDEF)))) | (1 << (int) RID_TYPEDEF)
| (1 << (int) RID_THREAD))))
{ {
if (specbits & 1 << (int) RID_AUTO if (specbits & 1 << (int) RID_AUTO
&& (pedantic || current_binding_level == global_binding_level)) && (pedantic || current_binding_level == global_binding_level))
...@@ -4214,8 +4244,10 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) ...@@ -4214,8 +4244,10 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
error ("function definition declared `register'"); error ("function definition declared `register'");
if (specbits & 1 << (int) RID_TYPEDEF) if (specbits & 1 << (int) RID_TYPEDEF)
error ("function definition declared `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) 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) else if (decl_context != NORMAL && nclasses > 0)
{ {
...@@ -4238,7 +4270,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) ...@@ -4238,7 +4270,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
} }
specbits &= ~((1 << (int) RID_TYPEDEF) | (1 << (int) RID_REGISTER) specbits &= ~((1 << (int) RID_TYPEDEF) | (1 << (int) RID_REGISTER)
| (1 << (int) RID_AUTO) | (1 << (int) RID_STATIC) | (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) else if (specbits & 1 << (int) RID_EXTERN && initialized && ! funcdef_flag)
...@@ -4249,12 +4281,25 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) ...@@ -4249,12 +4281,25 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
else else
error ("`%s' has both `extern' and initializer", name); error ("`%s' has both `extern' and initializer", name);
} }
else if (specbits & 1 << (int) RID_EXTERN && funcdef_flag else if (current_binding_level == global_binding_level)
&& current_binding_level != global_binding_level) {
error ("nested function `%s' declared `extern'", name); if (specbits & 1 << (int) RID_AUTO)
else if (current_binding_level == global_binding_level error ("top-level declaration of `%s' specifies `auto'", name);
&& 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. /* Now figure out the structure of the declarator proper.
...@@ -4842,6 +4887,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) ...@@ -4842,6 +4887,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
pedwarn ("invalid storage class for function `%s'", name); pedwarn ("invalid storage class for function `%s'", name);
if (specbits & (1 << (int) RID_REGISTER)) if (specbits & (1 << (int) RID_REGISTER))
error ("invalid storage class for function `%s'", name); 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. /* Function declaration not at top level.
Storage classes other than `extern' are not allowed Storage classes other than `extern' are not allowed
and `extern' makes no difference. */ and `extern' makes no difference. */
...@@ -4934,22 +4981,32 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) ...@@ -4934,22 +4981,32 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
pedwarn_with_decl (decl, "variable `%s' declared `inline'"); pedwarn_with_decl (decl, "variable `%s' declared `inline'");
DECL_EXTERNAL (decl) = extern_ref; DECL_EXTERNAL (decl) = extern_ref;
/* At top level, the presence of a `static' or `register' storage /* At top level, the presence of a `static' or `register' storage
class specifier, or the absence of all storage class specifiers class specifier, or the absence of all storage class specifiers
makes this declaration a definition (perhaps tentative). Also, makes this declaration a definition (perhaps tentative). Also,
the absence of both `static' and `register' makes it public. */ the absence of both `static' and `register' makes it public. */
if (current_binding_level == global_binding_level) if (current_binding_level == global_binding_level)
{ {
TREE_PUBLIC (decl) TREE_PUBLIC (decl) = !(specbits & ((1 << (int) RID_STATIC)
= !(specbits | (1 << (int) RID_REGISTER)));
& ((1 << (int) RID_STATIC) | (1 << (int) RID_REGISTER))); TREE_STATIC (decl) = !extern_ref;
TREE_STATIC (decl) = ! DECL_EXTERNAL (decl);
} }
/* Not at top level, only `static' makes a static definition. */ /* Not at top level, only `static' makes a static definition. */
else else
{ {
TREE_STATIC (decl) = (specbits & (1 << (int) RID_STATIC)) != 0; 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");
} }
} }
......
...@@ -3343,6 +3343,7 @@ static const struct resword reswords[] = ...@@ -3343,6 +3343,7 @@ static const struct resword reswords[] =
{ "__restrict__", RID_RESTRICT, 0 }, { "__restrict__", RID_RESTRICT, 0 },
{ "__signed", RID_SIGNED, 0 }, { "__signed", RID_SIGNED, 0 },
{ "__signed__", RID_SIGNED, 0 }, { "__signed__", RID_SIGNED, 0 },
{ "__thread", RID_THREAD, 0 },
{ "__typeof", RID_TYPEOF, 0 }, { "__typeof", RID_TYPEOF, 0 },
{ "__typeof__", RID_TYPEOF, 0 }, { "__typeof__", RID_TYPEOF, 0 },
{ "__unbounded", RID_UNBOUNDED, 0 }, { "__unbounded", RID_UNBOUNDED, 0 },
...@@ -3438,6 +3439,7 @@ static const short rid_to_yy[RID_MAX] = ...@@ -3438,6 +3439,7 @@ static const short rid_to_yy[RID_MAX] =
/* RID_BOUNDED */ TYPE_QUAL, /* RID_BOUNDED */ TYPE_QUAL,
/* RID_UNBOUNDED */ TYPE_QUAL, /* RID_UNBOUNDED */ TYPE_QUAL,
/* RID_COMPLEX */ TYPESPEC, /* RID_COMPLEX */ TYPESPEC,
/* RID_THREAD */ SCSPEC,
/* C++ */ /* C++ */
/* RID_FRIEND */ 0, /* RID_FRIEND */ 0,
......
2002-05-21 Richard Henderson <rth@redhat.com>
* lex.c (rid_to_yy): Add RID_THREAD.
2002-05-21 Alexandre Oliva <aoliva@redhat.com> 2002-05-21 Alexandre Oliva <aoliva@redhat.com>
* init.c (build_vec_init): Test for trivial copy-assignment when * init.c (build_vec_init): Test for trivial copy-assignment when
......
...@@ -474,6 +474,7 @@ const short rid_to_yy[RID_MAX] = ...@@ -474,6 +474,7 @@ const short rid_to_yy[RID_MAX] =
/* RID_BOUNDED */ 0, /* RID_BOUNDED */ 0,
/* RID_UNBOUNDED */ 0, /* RID_UNBOUNDED */ 0,
/* RID_COMPLEX */ TYPESPEC, /* RID_COMPLEX */ TYPESPEC,
/* RID_THREAD */ 0,
/* C++ */ /* C++ */
/* RID_FRIEND */ SCSPEC, /* RID_FRIEND */ SCSPEC,
......
...@@ -432,6 +432,7 @@ extensions, accepted by GCC in C89 mode and in C++. ...@@ -432,6 +432,7 @@ extensions, accepted by GCC in C89 mode and in C++.
* Target Builtins:: Built-in functions specific to particular targets. * Target Builtins:: Built-in functions specific to particular targets.
* Pragmas:: Pragmas accepted by GCC. * Pragmas:: Pragmas accepted by GCC.
* Unnamed Fields:: Unnamed struct/union fields within structs/unions. * Unnamed Fields:: Unnamed struct/union fields within structs/unions.
* Thread-Local:: Per-thread variables.
@end menu @end menu
@node Statement Exprs @node Statement Exprs
...@@ -6165,6 +6166,55 @@ It is ambiguous which @code{a} is being referred to with @samp{foo.a}. ...@@ -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 are not supported and must be avoided. In the future,
such constructs may be detected and treated as compilation errors. 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 @node C++ Extensions
@chapter Extensions to the C++ Language @chapter Extensions to the C++ Language
@cindex extensions, C++ language @cindex extensions, C++ language
......
...@@ -677,7 +677,7 @@ in the following sections. ...@@ -677,7 +677,7 @@ in the following sections.
-fverbose-asm -fpack-struct -fstack-check @gol -fverbose-asm -fpack-struct -fstack-check @gol
-fstack-limit-register=@var{reg} -fstack-limit-symbol=@var{sym} @gol -fstack-limit-register=@var{reg} -fstack-limit-symbol=@var{sym} @gol
-fargument-alias -fargument-noalias @gol -fargument-alias -fargument-noalias @gol
-fargument-noalias-global -fleading-underscore} -fargument-noalias-global -fleading-underscore -ftls-model=@var{model}}
@end table @end table
@menu @menu
...@@ -9915,6 +9915,14 @@ is to help link with legacy assembly code. ...@@ -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 Be warned that you should know what you are doing when invoking this
option, and that not all targets provide complete support for it. 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 @end table
@c man end @c man end
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* files which are fixed to work correctly with ANSI C and placed in a * files which are fixed to work correctly with ANSI C and placed in a
* directory that GNU C will search. * directory that GNU C will search.
* *
* This file contains 145 fixup descriptions. * This file contains 146 fixup descriptions.
* *
* See README for more information. * See README for more information.
* *
...@@ -4568,6 +4568,40 @@ static const char* apzSysz_Stdlib_For_SunPatch[] = { ...@@ -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 * Description of Tinfo_Cplusplus fix
*/ */
tSCC zTinfo_CplusplusName[] = tSCC zTinfo_CplusplusName[] =
...@@ -5672,9 +5706,9 @@ static const char* apzX11_SprintfPatch[] = { ...@@ -5672,9 +5706,9 @@ static const char* apzX11_SprintfPatch[] = {
* *
* List of all fixes * List of all fixes
*/ */
#define REGEX_COUNT 152 #define REGEX_COUNT 153
#define MACH_LIST_SIZE_LIMIT 279 #define MACH_LIST_SIZE_LIMIT 279
#define FIX_COUNT 145 #define FIX_COUNT 146
/* /*
* Enumerate the fixes * Enumerate the fixes
...@@ -5796,6 +5830,7 @@ typedef enum { ...@@ -5796,6 +5830,7 @@ typedef enum {
SVR4_PROFIL_FIXIDX, SVR4_PROFIL_FIXIDX,
SYSV68_STRING_FIXIDX, SYSV68_STRING_FIXIDX,
SYSZ_STDLIB_FOR_SUN_FIXIDX, SYSZ_STDLIB_FOR_SUN_FIXIDX,
THREAD_KEYWORD_FIXIDX,
TINFO_CPLUSPLUS_FIXIDX, TINFO_CPLUSPLUS_FIXIDX,
ULTRIX_ATEXIT_PARAM_FIXIDX, ULTRIX_ATEXIT_PARAM_FIXIDX,
ULTRIX_ATOF_PARAM_FIXIDX, ULTRIX_ATOF_PARAM_FIXIDX,
...@@ -6408,6 +6443,11 @@ tFixDesc fixDescList[ FIX_COUNT ] = { ...@@ -6408,6 +6443,11 @@ tFixDesc fixDescList[ FIX_COUNT ] = {
SYSZ_STDLIB_FOR_SUN_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE, SYSZ_STDLIB_FOR_SUN_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
aSysz_Stdlib_For_SunTests, apzSysz_Stdlib_For_SunPatch, 0 }, 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, { zTinfo_CplusplusName, zTinfo_CplusplusList,
apzTinfo_CplusplusMachs, apzTinfo_CplusplusMachs,
TINFO_CPLUSPLUS_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE, TINFO_CPLUSPLUS_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
......
/* -*- Mode: C -*- */ /* -*- Mode: C -*- */
autogen definitions fixincl; autogen definitions fixincl;
...@@ -2887,6 +2886,20 @@ fix = { ...@@ -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 * if the #if says _cplusplus, not the double underscore __cplusplus
* that it should be * that it should be
*/ */
......
...@@ -458,11 +458,22 @@ extern int flag_dump_unnumbered; ...@@ -458,11 +458,22 @@ extern int flag_dump_unnumbered;
extern int flag_pedantic_errors; extern int flag_pedantic_errors;
/* Nonzero means generate position-independent code. /* Nonzero means generate position-independent code. 1 vs 2 for a
This is not fully implemented yet. */ target-dependent "small" or "large" mode. */
extern int flag_pic; 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 /* Nonzero means generate extra code for exception handling and enable
exception handling. */ exception handling. */
......
...@@ -507,7 +507,8 @@ extern void no_asm_to_stream PARAMS ((FILE *)); ...@@ -507,7 +507,8 @@ extern void no_asm_to_stream PARAMS ((FILE *));
#define SECTION_STRINGS 0x10000 /* contains zero terminated strings without #define SECTION_STRINGS 0x10000 /* contains zero terminated strings without
embedded zeros */ embedded zeros */
#define SECTION_OVERRIDE 0x20000 /* allow override of default flags */ #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 unsigned int get_named_section_flags PARAMS ((const char *));
extern bool set_named_section_flags PARAMS ((const char *, unsigned int)); extern bool set_named_section_flags PARAMS ((const char *, unsigned int));
......
...@@ -352,6 +352,8 @@ print_node (file, prefix, node, indent) ...@@ -352,6 +352,8 @@ print_node (file, prefix, node, indent)
if (TREE_CODE (node) == VAR_DECL && DECL_IN_TEXT_SECTION (node)) if (TREE_CODE (node) == VAR_DECL && DECL_IN_TEXT_SECTION (node))
fputs (" in-text-section", file); 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)) if (TREE_CODE (node) == PARM_DECL && DECL_TRANSPARENT_UNION (node))
fputs (" transparent-union", file); fputs (" transparent-union", file);
......
...@@ -110,6 +110,10 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ...@@ -110,6 +110,10 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define TARGET_HAVE_NAMED_SECTIONS false #define TARGET_HAVE_NAMED_SECTIONS false
#endif #endif
#ifndef TARGET_HAVE_TLS
#define TARGET_HAVE_TLS false
#endif
#ifndef TARGET_ASM_EXCEPTION_SECTION #ifndef TARGET_ASM_EXCEPTION_SECTION
#define TARGET_ASM_EXCEPTION_SECTION default_exception_section #define TARGET_ASM_EXCEPTION_SECTION default_exception_section
#endif #endif
...@@ -244,6 +248,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ...@@ -244,6 +248,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
TARGET_STRIP_NAME_ENCODING, \ TARGET_STRIP_NAME_ENCODING, \
TARGET_HAVE_NAMED_SECTIONS, \ TARGET_HAVE_NAMED_SECTIONS, \
TARGET_HAVE_CTORS_DTORS, \ TARGET_HAVE_CTORS_DTORS, \
TARGET_HAVE_TLS \
} }
#include "hooks.h" #include "hooks.h"
...@@ -256,6 +256,9 @@ struct gcc_target ...@@ -256,6 +256,9 @@ struct gcc_target
/* True if "native" constructors and destructors are supported, /* True if "native" constructors and destructors are supported,
false if we're using collect2 for the job. */ false if we're using collect2 for the job. */
bool have_ctors_dtors; bool have_ctors_dtors;
/* True if thread-local storage is supported. */
bool have_tls;
}; };
extern struct gcc_target targetm; extern struct gcc_target targetm;
...@@ -685,12 +685,15 @@ int flag_shared_data; ...@@ -685,12 +685,15 @@ int flag_shared_data;
int flag_delayed_branch; int flag_delayed_branch;
/* Nonzero if we are compiling pure (sharable) code. /* Nonzero if we are compiling pure (sharable) code.
Value is 1 if we are doing reasonable (i.e. simple Value is 1 if we are doing "small" pic; value is 2 if we're doing
offset into offset table) pic. Value is 2 if we can "large" pic. */
only perform register offsets. */
int flag_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 /* Nonzero means generate extra code for exception handling and enable
exception handling. */ exception handling. */
...@@ -3547,6 +3550,7 @@ display_help () ...@@ -3547,6 +3550,7 @@ display_help ()
printf (_(" -finline-limit=<number> Limits the size of inlined functions to <number>\n")); 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 (_(" -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 (_(" -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--;) for (i = ARRAY_SIZE (f_options); i--;)
{ {
...@@ -3825,6 +3829,19 @@ decode_f_option (arg) ...@@ -3825,6 +3829,19 @@ decode_f_option (arg)
MAX_INLINE_INSNS); MAX_INLINE_INSNS);
set_param_value ("max-inline-insns", val); 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 #ifdef INSN_SCHEDULING
else if ((option_value = skip_leading_substring (arg, "sched-verbose="))) else if ((option_value = skip_leading_substring (arg, "sched-verbose=")))
fix_sched_param ("verbose", option_value); fix_sched_param ("verbose", option_value);
......
...@@ -1349,12 +1349,13 @@ staticp (arg) ...@@ -1349,12 +1349,13 @@ staticp (arg)
case FUNCTION_DECL: case FUNCTION_DECL:
/* Nested functions aren't static, since taking their address /* Nested functions aren't static, since taking their address
involves a trampoline. */ involves a trampoline. */
return (decl_function_context (arg) == 0 || DECL_NO_STATIC_CHAIN (arg)) return ((decl_function_context (arg) == 0 || DECL_NO_STATIC_CHAIN (arg))
&& ! DECL_NON_ADDR_CONST_P (arg); && ! DECL_NON_ADDR_CONST_P (arg));
case VAR_DECL: case VAR_DECL:
return (TREE_STATIC (arg) || DECL_EXTERNAL (arg)) return ((TREE_STATIC (arg) || DECL_EXTERNAL (arg))
&& ! DECL_NON_ADDR_CONST_P (arg); && ! DECL_THREAD_LOCAL (arg)
&& ! DECL_NON_ADDR_CONST_P (arg));
case CONSTRUCTOR: case CONSTRUCTOR:
return TREE_STATIC (arg); return TREE_STATIC (arg);
......
...@@ -1615,6 +1615,10 @@ struct tree_type ...@@ -1615,6 +1615,10 @@ struct tree_type
/* In a FUNCTION_DECL, nonzero if the function cannot be inlined. */ /* In a FUNCTION_DECL, nonzero if the function cannot be inlined. */
#define DECL_UNINLINABLE(NODE) (FUNCTION_DECL_CHECK (NODE)->decl.uninlinable) #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 /* In a FUNCTION_DECL, the saved representation of the body of the
entire function. Usually a COMPOUND_STMT, but in C++ this may also entire function. Usually a COMPOUND_STMT, but in C++ this may also
be a RETURN_INIT, CTOR_INITIALIZER, or TRY_BLOCK. */ be a RETURN_INIT, CTOR_INITIALIZER, or TRY_BLOCK. */
...@@ -1793,7 +1797,8 @@ struct tree_decl ...@@ -1793,7 +1797,8 @@ struct tree_decl
unsigned non_addressable : 1; unsigned non_addressable : 1;
unsigned user_align : 1; unsigned user_align : 1;
unsigned uninlinable : 1; unsigned uninlinable : 1;
/* Three unused bits. */ unsigned thread_local_flag : 1;
/* Two unused bits. */
unsigned lang_flag_0 : 1; unsigned lang_flag_0 : 1;
unsigned lang_flag_1 : 1; unsigned lang_flag_1 : 1;
......
...@@ -1586,19 +1586,28 @@ assemble_variable (decl, top_level, at_end, dont_output_data) ...@@ -1586,19 +1586,28 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
/* Handle uninitialized definitions. */ /* Handle uninitialized definitions. */
if ((DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node /* If the decl has been given an explicit section name, then it
#if defined ASM_EMIT_BSS isn't common, and shouldn't be handled as such. */
|| (flag_zero_initialized_in_bss if (DECL_SECTION_NAME (decl) || dont_output_data)
&& initializer_zerop (DECL_INITIAL (decl))) ;
#endif /* We don't implement common thread-local data at present. */
) else if (DECL_THREAD_LOCAL (decl))
/* If the target can't output uninitialized but not common global data {
in .bss, then we have to use .data. */ if (DECL_COMMON (decl))
#if ! defined ASM_EMIT_BSS sorry ("thread-local COMMON data not implemented");
&& DECL_COMMON (decl) }
#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 #endif
&& DECL_SECTION_NAME (decl) == NULL_TREE else if (DECL_INITIAL (decl) == 0
&& ! dont_output_data) || 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 size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
unsigned HOST_WIDE_INT rounded = size; unsigned HOST_WIDE_INT rounded = size;
...@@ -5101,9 +5110,14 @@ default_section_type_flags (decl, name, reloc) ...@@ -5101,9 +5110,14 @@ default_section_type_flags (decl, name, reloc)
|| strncmp (name, ".gnu.linkonce.b.", 16) == 0 || strncmp (name, ".gnu.linkonce.b.", 16) == 0
|| strcmp (name, ".sbss") == 0 || strcmp (name, ".sbss") == 0
|| strncmp (name, ".sbss.", 6) == 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; flags |= SECTION_BSS;
if (strcmp (name, ".tdata") == 0
|| strcmp (name, ".tbss") == 0)
flags |= SECTION_TLS;
return flags; return flags;
} }
...@@ -5146,6 +5160,8 @@ default_elf_asm_named_section (name, flags) ...@@ -5146,6 +5160,8 @@ default_elf_asm_named_section (name, flags)
*f++ = 'M'; *f++ = 'M';
if (flags & SECTION_STRINGS) if (flags & SECTION_STRINGS)
*f++ = 'S'; *f++ = 'S';
if (flags & SECTION_TLS)
*f++ = 'T';
*f = '\0'; *f = '\0';
if (flags & SECTION_BSS) if (flags & SECTION_BSS)
...@@ -5353,8 +5369,17 @@ categorize_decl_for_section (decl, reloc) ...@@ -5353,8 +5369,17 @@ categorize_decl_for_section (decl, reloc)
else else
ret = SECCAT_RODATA; 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 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) if (ret == SECCAT_BSS)
ret = SECCAT_SBSS; ret = SECCAT_SBSS;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment