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.
===================================================================
@@ -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).
===================================================================
@@ -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
===================================================================
@@ -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) {}
+ }
+
+}
===================================================================
@@ -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`
===================================================================
@@ -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;
===================================================================
@@ -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;
===================================================================
@@ -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
===================================================================
@@ -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"