Makefile.in (libgcc-support, [...]): Add emutls.c.

gcc/ChangeLog:
* Makefile.in (libgcc-support, libgcc.mvars): Add emutls.c.
* builtin-types.def (BT_WORD): Make unsigned.
(BT_FN_VOID_PTR_WORD_WORD_PTR): New.
* builtins.def (BUILT_IN_EMUTLS_GET_ADDRESS): New.
(BUILT_IN_EMUTLS_REGISTER_COMMON): New.
* c-decl.c (grokdeclarator): Don't error if !have_tls.
* c-parser.c (c_parser_omp_threadprivate): Likewise.
* dwarf2out.c (loc_descriptor_from_tree_1): Don't do anything for
emulated tls.
* expr.c (emutls_var_address): New.
(expand_expr_real_1): Expand emulated tls.
(expand_expr_addr_expr_1): Likewise.
* libgcc-std.ver: Add __emutls_get_address, __emutls_register_common.
* output.h (emutls_finish): Declare.
* toplev.c (compile_file): Call it.
* tree-ssa-address.c (gen_addr_rtx): Check for const-ness of the
address before wrapping in CONST.
* varasm.c (emutls_htab, emutls_object_type): New.
(EMUTLS_VAR_PREFIX, EMUTLS_TMPL_PREFIX): New.
(get_emutls_object_name, get_emutls_object_type): New.
(get_emutls_init_templ_addr, emutls_decl): New.
(emutls_common_1, emutls_finish): New.
(assemble_variable): When emulating tls, swap decls; generate
constructor for the emutls objects.
(do_assemble_alias): When emulating tls, swap decl and target name.
(default_encode_section_info): Don't add SYMBOL_FLAG_TLS_SHIFT
for emulated tls.
* varpool.c (decide_is_variable_needed): Look at force_output.
Recurse for emulated tls.
(cgraph_varpool_remove_unreferenced_decls): Remove checks redundant
with decide_is_variable_needed.
* emutls.c: New file.
* config/sparc/sol2.h (ASM_DECLARE_OBJECT_NAME): Only emit
tls_object for real tls.
gcc/cp/ChangeLog:
* decl.c (grokvardecl): Don't error if !have_tls.
(grokdeclarator): Likewise.
* parser.c (cp_parser_omp_threadprivate): Likewise.
gcc/fortran/ChangeLog:
* f95-lang.c (gfc_init_builtin_functions): Add __emutls_get_address
and __emutls_register_common.
* openmp.c (gfc_match_omp_threadprivate): Don't error if !have_tls.
* trans-common.c (build_common_decl): Don't check have_tls.
* trans-decl.c (gfc_finish_var_decl): Likewise.
* types.def (BT_WORD, BT_FN_PTR_PTR): New.
(BT_FN_VOID_PTR_WORD_WORD_PTR): New.
gcc/testsuite/ChangeLog:
* lib/target-supports.exp (check_effective_target_tls): Redefine
to mean non-emulated tls.
* gcc.dg/tls/alias-1.c: Remove tls requirement.
* gcc.dg/tls/asm-1.c, gcc.dg/tls/debug-1.c, gcc.dg/tls/diag-1.c,
gcc.dg/tls/diag-2.c, gcc.dg/tls/diag-3.c, gcc.dg/tls/diag-4.c,
gcc.dg/tls/diag-5.c, gcc.dg/tls/init-1.c, gcc.dg/tls/nonpic-1.c,
gcc.dg/tls/opt-10.c, gcc.dg/tls/opt-5.c, gcc.dg/tls/opt-6.c,
gcc.dg/tls/opt-8.c, gcc.dg/tls/opt-9.c, gcc.dg/tls/pic-1.c,
gcc.dg/tls/struct-1.c, gcc.dg/tls/trivial.c: Likewise.

From-SVN: r121800
This commit is contained in:
Richard Henderson 2007-02-10 11:19:10 -08:00 committed by Alexandre Oliva
parent ba9652fcb4
commit 8893239dc4
46 changed files with 677 additions and 82 deletions

View File

@ -1,3 +1,40 @@
2007-02-10 Richard Henderson <rth@redhat.com>, Jakub Jelinek <jakub@redhat.com>, Alexandre Oliva <aoliva@redhat.com>
* Makefile.in (libgcc-support, libgcc.mvars): Add emutls.c.
* builtin-types.def (BT_WORD): Make unsigned.
(BT_FN_VOID_PTR_WORD_WORD_PTR): New.
* builtins.def (BUILT_IN_EMUTLS_GET_ADDRESS): New.
(BUILT_IN_EMUTLS_REGISTER_COMMON): New.
* c-decl.c (grokdeclarator): Don't error if !have_tls.
* c-parser.c (c_parser_omp_threadprivate): Likewise.
* dwarf2out.c (loc_descriptor_from_tree_1): Don't do anything for
emulated tls.
* expr.c (emutls_var_address): New.
(expand_expr_real_1): Expand emulated tls.
(expand_expr_addr_expr_1): Likewise.
* libgcc-std.ver: Add __emutls_get_address, __emutls_register_common.
* output.h (emutls_finish): Declare.
* toplev.c (compile_file): Call it.
* tree-ssa-address.c (gen_addr_rtx): Check for const-ness of the
address before wrapping in CONST.
* varasm.c (emutls_htab, emutls_object_type): New.
(EMUTLS_VAR_PREFIX, EMUTLS_TMPL_PREFIX): New.
(get_emutls_object_name, get_emutls_object_type): New.
(get_emutls_init_templ_addr, emutls_decl): New.
(emutls_common_1, emutls_finish): New.
(assemble_variable): When emulating tls, swap decls; generate
constructor for the emutls objects.
(do_assemble_alias): When emulating tls, swap decl and target name.
(default_encode_section_info): Don't add SYMBOL_FLAG_TLS_SHIFT
for emulated tls.
* varpool.c (decide_is_variable_needed): Look at force_output.
Recurse for emulated tls.
(cgraph_varpool_remove_unreferenced_decls): Remove checks redundant
with decide_is_variable_needed.
* emutls.c: New file.
* config/sparc/sol2.h (ASM_DECLARE_OBJECT_NAME): Only emit
tls_object for real tls.
2007-02-10 Kaz Kojima <kkojima@gcc.gnu.org>
PR rtl-optimization/29599

