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:
Richard Henderson 2002-05-21 18:11:29 -07:00 committed by Richard Henderson
parent f5eb2fc83e
commit 3d78f2e96e
19 changed files with 327 additions and 49 deletions

View File

@ -1,3 +1,36 @@
2002-05-21 Richard Henderson <rth@redhat.com>
* c-common.h (enum rid): Add RID_THREAD.
* c-decl.c (start_decl): Do not set DECL_COMMON for tls variables.
(grokdeclarator): Grok __thread.
* c-parse.in (reswords): Add __thread.
(rid_to_yy): Add RID_THREAD.
* tree.h (DECL_THREAD_LOCAL): New.
(struct tree_decl): Add thread_local_flag.
* print-tree.c (print_node): Dump DECL_THREAD_LOCAL.
* tree.c (staticp): TLS variables are not static.
* target-def.h (TARGET_HAVE_TLS): New.
* target.h (have_tls): New.
* output.h (SECTION_TLS): New.
* varasm.c (assemble_variable): TLS variables can't be common for now.
(default_section_type_flags): Handle .tdata and .tbss.
(default_elf_asm_named_section): Handle SECTION_TLS.
(categorize_decl_for_section): Handle DECL_THREAD_LOCAL.
* flags.h (flag_tls_default): Declare.
* toplev.c (flag_tls_default): Define.
(display_help): Display help for it.
(decode_f_option): Set it.
* doc/extend.texi (Thread-Local): New node describing language-level
thread-local storage.
* doc/invoke.texi (-ftls-model): Document.
* fixinc/inclhack.def (thread_keyword): New.
* fixinc/fixincl.x: Rebuild.
2002-05-21 Jeffrey A Law <law@redhat.com>
* i386.c (ix86_sched_reorder_ppro): Fix typo/thinko.

View File

@ -58,7 +58,7 @@ enum rid
RID_VOLATILE, RID_SIGNED, RID_AUTO, RID_RESTRICT,
/* C extensions */
RID_BOUNDED, RID_UNBOUNDED, RID_COMPLEX,
RID_BOUNDED, RID_UNBOUNDED, RID_COMPLEX, RID_THREAD,
/* C++ */
RID_FRIEND, RID_VIRTUAL, RID_EXPLICIT, RID_EXPORT, RID_MUTABLE,

View File

