2003-02-24 Richard Henderson <rth@redhat.com> * config/i386/i386.c (struct ix86_address): Add seg. (no_seg_address_operand): New function. (ix86_decompose_address): Support segment overrides. (ix86_address_cost): Take segment overrides into account. (legitimate_address_p): Remove UNSPEC_TP special casing. (get_thread_pointer): Add to_reg argument. (legitimize_address): Move TLS emit code... (legitimize_tls_address): ...here. New function. (print_operand_address): Handle segment overrides. (ix86_expand_move): Use legitimize_tls_address. * config/i386/i386.h (MASK_SVR3_SHLIB, TARGET_SVR3_SHLIB): Remove. (MASK_TLS_DIRECT_SEG_REFS, TARGET_TLS_DIRECT_SEG_REFS): Define. (TARGET_SWITCHES): Remove -msvr3-shlib, add TARGET_TLS_DIRECT_SEG_REFS_DEFAULT to default. (TARGET_TLS_DIRECT_SEG_REFS_DEFAULT): Define to 0 if not defined. (RTX_COSTS): Handle segment overrides. (PREDICATE_CODES): Add no_seg_address_operand. * config/i386/i386.md (UNSPEC_TP_MEM): Define. (load_tp_si, load_tp_di, add_tp_si, add_tp_di): New insns. * config/i386/linux.h (TARGET_TLS_DIRECT_SEG_REFS_DEFAULT): Define. * config/i386/linux64.h (TARGET_TLS_DIRECT_SEG_REFS_DEFAULT): Define. --- gcc-3.3.2/gcc/config/i386/i386.c.tls-direct-segment-addressing 2003-12-15 15:56:19.000000000 +0100 +++ gcc-3.3.2/gcc/config/i386/i386.c 2003-12-15 15:56:22.000000000 +0100 @@ -798,7 +798,8 @@ static rtx maybe_get_pool_constant PARAM static rtx ix86_expand_int_compare PARAMS ((enum rtx_code, rtx, rtx)); static enum rtx_code ix86_prepare_fp_compare_args PARAMS ((enum rtx_code, rtx *, rtx *)); -static rtx get_thread_pointer PARAMS ((void)); +static rtx get_thread_pointer PARAMS ((int)); +static rtx legitimize_tls_address PARAMS ((rtx, enum tls_model, int)); static void get_pc_thunk_name PARAMS ((char [32], unsigned int)); static rtx gen_push PARAMS ((rtx)); static int memory_address_length PARAMS ((rtx addr)); @@ -839,6 +840,7 @@ struct ix86_address { rtx base, index, disp; HOST_WIDE_INT scale; + enum ix86_address_seg { SEG_DEFAULT, SEG_FS, SEG_GS } seg; }; static int ix86_decompose_address PARAMS ((rtx, struct ix86_address *)); @@ -3845,6 +3847,25 @@ no_seg_address_operand (register rtx op, return address_operand (op, mode); } +/* Return true if op if a valid address, and does not contain + a segment override. */ + +int +no_seg_address_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + struct ix86_address parts; + + if (! address_operand (op, mode)) + return 0; + + if (! ix86_decompose_address (op, &parts)) + abort (); + + return parts.seg == SEG_DEFAULT; +} + /* Return 1 if OP is a comparison that can be used in the CMPSS/CMPPS insns. */ int @@ -5455,8 +5476,7 @@ ix86_output_function_epilogue (file, siz /* Extract the parts of an RTL expression that is a valid memory address for an instruction. Return 0 if the structure of the address is grossly off. Return -1 if the address contains ASHIFT, so it is not - strictly valid, but still used for computing length of lea instruction. - */ + strictly valid, but still used for computing length of lea instruction. */ static int ix86_decompose_address (addr, out) @@ -5469,47 +5489,72 @@ ix86_decompose_address (addr, out) HOST_WIDE_INT scale = 1; rtx scale_rtx = NULL_RTX; int retval = 1; + enum ix86_address_seg seg = SEG_DEFAULT; if (REG_P (addr) || GET_CODE (addr) == SUBREG) base = addr; else if (GET_CODE (addr) == PLUS) { - rtx op0 = XEXP (addr, 0); - rtx op1 = XEXP (addr, 1); - enum rtx_code code0 = GET_CODE (op0); - enum rtx_code code1 = GET_CODE (op1); + rtx addends[4], op; + int n = 0, i; - if (code0 == REG || code0 == SUBREG) - { - if (code1 == REG || code1 == SUBREG) - index = op0, base = op1; /* index + base */ - else - base = op0, disp = op1; /* base + displacement */ - } - else if (code0 == MULT) - { - index = XEXP (op0, 0); - scale_rtx = XEXP (op0, 1); - if (code1 == REG || code1 == SUBREG) - base = op1; /* index*scale + base */ - else - disp = op1; /* index*scale + disp */ - } - else if (code0 == PLUS && GET_CODE (XEXP (op0, 0)) == MULT) + op = addr; + do { - index = XEXP (XEXP (op0, 0), 0); /* index*scale + base + disp */ - scale_rtx = XEXP (XEXP (op0, 0), 1); - base = XEXP (op0, 1); - disp = op1; + if (n >= 4) + return 0; + addends[n++] = XEXP (op, 1); + op = XEXP (op, 0); } - else if (code0 == PLUS) + while (GET_CODE (op) == PLUS); + if (n >= 4) + return 0; + addends[n] = op; + + for (i = 0; i <= n; ++i) { - index = XEXP (op0, 0); /* index + base + disp */ - base = XEXP (op0, 1); - disp = op1; + op = addends[i]; + switch (GET_CODE (op)) + { + case MULT: + if (index) + return 0; + index = XEXP (op, 0); + scale_rtx = XEXP (op, 1); + break; + + case UNSPEC: + if (XINT (op, 1) == UNSPEC_TP + && TARGET_TLS_DIRECT_SEG_REFS + && seg == SEG_DEFAULT) + seg = TARGET_64BIT ? SEG_FS : SEG_GS; + else + return 0; + break; + + case REG: + case SUBREG: + if (!base) + base = op; + else if (!index) + index = op; + else + return 0; + break; + + case CONST: + case CONST_INT: + case SYMBOL_REF: + case LABEL_REF: + if (disp) + return 0; + disp = op; + break; + + default: + return 0; + } } - else - return 0; } else if (GET_CODE (addr) == MULT) { @@ -5531,6 +5576,13 @@ ix86_decompose_address (addr, out) scale = 1 << scale; retval = -1; } + else if (GET_CODE (addr) == UNSPEC && XINT (addr, 1) == UNSPEC_TP_MEM) + { + if (seg != SEG_DEFAULT) + return 0; + seg = TARGET_64BIT ? SEG_FS : SEG_GS; + disp = const0_rtx; + } else disp = addr; /* displacement */ @@ -5578,6 +5630,7 @@ ix86_decompose_address (addr, out) out->index = index; out->disp = disp; out->scale = scale; + out->seg = seg; return retval; } @@ -5605,6 +5658,8 @@ ix86_address_cost (x) /* More complex memory references are better. */ if (parts.disp && parts.disp != const0_rtx) cost--; + if (parts.seg != SEG_DEFAULT) + cost--; /* Attempt to minimize number of registers in the address. */ if ((parts.base @@ -5945,13 +6000,6 @@ legitimate_address_p (mode, addr, strict debug_rtx (addr); } - if (GET_CODE (addr) == UNSPEC && XINT (addr, 1) == UNSPEC_TP) - { - if (TARGET_DEBUG_ADDR) - fprintf (stderr, "Success.\n"); - return TRUE; - } - if (ix86_decompose_address (addr, &parts) <= 0) { reason = "decomposition failed"; @@ -6420,20 +6468,151 @@ ix86_strip_name_encoding (str) return str; } -/* Load the thread pointer into a register. */ +/* Load the thread pointer. If TO_REG is true, force it into a register. */ static rtx -get_thread_pointer () +get_thread_pointer (to_reg) + int to_reg; { - rtx tp; + rtx tp, reg, insn; tp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx), UNSPEC_TP); - tp = gen_rtx_MEM (Pmode, tp); - RTX_UNCHANGING_P (tp) = 1; - set_mem_alias_set (tp, ix86_GOT_alias_set ()); - tp = force_reg (Pmode, tp); + if (!to_reg) + return tp; - return tp; + reg = gen_reg_rtx (Pmode); + insn = gen_rtx_SET (VOIDmode, reg, tp); + insn = emit_insn (insn); + + return reg; +} + +/* A subroutine of legitimize_address and ix86_expand_move. FOR_MOV is + false if we expect this to be used for a memory address and true if + we expect to load the address into a register. */ + +static rtx +legitimize_tls_address (x, model, for_mov) + rtx x; + enum tls_model model; + int for_mov; +{ + rtx dest, base, off, pic; + int type; + + switch (model) + { + case TLS_MODEL_GLOBAL_DYNAMIC: + dest = gen_reg_rtx (Pmode); + if (TARGET_64BIT) + { + rtx rax = gen_rtx_REG (Pmode, 0), insns; + + start_sequence (); + emit_call_insn (gen_tls_global_dynamic_64 (rax, x)); + insns = get_insns (); + end_sequence (); + + emit_libcall_block (insns, dest, rax, x); + } + else + emit_insn (gen_tls_global_dynamic_32 (dest, x)); + break; + + case TLS_MODEL_LOCAL_DYNAMIC: + base = gen_reg_rtx (Pmode); + if (TARGET_64BIT) + { + rtx rax = gen_rtx_REG (Pmode, 0), insns, note; + + start_sequence (); + emit_call_insn (gen_tls_local_dynamic_base_64 (rax)); + insns = get_insns (); + end_sequence (); + + note = gen_rtx_EXPR_LIST (VOIDmode, const0_rtx, NULL); + note = gen_rtx_EXPR_LIST (VOIDmode, ix86_tls_get_addr (), note); + emit_libcall_block (insns, base, rax, note); + } + else + emit_insn (gen_tls_local_dynamic_base_32 (base)); + + off = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_DTPOFF); + off = gen_rtx_CONST (Pmode, off); + + return gen_rtx_PLUS (Pmode, base, off); + + case TLS_MODEL_INITIAL_EXEC: + if (TARGET_64BIT) + { + pic = NULL; + type = UNSPEC_GOTNTPOFF; + } + else if (flag_pic) + { + 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; + } + else if (!TARGET_GNU_TLS) + { + pic = gen_reg_rtx (Pmode); + emit_insn (gen_set_got (pic)); + type = UNSPEC_GOTTPOFF; + } + else + { + pic = NULL; + type = UNSPEC_INDNTPOFF; + } + + off = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), type); + off = gen_rtx_CONST (Pmode, off); + if (pic) + off = gen_rtx_PLUS (Pmode, pic, off); + off = gen_rtx_MEM (Pmode, off); + RTX_UNCHANGING_P (off) = 1; + set_mem_alias_set (off, ix86_GOT_alias_set ()); + + if (TARGET_64BIT || TARGET_GNU_TLS) + { + base = get_thread_pointer (for_mov || !TARGET_TLS_DIRECT_SEG_REFS); + off = force_reg (Pmode, off); + return gen_rtx_PLUS (Pmode, base, off); + } + else + { + base = get_thread_pointer (true); + dest = gen_reg_rtx (Pmode); + emit_insn (gen_subsi3 (dest, base, off)); + } + break; + + case TLS_MODEL_LOCAL_EXEC: + off = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), + (TARGET_64BIT || TARGET_GNU_TLS + ? UNSPEC_NTPOFF : UNSPEC_TPOFF)); + off = gen_rtx_CONST (Pmode, off); + + if (TARGET_64BIT || TARGET_GNU_TLS) + { + base = get_thread_pointer (for_mov || !TARGET_TLS_DIRECT_SEG_REFS); + return gen_rtx_PLUS (Pmode, base, off); + } + else + { + base = get_thread_pointer (true); + dest = gen_reg_rtx (Pmode); + emit_insn (gen_subsi3 (dest, base, off)); + } + break; + + default: + abort (); + } + + return dest; } /* Try machine-dependent ways of modifying an illegitimate address @@ -6475,120 +6654,7 @@ legitimize_address (x, oldx, mode) log = tls_symbolic_operand (x, mode); if (log) - { - rtx dest, base, off, pic; - int type; - - switch (log) - { - case TLS_MODEL_GLOBAL_DYNAMIC: - dest = gen_reg_rtx (Pmode); - if (TARGET_64BIT) - { - rtx rax = gen_rtx_REG (Pmode, 0), insns; - - start_sequence (); - emit_call_insn (gen_tls_global_dynamic_64 (rax, x)); - insns = get_insns (); - end_sequence (); - - emit_libcall_block (insns, dest, rax, x); - } - else - emit_insn (gen_tls_global_dynamic_32 (dest, x)); - break; - - case TLS_MODEL_LOCAL_DYNAMIC: - base = gen_reg_rtx (Pmode); - if (TARGET_64BIT) - { - rtx rax = gen_rtx_REG (Pmode, 0), insns, note; - - start_sequence (); - emit_call_insn (gen_tls_local_dynamic_base_64 (rax)); - insns = get_insns (); - end_sequence (); - - note = gen_rtx_EXPR_LIST (VOIDmode, const0_rtx, NULL); - note = gen_rtx_EXPR_LIST (VOIDmode, ix86_tls_get_addr (), note); - emit_libcall_block (insns, base, rax, note); - } - else - emit_insn (gen_tls_local_dynamic_base_32 (base)); - - off = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_DTPOFF); - off = gen_rtx_CONST (Pmode, off); - - return gen_rtx_PLUS (Pmode, base, off); - - case TLS_MODEL_INITIAL_EXEC: - if (TARGET_64BIT) - { - pic = NULL; - type = UNSPEC_GOTNTPOFF; - } - else if (flag_pic) - { - 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; - } - else if (!TARGET_GNU_TLS) - { - pic = gen_reg_rtx (Pmode); - emit_insn (gen_set_got (pic)); - type = UNSPEC_GOTTPOFF; - } - else - { - pic = NULL; - type = UNSPEC_INDNTPOFF; - } - - base = get_thread_pointer (); - - off = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), type); - off = gen_rtx_CONST (Pmode, off); - if (pic) - off = gen_rtx_PLUS (Pmode, pic, off); - off = gen_rtx_MEM (Pmode, off); - RTX_UNCHANGING_P (off) = 1; - set_mem_alias_set (off, ix86_GOT_alias_set ()); - dest = gen_reg_rtx (Pmode); - - if (TARGET_64BIT || TARGET_GNU_TLS) - { - emit_move_insn (dest, off); - return gen_rtx_PLUS (Pmode, base, dest); - } - else - emit_insn (gen_subsi3 (dest, base, off)); - break; - - case TLS_MODEL_LOCAL_EXEC: - base = get_thread_pointer (); - - off = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), - (TARGET_64BIT || TARGET_GNU_TLS) - ? UNSPEC_NTPOFF : UNSPEC_TPOFF); - off = gen_rtx_CONST (Pmode, off); - - if (TARGET_64BIT || TARGET_GNU_TLS) - return gen_rtx_PLUS (Pmode, base, off); - else - { - dest = gen_reg_rtx (Pmode); - emit_insn (gen_subsi3 (dest, base, off)); - } - break; - - default: - abort (); - } - - return dest; - } + return legitimize_tls_address (x, log, false); if (flag_pic && SYMBOLIC_CONST (x)) return legitimize_pic_address (x, 0); @@ -7571,8 +7637,8 @@ print_operand (file, x, code) fprintf (file, "0x%lx", l); } - /* These float cases don't actually occur as immediate operands. */ - else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode) + /* These float cases don't actually occur as immediate operands. */ + else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode) { char dstr[30]; @@ -7627,19 +7693,6 @@ print_operand_address (file, addr) rtx base, index, disp; int scale; - if (GET_CODE (addr) == UNSPEC && XINT (addr, 1) == UNSPEC_TP) - { - if (ASSEMBLER_DIALECT == ASM_INTEL) - fputs ("DWORD PTR ", file); - if (ASSEMBLER_DIALECT == ASM_ATT || USER_LABEL_PREFIX[0] == 0) - putc ('%', file); - if (TARGET_64BIT) - fputs ("fs:0", file); - else - fputs ("gs:0", file); - return; - } - if (! ix86_decompose_address (addr, &parts)) abort (); @@ -7648,35 +7701,53 @@ print_operand_address (file, addr) disp = parts.disp; scale = parts.scale; + switch (parts.seg) + { + case SEG_DEFAULT: + break; + case SEG_FS: + if (USER_LABEL_PREFIX[0] == 0) + putc ('%', file); + fputs ("fs:", file); + break; + case SEG_GS: + if (USER_LABEL_PREFIX[0] == 0) + putc ('%', file); + fputs ("gs:", file); + break; + default: + abort (); + } + if (!base && !index) { /* Displacement only requires special attention. */ if (GET_CODE (disp) == CONST_INT) { - if (ASSEMBLER_DIALECT == ASM_INTEL) + if (ASSEMBLER_DIALECT == ASM_INTEL && parts.seg == SEG_DEFAULT) { if (USER_LABEL_PREFIX[0] == 0) putc ('%', file); fputs ("ds:", file); } - fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (addr)); + fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (disp)); } else if (flag_pic) - output_pic_addr_const (file, addr, 0); + output_pic_addr_const (file, disp, 0); else - output_addr_const (file, addr); + output_addr_const (file, disp); /* Use one byte shorter RIP relative addressing for 64bit mode. */ if (TARGET_64BIT - && ((GET_CODE (addr) == SYMBOL_REF - && ! tls_symbolic_operand (addr, GET_MODE (addr))) - || GET_CODE (addr) == LABEL_REF - || (GET_CODE (addr) == CONST - && GET_CODE (XEXP (addr, 0)) == PLUS - && (GET_CODE (XEXP (XEXP (addr, 0), 0)) == SYMBOL_REF - || GET_CODE (XEXP (XEXP (addr, 0), 0)) == LABEL_REF) - && GET_CODE (XEXP (XEXP (addr, 0), 1)) == CONST_INT))) + && ((GET_CODE (disp) == SYMBOL_REF + && ! tls_symbolic_operand (disp, GET_MODE (disp))) + || GET_CODE (disp) == LABEL_REF + || (GET_CODE (disp) == CONST + && GET_CODE (XEXP (disp, 0)) == PLUS + && (GET_CODE (XEXP (XEXP (disp, 0), 0)) == SYMBOL_REF + || GET_CODE (XEXP (XEXP (disp, 0), 0)) == LABEL_REF) + && GET_CODE (XEXP (XEXP (disp, 0), 1)) == CONST_INT))) fputs ("(%rip)", file); } else @@ -8390,22 +8461,22 @@ ix86_expand_move (mode, operands) rtx operands[]; { int strict = (reload_in_progress || reload_completed); - rtx insn, op0, op1, tmp; + rtx op0, op1; + enum tls_model model; op0 = operands[0]; op1 = operands[1]; - if (tls_symbolic_operand (op1, Pmode)) + model = tls_symbolic_operand (op1, Pmode); + if (model) { - op1 = legitimize_address (op1, op1, VOIDmode); - if (GET_CODE (op0) == MEM) - { - tmp = gen_reg_rtx (mode); - emit_insn (gen_rtx_SET (VOIDmode, tmp, op1)); - op1 = tmp; - } + op1 = legitimize_tls_address (op1, model, true); + op1 = force_operand (op1, op0); + if (op1 == op0) + return; } - else if (flag_pic && mode == Pmode && symbolic_operand (op1, Pmode)) + + if (flag_pic && mode == Pmode && symbolic_operand (op1, Pmode)) { #if TARGET_MACHO if (MACHOPIC_PURE) @@ -8421,14 +8492,14 @@ ix86_expand_move (mode, operands) else { if (MACHOPIC_INDIRECT) - op1 = machopic_indirect_data_reference (op1, 0); + op1 = machopic_indirect_data_reference (op1, 0); } if (op0 != op1) { insn = gen_rtx_SET (VOIDmode, op0, op1); emit_insn (insn); } - return; + return; #endif /* TARGET_MACHO */ if (GET_CODE (op0) == MEM) op1 = force_reg (Pmode, op1); @@ -8486,9 +8557,7 @@ ix86_expand_move (mode, operands) } } - insn = gen_rtx_SET (VOIDmode, op0, op1); - - emit_insn (insn); + emit_insn (gen_rtx_SET (VOIDmode, op0, op1)); } void --- gcc-3.3.2/gcc/config/i386/i386.h.tls-direct-segment-addressing 2003-12-15 15:56:19.000000000 +0100 +++ gcc-3.3.2/gcc/config/i386/i386.h 2003-12-15 15:56:22.000000000 +0100 @@ -203,6 +203,9 @@ extern int target_flags; #endif #endif +/* Avoid adding %gs:0 in TLS references; use %gs:address directly. */ +#define TARGET_TLS_DIRECT_SEG_REFS (target_flags & MASK_TLS_DIRECT_SEG_REFS) + #define TARGET_386 (ix86_cpu == PROCESSOR_I386) #define TARGET_486 (ix86_cpu == PROCESSOR_I486) #define TARGET_PENTIUM (ix86_cpu == PROCESSOR_PENTIUM) @@ -402,12 +405,21 @@ extern int x86_prefetch_sse; N_("Use red-zone in the x86-64 code") }, \ { "no-red-zone", MASK_NO_RED_ZONE, \ N_("Do not use red-zone in the x86-64 code") }, \ + { "tls-direct-seg-refs", MASK_TLS_DIRECT_SEG_REFS, \ + N_("Use direct references against %gs when accessing tls data") }, \ + { "no-tls-direct-seg-refs", -MASK_TLS_DIRECT_SEG_REFS, \ + N_("Do not use direct references against %gs when accessing tls data") }, \ SUBTARGET_SWITCHES \ - { "", TARGET_DEFAULT | TARGET_64BIT_DEFAULT | TARGET_SUBTARGET_DEFAULT, 0 }} + { "", \ + TARGET_DEFAULT | TARGET_64BIT_DEFAULT | TARGET_SUBTARGET_DEFAULT \ + | TARGET_TLS_DIRECT_SEG_REFS_DEFAULT, 0 }} #ifndef TARGET_64BIT_DEFAULT #define TARGET_64BIT_DEFAULT 0 #endif +#ifndef TARGET_TLS_DIRECT_SEG_REFS_DEFAULT +#define TARGET_TLS_DIRECT_SEG_REFS_DEFAULT 0 +#endif /* Once GDB has been enhanced to deal with functions without frame pointers, we can change this to allow for elimination of @@ -2888,6 +2900,10 @@ do { \ TOPLEVEL_COSTS_N_INSNS (ix86_cost->fsqrt); \ break; \ \ + case UNSPEC: \ + if (XINT ((X), 1) == UNSPEC_TP) \ + return 0; \ + \ egress_rtx_costs: \ break; --- gcc-3.3.2/gcc/config/i386/i386.md.tls-direct-segment-addressing 2003-12-15 15:56:19.000000000 +0100 +++ gcc-3.3.2/gcc/config/i386/i386.md 2003-12-15 15:56:22.000000000 +0100 @@ -75,6 +75,7 @@ (UNSPEC_TP 15) (UNSPEC_TLS_GD 16) (UNSPEC_TLS_LD_BASE 17) + (UNSPEC_TP_MEM 18) ; Other random patterns (UNSPEC_SCAS 20) @@ -14636,6 +14637,56 @@ (clobber (match_dup 5)) (clobber (reg:CC 17))])] "") + +;; Load and add the thread base pointer from %gs:0. + +(define_insn "*load_tp_si" + [(set (match_operand:SI 0 "register_operand" "=*a,r") + (unspec:SI [(const_int 0)] UNSPEC_TP))] + "!TARGET_64BIT" + "mov{l}\t{%%gs:0, %0|%0, DWORD PTR %%gs:0}" + [(set_attr "type" "imov") + (set_attr "modrm" "0") + (set_attr "length" "6,7") + (set_attr "memory" "load") + (set_attr "imm_disp" "false")]) + +(define_insn "*load_tp_di" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI [(const_int 0)] UNSPEC_TP))] + "TARGET_64BIT" + "mov{q}\t{%%fs:0, %0|%0, DWORD PTR %%fs:0}" + [(set_attr "type" "imov") + (set_attr "modrm" "0") + (set_attr "length" "7") + (set_attr "memory" "load") + (set_attr "imm_disp" "false")]) + +(define_insn "*add_tp_si" + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (unspec:SI [(const_int 0)] UNSPEC_TP) + (match_operand:SI 1 "register_operand" "0"))) + (clobber (reg:CC 17))] + "!TARGET_64BIT" + "add{l}\t{%%gs:0, %0|%0, DWORD PTR %%gs:0}" + [(set_attr "type" "alu") + (set_attr "modrm" "0") + (set_attr "length" "7") + (set_attr "memory" "load") + (set_attr "imm_disp" "false")]) + +(define_insn "*add_tp_di" + [(set (match_operand:DI 0 "register_operand" "=r") + (plus:DI (unspec:DI [(const_int 0)] UNSPEC_TP) + (match_operand:DI 1 "register_operand" "0"))) + (clobber (reg:CC 17))] + "TARGET_64BIT" + "add{q}\t{%%fs:0, %0|%0, DWORD PTR %%fs:0}" + [(set_attr "type" "alu") + (set_attr "modrm" "0") + (set_attr "length" "7") + (set_attr "memory" "load") + (set_attr "imm_disp" "false")]) ;; These patterns match the binary 387 instructions for addM3, subM3, ;; mulM3 and divM3. There are three patterns for each of DFmode and --- gcc-3.3.2/gcc/config/i386/linux.h.tls-direct-segment-addressing 2003-12-15 15:56:19.000000000 +0100 +++ gcc-3.3.2/gcc/config/i386/linux.h 2003-12-15 15:56:22.000000000 +0100 @@ -40,6 +40,10 @@ Boston, MA 02111-1307, USA. */ #undef DEFAULT_PCC_STRUCT_RETURN #define DEFAULT_PCC_STRUCT_RETURN 1 +/* We arrange for the whole %gs segment to map the tls area. */ +#undef TARGET_TLS_DIRECT_SEG_REFS_DEFAULT +#define TARGET_TLS_DIRECT_SEG_REFS_DEFAULT MASK_TLS_DIRECT_SEG_REFS + #undef ASM_COMMENT_START #define ASM_COMMENT_START "#" --- gcc-3.3.2/gcc/config/i386/linux64.h.tls-direct-segment-addressing 2003-12-15 15:56:19.000000000 +0100 +++ gcc-3.3.2/gcc/config/i386/linux64.h 2003-12-15 15:56:22.000000000 +0100 @@ -53,6 +53,10 @@ Boston, MA 02111-1307, USA. */ #undef DEFAULT_PCC_STRUCT_RETURN #define DEFAULT_PCC_STRUCT_RETURN 1 +/* We arrange for the whole %fs segment to map the tls area. */ +#undef TARGET_TLS_DIRECT_SEG_REFS_DEFAULT +#define TARGET_TLS_DIRECT_SEG_REFS_DEFAULT MASK_TLS_DIRECT_SEG_REFS + /* Provide a LINK_SPEC. Here we provide support for the special GCC options -static and -shared, which allow us to link things in one of these three modes by applying the appropriate combinations of --- gcc-3.3.2/gcc/doc/invoke.texi.tls-direct-segment-addressing 2003-12-15 15:56:19.000000000 +0100 +++ gcc-3.3.2/gcc/doc/invoke.texi 2003-12-15 15:56:22.000000000 +0100 @@ -477,7 +477,7 @@ in the following sections. -mthreads -mno-align-stringops -minline-all-stringops @gol -mpush-args -maccumulate-outgoing-args -m128bit-long-double @gol -m96bit-long-double -mregparm=@var{num} -momit-leaf-frame-pointer @gol --mno-red-zone@gol +-mno-red-zone -mno-tls-direct-seg-refs @gol -mcmodel=@var{code-model} @gol -m32 -m64} @@ -8210,6 +8210,17 @@ avoids the instructions to save, set up makes an extra register available in leaf functions. The option @option{-fomit-frame-pointer} removes the frame pointer for all functions which might make debugging harder. + +@item -mtls-direct-seg-refs +@itemx -mno-tls-direct-seg-refs +@opindex mtls-direct-seg-refs +Controls whether TLS variables may be accessed with offsets from the +TLS segment register (@code{%gs} for 32-bit, @code{%fs} for 64-bit), +or whether the thread base pointer must be added. Whether or not this +is legal depends on the operating system, and whether it maps the +segment to cover the entire TLS area. + +For systems that use GNU libc, the default is on. @end table These @samp{-m} switches are supported in addition to the above