View File

@ -1566,7 +1566,7 @@ GCC_EXTRA_PARTS := $(sort $(EXTRA_MULTILIB_PARTS) $(EXTRA_PARTS))
libgcc-support: libgcc.mvars stmp-int-hdrs $(STMP_FIXPROTO) $(TCONFIG_H) \
$(MACHMODE_H) $(FPBIT) $(DPBIT) $(TPBIT) $(LIB2ADD) \
$(LIB2ADD_ST) $(LIB2ADDEH) gcov-iov.h $(SFP_MACHINE)
$(LIB2ADD_ST) $(LIB2ADDEH) $(srcdir)/emutls.c gcov-iov.h $(SFP_MACHINE)
libgcc.mvars: config.status Makefile $(LIB2ADD) $(LIB2ADD_ST) specs \
xgcc$(exeext) stamp-as stamp-collect-ld stamp-nm
@ -1578,9 +1578,9 @@ libgcc.mvars: config.status Makefile $(LIB2ADD) $(LIB2ADD_ST) specs \
echo LIBGCOV = '$(LIBGCOV)' >> tmp-libgcc.mvars
echo LIB2ADD = '$(call srcdirify,$(LIB2ADD))' >> tmp-libgcc.mvars
echo LIB2ADD_ST = '$(call srcdirify,$(LIB2ADD_ST))' >> tmp-libgcc.mvars
echo LIB2ADDEH = '$(call srcdirify,$(LIB2ADDEH))' >> tmp-libgcc.mvars
echo LIB2ADDEHSTATIC = '$(call srcdirify,$(LIB2ADDEHSTATIC))' >> tmp-libgcc.mvars
echo LIB2ADDEHSHARED = '$(call srcdirify,$(LIB2ADDEHSHARED))' >> tmp-libgcc.mvars
echo LIB2ADDEH = '$(call srcdirify,$(LIB2ADDEH) $(srcdir)/emutls.c)' >> tmp-libgcc.mvars
echo LIB2ADDEHSTATIC = '$(call srcdirify,$(LIB2ADDEHSTATIC) $(srcdir)/emutls.c)' >> tmp-libgcc.mvars
echo LIB2ADDEHSHARED = '$(call srcdirify,$(LIB2ADDEHSHARED) $(srcdir)/emutls.c)' >> tmp-libgcc.mvars
echo LIB2_SIDITI_CONV_FUNCS = '$(LIB2_SIDITI_CONV_FUNCS)' >> tmp-libgcc.mvars
echo LIBUNWIND = '$(call srcdirify,$(LIBUNWIND))' >> tmp-libgcc.mvars
echo SHLIBUNWIND_LINK = '$(SHLIBUNWIND_LINK)' >> tmp-libgcc.mvars

View File