@ -3350,9 +3350,19 @@ start_decl (declarator, declspecs, initialized, attributes)
/* ANSI specifies that a tentative definition which is not merged with
a non-tentative definition behaves exactly like a definition with an
initializer equal to zero. (Section 3.7.2)
-fno-common gives strict ANSI behavior. Usually you don't want it.
This matters only for variables with external linkage. */
if (!initialized && (! flag_no_common || ! TREE_PUBLIC (decl)))
-fno-common gives strict ANSI behavior, though this tends to break
a large body of code that grew up without this rule.
Thread-local variables are never common, since there's no entrenched
body of code to break, and it allows more efficient variable references
in the presense of dynamic linking. */
if (TREE_CODE (decl) == VAR_DECL
&& !initialized
&& TREE_PUBLIC (decl)
&& !DECL_THREAD_LOCAL (decl)
&& !flag_no_common)
DECL_COMMON (decl) = 1;
/* Set attributes here so if duplicate decl, will have proper attributes. */
@ -3933,7 +3943,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
enum rid i = C_RID_CODE (id);
if ((int) i <= (int) RID_LAST_MODIFIER)
{
if (i == RID_LONG && (specbits & (1 << (int) i)))
if (i == RID_LONG && (specbits & (1 << (int) RID_LONG)))
{
if (longlong)
error ("`long long long' is too long for GCC");
@ -3947,6 +3957,19 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
}
else if (specbits & (1 << (int) i))
pedwarn ("duplicate `%s'", IDENTIFIER_POINTER (id));
/* Diagnose "__thread extern". Recall that this list
is in the reverse order seen in the text. */
if (i == RID_THREAD
&& (specbits & (1 << (int) RID_EXTERN
| 1 << (int) RID_STATIC)))
{
if (specbits & 1 << (int) RID_EXTERN)
error ("`__thread' before `extern'");
else
error ("`__thread' before `static'");
}
specbits |= 1 << (int) i;
goto found;
}
@ -4196,6 +4219,12 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
if (specbits & 1 << (int) RID_REGISTER) nclasses++;
if (specbits & 1 << (int) RID_TYPEDEF) nclasses++;
/* "static __thread" and "extern __thread" are allowed. */
if ((specbits & (1 << (int) RID_THREAD
| 1 << (int) RID_STATIC
| 1 << (int) RID_EXTERN)) == (1 << (int) RID_THREAD))
nclasses++;
/* Warn about storage classes that are invalid for certain
kinds of declarations (parameters, typenames, etc.). */
@ -4205,7 +4234,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
&& (specbits
& ((1 << (int) RID_REGISTER)
| (1 << (int) RID_AUTO)
| (1 << (int) RID_TYPEDEF))))
| (1 << (int) RID_TYPEDEF)
| (1 << (int) RID_THREAD))))
{
if (specbits & 1 << (int) RID_AUTO
&& (pedantic || current_binding_level == global_binding_level))
@ -4214,8 +4244,10 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
error ("function definition declared `register'");
if (specbits & 1 << (int) RID_TYPEDEF)
error ("function definition declared `typedef'");
if (specbits & 1 << (int) RID_THREAD)
error ("function definition declared `__thread'");
specbits &= ~((1 << (int) RID_TYPEDEF) | (1 << (int) RID_REGISTER)
| (1 << (int) RID_AUTO));
| (1 << (int) RID_AUTO) | (1 << (int) RID_THREAD));
}
else if (decl_context != NORMAL && nclasses > 0)
{
@ -4238,7 +4270,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
}
specbits &= ~((1 << (int) RID_TYPEDEF) | (1 << (int) RID_REGISTER)
| (1 << (int) RID_AUTO) | (1 << (int) RID_STATIC)
| (1 << (int) RID_EXTERN));
| (1 << (int) RID_EXTERN) | (1 << (int) RID_THREAD));
}
}
else if (specbits & 1 << (int) RID_EXTERN && initialized && ! funcdef_flag)
@ -4249,12 +4281,25 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
else
error ("`%s' has both `extern' and initializer", name);
}
else if (specbits & 1 << (int) RID_EXTERN && funcdef_flag
&& current_binding_level != global_binding_level)
error ("nested function `%s' declared `extern'", name);
else if (current_binding_level == global_binding_level
&& specbits & (1 << (int) RID_AUTO))
error ("top-level declaration of `%s' specifies `auto'", name);
else if (current_binding_level == global_binding_level)
{
if (specbits & 1 << (int) RID_AUTO)
error ("top-level declaration of `%s' specifies `auto'", name);
}
else
{
if (specbits & 1 << (int) RID_EXTERN && funcdef_flag)
error ("nested function `%s' declared `extern'", name);
else if ((specbits & (1 << (int) RID_THREAD
| 1 << (int) RID_EXTERN
| 1 << (int) RID_STATIC))
== (1 << (int) RID_THREAD))
{
error ("function-scope `%s' implicitly auto and declared `__thread'",
name);
specbits &= ~(1 << (int) RID_THREAD);
}
}
}
/* Now figure out the structure of the declarator proper.
@ -4842,6 +4887,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
pedwarn ("invalid storage class for function `%s'", name);
if (specbits & (1 << (int) RID_REGISTER))
error ("invalid storage class for function `%s'", name);
if (specbits & (1 << (int) RID_THREAD))
error ("invalid storage class for function `%s'", name);
/* Function declaration not at top level.
Storage classes other than `extern' are not allowed
and `extern' makes no difference. */
@ -4934,22 +4981,32 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
pedwarn_with_decl (decl, "variable `%s' declared `inline'");
DECL_EXTERNAL (decl) = extern_ref;
/* At top level, the presence of a `static' or `register' storage
class specifier, or the absence of all storage class specifiers
makes this declaration a definition (perhaps tentative). Also,
the absence of both `static' and `register' makes it public. */
if (current_binding_level == global_binding_level)
{
TREE_PUBLIC (decl)
= !(specbits
& ((1 << (int) RID_STATIC) | (1 << (int) RID_REGISTER)));
TREE_STATIC (decl) = ! DECL_EXTERNAL (decl);
TREE_PUBLIC (decl) = !(specbits & ((1 << (int) RID_STATIC)
| (1 << (int) RID_REGISTER)));
TREE_STATIC (decl) = !extern_ref;
}
/* Not at top level, only `static' makes a static definition. */
else
{
TREE_STATIC (decl) = (specbits & (1 << (int) RID_STATIC)) != 0;
TREE_PUBLIC (decl) = DECL_EXTERNAL (decl);
TREE_PUBLIC (decl) = extern_ref;
}
if (specbits & 1 << (int) RID_THREAD)
{
if (targetm.have_tls)
DECL_THREAD_LOCAL (decl) = 1;
else
/* A mere warning is sure to result in improper semantics
at runtime. Don't bother to allow this to compile. */
error ("thread-local storage not supported for this target");
}
}

