This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: TLS support for vxworks


Mark Mitchell wrote:

With a few minor nitpicks, yes. (No need to retest; just make the edits and check it in.)

done.


nathan

--
Nathan Sidwell    ::   http://www.codesourcery.com   ::         CodeSourcery

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.

	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.

Index: doc/tm.texi
===================================================================
--- doc/tm.texi	(revision 134722)
+++ doc/tm.texi	(working copy)
@@ -50,6 +50,7 @@
 * 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 @@
 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
Index: targhooks.h
===================================================================
--- targhooks.h	(revision 134722)
+++ targhooks.h	(working copy)
@@ -94,3 +94,5 @@
 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);
Index: tree.h
===================================================================
--- tree.h	(revision 134722)
+++ tree.h	(working copy)
@@ -3178,7 +3178,7 @@
 /* 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(())
 {
Index: target.h
===================================================================
--- target.h	(revision 134722)
+++ target.h	(working copy)
@@ -917,6 +917,34 @@
     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. */  
Index: testsuite/gcc.dg/tls/section-2.c
===================================================================
--- testsuite/gcc.dg/tls/section-2.c	(revision 0)
+++ testsuite/gcc.dg/tls/section-2.c	(revision 0)
@@ -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" } */
Index: testsuite/gcc.dg/tls/emutls-1.c
===================================================================
--- testsuite/gcc.dg/tls/emutls-1.c	(revision 0)
+++ testsuite/gcc.dg/tls/emutls-1.c	(revision 0)
@@ -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;
+}
Index: testsuite/lib/target-supports.exp
===================================================================
--- testsuite/lib/target-supports.exp	(revision 134722)
+++ testsuite/lib/target-supports.exp	(working copy)
@@ -518,6 +518,13 @@
 # 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; }
Index: builtins.def
===================================================================
--- builtins.def	(revision 134722)
+++ builtins.def	(working copy)
@@ -745,8 +745,16 @@
 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"
Index: dwarf2out.c
===================================================================
--- dwarf2out.c	(revision 134722)
+++ dwarf2out.c	(working copy)
@@ -9494,16 +9494,33 @@
       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;
+	  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;
-
+	       /* 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 @@
 	  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;
Index: coretypes.h
===================================================================
--- coretypes.h	(revision 134722)
+++ coretypes.h	(working copy)
@@ -69,7 +69,9 @@
    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
Index: varasm.c
===================================================================
--- varasm.c	(revision 134722)
+++ varasm.c	(working copy)
@@ -48,6 +48,7 @@
 #include "tm_p.h"
 #include "debug.h"
 #include "target.h"
+#include "targhooks.h"
 #include "tree-mudflap.h"
 #include "cgraph.h"
 #include "cfglayout.h"
@@ -194,68 +195,95 @@
 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 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;
+  const char *prefix = (targetm.emutls.var_prefix
+			? targetm.emutls.var_prefix
+			: "__emutls_v" EMUTLS_SEPARATOR);
+  return prefix_name (prefix, name);
+}
 
-  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;
-
+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);
 
@@ -269,26 +297,30 @@
 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 @@
       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 @@
 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 @@
     {
       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 @@
     }
 }
 
+/* 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,33 +2062,9 @@
 	      || (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);
+	  DECL_INITIAL (to) = targetm.emutls.var_init
+	    (to, decl, get_emutls_init_templ_addr (decl));
 
-	  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
@@ -5786,13 +5840,26 @@
     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 @@
     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 @@
 {
   /* 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
Index: target-def.h
===================================================================
--- target-def.h	(revision 134722)
+++ target-def.h	(working copy)
@@ -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,			\
Index: output.h
===================================================================
--- output.h	(revision 134722)
+++ output.h	(working copy)
@@ -460,7 +460,10 @@
 
   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.  */
Index: c-common.c
===================================================================
--- c-common.c	(revision 134722)
+++ c-common.c	(working copy)
@@ -5476,6 +5476,13 @@
 		     *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);
 	}
Index: config/i386/i386.c
===================================================================
--- config/i386/i386.c	(revision 134722)
+++ config/i386/i386.c	(working copy)
@@ -2854,6 +2854,9 @@
 	  /* 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 @@
 	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 @@
 	  /* 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;
 	}
     }
Index: config/vxworks.c
===================================================================
--- config/vxworks.c	(revision 134722)
+++ config/vxworks.c	(working copy)
@@ -26,6 +26,7 @@
 #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 @@
   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;
 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]