targhooks.h (default_emutls_var_fields, [...]): Declare.

* targhooks.h (default_emutls_var_fields,
	default_emutls_var_init): Declare.
	* tree.h (DECL_THREAD_LOCAL): Compare against TLS_MODEL_REAL.
	* target.h (struct gcc_target): Add struct emutls member.
	* target-def.h (TARGET_EMUTLS_GET_ADDRESS,
	TARGET_EMUTLS_REGISTER_COMMON, TARGET_EMUTLS_VAR_SECTION,
	TARGET_EMUTLS_TMPL_SECTION, TARGET_EMUTLS_VAR_PREFIX,
	TARGET_EMUTLS_TMPL_PREFIX, TARGET_EMUTLS_VAR_FIELDS,
	TARGET_EMUTLS_VAR_INIT, TARGET_EMUTLS_DEBUG_FORM_TLS_ADDRESS,
	TARGET_EMUTLS_VAR_ALIGN_FIXED, TARGET_EMUTLS): New.
	(TARGET_INITIALIZER): Add TARGET_EMUTLS.
	* builtins.def (BUILT_IN_EMUTLS_GET_ADDRESS,
	BUILT_IN_EMUTLS_REGISTER_COMMON): Get name from targetm structure.
	* dwarf2out.c (loc_descriptor_from_tree_1): Check if emutls can
	emit debug information.
	* coretypes.h (tls_model): Add TLS_MODEL_EMULATED, TLS_MODEL_REAL.
	* varasm.c: Include targhooks.h.
	(emutls_object_section, emutls_tmpl_section): New.
	(EMUTLS_VAR_PREFIX, EMUTLS_TMPL_PREFIX): Remove.
	(EMUTLS_SEPARATOR): New.
	(prefix_name): New.
	(get_emutls_object_name): New.
	(default_emutls_var_fields): New, broken out of ...
	(get_emutls_object_type): ... here.  Adjust to use target hooks.
	(get_emutls_init_templ_addr): Adjust to use target hooks.
	(emutls_decl): Adjust to use target hooks.
	(emutls_finish): Likewise.
	(default_emutls_var_init): New, broken out of ...
	(assemble_variable): ... here.  Adjust to use target hooks.
	* output.h (enum section_category): Add SECCAT_EMUTLS_VAR,
	SECCAT_EMUTLS_TMPL.
	* c-common.c (handle_section_attribute): Prevent overriding
	sections for emulated tls with special sections.
	* config/i386/i386.c (x86_64_elf_select_section): Add
	SECCAT_EMUTLS_VAR and SECCAT_EMUTLS_TMPL.
	(x86_64_elf_unique_section): Likewise.
	* config/vxworks.c: Include tree.h.
	(vxworks_emutls_var_fields, vxworks_emutls_var_init): New.
	(vxworks_override_options): Set TLS scheme.
	* gcc/doc/tm.texi (Emulated TLS): New node.

	gcc/testsuite/
	* gcc.dg/tls/section-2.c: New.
	* gcc.dg/tls/emutls-1.c: New.
	* lib/target-supports.exp (check_effective_target_tls_native):
	Exclude vxworks.

From-SVN: r134729
This commit is contained in:
Nathan Sidwell 2008-04-27 15:35:19 +00:00 committed by Nathan Sidwell
parent f509e29629
commit feb60f0328
18 changed files with 584 additions and 135 deletions

View File