View File

@ -3343,6 +3343,7 @@ static const struct resword reswords[] =
{ "__restrict__", RID_RESTRICT, 0 },
{ "__signed", RID_SIGNED, 0 },
{ "__signed__", RID_SIGNED, 0 },
{ "__thread", RID_THREAD, 0 },
{ "__typeof", RID_TYPEOF, 0 },
{ "__typeof__", RID_TYPEOF, 0 },
{ "__unbounded", RID_UNBOUNDED, 0 },
@ -3438,6 +3439,7 @@ static const short rid_to_yy[RID_MAX] =
/* RID_BOUNDED */ TYPE_QUAL,
/* RID_UNBOUNDED */ TYPE_QUAL,
/* RID_COMPLEX */ TYPESPEC,
/* RID_THREAD */ SCSPEC,
/* C++ */
/* RID_FRIEND */ 0,

View File

@ -1,3 +1,7 @@
2002-05-21 Richard Henderson <rth@redhat.com>
* lex.c (rid_to_yy): Add RID_THREAD.
2002-05-21 Alexandre Oliva <aoliva@redhat.com>
* init.c (build_vec_init): Test for trivial copy-assignment when

View File

@ -474,6 +474,7 @@ const short rid_to_yy[RID_MAX] =
/* RID_BOUNDED */ 0,
/* RID_UNBOUNDED */ 0,
/* RID_COMPLEX */ TYPESPEC,
/* RID_THREAD */ 0,
/* C++ */
/* RID_FRIEND */ SCSPEC,

View File

@ -432,6 +432,7 @@ extensions, accepted by GCC in C89 mode and in C++.
* Target Builtins:: Built-in functions specific to particular targets.
* Pragmas:: Pragmas accepted by GCC.
* Unnamed Fields:: Unnamed struct/union fields within structs/unions.
* Thread-Local:: Per-thread variables.
@end menu
@node Statement Exprs
@ -6165,6 +6166,55 @@ It is ambiguous which @code{a} is being referred to with @samp{foo.a}.
Such constructs are not supported and must be avoided. In the future,
such constructs may be detected and treated as compilation errors.
@node Thread-Local
@section Thread-Local Storage
@cindex Thread-Local Storage
@cindex TLS
@cindex __thread
Thread-local storage (TLS) is a mechanism by which variables are
allocated such that there is one instance of the variable per extant
thread. The run-time model GCC uses to implement this originates
in the IA-64 processor-specific ABI, but has since been migrated
to other processors as well. It requires significant support from
the linker (@command{ld}), dynamic linker (@command{ld.so}), and
system libraries (@file{libc.so} and @file{libpthread.so}), so it
is not supported everywhere.
At the user level, the extension is visible with a new storage
class keyword: @code{__thread}. For example:
@example
__thread int i;
extern __thread struct state s;
static __thread char *p;
@end example
The @code{__thread} specifier may be used alone, with the @code{extern}
or @code{static} specifiers, but with no other storage class specifier.
When used with @code{extern} or @code{static}, @code{__thread} must appear
immediately after the other storage class specifier.
The @code{__thread} specifier may be applied to any global, file-scoped
static, function-scoped static, or class-scoped static variable. It may
not be applied to function-scoped automatic or class-scoped member variables.
When the address-of operator is applied to a thread-local variable, it is
evaluated at run-time and returns the address of the current thread's
instance of that variable. An address so obtained may be used by any
thread. When a thread terminates, any pointers to thread-local variables
in that thread become invalid.
No static initialization may refer to the address of a thread-local variable.
In C++, a thread-local variable may not be initialized by a static
constructor.
See @uref{http://people.redhat.com/drepper/tls.pdf,
ELF Handling For Thread-Local Storage} for a detailed explanation of
the four thread-local storage addressing models, and how the run-time
is expected to function.
@node C++ Extensions
@chapter Extensions to the C++ Language
@cindex extensions, C++ language

