2011-06-21 Nathan Sidwell * 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