2011-05-10 Nathan Sidwell * 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"