@ -1,3 +1,46 @@
2008-04-27 Nathan Sidwell <nathan@codesourcery.com>
* targhooks.h (default_emutls_var_fields,
default_emutls_var_init): Declare.
* tree.h (DECL_THREAD_LOCAL): Compare against TLS_MODEL_REAL.
* target.h (struct gcc_target): Add struct emutls member.
* target-def.h (TARGET_EMUTLS_GET_ADDRESS,
TARGET_EMUTLS_REGISTER_COMMON, TARGET_EMUTLS_VAR_SECTION,
TARGET_EMUTLS_TMPL_SECTION, TARGET_EMUTLS_VAR_PREFIX,
TARGET_EMUTLS_TMPL_PREFIX, TARGET_EMUTLS_VAR_FIELDS,
TARGET_EMUTLS_VAR_INIT, TARGET_EMUTLS_DEBUG_FORM_TLS_ADDRESS,
TARGET_EMUTLS_VAR_ALIGN_FIXED, TARGET_EMUTLS): New.
(TARGET_INITIALIZER): Add TARGET_EMUTLS.
* builtins.def (BUILT_IN_EMUTLS_GET_ADDRESS,
BUILT_IN_EMUTLS_REGISTER_COMMON): Get name from targetm structure.
* dwarf2out.c (loc_descriptor_from_tree_1): Check if emutls can
emit debug information.
* coretypes.h (tls_model): Add TLS_MODEL_EMULATED, TLS_MODEL_REAL.
* varasm.c: Include targhooks.h.
(emutls_object_section, emutls_tmpl_section): New.
(EMUTLS_VAR_PREFIX, EMUTLS_TMPL_PREFIX): Remove.
(EMUTLS_SEPARATOR): New.
(prefix_name): New.
(get_emutls_object_name): New.
(default_emutls_var_fields): New, broken out of ...
(get_emutls_object_type): ... here. Adjust to use target hooks.
(get_emutls_init_templ_addr): Adjust to use target hooks.
(emutls_decl): Adjust to use target hooks.
(emutls_finish): Likewise.
(default_emutls_var_init): New, broken out of ...
(assemble_variable): ... here. Adjust to use target hooks.
* output.h (enum section_category): Add SECCAT_EMUTLS_VAR,
SECCAT_EMUTLS_TMPL.
* c-common.c (handle_section_attribute): Prevent overriding
sections for emulated tls with special sections.
* config/i386/i386.c (x86_64_elf_select_section): Add
SECCAT_EMUTLS_VAR and SECCAT_EMUTLS_TMPL.
(x86_64_elf_unique_section): Likewise.
* config/vxworks.c: Include tree.h.
(vxworks_emutls_var_fields, vxworks_emutls_var_init): New.
(vxworks_override_options): Set TLS scheme.
* gcc/doc/tm.texi (Emulated TLS): New node.
2008-04-26 Simon Baldwin <simonb@google.com>
PR c/35652

View File

@ -745,8 +745,16 @@ 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)
DEF_BUILTIN (BUILT_IN_EMUTLS_GET_ADDRESS, targetm.emutls.get_address,
BUILT_IN_NORMAL,
BT_FN_PTR_PTR, BT_FN_PTR_PTR,
true, true, true, ATTR_CONST_NOTHROW_NONNULL, false,
!targetm.have_tls)
DEF_BUILTIN (BUILT_IN_EMUTLS_REGISTER_COMMON,
targetm.emutls.register_common, BUILT_IN_NORMAL,
BT_FN_VOID_PTR_WORD_WORD_PTR, BT_FN_VOID_PTR_WORD_WORD_PTR,
true, true, true, ATTR_NOTHROW_LIST, false,
!targetm.have_tls)
/* Synchronization Primitives. */
#include "sync-builtins.def"

View File

@ -5476,6 +5476,13 @@ handle_section_attribute (tree *node, tree ARG_UNUSED (name), tree args,
*node);
*no_add_attrs = true;
}
else if (TREE_CODE (decl) == VAR_DECL
&& !targetm.have_tls && targetm.emutls.tmpl_section
&& DECL_THREAD_LOCAL_P (decl))
{
error ("section of %q+D cannot be overridden", *node);
*no_add_attrs = true;
}
else
DECL_SECTION_NAME (decl) = TREE_VALUE (args);
}

View File

@ -2854,6 +2854,9 @@ x86_64_elf_select_section (tree decl, int reloc,
/* We don't split these for medium model. Place them into
default sections and hope for best. */
break;
case SECCAT_EMUTLS_VAR:
case SECCAT_EMUTLS_TMPL:
gcc_unreachable ();
}
if (sname)
{
@ -2890,16 +2893,16 @@ x86_64_elf_unique_section (tree decl, int reloc)
case SECCAT_DATA_REL_LOCAL:
case SECCAT_DATA_REL_RO:
case SECCAT_DATA_REL_RO_LOCAL:
prefix = one_only ? ".gnu.linkonce.ld." : ".ldata.";
prefix = one_only ? ".ld" : ".ldata";
break;
case SECCAT_BSS:
prefix = one_only ? ".gnu.linkonce.lb." : ".lbss.";
prefix = one_only ? ".lb" : ".lbss";
break;
case SECCAT_RODATA:
case SECCAT_RODATA_MERGE_STR:
case SECCAT_RODATA_MERGE_STR_INIT:
case SECCAT_RODATA_MERGE_CONST:
prefix = one_only ? ".gnu.linkonce.lr." : ".lrodata.";
prefix = one_only ? ".lr" : ".lrodata";
break;
case SECCAT_SRODATA:
case SECCAT_SDATA:
@ -2911,23 +2914,28 @@ x86_64_elf_unique_section (tree decl, int reloc)
/* We don't split these for medium model. Place them into
default sections and hope for best. */
break;
case SECCAT_EMUTLS_VAR:
prefix = targetm.emutls.var_section;
break;
case SECCAT_EMUTLS_TMPL:
prefix = targetm.emutls.tmpl_section;
break;
}
if (prefix)
{
const char *name;
size_t nlen, plen;
const char *name, *linkonce;
char *string;
plen = strlen (prefix);
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
name = targetm.strip_name_encoding (name);
nlen = strlen (name);
string = (char *) alloca (nlen + plen + 1);
memcpy (string, prefix, plen);
memcpy (string + plen, name, nlen + 1);
DECL_SECTION_NAME (decl) = build_string (nlen + plen, string);
/* If we're using one_only, then there needs to be a .gnu.linkonce
prefix to the section name. */
linkonce = one_only ? ".gnu.linkonce" : "";
string = ACONCAT ((linkonce, prefix, ".", name, NULL));
DECL_SECTION_NAME (decl) = build_string (strlen (string), string);
return;
}
}

