This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
direct segment addressing for x86 tls
- From: Richard Henderson <rth at twiddle dot net>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 4 Jun 2003 17:38:09 -0700
- Subject: direct segment addressing for x86 tls
This is something I worked on back in February, which Jakub
polished and added to the 3.2-rhl8 branch, but I completely
forgot about putting onto mainline. I've updated it a bit,
and (hopefully) fixed some amd64 issues.
The effect is to make TLS code a bit smaller on x86 platforms.
static __thread int le;
extern __thread int ie;
int foo() { return le + ie; }
BEFORE
movl %gs:0, %edx
movl ie@INDNTPOFF, %eax
movl (%edx,%eax), %eax
addl le@NTPOFF(%edx), %eax
// 21 bytes
AFTER
movl ie@INDNTPOFF, %eax
movl %gs:(%eax), %eax
addl %gs:le@NTPOFF, %eax
// 15 bytes
r~
* 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.
Index: config/i386/i386.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.c,v
retrieving revision 1.569
diff -c -p -d -r1.569 i386.c
*** config/i386/i386.c 4 Jun 2003 16:44:50 -0000 1.569
--- config/i386/i386.c 5 Jun 2003 00:06:55 -0000
*************** static rtx maybe_get_pool_constant PARAM
*** 793,799 ****
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 void get_pc_thunk_name PARAMS ((char [32], unsigned int));
static rtx gen_push PARAMS ((rtx));
static int memory_address_length PARAMS ((rtx addr));
--- 793,800 ----
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 ((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));
*************** struct ix86_address
*** 835,840 ****
--- 836,842 ----
{
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 *));
*************** vector_move_operand (op, mode)
*** 3863,3868 ****
--- 3865,3889 ----
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
*************** ix86_output_function_epilogue (file, siz
*** 5403,5410 ****
/* 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.
! */
static int
ix86_decompose_address (addr, out)
--- 5424,5430 ----
/* 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. */
static int
ix86_decompose_address (addr, out)
*************** ix86_decompose_address (addr, out)
*** 5417,5463 ****
HOST_WIDE_INT scale = 1;
rtx scale_rtx = NULL_RTX;
int retval = 1;
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);
! 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)
{
! index = XEXP (XEXP (op0, 0), 0); /* index*scale + base + disp */
! scale_rtx = XEXP (XEXP (op0, 0), 1);
! base = XEXP (op0, 1);
! disp = op1;
}
! else if (code0 == PLUS)
{
! index = XEXP (op0, 0); /* index + base + disp */
! base = XEXP (op0, 1);
! disp = op1;
}
- else
- return 0;
}
else if (GET_CODE (addr) == MULT)
{
--- 5437,5508 ----
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 addends[4], op;
! int n = 0, i;
! op = addr;
! do
{
! if (n >= 4)
! return 0;
! addends[n++] = XEXP (op, 1);
! op = XEXP (op, 0);
}
! while (GET_CODE (op) == PLUS);
! if (n >= 4)
! return 0;
! addends[n] = op;
!
! for (i = n; i >= 0; --i)
{
! 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 if (GET_CODE (addr) == MULT)
{
*************** ix86_decompose_address (addr, out)
*** 5490,5499 ****
scale = INTVAL (scale_rtx);
}
! /* 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))
{
rtx tmp = base;
base = index;
--- 5535,5545 ----
scale = INTVAL (scale_rtx);
}
! /* 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
! || (REG_P (index) && REGNO (index) == STACK_POINTER_REGNUM)))
{
rtx tmp = base;
base = index;
*************** ix86_decompose_address (addr, out)
*** 5526,5531 ****
--- 5572,5578 ----
out->index = index;
out->disp = disp;
out->scale = scale;
+ out->seg = seg;
return retval;
}
*************** ix86_address_cost (x)
*** 5553,5558 ****
--- 5600,5607 ----
/* 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
*************** legitimate_address_p (mode, addr, strict
*** 5871,5883 ****
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";
--- 5920,5925 ----
*************** legitimize_pic_address (orig, reg)
*** 6267,6286 ****
return new;
}
! /* Load the thread pointer into a register. */
static rtx
! get_thread_pointer ()
{
! rtx tp;
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);
! return tp;
}
/* Try machine-dependent ways of modifying an illegitimate address
--- 6309,6459 ----
return new;
}
! /* Load the thread pointer. If TO_REG is true, force it into a register. */
static rtx
! get_thread_pointer (to_reg)
! int to_reg;
{
! rtx tp, reg, insn;
tp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx), UNSPEC_TP);
! if (!to_reg)
! 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
*************** legitimize_address (x, oldx, mode)
*** 6322,6441 ****
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;
! }
if (flag_pic && SYMBOLIC_CONST (x))
return legitimize_pic_address (x, 0);
--- 6495,6501 ----
log = tls_symbolic_operand (x, mode);
if (log)
! return legitimize_tls_address (x, log, false);
if (flag_pic && SYMBOLIC_CONST (x))
return legitimize_pic_address (x, 0);
*************** print_operand (file, x, code)
*** 7418,7425 ****
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)
{
char dstr[30];
--- 7478,7485 ----
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)
{
char dstr[30];
*************** print_operand_address (file, addr)
*** 7474,7492 ****
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 ();
--- 7534,7539 ----
*************** print_operand_address (file, addr)
*** 7495,7529 ****
disp = parts.disp;
scale = parts.scale;
if (!base && !index)
{
/* Displacement only requires special attention. */
if (GET_CODE (disp) == CONST_INT)
{
! if (ASSEMBLER_DIALECT == ASM_INTEL)
{
if (USER_LABEL_PREFIX[0] == 0)
putc ('%', file);
fputs ("ds:", file);
}
! fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (addr));
}
else if (flag_pic)
! output_pic_addr_const (file, addr, 0);
else
! output_addr_const (file, addr);
/* 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)))
fputs ("(%rip)", file);
}
else
--- 7542,7590 ----
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 && parts.seg == SEG_DEFAULT)
{
if (USER_LABEL_PREFIX[0] == 0)
putc ('%', file);
fputs ("ds:", file);
}
! fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (disp));
}
else if (flag_pic)
! output_pic_addr_const (file, disp, 0);
else
! output_addr_const (file, disp);
/* Use one byte shorter RIP relative addressing for 64bit mode. */
if (TARGET_64BIT
! && ((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
*************** ix86_expand_move (mode, operands)
*** 8220,8241 ****
rtx operands[];
{
int strict = (reload_in_progress || reload_completed);
! rtx insn, op0, op1, tmp;
op0 = operands[0];
op1 = operands[1];
! if (tls_symbolic_operand (op1, Pmode))
{
! 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;
! }
}
! else if (flag_pic && mode == Pmode && symbolic_operand (op1, Pmode))
{
#if TARGET_MACHO
if (MACHOPIC_PURE)
--- 8281,8302 ----
rtx operands[];
{
int strict = (reload_in_progress || reload_completed);
! rtx op0, op1;
! enum tls_model model;
op0 = operands[0];
op1 = operands[1];
! model = tls_symbolic_operand (op1, Pmode);
! if (model)
{
! op1 = legitimize_tls_address (op1, model, true);
! op1 = force_operand (op1, op0);
! if (op1 == op0)
! return;
}
!
! if (flag_pic && mode == Pmode && symbolic_operand (op1, Pmode))
{
#if TARGET_MACHO
if (MACHOPIC_PURE)
*************** ix86_expand_move (mode, operands)
*** 8248,8265 ****
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 */
if (GET_CODE (op0) == MEM)
op1 = force_reg (Pmode, op1);
else
--- 8309,8319 ----
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)
! return;
! #else
if (GET_CODE (op0) == MEM)
op1 = force_reg (Pmode, op1);
else
*************** ix86_expand_move (mode, operands)
*** 8272,8277 ****
--- 8326,8332 ----
return;
op1 = temp;
}
+ #endif /* TARGET_MACHO */
}
else
{
*************** ix86_expand_move (mode, operands)
*** 8316,8324 ****
}
}
! insn = gen_rtx_SET (VOIDmode, op0, op1);
!
! emit_insn (insn);
}
void
--- 8371,8377 ----
}
}
! emit_insn (gen_rtx_SET (VOIDmode, op0, op1));
}
void
*************** ix86_rtx_costs (x, code, outer_code, tot
*** 15092,15097 ****
--- 15145,15155 ----
case SQRT:
if (FLOAT_MODE_P (mode))
*total = COSTS_N_INSNS (ix86_cost->fsqrt);
+ return false;
+
+ case UNSPEC:
+ if (XINT (x, 1) == UNSPEC_TP)
+ *total = 0;
return false;
default:
Index: config/i386/i386.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.h,v
retrieving revision 1.338
diff -c -p -d -r1.338 i386.h
*** config/i386/i386.h 4 Jun 2003 17:50:42 -0000 1.338
--- config/i386/i386.h 5 Jun 2003 00:06:56 -0000
*************** extern int target_flags;
*** 122,127 ****
--- 122,128 ----
#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 */
*************** extern int target_flags;
*** 201,206 ****
--- 202,210 ----
#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)
*************** extern int x86_prefetch_sse;
*** 405,416 ****
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") }, \
SUBTARGET_SWITCHES \
! { "", TARGET_DEFAULT | TARGET_64BIT_DEFAULT | TARGET_SUBTARGET_DEFAULT, 0 }}
#ifndef TARGET_64BIT_DEFAULT
#define TARGET_64BIT_DEFAULT 0
#endif
/* Once GDB has been enhanced to deal with functions without frame
pointers, we can change this to allow for elimination of
--- 409,429 ----
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 \
! | 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
*************** do { \
*** 3034,3039 ****
--- 3047,3054 ----
{"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. */
Index: config/i386/i386.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.md,v
retrieving revision 1.464
diff -c -p -d -r1.464 i386.md
*** config/i386/i386.md 4 Jun 2003 20:06:34 -0000 1.464
--- config/i386/i386.md 5 Jun 2003 00:06:58 -0000
***************
*** 5312,5318 ****
(define_insn "*lea_1"
[(set (match_operand:SI 0 "register_operand" "=r")
! (match_operand:SI 1 "address_operand" "p"))]
"!TARGET_64BIT"
"lea{l}\t{%a1, %0|%0, %a1}"
[(set_attr "type" "lea")
--- 5312,5318 ----
(define_insn "*lea_1"
[(set (match_operand:SI 0 "register_operand" "=r")
! (match_operand:SI 1 "no_seg_address_operand" "p"))]
"!TARGET_64BIT"
"lea{l}\t{%a1, %0|%0, %a1}"
[(set_attr "type" "lea")
***************
*** 5320,5326 ****
(define_insn "*lea_1_rex64"
[(set (match_operand:SI 0 "register_operand" "=r")
! (subreg:SI (match_operand:DI 1 "address_operand" "p") 0))]
"TARGET_64BIT"
"lea{l}\t{%a1, %0|%0, %a1}"
[(set_attr "type" "lea")
--- 5320,5326 ----
(define_insn "*lea_1_rex64"
[(set (match_operand:SI 0 "register_operand" "=r")
! (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,5334 ****
(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)))]
"TARGET_64BIT"
"lea{l}\t{%a1, %k0|%k0, %a1}"
[(set_attr "type" "lea")
--- 5328,5335 ----
(define_insn "*lea_1_zext"
[(set (match_operand:DI 0 "register_operand" "=r")
! (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,5342 ****
(define_insn "*lea_2_rex64"
[(set (match_operand:DI 0 "register_operand" "=r")
! (match_operand:DI 1 "address_operand" "p"))]
"TARGET_64BIT"
"lea{q}\t{%a1, %0|%0, %a1}"
[(set_attr "type" "lea")
--- 5337,5343 ----
(define_insn "*lea_2_rex64"
[(set (match_operand:DI 0 "register_operand" "=r")
! (match_operand:DI 1 "no_seg_address_operand" "p"))]
"TARGET_64BIT"
"lea{q}\t{%a1, %0|%0, %a1}"
[(set_attr "type" "lea")
***************
*** 14636,14641 ****
--- 14637,14692 ----
(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
Index: config/i386/linux.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/linux.h,v
retrieving revision 1.45
diff -c -p -d -r1.45 linux.h
*** config/i386/linux.h 4 Jun 2003 16:44:50 -0000 1.45
--- config/i386/linux.h 5 Jun 2003 00:06:58 -0000
*************** Boston, MA 02111-1307, USA. */
*** 40,45 ****
--- 40,49 ----
#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 "#"
Index: config/i386/linux64.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/linux64.h,v
retrieving revision 1.22
diff -c -p -d -r1.22 linux64.h
*** config/i386/linux64.h 4 Jun 2003 16:44:50 -0000 1.22
--- config/i386/linux64.h 5 Jun 2003 00:06:58 -0000
*************** Boston, MA 02111-1307, USA. */
*** 47,52 ****
--- 47,56 ----
#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
Index: doc/invoke.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/invoke.texi,v
retrieving revision 1.288
diff -c -p -d -r1.288 invoke.texi
*** doc/invoke.texi 4 Jun 2003 20:59:56 -0000 1.288
--- doc/invoke.texi 5 Jun 2003 00:21:03 -0000
*************** in the following sections.
*** 490,496 ****
-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
-mcmodel=@var{code-model} @gol
-m32 -m64}
--- 490,496 ----
-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 -mno-tls-direct-seg-refs @gol
-mcmodel=@var{code-model} @gol
-m32 -m64}
*************** avoids the instructions to save, set up
*** 8401,8406 ****
--- 8401,8417 ----
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