This patches addresses your comments.
I've fixed:
* config and option items Joseph pointed out in
http://gcc.gnu.org/ml/gcc-patches/2011-05/msg00719.html
* md items Ramana pointed out in
http://gcc.gnu.org/ml/gcc-patches/2011-05/msg02109.html
* option naming and assembly issues Richard pointed out in
http://gcc.gnu.org/ml/gcc-patches/2011-06/msg00429.html
revalidated with defaults to both gnu and gnu2 style. ok?
nathan
--
Nathan Sidwell
2011-06-21 Nathan Sidwell <nat...@codesourcery.com>
* doc/invoke.texi (ARM Options): Document -mtls-dialect option.
* doc/install.texi (Configuration): Document --with-tls.
* config.gcc (arm*-*-linux*): Default to gnu tls.
(arm*-*-*): Add --with-tls option.
(all_defaults): Add 'tls'.
* config/arm/arm.c (enum tls_reloc): Add TLS_DESCSEQ.
(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_GNU2_TLS): New.
(OPTION_DEFAULT_SPECS): Add with-tls support.
* config/arm/arm.md (R1_REGNUM): Define.
(tlscall): New.
* config/arm/arm.opt (tls_type): New enumeration type and values.
(mtls-dialect): New switch.
* config/arm/arm-opts.h (enum tls_type): New.
testsuite/
* gcc.target/arm/tlscall.c: New.
Index: doc/invoke.texi
===================================================================
--- doc/invoke.texi (revision 174801)
+++ doc/invoke.texi (working copy)
@@ -476,7 +476,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}
@@ -10461,6 +10461,18 @@ 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{gnu} and @option{gnu2}. The
+@option{gnu} dialect selects the original GNU scheme for supporting
+local and global dynamic TLS models. The @option{gnu2} dialect
+selects the GNU descriptor scheme, which provides better performance
+for shared libraries. The GNU descriptor scheme is compatible with
+the original scheme, but does require new assembler, linker and
+library support. Initial and local exec TLS models are unaffected by
+this option and always use the original 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 174801)
+++ doc/install.texi (working copy)
@@ -1016,6 +1016,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{gnu} or
+@code{gnu2}, which select between the original GNU 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=gnu2" } */
+
+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 174801)
+++ config.gcc (working copy)
@@ -822,6 +822,7 @@ arm*-*-linux*) # ARM GNU/Linux with EL
tmake_file="$tmake_file arm/t-linux"
;;
esac
+ with_tls=${with_tls:-gnu}
tm_file="$tm_file arm/aout.h arm/arm.h"
tmake_file="${tmake_file} arm/t-arm-softfp soft-fp/t-softfp"
;;
@@ -3059,7 +3060,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"
@@ -3142,6 +3143,17 @@ case "${target}" in
;;
esac
+ case "$with_tls" in
+ "" \
+ | gnu | gnu2)
+ # 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
@@ -3621,7 +3633,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 174801)
+++ config/arm/arm.c (working copy)
@@ -1026,7 +1026,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. */
@@ -5871,6 +5872,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++);
@@ -5885,20 +5887,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)
{
@@ -5908,26 +5932,51 @@ 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);
+ if (TARGET_GNU2_TLS)
+ {
+ reg = arm_tls_descseq_addr (x, reg);
+
+ tp = arm_load_tp (NULL_RTX);
+
+ dest = gen_rtx_PLUS (Pmode, tp, reg);
+ }
+ else
+ {
+ /* Original scheme */
+ 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;
case TLS_MODEL_LOCAL_DYNAMIC:
- 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);
+ if (TARGET_GNU2_TLS)
+ {
+ 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);
+
+ dest = gen_rtx_PLUS (Pmode, tp, reg);
+ }
+ else
+ {
+ 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));
+ dest = gen_rtx_PLUS (Pmode, dest, addend);
+ }
+ return dest;
case TLS_MODEL_INITIAL_EXEC:
labelno = GEN_INT (pic_labelno++);
@@ -9374,6 +9423,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);
}
@@ -22928,6 +22982,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 ();
}
@@ -22937,9 +22994,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 174801)
+++ config/arm/arm.h (working copy)
@@ -220,6 +220,7 @@ 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_GNU2_TLS (target_tls_dialect == TLS_GNU2)
/* Only 16-bit thumb code. */
#define TARGET_THUMB1 (TARGET_THUMB && !arm_arch_thumb2)
@@ -313,7 +314,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)}}" }, \
@@ -321,7 +323,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
Index: config/arm/arm.opt
===================================================================
--- config/arm/arm.opt (revision 174801)
+++ config/arm/arm.opt (working copy)
@@ -21,6 +21,16 @@
HeaderInclude
config/arm/arm-opts.h
+Enum
+Name(tls_type) Type(enum arm_tls_type)
+TLS dialect to use:
+
+EnumValue
+Enum(tls_type) String(gnu) Value(TLS_GNU)
+
+EnumValue
+Enum(tls_type) String(gnu2) Value(TLS_GNU2)
+
mabi=
Target RejectNegative Joined Enum(arm_abi_type) Var(arm_abi) Init(ARM_DEFAULT_ABI)
Specify an ABI
@@ -190,6 +200,10 @@ mthumb-interwork
Target Report Mask(INTERWORK)
Support calls between Thumb and ARM instruction sets
+mtls-dialect=
+Target RejectNegative Joined Enum(tls_type) Var(target_tls_dialect) Init(TLS_GNU)
+Specify thread local storage scheme
+
mtp=
Target RejectNegative Joined Enum(arm_tp_type) Var(target_thread_pointer) Init(TP_AUTO)
Specify how to access the thread pointer
Index: config/arm/arm.md
===================================================================
--- config/arm/arm.md (revision 174801)
+++ config/arm/arm.md (working copy)
@@ -31,6 +31,7 @@
;; Register numbers
(define_constants
[(R0_REGNUM 0) ; First CORE register
+ (R1_REGNUM 1) ; Second CORE register
(IP_REGNUM 12) ; Scratch register
(SP_REGNUM 13) ; Stack pointer
(LR_REGNUM 14) ; Return address register
@@ -10703,6 +10704,27 @@
[(set_attr "conds" "clob")]
)
+;; tls descriptor call
+(define_insn "tlscall"
+ [(set (reg:SI R0_REGNUM)
+ (unspec:SI [(reg:SI R0_REGNUM)
+ (match_operand:SI 0 "" "X")
+ (match_operand 1 "" "")] UNSPEC_TLS))
+ (clobber (reg:SI R1_REGNUM))
+ (clobber (reg:SI LR_REGNUM))
+ (clobber (reg:SI CC_REGNUM))]
+ "TARGET_GNU2_TLS"
+ {
+ targetm.asm_out.internal_label (asm_out_file, "LPIC",
+ INTVAL (operands[1]));
+ return "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: config/arm/arm-opts.h
===================================================================
--- config/arm/arm-opts.h (revision 174801)
+++ config/arm/arm-opts.h (working copy)
@@ -68,4 +68,9 @@ enum arm_tp_type {
TP_CP15
};
+/* Which TLS scheme to use. */
+enum arm_tls_type {
+ TLS_GNU,
+ TLS_GNU2
+};
#endif