View File

@ -26,6 +26,7 @@ along with GCC; see the file COPYING3. If not see
#include "toplev.h"
#include "output.h"
#include "tm.h"
#include "tree.h"
/* Like default_named_section_asm_out_constructor, except that even
constructors with DEFAULT_INIT_PRIORITY must go in a numbered
@ -56,11 +57,87 @@ vxworks_asm_out_destructor (rtx symbol, int priority)
assemble_addr_to_section (symbol, sec);
}
/* Return the list of FIELD_DECLs that make up an emulated TLS
variable's control object. TYPE is the structure these are fields
of and *NAME will be filled in with the structure tag that should
be used. */
static tree
vxworks_emutls_var_fields (tree type, tree *name)
{
tree field, next_field;
*name = get_identifier ("__tls_var");
field = build_decl (FIELD_DECL, get_identifier ("size"),
unsigned_type_node);
DECL_CONTEXT (field) = type;
next_field = field;
field = build_decl (FIELD_DECL, get_identifier ("module_id"),
unsigned_type_node);
DECL_CONTEXT (field) = type;
TREE_CHAIN (field) = next_field;
next_field = field;
field = build_decl (FIELD_DECL, get_identifier ("offset"),
unsigned_type_node);
DECL_CONTEXT (field) = type;
TREE_CHAIN (field) = next_field;
return field;
}
/* Return the CONSTRUCTOR to initialize an emulated TLS control
object. VAR is the control object. DECL is the TLS object itself
and TMPL_ADDR is the address (an ADDR_EXPR) of the initializer for
that object. */
static tree
vxworks_emutls_var_init (tree var, tree decl, tree tmpl_addr)
{
VEC(constructor_elt,gc) *v = VEC_alloc (constructor_elt, gc, 3);
constructor_elt *elt;
tree type = TREE_TYPE (var);
tree field = TYPE_FIELDS (type);
elt = VEC_quick_push (constructor_elt, v, NULL);
elt->index = field;
elt->value = fold_convert (TREE_TYPE (field), tmpl_addr);
elt = VEC_quick_push (constructor_elt, v, NULL);
field = TREE_CHAIN (field);
elt->index = field;
elt->value = build_int_cst (TREE_TYPE (field), 0);
elt = VEC_quick_push (constructor_elt, v, NULL);
field = TREE_CHAIN (field);
elt->index = field;
elt->value = fold_convert (TREE_TYPE (field), DECL_SIZE_UNIT (decl));
return build_constructor (type, v);
}
/* Do VxWorks-specific parts of OVERRIDE_OPTIONS. */
void
vxworks_override_options (void)
{
/* We don't support __thread via target hooks. */
targetm.have_tls = false;
targetm.emutls.get_address = "__builtin___tls_lookup";
targetm.emutls.register_common = NULL;
targetm.emutls.var_section = ".tls_vars";
targetm.emutls.tmpl_section = ".tls_data";
targetm.emutls.var_prefix = "__tls__";
targetm.emutls.tmpl_prefix = "";
targetm.emutls.var_fields = vxworks_emutls_var_fields;
targetm.emutls.var_init = vxworks_emutls_var_init;
targetm.emutls.var_align_fixed = true;
targetm.emutls.debug_form_tls_address = true;
/* We can use .ctors/.dtors sections only in RTP mode. */
targetm.have_ctors_dtors = TARGET_VXWORKS_RTP;

View File

@ -69,7 +69,9 @@ struct cpp_reader;
to it, so it's here. */
enum tls_model {
TLS_MODEL_NONE,
TLS_MODEL_GLOBAL_DYNAMIC,
TLS_MODEL_EMULATED,
TLS_MODEL_REAL,
TLS_MODEL_GLOBAL_DYNAMIC = TLS_MODEL_REAL,
TLS_MODEL_LOCAL_DYNAMIC,
TLS_MODEL_INITIAL_EXEC,
TLS_MODEL_LOCAL_EXEC

View File

@ -50,6 +50,7 @@ through the macros defined in the @file{.h} file.
* Floating Point:: Handling floating point for cross-compilers.
* Mode Switching:: Insertion of mode-switching instructions.
* Target Attributes:: Defining target-specific uses of @code{__attribute__}.
* Emulated TLS:: Emulated TLS support.
* MIPS Coprocessors:: MIPS coprocessor support and how to customize it.
* PCH Target:: Validity checking for precompiled headers.
* C++ ABI:: Controlling C++ ABI changes.
@ -9192,6 +9193,84 @@ attributes, @code{false} otherwise. By default, if a function has a
target specific attribute attached to it, it will not be inlined.
@end deftypefn
@node Emulated TLS
@section Emulating TLS
@cindex Emulated TLS
For targets whose psABI does not provide Thread Local Storage via
specific relocations and instruction sequences, an emulation layer is
used. A set of target hooks allows this emulation layer to be
configured for the requirements of a particular target. For instance
the psABI may infact specify TLS support in terms of an emulation
layer.
The emulation layer works by creating a control object for every TLS
object. To access the TLS object, a lookup function is provided
which, when given the address of the control object, will return the
address of the current thread's instance of the TLS object.
@deftypevr {Target Hook} {const char *} TARGET_EMUTLS_GET_ADDRESS
Contains the name of the helper function that uses a TLS control
object to locate a TLS instance. The default causes libgcc's
emulated TLS helper function to be used.
@end deftypevr
@deftypevr {Target Hook} {const char *} TARGET_EMUTLS_REGISTER_COMMON
Contains the name of the helper function that should be used at
program startup to register TLS objects that are implicitly
initialized to zero. If this is @code{NULL}, all TLS objects will
have explicit initializers. The default causes libgcc's emulated TLS
registration function to be used.
@end deftypevr
@deftypevr {Target Hook} {const char *} TARGET_EMUTLS_VAR_SECTION
Contains the name of the section in which TLS control variables should
be placed. The default of @code{NULL} allows these to be placed in
any section.
@end deftypevr
@deftypevr {Target Hook} {const char *} TARGET_EMUTLS_TMPL_SECTION
Contains the name of the section in which TLS initializers should be
placed. The default of @code{NULL} allows these to be placed in any
section.
@end deftypevr
@deftypevr {Target Hook} {const char *} TARGET_EMUTLS_VAR_PREFIX
Contains the prefix to be prepended to TLS control variable names.
The default of @code{NULL} uses a target-specific prefix.
@end deftypevr
@deftypevr {Target Hook} {const char *} TARGET_EMUTLS_TMPL_PREFIX
Contains the prefix to be prepended to TLS initializer objects. The
default of @code{NULL} uses a target-specific prefix.
@end deftypevr
@deftypefn {Target Hook} tree TARGET_EMUTLS_VAR_FIELDS (tree @var{type}, tree *@var{name})
Specifies a function that generates the FIELD_DECLs for a TLS control
object type. @var{type} is the RECORD_TYPE the fields are for and
@var{name} should be filled with the structure tag, if the default of
@code{__emutls_object} is unsuitable. The default creates a type suitable
for libgcc's emulated TLS function.
@end deftypefn
@deftypefn {Target Hook} tree TARGET_EMUTLS_VAR_INIT (tree @var{var}, tree @var{decl}, tree @var{tmpl_addr})
Specifies a function that generates the CONSTRUCTOR to initialize a
TLS control object. @var{var} is the TLS control object, @var{decl}
is the TLS object and @var{tmpl_addr} is the address of the
initializer. The default initializes libgcc's emulated TLS control object.
@end deftypefn
@deftypevr {Target Hook} {bool} TARGET_EMUTLS_VAR_ALIGN_FIXED
Specifies whether the alignment of TLS control variable objects is
fixed and should not be increased as some backends may do to optimize
single objects. The default is false.
@end deftypevr
@deftypevr {Target Hook} {bool} TARGET_EMUTLS_DEBUG_FORM_TLS_ADDRESS
Specifies whether a DWARF @code{DW_OP_form_tls_address} location descriptor
may be used to describe emulated TLS control objects.
@end deftypevr
@node MIPS Coprocessors
@section Defining coprocessor specifics for MIPS targets.
@cindex MIPS coprocessor-definition macros

View File

@ -9494,16 +9494,33 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
if (DECL_THREAD_LOCAL_P (loc))
{
rtx rtl;
unsigned first_op;
unsigned second_op;
/* If this is not defined, we have no way to emit the data. */
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
look up addresses of objects in the current module. */
if (DECL_EXTERNAL (loc))
return 0;
if (targetm.have_tls)
{
/* If this is not defined, we have no way to emit the
data. */
if (!targetm.asm_out.output_dwarf_dtprel)
return 0;
/* The way DW_OP_GNU_push_tls_address is specified, we
can only look up addresses of objects in the current
module. */
if (DECL_EXTERNAL (loc))
return 0;
first_op = INTERNAL_DW_OP_tls_addr;
second_op = DW_OP_GNU_push_tls_address;
}
else
{
if (!targetm.emutls.debug_form_tls_address)
return 0;
loc = emutls_decl (loc);
first_op = DW_OP_addr;
second_op = DW_OP_form_tls_address;
}
rtl = rtl_for_decl_location (loc);
if (rtl == NULL_RTX)
return 0;
@ -9514,11 +9531,11 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
if (! CONSTANT_P (rtl))
return 0;
ret = new_loc_descr (INTERNAL_DW_OP_tls_addr, 0, 0);
ret = new_loc_descr (first_op, 0, 0);
ret->dw_loc_oprnd1.val_class = dw_val_class_addr;
ret->dw_loc_oprnd1.v.val_addr = rtl;
ret1 = new_loc_descr (DW_OP_GNU_push_tls_address, 0, 0);
ret1 = new_loc_descr (second_op, 0, 0);
add_loc_descr (&ret, ret1);
have_address = 1;

View File

@ -460,7 +460,10 @@ enum section_category
SECCAT_BSS,
SECCAT_SBSS,
SECCAT_TBSS
SECCAT_TBSS,
SECCAT_EMUTLS_VAR,
SECCAT_EMUTLS_TMPL
};
/* Information that is provided by all instances of the section type. */

View File

@ -692,6 +692,61 @@
TARGET_CXX_ADJUST_CLASS_AT_DEFINITION \
}
/* EMUTLS specific */
#ifndef TARGET_EMUTLS_GET_ADDRESS
#define TARGET_EMUTLS_GET_ADDRESS "__builtin___emutls_get_address"
#endif
#ifndef TARGET_EMUTLS_REGISTER_COMMON
#define TARGET_EMUTLS_REGISTER_COMMON "__builtin___emutls_register_common"
#endif
#ifndef TARGET_EMUTLS_VAR_SECTION
#define TARGET_EMUTLS_VAR_SECTION NULL
#endif
#ifndef TARGET_EMUTLS_TMPL_SECTION
#define TARGET_EMUTLS_TMPL_SECTION NULL
#endif
#ifndef TARGET_EMUTLS_VAR_PREFIX
#define TARGET_EMUTLS_VAR_PREFIX NULL
#endif
#ifndef TARGET_EMUTLS_TMPL_PREFIX
#define TARGET_EMUTLS_TMPL_PREFIX NULL
#endif
#ifndef TARGET_EMUTLS_VAR_FIELDS
#define TARGET_EMUTLS_VAR_FIELDS default_emutls_var_fields
#endif
#ifndef TARGET_EMUTLS_VAR_INIT
#define TARGET_EMUTLS_VAR_INIT default_emutls_var_init
#endif
#ifndef TARGET_EMUTLS_VAR_ALIGN_FIXED
#define TARGET_EMUTLS_VAR_ALIGN_FIXED false
#endif
#ifndef TARGET_EMUTLS_DEBUG_FORM_TLS_ADDRESS
#define TARGET_EMUTLS_DEBUG_FORM_TLS_ADDRESS false
#endif
#define TARGET_EMUTLS \
{ \
TARGET_EMUTLS_GET_ADDRESS, \
TARGET_EMUTLS_REGISTER_COMMON, \
TARGET_EMUTLS_VAR_SECTION, \
TARGET_EMUTLS_TMPL_SECTION, \
TARGET_EMUTLS_VAR_PREFIX, \
TARGET_EMUTLS_TMPL_PREFIX, \
TARGET_EMUTLS_VAR_FIELDS, \
TARGET_EMUTLS_VAR_INIT, \
TARGET_EMUTLS_VAR_ALIGN_FIXED, \
TARGET_EMUTLS_DEBUG_FORM_TLS_ADDRESS \
}
/* The whole shebang. */
#define TARGET_INITIALIZER \
{ \
@ -783,6 +838,7 @@
TARGET_INSTANTIATE_DECLS, \
TARGET_C, \
TARGET_CXX, \
TARGET_EMUTLS, \
TARGET_EXTRA_LIVE_ON_ENTRY, \
TARGET_UNWIND_TABLES_DEFAULT, \
TARGET_HAVE_NAMED_SECTIONS, \

View File

@ -917,6 +917,34 @@ struct gcc_target
void (*adjust_class_at_definition) (tree type);
} cxx;
/* Functions and data for emulated TLS support. */
struct emutls {
/* Name of the address and common functions. */
const char *get_address;
const char *register_common;
/* Prefixes for proxy variable and template. */
const char *var_section;
const char *tmpl_section;
/* Prefixes for proxy variable and template. */
const char *var_prefix;
const char *tmpl_prefix;
/* Function to generate field definitions of the proxy variable. */
tree (*var_fields) (tree, tree *);
/* Function to initialize a proxy variable. */
tree (*var_init) (tree, tree, tree);
/* Whether we are allowed to alter the usual alignment of the
proxy variable. */
bool var_align_fixed;
/* Whether we can emit debug information for TLS vars. */
bool debug_form_tls_address;
} emutls;
/* For targets that need to mark extra registers as live on entry to
the function, they should define this target hook and set their
bits in the bitmap passed in. */

View File

@ -94,3 +94,5 @@ extern void hook_void_bitmap (bitmap);
extern bool default_handle_c_option (size_t, const char *, int);
extern int default_reloc_rw_mask (void);
extern tree default_mangle_decl_assembler_name (tree, tree);
extern tree default_emutls_var_fields (tree, tree *);
extern tree default_emutls_var_init (tree, tree, tree);

View File

@ -1,3 +1,10 @@
2008-04-27 Nathan Sidwell <nathan@codesourcery.com>
* gcc.dg/tls/section-2.c: New.
* gcc.dg/tls/emutls-1.c: New.
* lib/target-supports.exp (check_effective_target_tls_native):
Exclude vxworks.
2008-04-26 H.J. Lu <hongjiu.lu@intel.com>
PR testsuite/36053

View File

@ -0,0 +1,21 @@
/* { dg-do run { target *-wrs-vxworks } } */
/* { dg-require-effective-target tls } */
/* vxworks' TLS model requires no extra padding on the tls proxy
objects. */
__thread int i;
__thread int j;
extern int __tls__i;
extern int __tls__j;
int main ()
{
int delta = ((char *)&__tls__j - (char *)&__tls__i);
if (delta < 0)
delta = -delta;
return delta != 12;
}

View File

@ -0,0 +1,7 @@
/* Verify that we get errors for trying to put TLS data in
sections which can't work. */
/* { dg-require-effective-target tls } */
#define A(X) __attribute__((section(X)))
__thread int i A("foo"); /* { dg-error "cannot be overridden" } */

View File

@ -518,6 +518,13 @@ proc check_effective_target_tls {} {
# This won't change for different subtargets so cache the result.
proc check_effective_target_tls_native {} {
# VxWorks uses emulated TLS machinery, but with non-standard helper
# functions, so we fail to automatically detect it.
global target_triplet
if { [regexp ".*-.*-vxworks.*" $target_triplet] } {
return 0
}
return [check_no_messages_and_pattern tls_native "!emutls" assembly {
__thread int i;
int f (void) { return i; }

View File

@ -3178,7 +3178,7 @@ extern void decl_fini_priority_insert (tree, priority_type);
/* In a VAR_DECL, nonzero if the data should be allocated from
thread-local storage. */
#define DECL_THREAD_LOCAL_P(NODE) \
(VAR_DECL_CHECK (NODE)->decl_with_vis.tls_model != TLS_MODEL_NONE)
(VAR_DECL_CHECK (NODE)->decl_with_vis.tls_model >= TLS_MODEL_REAL)
struct tree_var_decl GTY(())
{

View File

@ -48,6 +48,7 @@ along with GCC; see the file COPYING3. If not see
#include "tm_p.h"
#include "debug.h"
#include "target.h"
#include "targhooks.h"
#include "tree-mudflap.h"
#include "cgraph.h"
#include "cfglayout.h"
@ -194,30 +195,74 @@ static GTY(()) struct rtx_constant_pool *shared_constant_pool;
static GTY ((if_marked ("tree_map_marked_p"), param_is (struct tree_map)))
htab_t emutls_htab;
static GTY (()) tree emutls_object_type;
/* Emulated TLS objects have the TLS model TLS_MODEL_EMULATED. This
macro can be used on them to distinguish the control variable from
the initialization template. */
#define DECL_EMUTLS_VAR_P(D) (TREE_TYPE (D) == 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$"
#if !defined (NO_DOT_IN_LABEL)
# define EMUTLS_SEPARATOR "."
#elif !defined (NO_DOLLAR_IN_LABEL)
# define EMUTLS_SEPARATOR "$"
#else
# define EMUTLS_VAR_PREFIX "__emutls_v_"
# define EMUTLS_TMPL_PREFIX "__emutls_t_"
# define EMUTLS_SEPARATOR "_"
#endif
/* Create an IDENTIFIER_NODE by prefixing PREFIX to the
IDENTIFIER_NODE NAME's name. */
static tree
prefix_name (const char *prefix, tree name)
{
unsigned plen = strlen (prefix);
unsigned nlen = strlen (IDENTIFIER_POINTER (name));
char *toname = alloca (plen + nlen + 1);
memcpy (toname, prefix, plen);
memcpy (toname + plen, IDENTIFIER_POINTER (name), nlen + 1);
return get_identifier (toname);
}
/* 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));
const char *prefix = (targetm.emutls.var_prefix
? targetm.emutls.var_prefix
: "__emutls_v" EMUTLS_SEPARATOR);
return prefix_name (prefix, name);
}
return get_identifier (toname);
tree
default_emutls_var_fields (tree type, tree *name ATTRIBUTE_UNUSED)
{
tree word_type_node, field, next_field;
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;
return field;
}
/* Create the structure for struct __emutls_object. This should match the
@ -226,36 +271,19 @@ get_emutls_object_name (tree name)
static tree
get_emutls_object_type (void)
{
tree type, type_name, field, next_field, word_type_node;
tree type, type_name, field;
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 = NULL;
field = targetm.emutls.var_fields (type, &type_name);
if (!type_name)
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);
@ -269,26 +297,30 @@ static tree
get_emutls_init_templ_addr (tree decl)
{
tree name, to;
char *toname;
if (!DECL_INITIAL (decl))
if (targetm.emutls.register_common && !DECL_INITIAL (decl)
&& !DECL_SECTION_NAME (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);
if (!targetm.emutls.tmpl_prefix || targetm.emutls.tmpl_prefix[0])
{
const char *prefix = (targetm.emutls.tmpl_prefix
? targetm.emutls.tmpl_prefix
: "__emutls_t" EMUTLS_SEPARATOR);
name = prefix_name (prefix, name);
}
to = build_decl (VAR_DECL, name, TREE_TYPE (decl));
SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to));
DECL_TLS_MODEL (to) = TLS_MODEL_EMULATED;
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_SECTION_NAME (to) = DECL_SECTION_NAME (decl);
DECL_WEAK (to) = DECL_WEAK (decl);
if (DECL_ONE_ONLY (decl))
{
@ -348,14 +380,18 @@ emutls_decl (tree decl)
h->to = to;
*(struct tree_map **) loc = h;
DECL_TLS_MODEL (to) = TLS_MODEL_EMULATED;
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);
if (targetm.emutls.var_align_fixed)
/* If we're not allowed to change the proxy object's
alignment, pretend it's been set by the user. */
DECL_USER_ALIGN (to) = 1;
}
/* Note that these fields may need to be updated from time to time from
@ -413,16 +449,19 @@ emutls_common_1 (void **loc, void *xstmts)
void
emutls_finish (void)
{
tree body = NULL_TREE;
if (!targetm.emutls.register_common)
{
tree body = NULL_TREE;
if (emutls_htab == NULL)
return;
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);
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. */
@ -1125,7 +1164,12 @@ get_variable_section (tree decl, bool prefer_noswitch_p)
{
if (DECL_THREAD_LOCAL_P (decl))
return tls_comm_section;
if (TREE_PUBLIC (decl) && bss_initializer_p (decl))
/* This cannot be common bss for an emulated TLS object without
a register_common hook. */
else if (DECL_TLS_MODEL (decl) == TLS_MODEL_EMULATED
&& !targetm.emutls.register_common)
;
else if (TREE_PUBLIC (decl) && bss_initializer_p (decl))
return comm_section;
}
@ -1950,6 +1994,40 @@ assemble_variable_contents (tree decl, const char *name,
}
}
/* Initialize emulated tls object TO, which refers to TLS variable
DECL and is initialized by PROXY. */
tree
default_emutls_var_init (tree to, tree decl, tree proxy)
{
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 = proxy;
return build_constructor (type, v);
}
/* Assemble everything that is needed for a variable or function declaration.
Not used for automatic variables, and not used for function definitions.
Should not be called for variables of incomplete structure type.
@ -1984,32 +2062,8 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
|| (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);
DECL_INITIAL (to) = targetm.emutls.var_init
(to, decl, get_emutls_init_templ_addr (decl));
/* Make sure the template is marked as needed early enough.
Without this, if the variable is placed in a
@ -5786,13 +5840,26 @@ categorize_decl_for_section (const_tree decl, int reloc)
ret = SECCAT_RODATA;
/* There are no read-only thread-local sections. */
if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl))
if (TREE_CODE (decl) == VAR_DECL && DECL_TLS_MODEL (decl))
{
if (DECL_TLS_MODEL (decl) == TLS_MODEL_EMULATED)
{
if (DECL_EMUTLS_VAR_P (decl))
{
if (targetm.emutls.var_section)
ret = SECCAT_EMUTLS_VAR;
}
else
{
if (targetm.emutls.tmpl_prefix)
ret = SECCAT_EMUTLS_TMPL;
}
}
/* Note that this would be *just* SECCAT_BSS, except that there's
no concept of a read-only thread-local-data section. */
if (ret == SECCAT_BSS
|| (flag_zero_initialized_in_bss
&& initializer_zerop (DECL_INITIAL (decl))))
else if (ret == SECCAT_BSS
|| (flag_zero_initialized_in_bss
&& initializer_zerop (DECL_INITIAL (decl))))
ret = SECCAT_TBSS;
else
ret = SECCAT_TDATA;
@ -5884,6 +5951,12 @@ default_elf_select_section (tree decl, int reloc,
case SECCAT_TBSS:
sname = ".tbss";
break;
case SECCAT_EMUTLS_VAR:
sname = targetm.emutls.var_section;
break;
case SECCAT_EMUTLS_TMPL:
sname = targetm.emutls.tmpl_section;
break;
default:
gcc_unreachable ();
}
@ -5901,69 +5974,73 @@ default_unique_section (tree decl, int reloc)
{
/* We only need to use .gnu.linkonce if we don't have COMDAT groups. */
bool one_only = DECL_ONE_ONLY (decl) && !HAVE_COMDAT_GROUP;
const char *prefix, *name;
size_t nlen, plen;
const char *prefix, *name, *linkonce;
char *string;
switch (categorize_decl_for_section (decl, reloc))
{
case SECCAT_TEXT:
prefix = one_only ? ".gnu.linkonce.t." : ".text.";
prefix = one_only ? ".t" : ".text";
break;
case SECCAT_RODATA:
case SECCAT_RODATA_MERGE_STR:
case SECCAT_RODATA_MERGE_STR_INIT:
case SECCAT_RODATA_MERGE_CONST:
prefix = one_only ? ".gnu.linkonce.r." : ".rodata.";
prefix = one_only ? ".r" : ".rodata";
break;
case SECCAT_SRODATA:
prefix = one_only ? ".gnu.linkonce.s2." : ".sdata2.";
prefix = one_only ? ".s2" : ".sdata2";
break;
case SECCAT_DATA:
prefix = one_only ? ".gnu.linkonce.d." : ".data.";
prefix = one_only ? ".d" : ".data";
break;
case SECCAT_DATA_REL:
prefix = one_only ? ".gnu.linkonce.d.rel." : ".data.rel.";
prefix = one_only ? ".d.rel" : ".data.rel";
break;
case SECCAT_DATA_REL_LOCAL:
prefix = one_only ? ".gnu.linkonce.d.rel.local." : ".data.rel.local.";
prefix = one_only ? ".d.rel.local" : ".data.rel.local";
break;
case SECCAT_DATA_REL_RO:
prefix = one_only ? ".gnu.linkonce.d.rel.ro." : ".data.rel.ro.";
prefix = one_only ? ".d.rel.ro" : ".data.rel.ro";
break;
case SECCAT_DATA_REL_RO_LOCAL:
prefix = one_only ? ".gnu.linkonce.d.rel.ro.local."
: ".data.rel.ro.local.";
prefix = one_only ? ".d.rel.ro.local" : ".data.rel.ro.local";
break;
case SECCAT_SDATA:
prefix = one_only ? ".gnu.linkonce.s." : ".sdata.";
prefix = one_only ? ".s" : ".sdata";
break;
case SECCAT_BSS:
prefix = one_only ? ".gnu.linkonce.b." : ".bss.";
prefix = one_only ? ".b" : ".bss";
break;
case SECCAT_SBSS:
prefix = one_only ? ".gnu.linkonce.sb." : ".sbss.";
prefix = one_only ? ".sb" : ".sbss";
break;
case SECCAT_TDATA:
prefix = one_only ? ".gnu.linkonce.td." : ".tdata.";
prefix = one_only ? ".td" : ".tdata";
break;
case SECCAT_TBSS:
prefix = one_only ? ".gnu.linkonce.tb." : ".tbss.";
prefix = one_only ? ".tb" : ".tbss";
break;
case SECCAT_EMUTLS_VAR:
prefix = targetm.emutls.var_section;
break;
case SECCAT_EMUTLS_TMPL:
prefix = targetm.emutls.tmpl_section;
break;
default:
gcc_unreachable ();
}
plen = strlen (prefix);
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
name = targetm.strip_name_encoding (name);
nlen = strlen (name);
string = alloca (nlen + plen + 1);
memcpy (string, prefix, plen);
memcpy (string + plen, name, nlen + 1);
/* If we're using one_only, then there needs to be a .gnu.linkonce
prefix to the section name. */
linkonce = one_only ? ".gnu.linkonce" : "";
string = ACONCAT ((linkonce, prefix, ".", name, NULL));
DECL_SECTION_NAME (decl) = build_string (nlen + plen, string);
DECL_SECTION_NAME (decl) = build_string (strlen (string), string);
}
/* Like compute_reloc_for_constant, except for an RTX. The return value