From 2a6f0f815222f423a4fa14e19e16deccdd9b5cbd Mon Sep 17 00:00:00 2001 From: rth Date: Wed, 22 May 2002 01:11:29 +0000 Subject: [PATCH] * 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@53715 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 33 ++++++++++++++++++ gcc/c-common.h | 2 +- gcc/c-decl.c | 93 +++++++++++++++++++++++++++++++++++++++---------- gcc/c-parse.in | 2 ++ gcc/cp/ChangeLog | 4 +++ gcc/cp/lex.c | 1 + gcc/doc/extend.texi | 50 ++++++++++++++++++++++++++ gcc/doc/invoke.texi | 10 +++++- gcc/fixinc/fixincl.x | 46 ++++++++++++++++++++++-- gcc/fixinc/inclhack.def | 15 +++++++- gcc/flags.h | 15 ++++++-- gcc/output.h | 3 +- gcc/print-tree.c | 2 ++ gcc/target-def.h | 5 +++ gcc/target.h | 3 ++ gcc/toplev.c | 23 ++++++++++-- gcc/tree.c | 9 ++--- gcc/tree.h | 7 +++- gcc/varasm.c | 53 ++++++++++++++++++++-------- 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 + + * 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 * 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 + + * lex.c (rid_to_yy): Add RID_THREAD. + 2002-05-21 Alexandre Oliva * 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= Limits the size of inlined functions to \n")); printf (_(" -fmessage-length= Limits diagnostics messages lengths to 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; -- 2.7.4