Commit 74dc3e94 by Richard Henderson Committed by Richard Henderson

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
parent d7068b3d
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> 2003-06-04 Mark Mitchell <mark@codesourcery.com>
* Makefile.in (QMTESTRUNFLAGS): Set for DejaGNU emulation. * Makefile.in (QMTESTRUNFLAGS): Set for DejaGNU emulation.
......
...@@ -793,7 +793,8 @@ static rtx maybe_get_pool_constant PARAMS ((rtx)); ...@@ -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 rtx ix86_expand_int_compare PARAMS ((enum rtx_code, rtx, rtx));
static enum rtx_code ix86_prepare_fp_compare_args PARAMS ((enum rtx_code, static enum rtx_code ix86_prepare_fp_compare_args PARAMS ((enum rtx_code,
rtx *, rtx *)); 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 void get_pc_thunk_name PARAMS ((char [32], unsigned int));
static rtx gen_push PARAMS ((rtx)); static rtx gen_push PARAMS ((rtx));
static int memory_address_length PARAMS ((rtx addr)); static int memory_address_length PARAMS ((rtx addr));
...@@ -835,6 +836,7 @@ struct ix86_address ...@@ -835,6 +836,7 @@ struct ix86_address
{ {
rtx base, index, disp; rtx base, index, disp;
HOST_WIDE_INT scale; 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 *)); static int ix86_decompose_address PARAMS ((rtx, struct ix86_address *));
...@@ -3863,6 +3865,25 @@ vector_move_operand (op, mode) ...@@ -3863,6 +3865,25 @@ vector_move_operand (op, mode)
return (op == CONST0_RTX (GET_MODE (op))); 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 /* Return 1 if OP is a comparison that can be used in the CMPSS/CMPPS
insns. */ insns. */
int int
...@@ -5403,8 +5424,7 @@ ix86_output_function_epilogue (file, size) ...@@ -5403,8 +5424,7 @@ ix86_output_function_epilogue (file, size)
/* Extract the parts of an RTL expression that is a valid memory address /* 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 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 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 static int
ix86_decompose_address (addr, out) ix86_decompose_address (addr, out)
...@@ -5417,47 +5437,72 @@ ix86_decompose_address (addr, out) ...@@ -5417,47 +5437,72 @@ ix86_decompose_address (addr, out)
HOST_WIDE_INT scale = 1; HOST_WIDE_INT scale = 1;
rtx scale_rtx = NULL_RTX; rtx scale_rtx = NULL_RTX;
int retval = 1; int retval = 1;
enum ix86_address_seg seg = SEG_DEFAULT;
if (REG_P (addr) || GET_CODE (addr) == SUBREG) if (REG_P (addr) || GET_CODE (addr) == SUBREG)
base = addr; base = addr;
else if (GET_CODE (addr) == PLUS) else if (GET_CODE (addr) == PLUS)
{ {
rtx op0 = XEXP (addr, 0); rtx addends[4], op;
rtx op1 = XEXP (addr, 1); int n = 0, i;
enum rtx_code code0 = GET_CODE (op0);
enum rtx_code code1 = GET_CODE (op1);
if (code0 == REG || code0 == SUBREG) op = addr;
{ do
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 */ if (n >= 4)
scale_rtx = XEXP (XEXP (op0, 0), 1); return 0;
base = XEXP (op0, 1); addends[n++] = XEXP (op, 1);
disp = op1; 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 */ op = addends[i];
base = XEXP (op0, 1); switch (GET_CODE (op))
disp = op1; {
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) else if (GET_CODE (addr) == MULT)
{ {
...@@ -5490,10 +5535,11 @@ ix86_decompose_address (addr, out) ...@@ -5490,10 +5535,11 @@ ix86_decompose_address (addr, out)
scale = INTVAL (scale_rtx); 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 if (base && index && scale == 1
&& (index == arg_pointer_rtx || index == frame_pointer_rtx && (index == arg_pointer_rtx
|| index == stack_pointer_rtx)) || index == frame_pointer_rtx
|| (REG_P (index) && REGNO (index) == STACK_POINTER_REGNUM)))
{ {
rtx tmp = base; rtx tmp = base;
base = index; base = index;
...@@ -5526,6 +5572,7 @@ ix86_decompose_address (addr, out) ...@@ -5526,6 +5572,7 @@ ix86_decompose_address (addr, out)
out->index = index; out->index = index;
out->disp = disp; out->disp = disp;
out->scale = scale; out->scale = scale;
out->seg = seg;
return retval; return retval;
} }
...@@ -5553,6 +5600,8 @@ ix86_address_cost (x) ...@@ -5553,6 +5600,8 @@ ix86_address_cost (x)
/* More complex memory references are better. */ /* More complex memory references are better. */
if (parts.disp && parts.disp != const0_rtx) if (parts.disp && parts.disp != const0_rtx)
cost--; cost--;
if (parts.seg != SEG_DEFAULT)
cost--;
/* Attempt to minimize number of registers in the address. */ /* Attempt to minimize number of registers in the address. */
if ((parts.base if ((parts.base
...@@ -5871,13 +5920,6 @@ legitimate_address_p (mode, addr, strict) ...@@ -5871,13 +5920,6 @@ legitimate_address_p (mode, addr, strict)
debug_rtx (addr); 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) if (ix86_decompose_address (addr, &parts) <= 0)
{ {
reason = "decomposition failed"; reason = "decomposition failed";
...@@ -6267,20 +6309,151 @@ legitimize_pic_address (orig, reg) ...@@ -6267,20 +6309,151 @@ legitimize_pic_address (orig, reg)
return new; 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 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_UNSPEC (Pmode, gen_rtvec (1, const0_rtx), UNSPEC_TP);
tp = gen_rtx_MEM (Pmode, tp); if (!to_reg)
RTX_UNCHANGING_P (tp) = 1; return tp;
set_mem_alias_set (tp, ix86_GOT_alias_set ());
tp = force_reg (Pmode, 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 /* Try machine-dependent ways of modifying an illegitimate address
...@@ -6322,120 +6495,7 @@ legitimize_address (x, oldx, mode) ...@@ -6322,120 +6495,7 @@ legitimize_address (x, oldx, mode)
log = tls_symbolic_operand (x, mode); log = tls_symbolic_operand (x, mode);
if (log) if (log)
{ return legitimize_tls_address (x, log, false);
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)) if (flag_pic && SYMBOLIC_CONST (x))
return legitimize_pic_address (x, 0); return legitimize_pic_address (x, 0);
...@@ -7418,8 +7478,8 @@ print_operand (file, x, code) ...@@ -7418,8 +7478,8 @@ print_operand (file, x, code)
fprintf (file, "0x%lx", l); fprintf (file, "0x%lx", l);
} }
/* These float cases don't actually occur as immediate operands. */ /* These float cases don't actually occur as immediate operands. */
else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode) else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode)
{ {
char dstr[30]; char dstr[30];
...@@ -7474,19 +7534,6 @@ print_operand_address (file, addr) ...@@ -7474,19 +7534,6 @@ print_operand_address (file, addr)
rtx base, index, disp; rtx base, index, disp;
int scale; 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)) if (! ix86_decompose_address (addr, &parts))
abort (); abort ();
...@@ -7495,35 +7542,49 @@ print_operand_address (file, addr) ...@@ -7495,35 +7542,49 @@ print_operand_address (file, addr)
disp = parts.disp; disp = parts.disp;
scale = parts.scale; 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) if (!base && !index)
{ {
/* Displacement only requires special attention. */ /* Displacement only requires special attention. */
if (GET_CODE (disp) == CONST_INT) 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) if (USER_LABEL_PREFIX[0] == 0)
putc ('%', file); putc ('%', file);
fputs ("ds:", 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) else if (flag_pic)
output_pic_addr_const (file, addr, 0); output_pic_addr_const (file, disp, 0);
else else
output_addr_const (file, addr); output_addr_const (file, disp);
/* Use one byte shorter RIP relative addressing for 64bit mode. */ /* Use one byte shorter RIP relative addressing for 64bit mode. */
if (TARGET_64BIT if (TARGET_64BIT
&& ((GET_CODE (addr) == SYMBOL_REF && ((GET_CODE (disp) == SYMBOL_REF
&& ! tls_symbolic_operand (addr, GET_MODE (addr))) && ! tls_symbolic_operand (disp, GET_MODE (disp)))
|| GET_CODE (addr) == LABEL_REF || GET_CODE (disp) == LABEL_REF
|| (GET_CODE (addr) == CONST || (GET_CODE (disp) == CONST
&& GET_CODE (XEXP (addr, 0)) == PLUS && GET_CODE (XEXP (disp, 0)) == PLUS
&& (GET_CODE (XEXP (XEXP (addr, 0), 0)) == SYMBOL_REF && (GET_CODE (XEXP (XEXP (disp, 0), 0)) == SYMBOL_REF
|| GET_CODE (XEXP (XEXP (addr, 0), 0)) == LABEL_REF) || GET_CODE (XEXP (XEXP (disp, 0), 0)) == LABEL_REF)
&& GET_CODE (XEXP (XEXP (addr, 0), 1)) == CONST_INT))) && GET_CODE (XEXP (XEXP (disp, 0), 1)) == CONST_INT)))
fputs ("(%rip)", file); fputs ("(%rip)", file);
} }
else else
...@@ -8220,22 +8281,22 @@ ix86_expand_move (mode, operands) ...@@ -8220,22 +8281,22 @@ ix86_expand_move (mode, operands)
rtx operands[]; rtx operands[];
{ {
int strict = (reload_in_progress || reload_completed); int strict = (reload_in_progress || reload_completed);
rtx insn, op0, op1, tmp; rtx op0, op1;
enum tls_model model;
op0 = operands[0]; op0 = operands[0];
op1 = operands[1]; op1 = operands[1];
if (tls_symbolic_operand (op1, Pmode)) model = tls_symbolic_operand (op1, Pmode);
if (model)
{ {
op1 = legitimize_address (op1, op1, VOIDmode); op1 = legitimize_tls_address (op1, model, true);
if (GET_CODE (op0) == MEM) op1 = force_operand (op1, op0);
{ if (op1 == op0)
tmp = gen_reg_rtx (mode); return;
emit_insn (gen_rtx_SET (VOIDmode, tmp, op1));
op1 = tmp;
}
} }
else if (flag_pic && mode == Pmode && symbolic_operand (op1, Pmode))
if (flag_pic && mode == Pmode && symbolic_operand (op1, Pmode))
{ {
#if TARGET_MACHO #if TARGET_MACHO
if (MACHOPIC_PURE) if (MACHOPIC_PURE)
...@@ -8248,18 +8309,11 @@ ix86_expand_move (mode, operands) ...@@ -8248,18 +8309,11 @@ ix86_expand_move (mode, operands)
op1 = machopic_legitimize_pic_address (op1, mode, op1 = machopic_legitimize_pic_address (op1, mode,
temp == op1 ? 0 : temp); temp == op1 ? 0 : temp);
} }
else else if (MACHOPIC_INDIRECT)
{ op1 = machopic_indirect_data_reference (op1, 0);
if (MACHOPIC_INDIRECT) if (op0 == op1)
op1 = machopic_indirect_data_reference (op1, 0); return;
} #else
if (op0 != op1)
{
insn = gen_rtx_SET (VOIDmode, op0, op1);
emit_insn (insn);
}
return;
#endif /* TARGET_MACHO */
if (GET_CODE (op0) == MEM) if (GET_CODE (op0) == MEM)
op1 = force_reg (Pmode, op1); op1 = force_reg (Pmode, op1);
else else
...@@ -8272,6 +8326,7 @@ ix86_expand_move (mode, operands) ...@@ -8272,6 +8326,7 @@ ix86_expand_move (mode, operands)
return; return;
op1 = temp; op1 = temp;
} }
#endif /* TARGET_MACHO */
} }
else else
{ {
...@@ -8316,9 +8371,7 @@ ix86_expand_move (mode, operands) ...@@ -8316,9 +8371,7 @@ ix86_expand_move (mode, operands)
} }
} }
insn = gen_rtx_SET (VOIDmode, op0, op1); emit_insn (gen_rtx_SET (VOIDmode, op0, op1));
emit_insn (insn);
} }
void void
...@@ -15094,6 +15147,11 @@ ix86_rtx_costs (x, code, outer_code, total) ...@@ -15094,6 +15147,11 @@ ix86_rtx_costs (x, code, outer_code, total)
*total = COSTS_N_INSNS (ix86_cost->fsqrt); *total = COSTS_N_INSNS (ix86_cost->fsqrt);
return false; return false;
case UNSPEC:
if (XINT (x, 1) == UNSPEC_TP)
*total = 0;
return false;
default: default:
return false; return false;
} }
......
...@@ -122,6 +122,7 @@ extern int target_flags; ...@@ -122,6 +122,7 @@ extern int target_flags;
#define MASK_128BIT_LONG_DOUBLE 0x00040000 /* long double size is 128bit */ #define MASK_128BIT_LONG_DOUBLE 0x00040000 /* long double size is 128bit */
#define MASK_64BIT 0x00080000 /* Produce 64bit code */ #define MASK_64BIT 0x00080000 /* Produce 64bit code */
#define MASK_MS_BITFIELD_LAYOUT 0x00100000 /* Use native (MS) bitfield layout */ #define MASK_MS_BITFIELD_LAYOUT 0x00100000 /* Use native (MS) bitfield layout */
#define MASK_TLS_DIRECT_SEG_REFS 0x00200000 /* Avoid adding %gs:0 */
/* Unused: 0x03e0000 */ /* Unused: 0x03e0000 */
...@@ -201,6 +202,9 @@ extern int target_flags; ...@@ -201,6 +202,9 @@ extern int target_flags;
#endif #endif
#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_386 (ix86_tune == PROCESSOR_I386)
#define TARGET_486 (ix86_tune == PROCESSOR_I486) #define TARGET_486 (ix86_tune == PROCESSOR_I486)
#define TARGET_PENTIUM (ix86_tune == PROCESSOR_PENTIUM) #define TARGET_PENTIUM (ix86_tune == PROCESSOR_PENTIUM)
...@@ -405,12 +409,21 @@ extern int x86_prefetch_sse; ...@@ -405,12 +409,21 @@ extern int x86_prefetch_sse;
N_("Use red-zone in the x86-64 code") }, \ N_("Use red-zone in the x86-64 code") }, \
{ "no-red-zone", MASK_NO_RED_ZONE, \ { "no-red-zone", MASK_NO_RED_ZONE, \
N_("Do not use red-zone in the x86-64 code") }, \ 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 \ 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 #ifndef TARGET_64BIT_DEFAULT
#define TARGET_64BIT_DEFAULT 0 #define TARGET_64BIT_DEFAULT 0
#endif #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 /* Once GDB has been enhanced to deal with functions without frame
pointers, we can change this to allow for elimination of pointers, we can change this to allow for elimination of
...@@ -3034,6 +3047,8 @@ do { \ ...@@ -3034,6 +3047,8 @@ do { \
{"register_and_not_fp_reg_operand", {REG}}, \ {"register_and_not_fp_reg_operand", {REG}}, \
{"zero_extended_scalar_load_operand", {MEM}}, \ {"zero_extended_scalar_load_operand", {MEM}}, \
{"vector_move_operand", {CONST_VECTOR, SUBREG, REG, 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 /* A list of predicates that do special things with modes, and so
should not elicit warnings for VOIDmode match_operand. */ should not elicit warnings for VOIDmode match_operand. */
......
...@@ -5312,7 +5312,7 @@ ...@@ -5312,7 +5312,7 @@
(define_insn "*lea_1" (define_insn "*lea_1"
[(set (match_operand:SI 0 "register_operand" "=r") [(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" "!TARGET_64BIT"
"lea{l}\t{%a1, %0|%0, %a1}" "lea{l}\t{%a1, %0|%0, %a1}"
[(set_attr "type" "lea") [(set_attr "type" "lea")
...@@ -5320,7 +5320,7 @@ ...@@ -5320,7 +5320,7 @@
(define_insn "*lea_1_rex64" (define_insn "*lea_1_rex64"
[(set (match_operand:SI 0 "register_operand" "=r") [(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" "TARGET_64BIT"
"lea{l}\t{%a1, %0|%0, %a1}" "lea{l}\t{%a1, %0|%0, %a1}"
[(set_attr "type" "lea") [(set_attr "type" "lea")
...@@ -5328,7 +5328,8 @@ ...@@ -5328,7 +5328,8 @@
(define_insn "*lea_1_zext" (define_insn "*lea_1_zext"
[(set (match_operand:DI 0 "register_operand" "=r") [(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" "TARGET_64BIT"
"lea{l}\t{%a1, %k0|%k0, %a1}" "lea{l}\t{%a1, %k0|%k0, %a1}"
[(set_attr "type" "lea") [(set_attr "type" "lea")
...@@ -5336,7 +5337,7 @@ ...@@ -5336,7 +5337,7 @@
(define_insn "*lea_2_rex64" (define_insn "*lea_2_rex64"
[(set (match_operand:DI 0 "register_operand" "=r") [(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" "TARGET_64BIT"
"lea{q}\t{%a1, %0|%0, %a1}" "lea{q}\t{%a1, %0|%0, %a1}"
[(set_attr "type" "lea") [(set_attr "type" "lea")
...@@ -14636,6 +14637,56 @@ ...@@ -14636,6 +14637,56 @@
(clobber (match_dup 5)) (clobber (match_dup 5))
(clobber (reg:CC 17))])] (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, ;; These patterns match the binary 387 instructions for addM3, subM3,
;; mulM3 and divM3. There are three patterns for each of DFmode and ;; mulM3 and divM3. There are three patterns for each of DFmode and
......
...@@ -40,6 +40,10 @@ Boston, MA 02111-1307, USA. */ ...@@ -40,6 +40,10 @@ Boston, MA 02111-1307, USA. */
#undef DEFAULT_PCC_STRUCT_RETURN #undef DEFAULT_PCC_STRUCT_RETURN
#define DEFAULT_PCC_STRUCT_RETURN 1 #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 #undef ASM_COMMENT_START
#define ASM_COMMENT_START "#" #define ASM_COMMENT_START "#"
......
...@@ -47,6 +47,10 @@ Boston, MA 02111-1307, USA. */ ...@@ -47,6 +47,10 @@ Boston, MA 02111-1307, USA. */
#undef DEFAULT_PCC_STRUCT_RETURN #undef DEFAULT_PCC_STRUCT_RETURN
#define DEFAULT_PCC_STRUCT_RETURN 1 #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 /* Provide a LINK_SPEC. Here we provide support for the special GCC
options -static and -shared, which allow us to link things in one options -static and -shared, which allow us to link things in one
of these three modes by applying the appropriate combinations of of these three modes by applying the appropriate combinations of
......
...@@ -490,7 +490,7 @@ in the following sections. ...@@ -490,7 +490,7 @@ in the following sections.
-mthreads -mno-align-stringops -minline-all-stringops @gol -mthreads -mno-align-stringops -minline-all-stringops @gol
-mpush-args -maccumulate-outgoing-args -m128bit-long-double @gol -mpush-args -maccumulate-outgoing-args -m128bit-long-double @gol
-m96bit-long-double -mregparm=@var{num} -momit-leaf-frame-pointer @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 -mcmodel=@var{code-model} @gol
-m32 -m64} -m32 -m64}
...@@ -8401,6 +8401,17 @@ avoids the instructions to save, set up and restore frame pointers and ...@@ -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 makes an extra register available in leaf functions. The option
@option{-fomit-frame-pointer} removes the frame pointer for all functions @option{-fomit-frame-pointer} removes the frame pointer for all functions
which might make debugging harder. 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 @end table
These @samp{-m} switches are supported in addition to the above These @samp{-m} switches are supported in addition to the above
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment