From 4a55687c47b75f8a8efa1fd8d68dddd28c8406a9 Mon Sep 17 00:00:00 2001 From: aoliva Date: Thu, 19 Jan 2006 00:40:16 +0000 Subject: [PATCH] Introduce TLS descriptors for i386 and x86_64. * config/i386/i386.h (TARGET_GNU2_TLS): New macro. (TARGET_ANY_GNU_TLS): New macro. (enum tls_dialect): Added TLS_DIALECT_GNU2. (struct machine_function): Add tls_descriptor_call_expanded_p. (ix86_tls_descriptor_calls_expande_in_cfun): New macro. (ix86_current_function_calls_tls_descriptor): Likewise. * config/i386/i386.c (ix86_tls_dialect): Fix typo in comment. (override_options): Introduce gnu2 tls dialect. (ix86_frame_pointer_required): Functions containing TLSCALLs are not leaves. (ix86_select_alt_pic_regnum, ix86_compute_frame_layout): Likewise. (legitimize_tls_address): Adjust logic for GNU2 TLS. (ix86_init_machine_status): Initialize new field. (ix86_tls_get_addr): Use TARGET_ANY_GNU_TLS. (ix86_tls_module_base): New. * config/i386/i386-protos.h (ix86_tls_module_base): Declare it. * config/i386/i386.md (UNSPEC_TLSDESC): New constant. (tls_global_dynamic_32, tls_global_dynamic_64): Handle GNU2 TLS. (tls_local_dynamic_base_32, tls_local_dynamic_base_64): Likewise. (tls_dynamic_gnu2_32, *tls_dynamic_lea_32): New patterns. (*tls_dynamic_call_32, *tls_dynamic_gnu2_combine_32): Likewise. (tls_dynamic_gnu2_64, *tls_dynamic_lea_64): Likewise. (*tls_dynamic_call_64, *tls_dynamic_gnu2_combine_64): Likewise. * config/i386/predicates.md (tls_modbase_operand): New. (tp_or_register_operand): New. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@109934 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 30 ++++++++ gcc/config/i386/i386-protos.h | 4 +- gcc/config/i386/i386.c | 86 +++++++++++++++++----- gcc/config/i386/i386.h | 24 +++++- gcc/config/i386/i386.md | 167 +++++++++++++++++++++++++++++++++++++++++- gcc/config/i386/predicates.md | 11 ++- 6 files changed, 301 insertions(+), 21 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 642a89154ce..9511cdba041 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,33 @@ +2006-01-18 Alexandre Oliva + + Introduce TLS descriptors for i386 and x86_64. + * config/i386/i386.h (TARGET_GNU2_TLS): New macro. + (TARGET_ANY_GNU_TLS): New macro. + (enum tls_dialect): Added TLS_DIALECT_GNU2. + (struct machine_function): Add tls_descriptor_call_expanded_p. + (ix86_tls_descriptor_calls_expande_in_cfun): New macro. + (ix86_current_function_calls_tls_descriptor): Likewise. + * config/i386/i386.c (ix86_tls_dialect): Fix typo in comment. + (override_options): Introduce gnu2 tls dialect. + (ix86_frame_pointer_required): Functions containing TLSCALLs are + not leaves. + (ix86_select_alt_pic_regnum, ix86_compute_frame_layout): + Likewise. + (legitimize_tls_address): Adjust logic for GNU2 TLS. + (ix86_init_machine_status): Initialize new field. + (ix86_tls_get_addr): Use TARGET_ANY_GNU_TLS. + (ix86_tls_module_base): New. + * config/i386/i386-protos.h (ix86_tls_module_base): Declare it. + * config/i386/i386.md (UNSPEC_TLSDESC): New constant. + (tls_global_dynamic_32, tls_global_dynamic_64): Handle GNU2 TLS. + (tls_local_dynamic_base_32, tls_local_dynamic_base_64): Likewise. + (tls_dynamic_gnu2_32, *tls_dynamic_lea_32): New patterns. + (*tls_dynamic_call_32, *tls_dynamic_gnu2_combine_32): Likewise. + (tls_dynamic_gnu2_64, *tls_dynamic_lea_64): Likewise. + (*tls_dynamic_call_64, *tls_dynamic_gnu2_combine_64): Likewise. + * config/i386/predicates.md (tls_modbase_operand): New. + (tp_or_register_operand): New. + 2006-01-18 Daniel Berlin * ipa-reference.c (check_operand): Allow FUNCTION_DECL. diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h index 188c9677b77..ed9d4f3d62e 100644 --- a/gcc/config/i386/i386-protos.h +++ b/gcc/config/i386/i386-protos.h @@ -1,6 +1,7 @@ /* Definitions of target machine for GCC for IA-32. Copyright (C) 1988, 1992, 1994, 1995, 1996, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. This file is part of GCC. @@ -179,6 +180,7 @@ extern int x86_field_alignment (tree, int); #endif extern rtx ix86_tls_get_addr (void); +extern rtx ix86_tls_module_base (void); extern void ix86_expand_vector_init (bool, rtx, rtx); extern void ix86_expand_vector_set (bool, rtx, rtx, int); diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index f4838de8d4b..e45d2a266bd 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -1,6 +1,6 @@ /* Subroutines used for code generation on IA-32. Copyright (C) 1988, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, - 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GCC. @@ -876,7 +876,7 @@ struct ix86_frame enum cmodel ix86_cmodel; /* Asm dialect. */ enum asm_dialect ix86_asm_dialect = ASM_ATT; -/* TLS dialext. */ +/* TLS dialects. */ enum tls_dialect ix86_tls_dialect = TLS_DIALECT_GNU; /* Which unit we are generating floating point math for. */ @@ -1626,6 +1626,8 @@ override_options (void) { if (strcmp (ix86_tls_dialect_string, "gnu") == 0) ix86_tls_dialect = TLS_DIALECT_GNU; + else if (strcmp (ix86_tls_dialect_string, "gnu2") == 0) + ix86_tls_dialect = TLS_DIALECT_GNU2; else if (strcmp (ix86_tls_dialect_string, "sun") == 0) ix86_tls_dialect = TLS_DIALECT_SUN; else @@ -4415,7 +4417,8 @@ ix86_frame_pointer_required (void) the frame pointer by default. Turn it back on now if we've not got a leaf function. */ if (TARGET_OMIT_LEAF_FRAME_POINTER - && (!current_function_is_leaf)) + && (!current_function_is_leaf + || ix86_current_function_calls_tls_descriptor)) return 1; if (current_function_profile) @@ -4597,7 +4600,8 @@ gen_push (rtx arg) static unsigned int ix86_select_alt_pic_regnum (void) { - if (current_function_is_leaf && !current_function_profile) + if (current_function_is_leaf && !current_function_profile + && !ix86_current_function_calls_tls_descriptor) { int i; for (i = 2; i >= 0; --i) @@ -4788,7 +4792,8 @@ ix86_compute_frame_layout (struct ix86_frame *frame) expander assumes that last current_function_outgoing_args_size of stack frame are unused. */ if (ACCUMULATE_OUTGOING_ARGS - && (!current_function_is_leaf || current_function_calls_alloca)) + && (!current_function_is_leaf || current_function_calls_alloca + || ix86_current_function_calls_tls_descriptor)) { offset += current_function_outgoing_args_size; frame->outgoing_arguments_size = current_function_outgoing_args_size; @@ -4798,7 +4803,8 @@ ix86_compute_frame_layout (struct ix86_frame *frame) /* Align stack boundary. Only needed if we're calling another function or using alloca. */ - if (!current_function_is_leaf || current_function_calls_alloca) + if (!current_function_is_leaf || current_function_calls_alloca + || ix86_current_function_calls_tls_descriptor) frame->padding2 = ((offset + preferred_alignment - 1) & -preferred_alignment) - offset; else @@ -4819,7 +4825,8 @@ ix86_compute_frame_layout (struct ix86_frame *frame) frame->save_regs_using_mov = false; if (TARGET_RED_ZONE && current_function_sp_is_unchanging - && current_function_is_leaf) + && current_function_is_leaf + && !ix86_current_function_calls_tls_descriptor) { frame->red_zone_size = frame->to_allocate; if (frame->save_regs_using_mov) @@ -6351,14 +6358,16 @@ get_thread_pointer (int to_reg) static rtx legitimize_tls_address (rtx x, enum tls_model model, int for_mov) { - rtx dest, base, off, pic; + rtx dest, base, off, pic, tp; int type; switch (model) { case TLS_MODEL_GLOBAL_DYNAMIC: dest = gen_reg_rtx (Pmode); - if (TARGET_64BIT) + tp = TARGET_GNU2_TLS ? get_thread_pointer (1) : 0; + + if (TARGET_64BIT && ! TARGET_GNU2_TLS) { rtx rax = gen_rtx_REG (Pmode, 0), insns; @@ -6369,13 +6378,24 @@ legitimize_tls_address (rtx x, enum tls_model model, int for_mov) emit_libcall_block (insns, dest, rax, x); } + else if (TARGET_64BIT && TARGET_GNU2_TLS) + emit_insn (gen_tls_global_dynamic_64 (dest, x)); else emit_insn (gen_tls_global_dynamic_32 (dest, x)); + + if (TARGET_GNU2_TLS) + { + dest = force_reg (Pmode, gen_rtx_PLUS (Pmode, tp, dest)); + + set_unique_reg_note (get_last_insn (), REG_EQUIV, x); + } break; case TLS_MODEL_LOCAL_DYNAMIC: base = gen_reg_rtx (Pmode); - if (TARGET_64BIT) + tp = TARGET_GNU2_TLS ? get_thread_pointer (1) : 0; + + if (TARGET_64BIT && ! TARGET_GNU2_TLS) { rtx rax = gen_rtx_REG (Pmode, 0), insns, note; @@ -6388,13 +6408,25 @@ legitimize_tls_address (rtx x, enum tls_model model, int for_mov) note = gen_rtx_EXPR_LIST (VOIDmode, ix86_tls_get_addr (), note); emit_libcall_block (insns, base, rax, note); } + else if (TARGET_64BIT && TARGET_GNU2_TLS) + emit_insn (gen_tls_local_dynamic_base_64 (base)); else emit_insn (gen_tls_local_dynamic_base_32 (base)); + if (TARGET_GNU2_TLS) + { + rtx x = ix86_tls_module_base (); + + base = force_reg (Pmode, gen_rtx_PLUS (Pmode, tp, base)); + + set_unique_reg_note (get_last_insn (), REG_EQUIV, x); + } + off = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_DTPOFF); off = gen_rtx_CONST (Pmode, off); - return gen_rtx_PLUS (Pmode, base, off); + dest = force_reg (Pmode, gen_rtx_PLUS (Pmode, base, off)); + break; case TLS_MODEL_INITIAL_EXEC: if (TARGET_64BIT) @@ -6407,9 +6439,9 @@ legitimize_tls_address (rtx x, enum tls_model model, int for_mov) if (reload_in_progress) regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1; pic = pic_offset_table_rtx; - type = TARGET_GNU_TLS ? UNSPEC_GOTNTPOFF : UNSPEC_GOTTPOFF; + type = TARGET_ANY_GNU_TLS ? UNSPEC_GOTNTPOFF : UNSPEC_GOTTPOFF; } - else if (!TARGET_GNU_TLS) + else if (!TARGET_ANY_GNU_TLS) { pic = gen_reg_rtx (Pmode); emit_insn (gen_set_got (pic)); @@ -6428,7 +6460,7 @@ legitimize_tls_address (rtx x, enum tls_model model, int for_mov) off = gen_const_mem (Pmode, off); set_mem_alias_set (off, ix86_GOT_alias_set ()); - if (TARGET_64BIT || TARGET_GNU_TLS) + if (TARGET_64BIT || TARGET_ANY_GNU_TLS) { base = get_thread_pointer (for_mov || !TARGET_TLS_DIRECT_SEG_REFS); off = force_reg (Pmode, off); @@ -6444,11 +6476,11 @@ legitimize_tls_address (rtx x, enum tls_model model, int for_mov) case TLS_MODEL_LOCAL_EXEC: off = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), - (TARGET_64BIT || TARGET_GNU_TLS) + (TARGET_64BIT || TARGET_ANY_GNU_TLS) ? UNSPEC_NTPOFF : UNSPEC_TPOFF); off = gen_rtx_CONST (Pmode, off); - if (TARGET_64BIT || TARGET_GNU_TLS) + if (TARGET_64BIT || TARGET_ANY_GNU_TLS) { base = get_thread_pointer (for_mov || !TARGET_TLS_DIRECT_SEG_REFS); return gen_rtx_PLUS (Pmode, base, off); @@ -12900,6 +12932,7 @@ ix86_init_machine_status (void) f = ggc_alloc_cleared (sizeof (struct machine_function)); f->use_fast_prologue_epilogue_nregs = -1; + f->tls_descriptor_call_expanded_p = 0; return f; } @@ -12942,13 +12975,32 @@ ix86_tls_get_addr (void) if (!ix86_tls_symbol) { ix86_tls_symbol = gen_rtx_SYMBOL_REF (Pmode, - (TARGET_GNU_TLS && !TARGET_64BIT) + (TARGET_ANY_GNU_TLS + && !TARGET_64BIT) ? "___tls_get_addr" : "__tls_get_addr"); } return ix86_tls_symbol; } + +/* Construct the SYMBOL_REF for the _TLS_MODULE_BASE_ symbol. */ + +static GTY(()) rtx ix86_tls_module_base_symbol; +rtx +ix86_tls_module_base (void) +{ + + if (!ix86_tls_module_base_symbol) + { + ix86_tls_module_base_symbol = gen_rtx_SYMBOL_REF (Pmode, + "_TLS_MODULE_BASE_"); + SYMBOL_REF_FLAGS (ix86_tls_module_base_symbol) + |= TLS_MODEL_GLOBAL_DYNAMIC << SYMBOL_FLAG_TLS_SHIFT; + } + + return ix86_tls_module_base_symbol; +} /* Calculate the length of the memory address in the instruction encoding. Does not include the one-byte modrm, opcode, or prefix. */ diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index 88398d9ec2d..b402f3d95db 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -1,6 +1,6 @@ /* Definitions of target machine for GCC for IA-32. Copyright (C) 1988, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000, - 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GCC. @@ -225,6 +225,8 @@ extern int x86_prefetch_sse; && (ix86_fpmath & FPMATH_387)) #define TARGET_GNU_TLS (ix86_tls_dialect == TLS_DIALECT_GNU) +#define TARGET_GNU2_TLS (ix86_tls_dialect == TLS_DIALECT_GNU2) +#define TARGET_ANY_GNU_TLS (TARGET_GNU_TLS || TARGET_GNU2_TLS) #define TARGET_SUN_TLS (ix86_tls_dialect == TLS_DIALECT_SUN) #define TARGET_CMPXCHG (x86_cmpxchg & (1 << ix86_arch)) @@ -2134,6 +2136,7 @@ extern enum fpmath_unit ix86_fpmath; enum tls_dialect { TLS_DIALECT_GNU, + TLS_DIALECT_GNU2, TLS_DIALECT_SUN }; @@ -2275,11 +2278,30 @@ struct machine_function GTY(()) /* Number of saved registers USE_FAST_PROLOGUE_EPILOGUE has been computed for. */ int use_fast_prologue_epilogue_nregs; + /* If true, the current function needs the default PIC register, not + an alternate register (on x86) and must not use the red zone (on + x86_64), even if it's a leaf function. We don't want the + function to be regarded as non-leaf because TLS calls need not + affect register allocation. This flag is set when a TLS call + instruction is expanded within a function, and never reset, even + if all such instructions are optimized away. Use the + ix86_current_function_calls_tls_descriptor macro for a better + approximation. */ + int tls_descriptor_call_expanded_p; }; #define ix86_stack_locals (cfun->machine->stack_locals) #define ix86_save_varrargs_registers (cfun->machine->save_varrargs_registers) #define ix86_optimize_mode_switching (cfun->machine->optimize_mode_switching) +#define ix86_tls_descriptor_calls_expanded_in_cfun \ + (cfun->machine->tls_descriptor_call_expanded_p) +/* Since tls_descriptor_call_expanded is not cleared, even if all TLS + calls are optimized away, we try to detect cases in which it was + optimized away. Since such instructions (use (reg REG_SP)), we can + verify whether there's any such instruction live by testing that + REG_SP is live. */ +#define ix86_current_function_calls_tls_descriptor \ + (ix86_tls_descriptor_calls_expanded_in_cfun && regs_ever_live[SP_REG]) /* Control behavior of x86_file_start. */ #define X86_FILE_START_VERSION_DIRECTIVE false diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 146ed096c6a..6b3b91cdc45 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -1,6 +1,6 @@ ;; GCC machine description for IA-32 and x86-64. ;; Copyright (C) 1988, 1994, 1995, 1996, 1997, 1998, 1999, 2000, -;; 2001, 2002, 2003, 2004, 2005 +;; 2001, 2002, 2003, 2004, 2005, 2006 ;; Free Software Foundation, Inc. ;; Mostly by William Schelter. ;; x86_64 support added by Jan Hubicka @@ -73,6 +73,7 @@ (UNSPEC_TP 16) (UNSPEC_TLS_GD 17) (UNSPEC_TLS_LD_BASE 18) + (UNSPEC_TLSDESC 19) ; Other random patterns (UNSPEC_SCAS 20) @@ -14161,6 +14162,12 @@ operands[2] = gen_reg_rtx (Pmode); emit_insn (gen_set_got (operands[2])); } + if (TARGET_GNU2_TLS) + { + emit_insn (gen_tls_dynamic_gnu2_32 + (operands[0], operands[1], operands[2])); + DONE; + } operands[3] = ix86_tls_get_addr (); }) @@ -14182,6 +14189,12 @@ UNSPEC_TLS_GD)])] "" { + if (TARGET_GNU2_TLS) + { + emit_insn (gen_tls_dynamic_gnu2_64 + (operands[0], operands[1])); + DONE; + } operands[2] = ix86_tls_get_addr (); }) @@ -14228,6 +14241,12 @@ operands[1] = gen_reg_rtx (Pmode); emit_insn (gen_set_got (operands[1])); } + if (TARGET_GNU2_TLS) + { + emit_insn (gen_tls_dynamic_gnu2_32 + (operands[0], ix86_tls_module_base (), operands[1])); + DONE; + } operands[2] = ix86_tls_get_addr (); }) @@ -14247,6 +14266,12 @@ (unspec:DI [(const_int 0)] UNSPEC_TLS_LD_BASE)])] "" { + if (TARGET_GNU2_TLS) + { + emit_insn (gen_tls_dynamic_gnu2_64 + (operands[0], ix86_tls_module_base ())); + DONE; + } operands[1] = ix86_tls_get_addr (); }) @@ -14324,6 +14349,146 @@ (set_attr "length" "7") (set_attr "memory" "load") (set_attr "imm_disp" "false")]) + +;; GNU2 TLS patterns can be split. + +(define_expand "tls_dynamic_gnu2_32" + [(set (match_dup 3) + (plus:SI (match_operand:SI 2 "register_operand" "") + (const:SI + (unspec:SI [(match_operand:SI 1 "tls_symbolic_operand" "")] + UNSPEC_TLSDESC)))) + (parallel + [(set (match_operand:SI 0 "register_operand" "") + (unspec:SI [(match_dup 1) (match_dup 3) + (match_dup 2) (reg:SI SP_REG)] + UNSPEC_TLSDESC)) + (clobber (reg:CC FLAGS_REG))])] + "!TARGET_64BIT && TARGET_GNU2_TLS" +{ + operands[3] = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode); + ix86_tls_descriptor_calls_expanded_in_cfun = true; +}) + +(define_insn "*tls_dynamic_lea_32" + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_operand:SI 1 "register_operand" "b") + (const:SI + (unspec:SI [(match_operand:SI 2 "tls_symbolic_operand" "")] + UNSPEC_TLSDESC))))] + "!TARGET_64BIT && TARGET_GNU2_TLS" + "lea{l}\t{%a2@TLSDESC(%1), %0|%0, %a2@TLSDESC[%1]}" + [(set_attr "type" "lea") + (set_attr "mode" "SI") + (set_attr "length" "6") + (set_attr "length_address" "4")]) + +(define_insn "*tls_dynamic_call_32" + [(set (match_operand:SI 0 "register_operand" "=a") + (unspec:SI [(match_operand:SI 1 "tls_symbolic_operand" "") + (match_operand:SI 2 "register_operand" "0") + ;; we have to make sure %ebx still points to the GOT + (match_operand:SI 3 "register_operand" "b") + (reg:SI SP_REG)] + UNSPEC_TLSDESC)) + (clobber (reg:CC FLAGS_REG))] + "!TARGET_64BIT && TARGET_GNU2_TLS" + "call\t{*%a1@TLSCALL(%2)|[DWORD PTR [%2+%a1@TLSCALL]]}" + [(set_attr "type" "call") + (set_attr "length" "2") + (set_attr "length_address" "0")]) + +(define_insn_and_split "*tls_dynamic_gnu2_combine_32" + [(set (match_operand:SI 0 "register_operand" "=&a") + (plus:SI + (plus:SI (match_operand:SI 3 "tp_or_register_operand" "ir") + (unspec:SI [(match_operand:SI 4 "tls_modbase_operand" "") + (match_operand:SI 5 "" "") + (match_operand:SI 2 "register_operand" "b") + (reg:SI SP_REG)] + UNSPEC_TLSDESC)) + (const:SI (unspec:SI + [(match_operand:SI 1 "tls_symbolic_operand" "")] + UNSPEC_DTPOFF)))) + (clobber (reg:CC FLAGS_REG))] + "!TARGET_64BIT && TARGET_GNU2_TLS" + "#" + "" + [(parallel + [(set (match_dup 0) + (plus:SI (match_dup 3) + (match_dup 5))) + (clobber (reg:CC FLAGS_REG))])] +{ + operands[5] = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode); + emit_insn (gen_tls_dynamic_gnu2_32 (operands[5], operands[1], operands[2])); +}) + +(define_expand "tls_dynamic_gnu2_64" + [(set (match_dup 2) + (unspec:DI [(match_operand:DI 1 "tls_symbolic_operand" "")] + UNSPEC_TLSDESC)) + (parallel + [(set (match_operand:DI 0 "register_operand" "") + (unspec:DI [(match_dup 1) (match_dup 2) (reg:DI SP_REG)] + UNSPEC_TLSDESC)) + (clobber (reg:CC FLAGS_REG))])] + "TARGET_64BIT && TARGET_GNU2_TLS" +{ + operands[2] = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode); + ix86_tls_descriptor_calls_expanded_in_cfun = true; +}) + +(define_insn "*tls_dynamic_lea_64" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI [(match_operand:DI 1 "tls_symbolic_operand" "")] + UNSPEC_TLSDESC))] + "TARGET_64BIT && TARGET_GNU2_TLS" + "lea{q}\t{%a1@TLSDESC(%%rip), %0|%0, %a1@TLSDESC[%%rip]}" + [(set_attr "type" "lea") + (set_attr "mode" "DI") + (set_attr "length" "7") + (set_attr "length_address" "4")]) + +(define_insn "*tls_dynamic_call_64" + [(set (match_operand:DI 0 "register_operand" "=a") + (unspec:DI [(match_operand:DI 1 "tls_symbolic_operand" "") + (match_operand:DI 2 "register_operand" "0") + (reg:DI SP_REG)] + UNSPEC_TLSDESC)) + (clobber (reg:CC FLAGS_REG))] + "TARGET_64BIT && TARGET_GNU2_TLS" + "call\t{*%a1@TLSCALL(%2)|[QWORD PTR [%2+%a1@TLSCALL]]}" + [(set_attr "type" "call") + (set_attr "length" "2") + (set_attr "length_address" "0")]) + +(define_insn_and_split "*tls_dynamic_gnu2_combine_64" + [(set (match_operand:DI 0 "register_operand" "=&a") + (plus:DI + (plus:DI (match_operand:DI 2 "tp_or_register_operand" "ir") + (unspec:DI [(match_operand:DI 3 "tls_modbase_operand" "") + (match_operand:DI 4 "" "") + (reg:DI SP_REG)] + UNSPEC_TLSDESC)) + (const:DI (unspec:DI + [(match_operand:DI 1 "tls_symbolic_operand" "")] + UNSPEC_DTPOFF)))) + (clobber (reg:CC FLAGS_REG))] + "TARGET_64BIT && TARGET_GNU2_TLS" + "#" + "" + [(parallel + [(set (match_dup 0) + (plus:DI (match_dup 2) + (match_dup 4))) + (clobber (reg:CC FLAGS_REG))])] +{ + operands[4] = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode); + emit_insn (gen_tls_dynamic_gnu2_64 (operands[4], operands[1])); +}) + +;; ;; These patterns match the binary 387 instructions for addM3, subM3, ;; mulM3 and divM3. There are three patterns for each of DFmode and diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md index bc16628439b..d87284d9ab9 100644 --- a/gcc/config/i386/predicates.md +++ b/gcc/config/i386/predicates.md @@ -1,5 +1,5 @@ ;; Predicate definitions for IA-32 and x86-64. -;; Copyright (C) 2004, 2005 Free Software Foundation, Inc. +;; Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. ;; ;; This file is part of GCC. ;; @@ -467,6 +467,15 @@ (and (match_code "symbol_ref") (match_test "SYMBOL_REF_TLS_MODEL (op) != 0"))) +(define_predicate "tls_modbase_operand" + (and (match_code "symbol_ref") + (match_test "op == ix86_tls_module_base ()"))) + +(define_predicate "tp_or_register_operand" + (ior (match_operand 0 "register_operand") + (and (match_code "unspec") + (match_test "XINT (op, 1) == UNSPEC_TP")))) + ;; Test for a pc-relative call operand (define_predicate "constant_call_address_operand" (ior (match_code "symbol_ref") -- 2.11.4.GIT