diff options
author | Richard Henderson <rth@gcc.gnu.org> | 2006-10-04 14:09:20 -0700 |
---|---|---|
committer | Richard Henderson <rth@gcc.gnu.org> | 2006-10-04 14:09:20 -0700 |
commit | e701a32a98fd67d7f2f69889080303d32b388cc7 (patch) | |
tree | c4b6efa5601a2114eda9c1a31ae3155935113ab0 /gcc/emutls.c | |
parent | 7d610414458c12ed69c90dcc80d754cf6f38b21a (diff) | |
download | gcc-e701a32a98fd67d7f2f69889080303d32b388cc7.zip gcc-e701a32a98fd67d7f2f69889080303d32b388cc7.tar.gz gcc-e701a32a98fd67d7f2f69889080303d32b388cc7.tar.bz2 |
Makefile.in (libgcc.mk, [...]): Add emutls.c.
gcc/
* Makefile.in (libgcc.mk, LIBGCC_DEPS): 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.
* cgraph.c (decide_is_variable_needed): Look at force_output.
Recurse for emulated tls.
* cgraphunit.c (cgraph_varpool_remove_unreferenced_decls): Remove
checks redundant with decide_is_variable_needed.
(cgraph_build_static_cdtor): Do cgraph_varpool_assemble_pending_decls.
* 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.
* emutls.c: New file.
* config/sparc/sol2.h (ASM_DECLARE_OBJECT_NAME): Only emit
tls_object for real tls.
gcc/cp/
* decl.c (grokvardecl): Don't error if !have_tls.
(grokdeclarator): Likewise.
* parser.c (cp_parser_omp_threadprivate): Likewise.
gcc/fortran/
* 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/
* 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: r117440
Diffstat (limited to 'gcc/emutls.c')
-rw-r--r-- | gcc/emutls.c | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/gcc/emutls.c b/gcc/emutls.c new file mode 100644 index 0000000..f26d217 --- /dev/null +++ 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; +} |