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]

[ARM] TLS Descriptor support


This patch implements TLS descriptor support in GCC. TLS descriptors are described at http://www.codesourcery.com/publications/RFC-TLSDESC-ARM.txt and blessed by ARM, who have reserved the relocation numbers.

Binutils and GLIBC patches are already committed (there is an orthogonal glibc patch to do with make dependencies that I need to post though).

This patch adds a --with-tls={arm|gnu} configuration option, to specify the default scheme. It can be overridden with a -mtls-dialect={arm|gnu} option (this is the name used by the x86 backend, which also has tlsdescriptor support). I have not added --with-tls support to the x86 bits of config.gcc etc, but it would be simple to do so.

The arm.{c,h,md} changes are fairly mechanical -- a new tls pattern and smarts to emit it appropriately.

This patch has been tested for both default arm and default gnu tls schemes using the gcc and glibc testsuites for an arm-linux-gnueabi target.

ok?

nathan

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

2011-05-10  Nathan Sidwell  <nathan@codesourcery.com>

	* doc/invoke.texi (ARM Options): Document -mtls-dialect option.
	* doc/install.texi (Configuration): Document --with-tls.
	* config.gcc (arm*-*-linux*): Default to arm-style tls.
	(arm*-*-*): Add --with-tls option.
	(all_defaults): Add 'tls'.
	* config/arm/arm.c (target_tls_dialect): New.
	(enum tls_reloc): Add TLS_DESCSEQ.
	(arm_override_options): Process target_tls_dialect_switch value.
	(arm_call_tls_get_addr): Clean up. Assert not tls descriptor.
	(arm_tls_descseq_addr): New.
	(legitimize_tls_address): Add tlsdesc support.
	(arm_cannot_copy_insn_p): Check for tlscall.
	(arm_emit_tls_decoration): Likewise.
	* config/arm/arm.h (TARGET_ARM_TLS, TARGET_GNU_TLS): New.
	(OPTION_DEFAULT_SPECS): Add with-tls support.
	(enum arm_tls_type): New.
	(target_tls_dialect): New.
	* config/arm/arm.opt (mtls-dialect): New switch.
	* config/arm/arm.md (tlscall): New.

	testsuite/
	* gcc.target/arm/tlscall.c: New.

Index: doc/invoke.texi
===================================================================
--- doc/invoke.texi	(revision 172962)
+++ doc/invoke.texi	(working copy)
@@ -469,7 +469,7 @@ Objective-C and Objective-C++ Dialects}.
 -mthumb  -marm @gol
 -mtpcs-frame  -mtpcs-leaf-frame @gol
 -mcaller-super-interworking  -mcallee-super-interworking @gol
--mtp=@var{name} @gol
+-mtp=@var{name} -mtls-dialect=@var{dialect} @gol
 -mword-relocations @gol
 -mfix-cortex-m3-ldrd}
 
@@ -10332,6 +10332,17 @@ models are @option{soft}, which generate
 best available method for the selected processor.  The default setting is
 @option{auto}.
 
+@item -mtls-dialect=@var{dialect}
+@opindex mtls-dialect
+Specify the dialect to use for accessing thread local storage.  Two
+dialects are supported - @option{arm} and @option{gnu}.  The
+@option{arm} dialect selects the ARM EABI scheme for supporting local
+and global dynamic tls models.  The @option{gnu} dialect selects the
+experimental GNU scheme.  The GNU scheme is compatible with the ARM
+scheme, but does require new assembler, linker and library
+support.  Initial and local exec TLS models are unaffected by this
+option and use the ARM EABI scheme.
+
 @item -mword-relocations
 @opindex mword-relocations
 Only generate absolute relocations on word sized values (i.e. R_ARM_ABS32).
Index: doc/install.texi
===================================================================
--- doc/install.texi	(revision 172962)
+++ doc/install.texi	(working copy)
@@ -1003,6 +1003,12 @@ information normally used on 386 SVR4 pl
 workable alternative.  This requires gas and gdb, as the normal SVR4
 tools can not generate or interpret stabs.
 