@ -77,7 +77,7 @@ DEF_PRIMITIVE_TYPE (BT_INTMAX, intmax_type_node)
DEF_PRIMITIVE_TYPE (BT_UINTMAX, uintmax_type_node)
DEF_PRIMITIVE_TYPE (BT_UINT32, uint32_type_node)
DEF_PRIMITIVE_TYPE (BT_UINT64, uint64_type_node)
DEF_PRIMITIVE_TYPE (BT_WORD, (*lang_hooks.types.type_for_mode) (word_mode, 0))
DEF_PRIMITIVE_TYPE (BT_WORD, (*lang_hooks.types.type_for_mode) (word_mode, 1))
DEF_PRIMITIVE_TYPE (BT_FLOAT, float_type_node)
DEF_PRIMITIVE_TYPE (BT_DOUBLE, double_type_node)
DEF_PRIMITIVE_TYPE (BT_LONGDOUBLE, long_double_type_node)
@ -388,6 +388,8 @@ DEF_FUNCTION_TYPE_4 (BT_FN_INT_FILEPTR_INT_CONST_STRING_VALIST_ARG,
BT_INT, BT_FILEPTR, BT_INT, BT_CONST_STRING, BT_VALIST_ARG)
DEF_FUNCTION_TYPE_4 (BT_FN_VOID_OMPFN_PTR_UINT_UINT,
BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, BT_UINT)
DEF_FUNCTION_TYPE_4 (BT_FN_VOID_PTR_WORD_WORD_PTR,
BT_VOID, BT_PTR, BT_WORD, BT_WORD, BT_PTR)
DEF_FUNCTION_TYPE_5 (BT_FN_INT_STRING_INT_SIZE_CONST_STRING_VALIST_ARG,
BT_INT, BT_STRING, BT_INT, BT_SIZE, BT_CONST_STRING,

View File

@ -1,6 +1,6 @@
/* This file contains the definitions and documentation for the
builtins used in the GNU compiler.
Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005
Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
This file is part of GCC.
@ -729,6 +729,10 @@ DEF_EXT_LIB_BUILTIN (BUILT_IN_VPRINTF_CHK, "__vprintf_chk", BT_FN_INT_INT_CON
DEF_BUILTIN_STUB (BUILT_IN_PROFILE_FUNC_ENTER, "profile_func_enter")
DEF_BUILTIN_STUB (BUILT_IN_PROFILE_FUNC_EXIT, "profile_func_exit")
/* TLS emulation. */
DEF_EXT_LIB_BUILTIN (BUILT_IN_EMUTLS_GET_ADDRESS, "__emutls_get_address", BT_FN_PTR_PTR, ATTR_CONST_NOTHROW_NONNULL)
DEF_EXT_LIB_BUILTIN (BUILT_IN_EMUTLS_REGISTER_COMMON, "__emutls_register_common", BT_FN_VOID_PTR_WORD_WORD_PTR, ATTR_NOTHROW_LIST)
/* Synchronization Primitives. */
#include "sync-builtins.def"

View File

@ -4927,14 +4927,7 @@ grokdeclarator (const struct c_declarator *declarator,
}
if (threadp)
{
if (targetm.have_tls)
DECL_TLS_MODEL (decl) = decl_default_tls_model (decl);
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");
}
DECL_TLS_MODEL (decl) = decl_default_tls_model (decl);
}
if (storage_class == csc_extern

View File

@ -7783,9 +7783,6 @@ c_parser_omp_threadprivate (c_parser *parser)
c_parser_consume_pragma (parser);
vars = c_parser_omp_var_list_parens (parser, 0, NULL);
if (!targetm.have_tls)
sorry ("threadprivate variables not supported in this target");
/* Mark every variable in VARS to be assigned thread local storage. */
for (t = vars; t; t = TREE_CHAIN (t))
{

View File

@ -89,7 +89,7 @@ Boston, MA 02110-1301, USA. */
{ \
HOST_WIDE_INT size; \
\
if (DECL_THREAD_LOCAL_P (DECL)) \
if (targetm.have_tls && DECL_THREAD_LOCAL_P (DECL)) \
ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "tls_object"); \
else \
ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object"); \

View File

@ -1,3 +1,9 @@
2007-02-10 Richard Henderson <rth@redhat.com>, Jakub Jelinek <jakub@redhat.com>
* decl.c (grokvardecl): Don't error if !have_tls.
(grokdeclarator): Likewise.
* parser.c (cp_parser_omp_threadprivate): Likewise.
2007-02-07 Jakub Jelinek <jakub@redhat.com>
PR c++/30703

View File

@ -6363,14 +6363,7 @@ grokvardecl (tree type,
}
if (declspecs->specs[(int)ds_thread])
{
if (targetm.have_tls)
DECL_TLS_MODEL (decl) = decl_default_tls_model (decl);
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");
}
DECL_TLS_MODEL (decl) = decl_default_tls_model (decl);
if (TREE_PUBLIC (decl))
{
@ -8539,15 +8532,7 @@ grokdeclarator (const cp_declarator *declarator,
DECL_EXTERNAL (decl) = 1;
if (thread_p)
{
if (targetm.have_tls)
DECL_TLS_MODEL (decl) = decl_default_tls_model (decl);
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");
}
DECL_TLS_MODEL (decl) = decl_default_tls_model (decl);
}
else
{

View File

@ -19312,9 +19312,6 @@ cp_parser_omp_threadprivate (cp_parser *parser, cp_token *pragma_tok)
vars = cp_parser_omp_var_list (parser, 0, NULL);
cp_parser_require_pragma_eol (parser, pragma_tok);
if (!targetm.have_tls)
sorry ("threadprivate variables not supported in this target");
finish_omp_threadprivate (vars);
}

View File

@ -9226,7 +9226,7 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
rtx rtl;
/* If this is not defined, we have no way to emit the data. */
if (!targetm.asm_out.output_dwarf_dtprel)
if (!targetm.have_tls || !targetm.asm_out.output_dwarf_dtprel)
return 0;
/* The way DW_OP_GNU_push_tls_address is specified, we can only

View File

@ -0,0 +1,193 @@
/* TLS emulation.
Copyright (C) 2006 Free Software Foundation, Inc.
Contributed by Jakub Jelinek <jakub@redhat.com>.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
In addition to the permissions in the GNU General Public License, the
Free Software Foundation gives you unlimited permission to link the
compiled version of this file into combinations with other programs,
and to distribute those combinations without any restriction coming
from the use of this file. (The General Public License restrictions
do apply in other respects; for example, they cover modification of
the file, and distribution when not linked into a combine
executable.)
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA. */
#include "tconfig.h"
#include "tsystem.h"
#include "coretypes.h"
#include "tm.h"
#include "gthr.h"
typedef unsigned int word __attribute__((mode(word)));
typedef unsigned int pointer __attribute__((mode(pointer)));
struct __emutls_object
{
word size;
word align;
union {
pointer offset;
void *ptr;
} loc;
void *templ;
};
#ifdef __GTHREADS
#ifdef __GTHREAD_MUTEX_INIT
static __gthread_mutex_t emutls_mutex = __GTHREAD_MUTEX_INIT;
#else
static __gthread_mutex_t emutls_mutex;
#endif
static __gthread_key_t emutls_key;
static pointer emutls_size;
static void
emutls_destroy (void *ptr)
{
void ***arr = (void ***) ptr;
unsigned long int size = (unsigned long int) arr[0];
++arr;
while (--size)
{
if (*arr)
free ((*arr)[-1]);
++arr;
}
free (ptr);
}
static void
emutls_init (void)
{
#ifndef __GTHREAD_MUTEX_INIT
__GTHREAD_MUTEX_INIT_FUNCTION (&emutls_mutex);
#endif
if (__gthread_key_create (&emutls_key, emutls_destroy) != 0)
abort ();
}
#endif
static void *
emutls_alloc (struct __emutls_object *obj)
{
void *ptr;
void *ret;
/* We could use here posix_memalign if available and adjust
emutls_destroy accordingly. */
if (obj->align <= sizeof (void *))
{
ptr = malloc (obj->size + sizeof (void *));
if (ptr == NULL)
abort ();
((void **) ptr)[0] = ptr;
ret = ptr + sizeof (void *);
}
else
{
ptr = malloc (obj->size + sizeof (void *) + obj->align - 1);
if (ptr == NULL)
abort ();
ret = (void *) (((pointer) (ptr + sizeof (void *) + obj->align - 1))
& ~(pointer)(obj->align - 1));
((void **) ret)[-1] = ptr;
}
if (obj->templ)
memcpy (ret, obj->templ, obj->size);
else
memset (ret, 0, obj->size);
return ret;
}
void *
__emutls_get_address (struct __emutls_object *obj)
{
if (! __gthread_active_p ())
{
if (__builtin_expect (obj->loc.ptr == NULL, 0))
obj->loc.ptr = emutls_alloc (obj);
return obj->loc.ptr;
}
#ifndef __GTHREADS
abort ();
#else
pointer offset;
if (__builtin_expect (obj->loc.offset == 0, 0))
{
static __gthread_once_t once = __GTHREAD_ONCE_INIT;
__gthread_once (&once, emutls_init);
__gthread_mutex_lock (&emutls_mutex);
offset = ++emutls_size;
obj->loc.offset = offset;
__gthread_mutex_unlock (&emutls_mutex);
}
else
offset = obj->loc.offset;
void **arr = (void **) __gthread_getspecific (emutls_key);
if (__builtin_expect (arr == NULL, 0))
{
pointer size = offset + 32;
arr = calloc (size, sizeof (void *));
if (arr == NULL)
abort ();
arr[0] = (void *) size;
__gthread_setspecific (emutls_key, (void *) arr);
}
else if (__builtin_expect (offset >= (pointer) arr[0], 0))
{
pointer orig_size = (pointer) arr[0];
pointer size = orig_size * 2;
if (offset >= size)
size = offset + 32;
arr = realloc (arr, size * sizeof (void *));
if (arr == NULL)
abort ();
memset (arr + orig_size, 0, (size - orig_size) * sizeof (void *));
__gthread_setspecific (emutls_key, (void *) arr);
}
void *ret = arr[offset];
if (__builtin_expect (ret == NULL, 0))
{
ret = emutls_alloc (obj);
arr[offset] = ret;
}
return ret;
#endif
}
void
__emutls_register_common (struct __emutls_object *obj,
word size, word align, void *templ)
{
if (obj->size < size)
{
obj->size = size;
obj->templ = NULL;
}
if (obj->align < align)
obj->align = align;
if (templ && size == obj->size)
obj->templ = templ;
}

View File

@ -6421,6 +6421,19 @@ highest_pow2_factor_for_target (tree target, tree exp)
return MAX (factor, target_align);
}
/* Return &VAR expression for emulated thread local VAR. */
static tree
emutls_var_address (tree var)
{
tree emuvar = emutls_decl (var);
tree fn = built_in_decls [BUILT_IN_EMUTLS_GET_ADDRESS];
tree arg = build_fold_addr_expr_with_type (emuvar, ptr_type_node);
tree arglist = build_tree_list (NULL_TREE, arg);
tree call = build_function_call_expr (fn, arglist);
return fold_convert (build_pointer_type (TREE_TYPE (var)), call);
}
/* Expands variable VAR. */
void
@ -6549,6 +6562,18 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode,
inner = TREE_OPERAND (exp, 0);
break;
case VAR_DECL:
/* TLS emulation hook - replace __thread VAR's &VAR with
__emutls_get_address (&_emutls.VAR). */
if (! targetm.have_tls
&& TREE_CODE (exp) == VAR_DECL
&& DECL_THREAD_LOCAL_P (exp))
{
exp = emutls_var_address (exp);
return expand_expr (exp, target, tmode, modifier);
}
/* Fall through. */
default:
/* If the object is a DECL, then expand it for its rtl. Don't bypass
expand_expr, as that can have various side effects; LABEL_DECLs for
@ -6924,6 +6949,16 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
&& (TREE_STATIC (exp) || DECL_EXTERNAL (exp)))
layout_decl (exp, 0);
/* TLS emulation hook - replace __thread vars with
*__emutls_get_address (&_emutls.var). */
if (! targetm.have_tls
&& TREE_CODE (exp) == VAR_DECL
&& DECL_THREAD_LOCAL_P (exp))
{
exp = build_fold_indirect_ref (emutls_var_address (exp));
return expand_expr_real_1 (exp, target, tmode, modifier, NULL);
}
/* ... fall through ... */
case FUNCTION_DECL:

View File

@ -1,3 +1,13 @@
2007-02-10 Richard Henderson <rth@redhat.com>, Jakub Jelinek <jakub@redhat.com>
* f95-lang.c (gfc_init_builtin_functions): Add __emutls_get_address
and __emutls_register_common.
* openmp.c (gfc_match_omp_threadprivate): Don't error if !have_tls.
* trans-common.c (build_common_decl): Don't check have_tls.
* trans-decl.c (gfc_finish_var_decl): Likewise.
* types.def (BT_WORD, BT_FN_PTR_PTR): New.
(BT_FN_VOID_PTR_WORD_WORD_PTR): New.
2007-02-09 Tobias Burnus <burnus@net-b.de>
PR fortran/30512

View File

@ -1136,6 +1136,14 @@ gfc_init_builtin_functions (void)
BUILT_IN_TRAP, NULL, false);
TREE_THIS_VOLATILE (built_in_decls[BUILT_IN_TRAP]) = 1;
gfc_define_builtin ("__emutls_get_address",
builtin_types[BT_FN_PTR_PTR], BUILT_IN_EMUTLS_GET_ADDRESS,
"__emutls_get_address", true);
gfc_define_builtin ("__emutls_register_common",
builtin_types[BT_FN_VOID_PTR_WORD_WORD_PTR],
BUILT_IN_EMUTLS_REGISTER_COMMON,
"__emutls_register_common", false);
build_common_builtin_nodes ();
targetm.init_builtins ();
}

