diff options
author | Richard Henderson <rth@redhat.com> | 2003-06-04 17:23:23 -0700 |
---|---|---|
committer | Richard Henderson <rth@gcc.gnu.org> | 2003-06-04 17:23:23 -0700 |
commit | 74dc3e94edfd887109df4c9b956053de96fb21bb (patch) | |
tree | 68a0fa8732f08f9b84bdcad7829831a39e3d9f08 /gcc | |
parent | d7068b3d2acc18be3975a44362bc34ba3d9dc2e1 (diff) | |
download | gcc-74dc3e94edfd887109df4c9b956053de96fb21bb.zip gcc-74dc3e94edfd887109df4c9b956053de96fb21bb.tar.gz gcc-74dc3e94edfd887109df4c9b956053de96fb21bb.tar.bz2 |
i386.c (struct ix86_address): Add seg.
* config/i386/i386.c (struct ix86_address): Add seg.
(no_seg_address_operand): New.
(ix86_decompose_address): Restructure PLUS loop. Accept one
UNSPEC_TP if TARGET_TLS_DIRECT_SEG_REFS. Adjust ESP swap test
to test for a regnum, not stack_pointer_rtx.
(ix86_address_cost): Reduce cost if non-default segment.
(legitimate_address_p): Remove UNSPEC_TP check.
(get_thread_pointer): Add to_reg argument. Don't represent
the thread pointer as a memory load.
(legitimize_tls_address): Split out of ...
(legitimize_address): ... here.
(print_operand_address): Handle parts.seg.
(ix86_expand_move): Use legitimize_tls_address.
(ix86_rtx_costs): Handle UNSPEC_TP.
* config/i386/i386.h (MASK_TLS_DIRECT_SEG_REFS): New.
(TARGET_TLS_DIRECT_SEG_REFS): New.
(TARGET_SWITCHES): Add tls-direct-seg-refs.
(TARGET_TLS_DIRECT_SEG_REFS_DEFAULT): Default.
(PREDICATE_CODES): Add no_seg_address_operand.
* config/i386/i386.md (lea_1): Use it.
(lea_1_rex64, lea_1_zext, lea_2_rex64): Likewise.
(load_tp_si, add_tp_si, load_tp_di, add_tp_di): New.
* config/i386/linux.h (TARGET_TLS_DIRECT_SEG_REFS_DEFAULT): New.
* config/i386/linux64.h (TARGET_TLS_DIRECT_SEG_REFS_DEFAULT): New.
* doc/invoke.texi: Add -mtls-direct-seg-refs.
From-SVN: r67475
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 28 | ||||
-rw-r--r-- | gcc/config/i386/i386.c | 494 | ||||
-rw-r--r-- | gcc/config/i386/i386.h | 17 | ||||
-rw-r--r-- | gcc/config/i386/i386.md | 59 | ||||
-rw-r--r-- | gcc/config/i386/linux.h | 4 | ||||
-rw-r--r-- | gcc/config/i386/linux64.h | 4 | ||||
-rw-r--r-- | gcc/doc/invoke.texi | 13 |
7 files changed, 395 insertions, 224 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a3a252a..a057fc2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,31 @@ +2003-06-04 Richard Henderson <rth@redhat.com> + + * config/i386/i386.c (struct ix86_address): Add seg. + (no_seg_address_operand): New. + (ix86_decompose_address): Restructure PLUS loop. Accept one + UNSPEC_TP if TARGET_TLS_DIRECT_SEG_REFS. Adjust ESP swap test + to test for a regnum, not stack_pointer_rtx. + (ix86_address_cost): Reduce cost if non-default segment. + (legitimate_address_p): Remove UNSPEC_TP check. + (get_thread_pointer): Add to_reg argument. Don't represent + the thread pointer as a memory load. + (legitimize_tls_address): Split out of ... + (legitimize_address): ... here. + (print_operand_address): Handle parts.seg. + (ix86_expand_move): Use legitimize_tls_address. + (ix86_rtx_costs): Handle UNSPEC_TP. + * config/i386/i386.h (MASK_TLS_DIRECT_SEG_REFS): New. + (TARGET_TLS_DIRECT_SEG_REFS): New. + (TARGET_SWITCHES): Add tls-direct-seg-refs. + (TARGET_TLS_DIRECT_SEG_REFS_DEFAULT): Default. + (PREDICATE_CODES): Add no_seg_address_operand. + * config/i386/i386.md (lea_1): Use it. + (lea_1_rex64, lea_1_zext, lea_2_rex64): Likewise. + (load_tp_si, add_tp_si, load_tp_di, add_tp_di): New. + * config/i386/linux.h (TARGET_TLS_DIRECT_SEG_REFS_DEFAULT): New. + * config/i386/linux64.h (TARGET_TLS_DIRECT_SEG_REFS_DEFAULT): New. + * doc/invoke.texi: Add -mtls-direct-seg-refs. + 2003-06-04 Mark Mitchell <mark@codesourcery.com> * Makefile.in (QMTESTRUNFLAGS): Set for DejaGNU emulation. diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index f2d94c2..f36c99c 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -793,7 +793,8 @@ static rtx maybe_get_pool_constant PARAMS ((rtx)); 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)); @@ -835,6 +836,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 *)); @@ -3863,6 +3865,25 @@ vector_move_operand (op, mode) return (op == CONST0_RTX (GET_MODE (op))); } +/* 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 @@ -5403,8 +5424,7 @@ ix86_output_function_epilogue (file, size) /* 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) @@ -5417,47 +5437,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 = n; i >= 0; --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) { @@ -5490,10 +5535,11 @@ ix86_decompose_address (addr, out) scale = INTVAL (scale_rtx); } - /* Allow arg pointer and stack pointer as index if there is not scaling */ + /* Allow arg pointer and stack pointer as index if there is not scaling. */ if (base && index && scale == 1 - && (index == arg_pointer_rtx || index == frame_pointer_rtx - || index == stack_pointer_rtx)) + && (index == arg_pointer_rtx + || index == frame_pointer_rtx + || (REG_P (index) && REGNO (index) == STACK_POINTER_REGNUM))) { rtx tmp = base; base = index; @@ -5526,6 +5572,7 @@ ix86_decompose_address (addr, out) out->index = index; out->disp = disp; out->scale = scale; + out->seg = seg; return retval; } @@ -5553,6 +5600,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 @@ -5871,13 +5920,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"; @@ -6267,20 +6309,151 @@ legitimize_pic_address (orig, reg) return new; } -/* 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 @@ -6322,120 +6495,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); @@ -7418,8 +7478,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]; @@ -7474,19 +7534,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 (); @@ -7495,35 +7542,49 @@ print_operand_address (file, addr) disp = parts.disp; scale = parts.scale; + switch (parts.seg) + { + case SEG_DEFAULT: + break; + case SEG_FS: + case SEG_GS: + if (USER_LABEL_PREFIX[0] == 0) + putc ('%', file); + fputs ((parts.seg == SEG_FS ? "fs:" : "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 @@ -8220,22 +8281,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) @@ -8248,18 +8309,11 @@ ix86_expand_move (mode, operands) op1 = machopic_legitimize_pic_address (op1, mode, temp == op1 ? 0 : temp); } - else - { - if (MACHOPIC_INDIRECT) - op1 = machopic_indirect_data_reference (op1, 0); - } - if (op0 != op1) - { - insn = gen_rtx_SET (VOIDmode, op0, op1); - emit_insn (insn); - } - return; -#endif /* TARGET_MACHO */ + else if (MACHOPIC_INDIRECT) + op1 = machopic_indirect_data_reference (op1, 0); + if (op0 == op1) + return; +#else if (GET_CODE (op0) == MEM) op1 = force_reg (Pmode, op1); else @@ -8272,6 +8326,7 @@ ix86_expand_move (mode, operands) return; op1 = temp; } +#endif /* TARGET_MACHO */ } else { @@ -8316,9 +8371,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 @@ -15094,6 +15147,11 @@ ix86_rtx_costs (x, code, outer_code, total) *total = COSTS_N_INSNS (ix86_cost->fsqrt); return false; + case UNSPEC: + if (XINT (x, 1) == UNSPEC_TP) + *total = 0; + return false; + default: return false; } diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index fe47b03..f543c28 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -122,6 +122,7 @@ extern int target_flags; #define MASK_128BIT_LONG_DOUBLE 0x00040000 /* long double size is 128bit */ #define MASK_64BIT 0x00080000 /* Produce 64bit code */ #define MASK_MS_BITFIELD_LAYOUT 0x00100000 /* Use native (MS) bitfield layout */ +#define MASK_TLS_DIRECT_SEG_REFS 0x00200000 /* Avoid adding %gs:0 */ /* Unused: 0x03e0000 */ @@ -201,6 +202,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_tune == PROCESSOR_I386) #define TARGET_486 (ix86_tune == PROCESSOR_I486) #define TARGET_PENTIUM (ix86_tune == PROCESSOR_PENTIUM) @@ -405,12 +409,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 @@ -3034,6 +3047,8 @@ do { \ {"register_and_not_fp_reg_operand", {REG}}, \ {"zero_extended_scalar_load_operand", {MEM}}, \ {"vector_move_operand", {CONST_VECTOR, SUBREG, REG, MEM}}, \ + {"no_seg_address_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, \ + LABEL_REF, SUBREG, REG, MEM, PLUS, MULT}}, /* A list of predicates that do special things with modes, and so should not elicit warnings for VOIDmode match_operand. */ diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 6806c7a..a027a76 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -5312,7 +5312,7 @@ (define_insn "*lea_1" [(set (match_operand:SI 0 "register_operand" "=r") - (match_operand:SI 1 "address_operand" "p"))] + (match_operand:SI 1 "no_seg_address_operand" "p"))] "!TARGET_64BIT" "lea{l}\t{%a1, %0|%0, %a1}" [(set_attr "type" "lea") @@ -5320,7 +5320,7 @@ (define_insn "*lea_1_rex64" [(set (match_operand:SI 0 "register_operand" "=r") - (subreg:SI (match_operand:DI 1 "address_operand" "p") 0))] + (subreg:SI (match_operand:DI 1 "no_seg_address_operand" "p") 0))] "TARGET_64BIT" "lea{l}\t{%a1, %0|%0, %a1}" [(set_attr "type" "lea") @@ -5328,7 +5328,8 @@ (define_insn "*lea_1_zext" [(set (match_operand:DI 0 "register_operand" "=r") - (zero_extend:DI (subreg:SI (match_operand:DI 1 "address_operand" "p") 0)))] + (zero_extend:DI + (subreg:SI (match_operand:DI 1 "no_seg_address_operand" "p") 0)))] "TARGET_64BIT" "lea{l}\t{%a1, %k0|%k0, %a1}" [(set_attr "type" "lea") @@ -5336,7 +5337,7 @@ (define_insn "*lea_2_rex64" [(set (match_operand:DI 0 "register_operand" "=r") - (match_operand:DI 1 "address_operand" "p"))] + (match_operand:DI 1 "no_seg_address_operand" "p"))] "TARGET_64BIT" "lea{q}\t{%a1, %0|%0, %a1}" [(set_attr "type" "lea") @@ -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" "=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" "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 "*load_tp_di" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI [(const_int 0)] UNSPEC_TP))] + "TARGET_64BIT" + "mov{l}\t{%%fs:0, %0|%0, QWORD 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_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, QWORD 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 diff --git a/gcc/config/i386/linux.h b/gcc/config/i386/linux.h index 3041368..8f0a22c 100644 --- a/gcc/config/i386/linux.h +++ b/gcc/config/i386/linux.h @@ -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 "#" diff --git a/gcc/config/i386/linux64.h b/gcc/config/i386/linux64.h index 341ef32..ec398de 100644 --- a/gcc/config/i386/linux64.h +++ b/gcc/config/i386/linux64.h @@ -47,6 +47,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 diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 66ef987..b87d310 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -490,7 +490,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} @@ -8401,6 +8401,17 @@ avoids the instructions to save, set up and restore frame pointers and 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 |