+@item --with-tls=@var{dialect}
+Specify the default tls dialect, for systems were there is a choice.
+For ARM targets, possible values for @var{dialect} are @code{arm} or
+@code{gnu}, which select between the ARM EABI dialect and the GNU TLS
+descriptor-based dialect.
+
 @item --disable-multilib
 Specify that multiple target
 libraries to support different target variants, calling
Index: testsuite/gcc.target/arm/tlscall.c
===================================================================
--- testsuite/gcc.target/arm/tlscall.c	(revision 0)
+++ testsuite/gcc.target/arm/tlscall.c	(revision 0)
@@ -0,0 +1,31 @@
+/* Test non-duplication of tlscall insn */
+
+/* { dg-do assemble } */
+/* { dg-options "-O2 -fPIC -mtls-dialect=gnu" } */
+
+typedef struct _IO_FILE FILE;
+
+extern int foo(void);
+extern int bar(void);
+
+void uuid__generate_time()
+{
+ static int has_init = 0;
+ static __thread int state_fd = -2;
+ static __thread FILE *state_f;
+
+ if (!has_init) {
+   foo();
+   has_init = 1;
+ }
+
+ if (state_fd == -2) {
+  if (!state_f) {
+   state_fd = -1;
+  }
+ }
+ if (state_fd >= 0) {
+  while (bar() < 0) {}
+ }
+
+}
Index: config.gcc
===================================================================
--- config.gcc	(revision 172962)
+++ config.gcc	(working copy)
@@ -813,6 +813,7 @@ arm*-*-linux*)			# ARM GNU/Linux with EL
 	    tmake_file="$tmake_file arm/t-linux"
 	    ;;
 	esac
+	with_tls=${with_tls:arm}
 	tm_file="$tm_file arm/aout.h arm/arm.h"
 	tmake_file="${tmake_file} arm/t-arm-softfp soft-fp/t-softfp"
 	;;
@@ -3064,7 +3065,7 @@ case "${target}" in
 		;;
 
 	arm*-*-*)
-		supported_defaults="arch cpu float tune fpu abi mode"
+		supported_defaults="arch cpu float tune fpu abi mode tls"
 		for which in cpu tune; do
 			# See if it matches any of the entries in arm-cores.def
 			eval "val=\$with_$which"
@@ -3147,6 +3148,17 @@ case "${target}" in
 			;;
 		esac
 
+		case "$with_tls" in
+		"" \
+		| arm | gnu)
+			# OK
+			;;
+		*)
+			echo "Unknown TLS method used in --with-tls=$with_tls" 1>&2
+			exit 1
+			;;
+		esac
+
 		if test "x$with_arch" != x && test "x$with_cpu" != x; then
 			echo "Warning: --with-arch overrides --with-cpu=$with_cpu" 1>&2
 		fi
@@ -3624,7 +3636,7 @@ case ${target} in
 esac
 
 t=
-all_defaults="abi cpu cpu_32 cpu_64 arch arch_32 arch_64 tune tune_32 tune_64 schedule float mode fpu divide llsc mips-plt synci"
+all_defaults="abi cpu cpu_32 cpu_64 arch arch_32 arch_64 tune tune_32 tune_64 schedule float mode fpu divide llsc mips-plt synci tls"
 for option in $all_defaults
 do
 	eval "val=\$with_"`echo $option | sed s/-/_/g`
Index: config/arm/arm.c
===================================================================
--- config/arm/arm.c	(revision 172962)
+++ config/arm/arm.c	(working copy)
@@ -644,6 +644,9 @@ enum arm_abi_type arm_abi;
 /* Which thread pointer model to use.  */
 enum arm_tp_type target_thread_pointer = TP_AUTO;
 
+/* Which tls dialect to use.  */
+enum arm_tls_type target_tls_dialect = TLS_ARM;
+
 /* Used to parse -mstructure_size_boundary command line option.  */
 int    arm_structure_size_boundary = DEFAULT_STRUCTURE_SIZE_BOUNDARY;
 