View File

@ -469,12 +469,6 @@ gfc_match_omp_threadprivate (void)
if (m != MATCH_YES)
return m;
if (!targetm.have_tls)
{
sorry ("threadprivate variables not supported in this target");
goto cleanup;
}
for (;;)
{
m = gfc_match_symbol (&sym, 0);

View File

@ -388,7 +388,7 @@ build_common_decl (gfc_common_head *com, tree union_type, bool is_init)
gfc_set_decl_location (decl, &com->where);
if (com->threadprivate && targetm.have_tls)
if (com->threadprivate)
DECL_TLS_MODEL (decl) = decl_default_tls_model (decl);
/* Place the back end declaration for this common block in

View File

@ -538,7 +538,7 @@ gfc_finish_var_decl (tree decl, gfc_symbol * sym)
TREE_STATIC (decl) = 1;
/* Handle threadprivate variables. */
if (sym->attr.threadprivate && targetm.have_tls
if (sym->attr.threadprivate
&& (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
DECL_TLS_MODEL (decl) = decl_default_tls_model (decl);
}

View File

@ -55,6 +55,7 @@ DEF_PRIMITIVE_TYPE (BT_BOOL, boolean_type_node)
DEF_PRIMITIVE_TYPE (BT_INT, integer_type_node)
DEF_PRIMITIVE_TYPE (BT_UINT, unsigned_type_node)
DEF_PRIMITIVE_TYPE (BT_LONG, long_integer_type_node)
DEF_PRIMITIVE_TYPE (BT_WORD, (*lang_hooks.types.type_for_mode) (word_mode, 1))
DEF_PRIMITIVE_TYPE (BT_I1, builtin_type_for_size (BITS_PER_UNIT*1, 1))
DEF_PRIMITIVE_TYPE (BT_I2, builtin_type_for_size (BITS_PER_UNIT*2, 1))
@ -81,6 +82,7 @@ DEF_FUNCTION_TYPE_1 (BT_FN_VOID_PTR, BT_VOID, BT_PTR)
DEF_FUNCTION_TYPE_1 (BT_FN_VOID_PTRPTR, BT_VOID, BT_PTR_PTR)
DEF_FUNCTION_TYPE_1 (BT_FN_VOID_VPTR, BT_VOID, BT_VOLATILE_PTR)
DEF_FUNCTION_TYPE_1 (BT_FN_UINT_UINT, BT_UINT, BT_UINT)
DEF_FUNCTION_TYPE_1 (BT_FN_PTR_PTR, BT_PTR, BT_PTR)
DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR, BT_FN_VOID_PTR)
@ -113,6 +115,8 @@ DEF_FUNCTION_TYPE_3 (BT_FN_VOID_OMPFN_PTR_UINT, BT_VOID, BT_PTR_FN_VOID_PTR,
DEF_FUNCTION_TYPE_4 (BT_FN_VOID_OMPFN_PTR_UINT_UINT,
BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, BT_UINT)
DEF_FUNCTION_TYPE_4 (BT_FN_VOID_PTR_WORD_WORD_PTR,
BT_VOID, BT_PTR, BT_WORD, BT_WORD, BT_PTR)
DEF_FUNCTION_TYPE_5 (BT_FN_BOOL_LONG_LONG_LONG_LONGPTR_LONGPTR,
BT_BOOL, BT_LONG, BT_LONG, BT_LONG,

View File

@ -280,4 +280,6 @@ GCC_4.3.0 {
# byte swapping routines
__bswapsi2
__bswapdi2
__emutls_get_address
__emutls_register_common
}

View File

@ -158,6 +158,9 @@ extern void merge_weak (tree, tree);
/* Emit any pending weak declarations. */
extern void weak_finish (void);
/* Emit any pending emutls declarations and initializations. */
extern void emutls_finish (void);
/* Decode an `asm' spec for a declaration as a register name.
Return the register number, or -1 if nothing specified,
or -2 if the ASMSPEC is not `cc' or `memory' and is not recognized,

View File

@ -1,3 +1,15 @@
2007-02-10 Richard Henderson <rth@redhat.com>
* lib/target-supports.exp (check_effective_target_tls): Redefine
to mean non-emulated tls.
* gcc.dg/tls/alias-1.c: Remove tls requirement.
* gcc.dg/tls/asm-1.c, gcc.dg/tls/debug-1.c, gcc.dg/tls/diag-1.c,
gcc.dg/tls/diag-2.c, gcc.dg/tls/diag-3.c, gcc.dg/tls/diag-4.c,
gcc.dg/tls/diag-5.c, gcc.dg/tls/init-1.c, gcc.dg/tls/nonpic-1.c,
gcc.dg/tls/opt-10.c, gcc.dg/tls/opt-5.c, gcc.dg/tls/opt-6.c,
gcc.dg/tls/opt-8.c, gcc.dg/tls/opt-9.c, gcc.dg/tls/pic-1.c,
gcc.dg/tls/struct-1.c, gcc.dg/tls/trivial.c: Likewise.
2007-02-10 Zdenek Dvorak <dvorakz@suse.cz>
* gcc.dg/tree-ssa/loop-25.c: Verify the result in the profile pass.

View File

@ -1,7 +1,6 @@
/* { dg-do link } */
/* { dg-require-alias "" } */
/* { dg-require-visibility "" } */
/* { dg-require-effective-target tls } */
/* Test that encode_section_info handles the change from externally
defined to locally defined (via hidden). Extracted from glibc. */

View File

@ -1,5 +1,4 @@
/* { dg-options "-Werror" } */
/* { dg-require-effective-target tls } */
__thread int i;
int foo ()

View File

@ -1,5 +1,4 @@
/* { dg-do assemble } */
/* { dg-options "-g" } */
/* { dg-require-effective-target tls } */
__thread int i;

View File

@ -1,5 +1,4 @@
/* Valid __thread specifiers. */
/* { dg-require-effective-target tls } */
__thread int g1;
extern __thread int g2;

View File

@ -1,5 +1,4 @@
/* Invalid __thread specifiers. */
/* { dg-require-effective-target tls } */
__thread extern int g1; /* { dg-error "'__thread' before 'extern'" } */
__thread static int g2; /* { dg-error "'__thread' before 'static'" } */

View File

@ -1,5 +1,4 @@
/* Report invalid extern and __thread combinations. */
/* { dg-require-effective-target tls } */
extern int j; /* { dg-error "previous declaration" } */
__thread int j; /* { dg-error "follows non-thread-local" } */

View File

@ -1,6 +1,5 @@
/* Invalid __thread specifiers. As diag-4.c but some cases in
different orders. */
/* { dg-require-effective-target tls } */
__thread typedef int g4; /* { dg-error "'__thread' used with 'typedef'" } */

View File

@ -1,4 +1,3 @@
/* __thread specifiers on empty declarations. */
/* { dg-require-effective-target tls } */
__thread struct foo; /* { dg-warning "warning: useless '__thread' in empty declaration" } */

View File

@ -1,5 +1,4 @@
/* Invalid initializations. */
/* { dg-require-effective-target tls } */
extern __thread int i;
int *p = &i; /* { dg-error "initializer element is not constant" } */

View File

@ -1,6 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -ftls-model=initial-exec" } */
/* { dg-require-effective-target tls } */
extern __thread long e1;
extern __thread int e2;

View File

@ -1,6 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O3 -fpic" } */
/* { dg-require-effective-target tls } */
/* The web pass was creating unrecognisable pic_load_dot_plus_four insns
on ARM. */

View File

@ -1,6 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2" } */
/* { dg-require-effective-target tls } */
/* Sched1 moved {load_tp} pattern between strlen call and the copy
of the hard return value to its pseudo. This resulted in a
reload abort, since the hard register was not spillable. */

View File

@ -1,6 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2" } */
/* { dg-require-effective-target tls } */
extern void abort (void);
extern void exit (int);

View File

@ -1,7 +1,6 @@
/* PR 18910 */
/* { dg-do compile } */
/* { dg-options "-O2" } */
/* { dg-require-effective-target tls } */
static __thread void *foo [2];
void

View File

@ -1,7 +1,6 @@
/* PR 21412 */
/* { dg-do compile */
/* { dg-options "-O2 -fPIC" } */
/* { dg-require-effective-target tls } */
struct S { int x[10]; };
extern __thread struct S s;

View File

@ -1,6 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fpic -ftls-model=global-dynamic" } */
/* { dg-require-effective-target tls } */
extern __thread long e1;
extern __thread int e2;

View File

@ -2,7 +2,6 @@
to allow addends for @dtpoff relocs or not. */
/* { dg-do compile } */
/* { dg-options "-O2 -fpic" } */
/* { dg-require-effective-target tls } */
struct S {
int s0, s1, s2, s3;

View File

@ -1,3 +1 @@
/* { dg-require-effective-target tls } */
__thread int i;

View File

@ -384,7 +384,7 @@ proc check_effective_target_pcc_bitfield_type_matters { } {
}]
}
# Return 1 if thread local storage (TLS) is supported, 0 otherwise.
# Return 1 if *native* thread local storage (TLS) is supported, 0 otherwise.
#
# This won't change for different subtargets so cache the result.
@ -406,11 +406,19 @@ proc check_effective_target_tls {} {
close $f
# Test for thread-local data supported by the platform.
set comp_output \
[${tool}_target_compile $src $asm assembly ""]
set comp_output [${tool}_target_compile $src $asm assembly ""]
file delete $src
if { [string match "*not supported*" $comp_output] } {
set et_tls_saved 0
} else {
set fd [open $asm r]
set text [read $fd]
close $fd
if { [string match "*emutls*" $text]} {
set et_tls_saved 0
} else {
set et_tls_saved 1
}
}
remove-build-file $asm
}

View File

@ -1048,11 +1048,14 @@ compile_file (void)
if (flag_mudflap)
mudflap_finish_file ();
/* Likewise for emulated thread-local storage. */
if (!targetm.have_tls)
emutls_finish ();
output_shared_constant_pool ();
output_object_blocks ();
/* Write out any pending weak symbol declarations. */
weak_finish ();
/* Do dbx symbols. */

View File

@ -1,5 +1,5 @@
/* Memory address lowering and addressing mode selection.
Copyright (C) 2004 Free Software Foundation, Inc.
Copyright (C) 2004, 2006 Free Software Foundation, Inc.
This file is part of GCC.
@ -135,10 +135,15 @@ gen_addr_rtx (rtx symbol, rtx base, rtx index, rtx step, rtx offset,
act_elem = symbol;
if (offset)
{
act_elem = gen_rtx_CONST (Pmode,
gen_rtx_PLUS (Pmode, act_elem, offset));
act_elem = gen_rtx_PLUS (Pmode, act_elem, offset);
if (offset_p)
*offset_p = &XEXP (XEXP (act_elem, 0), 1);
*offset_p = &XEXP (act_elem, 1);
if (GET_CODE (symbol) == SYMBOL_REF
|| GET_CODE (symbol) == LABEL_REF
|| GET_CODE (symbol) == CONST)
act_elem = gen_rtx_CONST (Pmode, act_elem);
}
if (*addr)

View File

@ -4599,6 +4599,7 @@ extern void set_user_assembler_name (tree, const char *);
extern void process_pending_assemble_externals (void);
extern void finish_aliases_1 (void);
extern void finish_aliases_2 (void);
extern tree emutls_decl (tree);
/* In stmt.c */
extern void expand_computed_goto (tree);

View File

@ -1,6 +1,6 @@
/* Output variables, constants and external declarations, for GNU compiler.
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
Free Software Foundation, Inc.
This file is part of GCC.
@ -53,6 +53,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
#include "cgraph.h"
#include "cfglayout.h"
#include "basic-block.h"
#include "tree-iterator.h"
#ifdef XCOFF_DEBUGGING_INFO
#include "xcoffout.h" /* Needed for external data
@ -199,6 +200,242 @@ static GTY(()) int anchor_labelno;
/* A pool of constants that can be shared between functions. */
static GTY(()) struct rtx_constant_pool *shared_constant_pool;
/* TLS emulation. */
static GTY ((if_marked ("tree_map_marked_p"), param_is (struct tree_map)))
htab_t emutls_htab;
static GTY (()) tree emutls_object_type;
#ifndef NO_DOT_IN_LABEL
# define EMUTLS_VAR_PREFIX "__emutls_v."
# define EMUTLS_TMPL_PREFIX "__emutls_t."
#elif !defined NO_DOLLAR_IN_LABEL
# define EMUTLS_VAR_PREFIX "__emutls_v$"
# define EMUTLS_TMPL_PREFIX "__emutls_t$"
#else
# define EMUTLS_VAR_PREFIX "__emutls_v_"
# define EMUTLS_TMPL_PREFIX "__emutls_t_"
#endif
/* Create an identifier for the struct __emutls_object, given an identifier
of the DECL_ASSEMBLY_NAME of the original object. */
static tree
get_emutls_object_name (tree name)
{
char *toname = alloca (strlen (IDENTIFIER_POINTER (name))
+ sizeof (EMUTLS_VAR_PREFIX));
strcpy (toname, EMUTLS_VAR_PREFIX);
strcpy (toname + sizeof (EMUTLS_VAR_PREFIX) - 1, IDENTIFIER_POINTER (name));
return get_identifier (toname);
}
/* Create the structure for struct __emutls_object. This should match the
structure at the top of emutls.c, modulo the union there. */
static tree
get_emutls_object_type (void)
{
tree type, type_name, field, next_field, word_type_node;
type = emutls_object_type;
if (type)
return type;
emutls_object_type = type = lang_hooks.types.make_type (RECORD_TYPE);
type_name = get_identifier ("__emutls_object");
type_name = build_decl (TYPE_DECL, type_name, type);
TYPE_NAME (type) = type_name;
field = build_decl (FIELD_DECL, get_identifier ("__templ"), ptr_type_node);
DECL_CONTEXT (field) = type;
next_field = field;
field = build_decl (FIELD_DECL, get_identifier ("__offset"), ptr_type_node);
DECL_CONTEXT (field) = type;
TREE_CHAIN (field) = next_field;
next_field = field;
word_type_node = lang_hooks.types.type_for_mode (word_mode, 1);
field = build_decl (FIELD_DECL, get_identifier ("__align"), word_type_node);
DECL_CONTEXT (field) = type;
TREE_CHAIN (field) = next_field;
next_field = field;
field = build_decl (FIELD_DECL, get_identifier ("__size"), word_type_node);
DECL_CONTEXT (field) = type;
TREE_CHAIN (field) = next_field;
TYPE_FIELDS (type) = field;
layout_type (type);
return type;
}
/* Create a read-only variable like DECL, with the same DECL_INITIAL.
This will be used for initializing the emulated tls data area. */
static tree
get_emutls_init_templ_addr (tree decl)
{
tree name, to;
char *toname;
if (!DECL_INITIAL (decl))
return null_pointer_node;
name = DECL_ASSEMBLER_NAME (decl);
toname = alloca (strlen (IDENTIFIER_POINTER (name))
+ sizeof (EMUTLS_TMPL_PREFIX));
strcpy (toname, EMUTLS_TMPL_PREFIX);
strcpy (toname + sizeof (EMUTLS_TMPL_PREFIX) - 1, IDENTIFIER_POINTER (name));
name = get_identifier (toname);
to = build_decl (VAR_DECL, name, TREE_TYPE (decl));
SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to));
DECL_ARTIFICIAL (to) = 1;
TREE_USED (to) = TREE_USED (decl);
TREE_READONLY (to) = 1;
DECL_IGNORED_P (to) = 1;
DECL_CONTEXT (to) = DECL_CONTEXT (decl);
DECL_WEAK (to) = DECL_WEAK (decl);
if (DECL_ONE_ONLY (decl))
{
make_decl_one_only (to);
TREE_STATIC (to) = TREE_STATIC (decl);
TREE_PUBLIC (to) = TREE_PUBLIC (decl);
DECL_VISIBILITY (to) = DECL_VISIBILITY (decl);
}
else
TREE_STATIC (to) = 1;
DECL_INITIAL (to) = DECL_INITIAL (decl);
DECL_INITIAL (decl) = NULL;
varpool_finalize_decl (to);
return build_fold_addr_expr (to);
}
/* When emulating tls, we use a control structure for use by the runtime.
Create and return this structure. */
tree
emutls_decl (tree decl)
{
tree name, to;
struct tree_map *h, in;
void **loc;
if (targetm.have_tls || decl == NULL || decl == error_mark_node
|| TREE_CODE (decl) != VAR_DECL || ! DECL_THREAD_LOCAL_P (decl))
return decl;
/* Look up the object in the hash; return the control structure if
it has already been created. */
if (! emutls_htab)
emutls_htab = htab_create_ggc (512, tree_map_hash, tree_map_eq, 0);
name = DECL_ASSEMBLER_NAME (decl);
/* Note that we use the hash of the decl's name, rather than a hash
of the decl's pointer. In emutls_finish we iterate through the
hash table, and we want this traversal to be predictable. */
in.hash = htab_hash_string (IDENTIFIER_POINTER (name));
in.from = decl;
loc = htab_find_slot_with_hash (emutls_htab, &in, in.hash, INSERT);
h = *loc;
if (h != NULL)
to = h->to;
else
{
to = build_decl (VAR_DECL, get_emutls_object_name (name),
get_emutls_object_type ());
h = ggc_alloc (sizeof (struct tree_map));
h->hash = in.hash;
h->from = decl;
h->to = to;
*(struct tree_map **) loc = h;
DECL_ARTIFICIAL (to) = 1;
DECL_IGNORED_P (to) = 1;
TREE_READONLY (to) = 0;
SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to));
if (DECL_ONE_ONLY (decl))
make_decl_one_only (to);
DECL_CONTEXT (to) = DECL_CONTEXT (decl);
}
/* Note that these fields may need to be updated from time to time from
the original decl. Consider:
extern __thread int i;
int foo() { return i; }
__thread int i = 1;
in which I goes from external to locally defined and initialized. */
TREE_STATIC (to) = TREE_STATIC (decl);
TREE_USED (to) = TREE_USED (decl);
TREE_PUBLIC (to) = TREE_PUBLIC (decl);
DECL_EXTERNAL (to) = DECL_EXTERNAL (decl);
DECL_COMMON (to) = DECL_COMMON (decl);
DECL_WEAK (to) = DECL_WEAK (decl);
DECL_VISIBILITY (to) = DECL_VISIBILITY (decl);
return to;
}
static int
emutls_common_1 (void **loc, void *xstmts)
{
struct tree_map *h = *(struct tree_map **) loc;
tree args, x, *pstmts = (tree *) xstmts;
tree word_type_node;
if (! DECL_COMMON (h->from)
|| (DECL_INITIAL (h->from)
&& DECL_INITIAL (h->from) != error_mark_node))
return 1;
word_type_node = lang_hooks.types.type_for_mode (word_mode, 1);
/* The idea was to call get_emutls_init_templ_addr here, but if we
do this and there is an initializer, -fanchor_section loses,
because it would be too late to ensure the template is
output. */
x = null_pointer_node;
args = tree_cons (NULL, x, NULL);
x = build_int_cst (word_type_node, DECL_ALIGN_UNIT (h->from));
args = tree_cons (NULL, x, args);
x = fold_convert (word_type_node, DECL_SIZE_UNIT (h->from));
args = tree_cons (NULL, x, args);
x = build_fold_addr_expr (h->to);
args = tree_cons (NULL, x, args);
x = built_in_decls[BUILT_IN_EMUTLS_REGISTER_COMMON];
x = build_function_call_expr (x, args);
append_to_statement_list (x, pstmts);
return 1;
}
void
emutls_finish (void)
{
tree body = NULL_TREE;
if (emutls_htab == NULL)
return;
htab_traverse_noresize (emutls_htab, emutls_common_1, &body);
if (body == NULL_TREE)
return;
cgraph_build_static_cdtor ('I', body, DEFAULT_INIT_PRIORITY);
}
/* Helper routines for maintaining section_htab. */
static int
@ -1733,6 +1970,59 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
rtx decl_rtl, symbol;
section *sect;
if (! targetm.have_tls
&& TREE_CODE (decl) == VAR_DECL
&& DECL_THREAD_LOCAL_P (decl))
{
tree to = emutls_decl (decl);
/* If this variable is defined locally, then we need to initialize the
control structure with size and alignment information. We do this
at the last moment because tentative definitions can take a locally
defined but uninitialized variable and initialize it later, which
would result in incorrect contents. */
if (! DECL_EXTERNAL (to)
&& (! DECL_COMMON (to)
|| (DECL_INITIAL (decl)
&& DECL_INITIAL (decl) != error_mark_node)))
{
VEC(constructor_elt,gc) *v = VEC_alloc (constructor_elt, gc, 4);
constructor_elt *elt;
tree type = TREE_TYPE (to);
tree field = TYPE_FIELDS (type);
elt = VEC_quick_push (constructor_elt, v, NULL);
elt->index = field;
elt->value = fold_convert (TREE_TYPE (field), DECL_SIZE_UNIT (decl));
elt = VEC_quick_push (constructor_elt, v, NULL);
field = TREE_CHAIN (field);
elt->index = field;
elt->value = build_int_cst (TREE_TYPE (field),
DECL_ALIGN_UNIT (decl));
elt = VEC_quick_push (constructor_elt, v, NULL);
field = TREE_CHAIN (field);
elt->index = field;
elt->value = null_pointer_node;
elt = VEC_quick_push (constructor_elt, v, NULL);
field = TREE_CHAIN (field);
elt->index = field;
elt->value = get_emutls_init_templ_addr (decl);
DECL_INITIAL (to) = build_constructor (type, v);
/* Make sure the template is marked as needed early enough.
Without this, if the variable is placed in a
section-anchored block, the template will only be marked
when it's too late. */
record_references_in_initializer (to);
}
decl = to;
}
if (lang_hooks.decls.prepare_assemble_variable)
lang_hooks.decls.prepare_assemble_variable (decl);
@ -4856,6 +5146,14 @@ do_assemble_alias (tree decl, tree target)
{
ultimate_transparent_alias_target (&target);
if (!targetm.have_tls
&& TREE_CODE (decl) == VAR_DECL
&& DECL_THREAD_LOCAL_P (decl))
{
decl = emutls_decl (decl);
target = get_emutls_object_name (target);
}
if (!TREE_SYMBOL_REFERENCED (target))
weakref_targets = tree_cons (decl, target, weakref_targets);
@ -4873,6 +5171,14 @@ do_assemble_alias (tree decl, tree target)
return;
}
if (!targetm.have_tls
&& TREE_CODE (decl) == VAR_DECL
&& DECL_THREAD_LOCAL_P (decl))
{
decl = emutls_decl (decl);
target = get_emutls_object_name (target);
}
#ifdef ASM_OUTPUT_DEF
/* Make name accessible from other files, if appropriate. */
@ -5760,7 +6066,8 @@ default_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
flags |= SYMBOL_FLAG_FUNCTION;
if (targetm.binds_local_p (decl))
flags |= SYMBOL_FLAG_LOCAL;
if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl))
if (targetm.have_tls && TREE_CODE (decl) == VAR_DECL
&& DECL_THREAD_LOCAL_P (decl))
flags |= DECL_TLS_MODEL (decl) << SYMBOL_FLAG_TLS_SHIFT;
else if (targetm.in_small_data_p (decl))
flags |= SYMBOL_FLAG_SMALL;