View File

@ -677,7 +677,7 @@ in the following sections.
-fverbose-asm -fpack-struct -fstack-check @gol
-fstack-limit-register=@var{reg} -fstack-limit-symbol=@var{sym} @gol
-fargument-alias -fargument-noalias @gol
-fargument-noalias-global -fleading-underscore}
-fargument-noalias-global -fleading-underscore -ftls-model=@var{model}}
@end table
@menu
@ -9915,6 +9915,14 @@ is to help link with legacy assembly code.
Be warned that you should know what you are doing when invoking this
option, and that not all targets provide complete support for it.
@item -ftls-model=@var{model}
Alter the thread-local storage model to be used (@pxref{Thread-Local}).
The @var{model} argument should be one of @code{global-dynamic},
@code{local-dynamic}, @code{initial-exec} or @code{local-exec}.
The default without @option{-fpic} is @code{initial-exec}; with
@option{-fpic} the default is @code{global-dynamic}.
@end table
@c man end

View File

@ -5,7 +5,7 @@
* files which are fixed to work correctly with ANSI C and placed in a
* directory that GNU C will search.
*
* This file contains 145 fixup descriptions.
* This file contains 146 fixup descriptions.
*
* See README for more information.
*
@ -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,

View File

@ -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

View File

@ -458,11 +458,22 @@ extern int flag_dump_unnumbered;
extern int flag_pedantic_errors;
/* Nonzero means generate position-independent code.
This is not fully implemented yet. */
/* Nonzero means generate position-independent code. 1 vs 2 for a
target-dependent "small" or "large" mode. */
extern int flag_pic;
/* Set to the default thread-local storage (tls) model to use. */
enum tls_model {
TLS_MODEL_GLOBAL_DYNAMIC,
TLS_MODEL_LOCAL_DYNAMIC,
TLS_MODEL_INITIAL_EXEC,
TLS_MODEL_LOCAL_EXEC
};
extern enum tls_model flag_tls_default;
/* Nonzero means generate extra code for exception handling and enable
exception handling. */

View File

@ -507,7 +507,8 @@ extern void no_asm_to_stream PARAMS ((FILE *));
#define SECTION_STRINGS 0x10000 /* contains zero terminated strings without
embedded zeros */
#define SECTION_OVERRIDE 0x20000 /* allow override of default flags */
#define SECTION_MACH_DEP 0x40000 /* subsequent bits reserved for target */
#define SECTION_TLS 0x40000 /* contains thread-local storage */
#define SECTION_MACH_DEP 0x80000 /* subsequent bits reserved for target */
extern unsigned int get_named_section_flags PARAMS ((const char *));
extern bool set_named_section_flags PARAMS ((const char *, unsigned int));

View File

@ -352,6 +352,8 @@ print_node (file, prefix, node, indent)
if (TREE_CODE (node) == VAR_DECL && DECL_IN_TEXT_SECTION (node))
fputs (" in-text-section", file);
if (TREE_CODE (node) == VAR_DECL && DECL_THREAD_LOCAL (node))
fputs (" thread-local", file);
if (TREE_CODE (node) == PARM_DECL && DECL_TRANSPARENT_UNION (node))
fputs (" transparent-union", file);

View 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"

View File

@ -256,6 +256,9 @@ struct gcc_target
/* True if "native" constructors and destructors are supported,
false if we're using collect2 for the job. */
bool have_ctors_dtors;
/* True if thread-local storage is supported. */
bool have_tls;
};
extern struct gcc_target targetm;

View File