@@ -1031,7 +1034,8 @@ enum tls_reloc {
   TLS_LDM32,
   TLS_LDO32,
   TLS_IE32,
-  TLS_LE32
+  TLS_LE32,
+  TLS_DESCSEQ	/* GNU scheme */
 };
 
 /* The maximum number of insns to be used when loading a constant.  */
@@ -1755,6 +1759,17 @@ arm_option_override (void)
 	error ("invalid thread pointer option: -mtp=%s", target_thread_switch);
     }
 
+  if (target_tls_dialect_switch)
+    {
+      if (strcmp (target_tls_dialect_switch, "arm") == 0)
+	target_tls_dialect = TLS_ARM;
+      else if (strcmp (target_tls_dialect_switch, "gnu") == 0)
+	target_tls_dialect = TLS_GNU;
+      else
+	error ("invalid thread dialect option: -mtls-dialect=%s",
+	       target_tls_dialect_switch);
+    }
+
   /* Use the cp15 method if it is available.  */
   if (target_thread_pointer == TP_AUTO)
     {
@@ -5957,6 +5972,7 @@ arm_call_tls_get_addr (rtx x, rtx reg, r
 {
   rtx insns, label, labelno, sum;
 
+  gcc_assert (reloc != TLS_DESCSEQ);
   start_sequence ();
 
   labelno = GEN_INT (pic_labelno++);
@@ -5971,20 +5987,42 @@ arm_call_tls_get_addr (rtx x, rtx reg, r
 
   if (TARGET_ARM)
     emit_insn (gen_pic_add_dot_plus_eight (reg, reg, labelno));
-  else if (TARGET_THUMB2)
-    emit_insn (gen_pic_add_dot_plus_four (reg, reg, labelno));
-  else /* TARGET_THUMB1 */
+  else
     emit_insn (gen_pic_add_dot_plus_four (reg, reg, labelno));
-
-  *valuep = emit_library_call_value (get_tls_get_addr (), NULL_RTX, LCT_PURE, /* LCT_CONST?  */
+  
+  *valuep = emit_library_call_value (get_tls_get_addr (), NULL_RTX,
+				     LCT_PURE, /* LCT_CONST?  */
 				     Pmode, 1, reg, Pmode);
-
+  
   insns = get_insns ();
   end_sequence ();
 
   return insns;
 }
 
+static rtx
+arm_tls_descseq_addr (rtx x, rtx reg)
+{
+  rtx labelno = GEN_INT (pic_labelno++);
+  rtx label = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, labelno), UNSPEC_PIC_LABEL);
+  rtx sum = gen_rtx_UNSPEC (Pmode,
+			    gen_rtvec (4, x, GEN_INT (TLS_DESCSEQ),
+				       gen_rtx_CONST (VOIDmode, label),
+				       GEN_INT (!TARGET_ARM)),
+			    UNSPEC_TLS);
+  rtx reg0 = load_tls_operand (sum, gen_rtx_REG (SImode, 0));
+  
+  emit_insn (gen_tlscall (x, labelno));
+  if (!reg)
+    reg = gen_reg_rtx (SImode);
+  else
+    gcc_assert (REGNO (reg) != 0);
+
+  emit_move_insn (reg, reg0);
+
+  return reg;
+}
+
 rtx
 legitimize_tls_address (rtx x, rtx reg)
 {
@@ -5994,26 +6032,49 @@ legitimize_tls_address (rtx x, rtx reg)
   switch (model)
     {
     case TLS_MODEL_GLOBAL_DYNAMIC:
-      insns = arm_call_tls_get_addr (x, reg, &ret, TLS_GD32);
-      dest = gen_reg_rtx (Pmode);
-      emit_libcall_block (insns, dest, ret, x);
-      return dest;
+      if (TARGET_ARM_TLS)
+	{
+	  insns = arm_call_tls_get_addr (x, reg, &ret, TLS_GD32);
+	  dest = gen_reg_rtx (Pmode);
+	  emit_libcall_block (insns, dest, ret, x);
+	  return dest;
+	}
+      else
+	{
+	  reg = arm_tls_descseq_addr (x, reg);
 
-    case TLS_MODEL_LOCAL_DYNAMIC:
-      insns = arm_call_tls_get_addr (x, reg, &ret, TLS_LDM32);
+	  tp = arm_load_tp (NULL_RTX);
+	  
+	  return gen_rtx_PLUS (Pmode, tp, reg);
+	}
 
-      /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
-	 share the LDM result with other LD model accesses.  */
-      eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const1_rtx),
-			    UNSPEC_TLS);
-      dest = gen_reg_rtx (Pmode);
-      emit_libcall_block (insns, dest, ret, eqv);
+    case TLS_MODEL_LOCAL_DYNAMIC:
+      if (TARGET_ARM_TLS)
+	{
+	  insns = arm_call_tls_get_addr (x, reg, &ret, TLS_LDM32);
+	  
+	  /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
+	     share the LDM result with other LD model accesses.  */
+	  eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const1_rtx),
+				UNSPEC_TLS);
+	  dest = gen_reg_rtx (Pmode);
+	  emit_libcall_block (insns, dest, ret, eqv);
+	  
+	  /* Load the addend.  */
+	  addend = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x,
+						     GEN_INT (TLS_LDO32)),
+				   UNSPEC_TLS);
+	  addend = force_reg (SImode, gen_rtx_CONST (SImode, addend));
+	  return gen_rtx_PLUS (Pmode, dest, addend);
+	}
+      else
+	{
+	  reg = arm_tls_descseq_addr (x, reg);
 
-      /* Load the addend.  */
-      addend = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (TLS_LDO32)),
-			       UNSPEC_TLS);
-      addend = force_reg (SImode, gen_rtx_CONST (SImode, addend));
-      return gen_rtx_PLUS (Pmode, dest, addend);
+	  tp = arm_load_tp (NULL_RTX);
+	  
+	  return gen_rtx_PLUS (Pmode, tp, reg);
+	}
 
     case TLS_MODEL_INITIAL_EXEC:
       labelno = GEN_INT (pic_labelno++);
