summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog37
-rw-r--r--gcc/Makefile.in8
-rw-r--r--gcc/builtin-types.def4
-rw-r--r--gcc/builtins.def6
-rw-r--r--gcc/c-decl.c9
-rw-r--r--gcc/c-parser.c3
-rw-r--r--gcc/config/sparc/sol2.h2
-rw-r--r--gcc/cp/ChangeLog6
-rw-r--r--gcc/cp/decl.c19
-rw-r--r--gcc/cp/parser.c3
-rw-r--r--gcc/dwarf2out.c2
-rw-r--r--gcc/emutls.c193
-rw-r--r--gcc/expr.c35
-rw-r--r--gcc/fortran/ChangeLog10
-rw-r--r--gcc/fortran/f95-lang.c8
-rw-r--r--gcc/fortran/openmp.c6
-rw-r--r--gcc/fortran/trans-common.c2
-rw-r--r--gcc/fortran/trans-decl.c2
-rw-r--r--gcc/fortran/types.def4
-rw-r--r--gcc/libgcc-std.ver2
-rw-r--r--gcc/output.h3
-rw-r--r--gcc/testsuite/ChangeLog12
-rw-r--r--gcc/testsuite/gcc.dg/tls/alias-1.c1
-rw-r--r--gcc/testsuite/gcc.dg/tls/asm-1.c1
-rw-r--r--gcc/testsuite/gcc.dg/tls/debug-1.c1
-rw-r--r--gcc/testsuite/gcc.dg/tls/diag-1.c1
-rw-r--r--gcc/testsuite/gcc.dg/tls/diag-2.c1
-rw-r--r--gcc/testsuite/gcc.dg/tls/diag-3.c1
-rw-r--r--gcc/testsuite/gcc.dg/tls/diag-4.c1
-rw-r--r--gcc/testsuite/gcc.dg/tls/diag-5.c1
-rw-r--r--gcc/testsuite/gcc.dg/tls/init-1.c1
-rw-r--r--gcc/testsuite/gcc.dg/tls/nonpic-1.c1
-rw-r--r--gcc/testsuite/gcc.dg/tls/opt-10.c1
-rw-r--r--gcc/testsuite/gcc.dg/tls/opt-5.c1
-rw-r--r--gcc/testsuite/gcc.dg/tls/opt-6.c1
-rw-r--r--gcc/testsuite/gcc.dg/tls/opt-8.c1
-rw-r--r--gcc/testsuite/gcc.dg/tls/opt-9.c1
-rw-r--r--gcc/testsuite/gcc.dg/tls/pic-1.c1
-rw-r--r--gcc/testsuite/gcc.dg/tls/struct-1.c1
-rw-r--r--gcc/testsuite/gcc.dg/tls/trivial.c2
-rw-r--r--gcc/testsuite/lib/target-supports.exp14
-rw-r--r--gcc/toplev.c5
-rw-r--r--gcc/tree-ssa-address.c13
-rw-r--r--gcc/tree.h1
-rw-r--r--gcc/varasm.c311
-rw-r--r--gcc/varpool.c20
46 files changed, 677 insertions, 82 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 584726dbebe..22d12f55f10 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 6b8882608d3..7bb1434b0e9 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -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
diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def
index bac7480438c..ea0ff8e915e 100644
--- a/gcc/builtin-types.def
+++ b/gcc/builtin-types.def
@@ -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,
diff --git a/gcc/builtins.def b/gcc/builtins.def
index b5a88cd2bf1..48c97bf912e 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -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"
diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index 3bdf70e12ba..648c805828d 100644
--- a/gcc/c-decl.c
+++ b/gcc/c-decl.c
@@ -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
diff --git a/gcc/c-parser.c b/gcc/c-parser.c
index b688b15673f..665b494e231 100644
--- a/gcc/c-parser.c
+++ b/gcc/c-parser.c
@@ -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))
{
diff --git a/gcc/config/sparc/sol2.h b/gcc/config/sparc/sol2.h
index d07e0c63685..7a79a7d7112 100644
--- a/gcc/config/sparc/sol2.h
+++ b/gcc/config/sparc/sol2.h
@@ -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"); \
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 59f7260dfb0..55739107945 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index e6f06640037..b6d0e5387f7 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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
{
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 6aef931fc7d..8e130b64cfd 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -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);
}
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index d529d8c879d..5516f3f2617 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -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
diff --git a/gcc/emutls.c b/gcc/emutls.c
index e69de29bb2d..f26d21772e3 100644
--- a/gcc/emutls.c
+++ b/gcc/emutls.c
@@ -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;
+}
diff --git a/gcc/expr.c b/gcc/expr.c
index a04e931acd0..09a67891eef 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -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:
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index da3698537c3..a0cf78f670b 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -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
diff --git a/gcc/fortran/f95-lang.c b/gcc/fortran/f95-lang.c
index bf0ae81cc46..8f9c206c77f 100644
--- a/gcc/fortran/f95-lang.c
+++ b/gcc/fortran/f95-lang.c
@@ -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 ();
}
diff --git a/gcc/fortran/openmp.c b/gcc/fortran/openmp.c
index 9694c89743f..42b5aa15dba 100644
--- a/gcc/fortran/openmp.c
+++ b/gcc/fortran/openmp.c
@@ -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);
diff --git a/gcc/fortran/trans-common.c b/gcc/fortran/trans-common.c
index 83da32f5234..ea73537471e 100644
--- a/gcc/fortran/trans-common.c
+++ b/gcc/fortran/trans-common.c
@@ -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
diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c
index 3b52b9d830b..1bf11e30c29 100644
--- a/gcc/fortran/trans-decl.c
+++ b/gcc/fortran/trans-decl.c
@@ -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);
}
diff --git a/gcc/fortran/types.def b/gcc/fortran/types.def
index 5a3e5d72221..0abd8459d96 100644
--- a/gcc/fortran/types.def
+++ b/gcc/fortran/types.def
@@ -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,
diff --git a/gcc/libgcc-std.ver b/gcc/libgcc-std.ver
index 6e747ed7bc1..4b707944e80 100644
--- a/gcc/libgcc-std.ver
+++ b/gcc/libgcc-std.ver
@@ -280,4 +280,6 @@ GCC_4.3.0 {
# byte swapping routines
__bswapsi2
__bswapdi2
+ __emutls_get_address
+ __emutls_register_common
}
diff --git a/gcc/output.h b/gcc/output.h
index 8340d412c69..4e7ccf61308 100644
--- a/gcc/output.h
+++ b/gcc/output.h
@@ -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,
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 6f3a283203e..0998a308522 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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.
diff --git a/gcc/testsuite/gcc.dg/tls/alias-1.c b/gcc/testsuite/gcc.dg/tls/alias-1.c
index 28cb47e5041..1098190ebd0 100644
--- a/gcc/testsuite/gcc.dg/tls/alias-1.c
+++ b/gcc/testsuite/gcc.dg/tls/alias-1.c
@@ -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. */
diff --git a/gcc/testsuite/gcc.dg/tls/asm-1.c b/gcc/testsuite/gcc.dg/tls/asm-1.c
index b77e550d7bf..476fe7cbb72 100644
--- a/gcc/testsuite/gcc.dg/tls/asm-1.c
+++ b/gcc/testsuite/gcc.dg/tls/asm-1.c
@@ -1,5 +1,4 @@
/* { dg-options "-Werror" } */
-/* { dg-require-effective-target tls } */
__thread int i;
int foo ()
diff --git a/gcc/testsuite/gcc.dg/tls/debug-1.c b/gcc/testsuite/gcc.dg/tls/debug-1.c
index 67d7be69cc5..719f0645771 100644
--- a/gcc/testsuite/gcc.dg/tls/debug-1.c
+++ b/gcc/testsuite/gcc.dg/tls/debug-1.c
@@ -1,5 +1,4 @@
/* { dg-do assemble } */
/* { dg-options "-g" } */
-/* { dg-require-effective-target tls } */
__thread int i;
diff --git a/gcc/testsuite/gcc.dg/tls/diag-1.c b/gcc/testsuite/gcc.dg/tls/diag-1.c
index 56b570c94a5..ae4f3d4a3c2 100644
--- a/gcc/testsuite/gcc.dg/tls/diag-1.c
+++ b/gcc/testsuite/gcc.dg/tls/diag-1.c
@@ -1,5 +1,4 @@
/* Valid __thread specifiers. */
-/* { dg-require-effective-target tls } */
__thread int g1;
extern __thread int g2;
diff --git a/gcc/testsuite/gcc.dg/tls/diag-2.c b/gcc/testsuite/gcc.dg/tls/diag-2.c
index 8276cb3be49..5e7e17bee5a 100644
--- a/gcc/testsuite/gcc.dg/tls/diag-2.c
+++ b/gcc/testsuite/gcc.dg/tls/diag-2.c
@@ -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'" } */
diff --git a/gcc/testsuite/gcc.dg/tls/diag-3.c b/gcc/testsuite/gcc.dg/tls/diag-3.c
index 45d89b43722..f1ce06b70d8 100644
--- a/gcc/testsuite/gcc.dg/tls/diag-3.c
+++ b/gcc/testsuite/gcc.dg/tls/diag-3.c
@@ -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" } */
diff --git a/gcc/testsuite/gcc.dg/tls/diag-4.c b/gcc/testsuite/gcc.dg/tls/diag-4.c
index fed2f3accd3..df3705d04ee 100644
--- a/gcc/testsuite/gcc.dg/tls/diag-4.c
+++ b/gcc/testsuite/gcc.dg/tls/diag-4.c
@@ -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'" } */
diff --git a/gcc/testsuite/gcc.dg/tls/diag-5.c b/gcc/testsuite/gcc.dg/tls/diag-5.c
index 219396d768a..623832c3812 100644
--- a/gcc/testsuite/gcc.dg/tls/diag-5.c
+++ b/gcc/testsuite/gcc.dg/tls/diag-5.c
@@ -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" } */
diff --git a/gcc/testsuite/gcc.dg/tls/init-1.c b/gcc/testsuite/gcc.dg/tls/init-1.c
index fa4208dce0c..97258643bf2 100644
--- a/gcc/testsuite/gcc.dg/tls/init-1.c
+++ b/gcc/testsuite/gcc.dg/tls/init-1.c
@@ -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" } */
diff --git a/gcc/testsuite/gcc.dg/tls/nonpic-1.c b/gcc/testsuite/gcc.dg/tls/nonpic-1.c
index 9c592a98556..0896df60b56 100644
--- a/gcc/testsuite/gcc.dg/tls/nonpic-1.c
+++ b/gcc/testsuite/gcc.dg/tls/nonpic-1.c
@@ -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;
diff --git a/gcc/testsuite/gcc.dg/tls/opt-10.c b/gcc/testsuite/gcc.dg/tls/opt-10.c
index a710a062ca3..f31c1fff816 100644
--- a/gcc/testsuite/gcc.dg/tls/opt-10.c
+++ b/gcc/testsuite/gcc.dg/tls/opt-10.c
@@ -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. */
diff --git a/gcc/testsuite/gcc.dg/tls/opt-5.c b/gcc/testsuite/gcc.dg/tls/opt-5.c
index 0604f3253c1..d8a686ddb46 100644
--- a/gcc/testsuite/gcc.dg/tls/opt-5.c
+++ b/gcc/testsuite/gcc.dg/tls/opt-5.c
@@ -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. */
diff --git a/gcc/testsuite/gcc.dg/tls/opt-6.c b/gcc/testsuite/gcc.dg/tls/opt-6.c
index 8a01c019c10..de04c1cb3fc 100644
--- a/gcc/testsuite/gcc.dg/tls/opt-6.c
+++ b/gcc/testsuite/gcc.dg/tls/opt-6.c
@@ -1,6 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2" } */
-/* { dg-require-effective-target tls } */
extern void abort (void);
extern void exit (int);
diff --git a/gcc/testsuite/gcc.dg/tls/opt-8.c b/gcc/testsuite/gcc.dg/tls/opt-8.c
index a7331115352..dec0eabcb4c 100644
--- a/gcc/testsuite/gcc.dg/tls/opt-8.c
+++ b/gcc/testsuite/gcc.dg/tls/opt-8.c
@@ -1,7 +1,6 @@
/* PR 18910 */
/* { dg-do compile } */
/* { dg-options "-O2" } */
-/* { dg-require-effective-target tls } */
static __thread void *foo [2];
void
diff --git a/gcc/testsuite/gcc.dg/tls/opt-9.c b/gcc/testsuite/gcc.dg/tls/opt-9.c
index cc62ef57a5d..3829c66fc55 100644
--- a/gcc/testsuite/gcc.dg/tls/opt-9.c
+++ b/gcc/testsuite/gcc.dg/tls/opt-9.c
@@ -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;
diff --git a/gcc/testsuite/gcc.dg/tls/pic-1.c b/gcc/testsuite/gcc.dg/tls/pic-1.c
index bcd42bd8572..f5b020b7db6 100644
--- a/gcc/testsuite/gcc.dg/tls/pic-1.c
+++ b/gcc/testsuite/gcc.dg/tls/pic-1.c
@@ -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;
diff --git a/gcc/testsuite/gcc.dg/tls/struct-1.c b/gcc/testsuite/gcc.dg/tls/struct-1.c
index 5fd6be43905..11151236d90 100644
--- a/gcc/testsuite/gcc.dg/tls/struct-1.c
+++ b/gcc/testsuite/gcc.dg/tls/struct-1.c
@@ -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;
diff --git a/gcc/testsuite/gcc.dg/tls/trivial.c b/gcc/testsuite/gcc.dg/tls/trivial.c
index 96b8e49a665..1fd70631f33 100644
--- a/gcc/testsuite/gcc.dg/tls/trivial.c
+++ b/gcc/testsuite/gcc.dg/tls/trivial.c
@@ -1,3 +1 @@
-/* { dg-require-effective-target tls } */
-
__thread int i;
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index d1daf0fecf0..ec63866614e 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -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
}
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 56a78b44e60..4ad6f1d983e 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -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. */
diff --git a/gcc/tree-ssa-address.c b/gcc/tree-ssa-address.c
index 69a41a48edf..ef3bfb7cbfb 100644
--- a/gcc/tree-ssa-address.c
+++ b/gcc/tree-ssa-address.c
@@ -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)
diff --git a/gcc/tree.h b/gcc/tree.h
index 55117805e3d..26e0676d0c2 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -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);
diff --git a/gcc/varasm.c b/gcc/varasm.c
index c2ae6e23f1c..48aba4e4a16 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -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;
diff --git a/gcc/varpool.c b/gcc/varpool.c
index a3af8c7c2f5..65c22d491b4 100644
--- a/gcc/varpool.c
+++ b/gcc/varpool.c
@@ -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