@ -685,12 +685,15 @@ int flag_shared_data;
int flag_delayed_branch;
/* Nonzero if we are compiling pure (sharable) code.
Value is 1 if we are doing reasonable (i.e. simple
offset into offset table) pic. Value is 2 if we can
only perform register offsets. */
Value is 1 if we are doing "small" pic; value is 2 if we're doing
"large" pic. */
int flag_pic;
/* Set to the default thread-local storage (tls) model to use. */
enum tls_model flag_tls_default;
/* Nonzero means generate extra code for exception handling and enable
exception handling. */
@ -3547,6 +3550,7 @@ display_help ()
printf (_(" -finline-limit=<number> Limits the size of inlined functions to <number>\n"));
printf (_(" -fmessage-length=<number> Limits diagnostics messages lengths to <number> characters per line. 0 suppresses line-wrapping\n"));
printf (_(" -fdiagnostics-show-location=[once | every-line] Indicates how often source location information should be emitted, as prefix, at the beginning of diagnostics when line-wrapping\n"));
printf (_(" -ftls-model=[global-dynamic | local-dynamic | initial-exec | local-exec] Indicates the default thread-local storage code generation model\n"));
for (i = ARRAY_SIZE (f_options); i--;)
{
@ -3825,6 +3829,19 @@ decode_f_option (arg)
MAX_INLINE_INSNS);
set_param_value ("max-inline-insns", val);
}
else if ((option_value = skip_leading_substring (arg, "tls-model=")))
{
if (strcmp (option_value, "global-dynamic") == 0)
flag_tls_default = TLS_MODEL_GLOBAL_DYNAMIC;
else if (strcmp (option_value, "local-dynamic") == 0)
flag_tls_default = TLS_MODEL_LOCAL_DYNAMIC;
else if (strcmp (option_value, "initial-exec") == 0)
flag_tls_default = TLS_MODEL_INITIAL_EXEC;
else if (strcmp (option_value, "local-exec") == 0)
flag_tls_default = TLS_MODEL_LOCAL_EXEC;
else
warning ("`%s': unknown tls-model option", arg - 2);
}
#ifdef INSN_SCHEDULING
else if ((option_value = skip_leading_substring (arg, "sched-verbose=")))
fix_sched_param ("verbose", option_value);

View File

@ -1349,12 +1349,13 @@ staticp (arg)
case FUNCTION_DECL:
/* Nested functions aren't static, since taking their address
involves a trampoline. */
return (decl_function_context (arg) == 0 || DECL_NO_STATIC_CHAIN (arg))
&& ! DECL_NON_ADDR_CONST_P (arg);
return ((decl_function_context (arg) == 0 || DECL_NO_STATIC_CHAIN (arg))
&& ! DECL_NON_ADDR_CONST_P (arg));
case VAR_DECL:
return (TREE_STATIC (arg) || DECL_EXTERNAL (arg))
&& ! DECL_NON_ADDR_CONST_P (arg);
return ((TREE_STATIC (arg) || DECL_EXTERNAL (arg))
&& ! DECL_THREAD_LOCAL (arg)
&& ! DECL_NON_ADDR_CONST_P (arg));
case CONSTRUCTOR:
return TREE_STATIC (arg);

View File

@ -1615,6 +1615,10 @@ struct tree_type
/* In a FUNCTION_DECL, nonzero if the function cannot be inlined. */
#define DECL_UNINLINABLE(NODE) (FUNCTION_DECL_CHECK (NODE)->decl.uninlinable)
/* In a VAR_DECL, nonzero if the data should be allocated from
thread-local storage. */
#define DECL_THREAD_LOCAL(NODE) (VAR_DECL_CHECK (NODE)->decl.thread_local_flag)
/* In a FUNCTION_DECL, the saved representation of the body of the
entire function. Usually a COMPOUND_STMT, but in C++ this may also
be a RETURN_INIT, CTOR_INITIALIZER, or TRY_BLOCK. */
@ -1793,7 +1797,8 @@ struct tree_decl
unsigned non_addressable : 1;
unsigned user_align : 1;
unsigned uninlinable : 1;
/* Three unused bits. */
unsigned thread_local_flag : 1;
/* Two unused bits. */
unsigned lang_flag_0 : 1;
unsigned lang_flag_1 : 1;

View File

@ -1586,19 +1586,28 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
/* Handle uninitialized definitions. */
if ((DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node
#if defined ASM_EMIT_BSS
|| (flag_zero_initialized_in_bss
&& initializer_zerop (DECL_INITIAL (decl)))
/* 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;