@@ -9445,6 +9506,11 @@ arm_note_pic_base (rtx *x, void *date AT
 static bool
 arm_cannot_copy_insn_p (rtx insn)
 {
+  /* The tls call insn cannot be copied, as it is paired with a data
+     word.  */
+  if (recog_memoized (insn) == CODE_FOR_tlscall)
+    return true;
+  
   return for_each_rtx (&PATTERN (insn), arm_note_pic_base, NULL);
 }
 
@@ -22985,6 +23051,9 @@ arm_emit_tls_decoration (FILE *fp, rtx x
     case TLS_LE32:
       fputs ("(tpoff)", fp);
       break;
+    case TLS_DESCSEQ:
+      fputs ("(tlsdesc)", fp);
+      break;
     default:
       gcc_unreachable ();
     }
@@ -22994,9 +23063,11 @@ arm_emit_tls_decoration (FILE *fp, rtx x
     case TLS_GD32:
     case TLS_LDM32:
     case TLS_IE32:
+    case TLS_DESCSEQ:
       fputs (" + (. - ", fp);
       output_addr_const (fp, XVECEXP (x, 0, 2));
-      fputs (" - ", fp);
+      /* For DESCSEQ the 3rd operand encodes thumbness, and is added */
+      fputs (reloc == TLS_DESCSEQ ? " + " : " - ", fp);
       output_addr_const (fp, XVECEXP (x, 0, 3));
       fputc (')', fp);
       break;
Index: config/arm/arm.h
===================================================================
--- config/arm/arm.h	(revision 172962)
+++ config/arm/arm.h	(working copy)
@@ -218,6 +218,8 @@ extern void (*arm_lang_output_object_att
 
 #define TARGET_HARD_TP			(target_thread_pointer == TP_CP15)
 #define TARGET_SOFT_TP			(target_thread_pointer == TP_SOFT)
+#define TARGET_ARM_TLS			(target_tls_dialect == TLS_ARM)
+#define TARGET_GNU_TLS			(target_tls_dialect == TLS_GNU)
 
 /* Only 16-bit thumb code.  */
 #define TARGET_THUMB1			(TARGET_THUMB && !arm_arch_thumb2)
@@ -306,7 +308,8 @@ extern void (*arm_lang_output_object_att
      by -march).
    --with-float is ignored if -mfloat-abi is specified.
    --with-fpu is ignored if -mfpu is specified.
-   --with-abi is ignored is -mabi is specified.  */
+   --with-abi is ignored if -mabi is specified.
+   --with-tls is ignored if -mtls-dialect is specified. */
 #define OPTION_DEFAULT_SPECS \
   {"arch", "%{!march=*:%{!mcpu=*:-march=%(VALUE)}}" }, \
   {"cpu", "%{!march=*:%{!mcpu=*:-mcpu=%(VALUE)}}" }, \
@@ -314,7 +317,8 @@ extern void (*arm_lang_output_object_att
   {"float", "%{!mfloat-abi=*:-mfloat-abi=%(VALUE)}" }, \
   {"fpu", "%{!mfpu=*:-mfpu=%(VALUE)}"}, \
   {"abi", "%{!mabi=*:-mabi=%(VALUE)}"}, \
-  {"mode", "%{!marm:%{!mthumb:-m%(VALUE)}}"},
+  {"mode", "%{!marm:%{!mthumb:-m%(VALUE)}}"}, \
+  {"tls", "%{!mtls-dialect:-mtls-dialect=%(VALUE)}"},
 
 /* Which floating point model to use.  */
 enum arm_fp_model
@@ -400,7 +404,13 @@ enum arm_tp_type {
   TP_CP15
 };
 
+enum arm_tls_type {
+  TLS_ARM,
+  TLS_GNU
+};
+
 extern enum arm_tp_type target_thread_pointer;
+extern enum arm_tls_type target_tls_dialect;
 
 /* Nonzero if this chip supports the ARM Architecture 3M extensions.  */
 extern int arm_arch3m;
Index: config/arm/arm.opt
===================================================================
--- config/arm/arm.opt	(revision 172962)
+++ config/arm/arm.opt	(working copy)
@@ -138,6 +138,10 @@ mthumb-interwork
 Target Report Mask(INTERWORK)
 Support calls between Thumb and ARM instruction sets
 
+mtls-dialect=
+Target RejectNegative Joined Var(target_tls_dialect_switch)
+Specify thread local storage scheme
+
 mtp=
 Target RejectNegative Joined Var(target_thread_switch)
 Specify how to access the thread pointer
Index: config/arm/arm.md
===================================================================
--- config/arm/arm.md	(revision 172962)
+++ config/arm/arm.md	(working copy)
@@ -10620,6 +10620,28 @@
   [(set_attr "conds" "clob")]
 )
 
+;; tls descriptor call
+(define_insn "tlscall"
+  [(set (reg:SI 0) (unspec:SI [(reg:SI 0)
+                               (match_operand:SI 0 "" "X")
+			       (match_operand 1 "" "")] UNSPEC_TLS))
+   (clobber (reg:SI 1))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (reg:SI CC_REGNUM))]
+  "TARGET_GNU_TLS"
+  {
+    targetm.asm_out.internal_label (asm_out_file, "LPIC",
+				    INTVAL (operands[1]));
+    /* The + is to avoid an assembly parse ambiguity with symbols that
+       look like register names, which is unsuccessfully recovered from.  */
+    return TARGET_THUMB2 ? "blx\\t%c0(tlscall)" : "bl\\t+%c0(tlscall)";
+  }
+  [(set_attr "conds" "clob")
+   (set_attr "length" "4")]
+)
+
+;;
+
 ;; We only care about the lower 16 bits of the constant 
 ;; being inserted into the upper 16 bits of the register.
 (define_insn "*arm_movtas_ze" 

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