View File

@ -1,5 +1,5 @@
/* Callgraph handling code.
Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
Contributed by Jan Hubicka
This file is part of GCC.
@ -218,7 +218,7 @@ bool
decide_is_variable_needed (struct varpool_node *node, tree decl)
{
/* If the user told us it is used, then it must be so. */
if (node->externally_visible)
if (node->externally_visible || node->force_output)
return true;
if (!flag_unit_at_a_time
&& lookup_attribute ("used", DECL_ATTRIBUTES (decl)))
@ -242,6 +242,17 @@ decide_is_variable_needed (struct varpool_node *node, tree decl)
&& !DECL_EXTERNAL (decl))
return true;
/* When emulating tls, we actually see references to the control
variable, rather than the user-level variable. */
if (!targetm.have_tls
&& TREE_CODE (decl) == VAR_DECL
&& DECL_THREAD_LOCAL_P (decl))
{
tree control = emutls_decl (decl);
if (decide_is_variable_needed (varpool_node (control), control))
return true;
}
/* When not reordering top level variables, we have to assume that
we are going to keep everything. */
if (flag_unit_at_a_time && flag_toplevel_reorder)
@ -374,10 +385,7 @@ varpool_remove_unreferenced_decls (void)
node->needed = 0;
if (node->finalized
&& ((DECL_ASSEMBLER_NAME_SET_P (decl)
&& TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
|| node->force_output
|| decide_is_variable_needed (node, decl)
&& (decide_is_variable_needed (node, decl)
/* ??? Cgraph does not yet rule the world with an iron hand,
and does not control the emission of debug information.
After a variable has its DECL_RTL set, we must assume that