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
This commit is contained in:
parent
f5eb2fc83e
commit
3d78f2e96e
@ -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.
|
||||
|
@ -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,
|
||||
|
93
gcc/c-decl.c
93
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");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
*
|
||||
@ -4566,6 +4566,40 @@ static const char* apzSysz_Stdlib_For_SunPatch[] = {
|
||||
"void *\t%1(",
|
||||
(char*)NULL };
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* 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
|
||||
@ -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,
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
/* -*- Mode: C -*- */
|
||||
|
||||
autogen definitions fixincl;
|
||||
@ -2886,6 +2885,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
|
||||
|
15
gcc/flags.h
15
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. */
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
23
gcc/toplev.c
23
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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
53
gcc/varasm.c
53
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)))
|
||||
/* 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
|
||||
)
|
||||
/* 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)
|
||||
#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;
|
||||
|
Loading…
Reference in New Issue
Block a user