+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
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"
*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);
}
/* 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)
{
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:
/* 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;
}
}
#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
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;
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
* 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.
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
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;
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;
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. */
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 \
{ \
TARGET_INSTANTIATE_DECLS, \
TARGET_C, \
TARGET_CXX, \
+ TARGET_EMUTLS, \
TARGET_EXTRA_LIVE_ON_ENTRY, \
TARGET_UNWIND_TABLES_DEFAULT, \
TARGET_HAVE_NAMED_SECTIONS, \
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. */
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);
+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
--- /dev/null
+/* { 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;
+}
--- /dev/null
+/* 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" } */
# 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; }
/* 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(())
{
#include "tm_p.h"
#include "debug.h"
#include "target.h"
+#include "targhooks.h"
#include "tree-mudflap.h"
#include "cgraph.h"
#include "cfglayout.h"
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$"
+/* 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)
+
+#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 for the struct __emutls_object, given an identifier
- of the DECL_ASSEMBLY_NAME of the original object. */
+/* Create an IDENTIFIER_NODE by prefixing PREFIX to the
+ IDENTIFIER_NODE NAME's name. */
static tree
-get_emutls_object_name (tree name)
+prefix_name (const char *prefix, 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));
+ 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 the structure for struct __emutls_object. This should match the
- structure at the top of emutls.c, modulo the union there. */
+/* 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_type (void)
+get_emutls_object_name (tree name)
{
- 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;
+ const char *prefix = (targetm.emutls.var_prefix
+ ? targetm.emutls.var_prefix
+ : "__emutls_v" EMUTLS_SEPARATOR);
+ return prefix_name (prefix, name);
+}
+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);
+
+ 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);
+ 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
+ structure at the top of emutls.c, modulo the union there. */
+
+static tree
+get_emutls_object_type (void)
+{
+ 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 = 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;
TYPE_FIELDS (type) = field;
layout_type (type);
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))
{
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
void
emutls_finish (void)
{
- tree body = NULL_TREE;
-
- if (emutls_htab == NULL)
- return;
+ if (!targetm.emutls.register_common)
+ {
+ tree body = NULL_TREE;
- htab_traverse_noresize (emutls_htab, emutls_common_1, &body);
- if (body == NULL_TREE)
- return;
+ if (emutls_htab == NULL)
+ 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. */
{
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;
}
}
}
+/* 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.
|| (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
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;
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 ();
}
{
/* 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