aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRichard Henderson <rth@redhat.com>2003-06-04 17:23:23 -0700
committerRichard Henderson <rth@gcc.gnu.org>2003-06-04 17:23:23 -0700
commit74dc3e94edfd887109df4c9b956053de96fb21bb (patch)
tree68a0fa8732f08f9b84bdcad7829831a39e3d9f08 /gcc
parentd7068b3d2acc18be3975a44362bc34ba3d9dc2e1 (diff)
downloadgcc-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/ChangeLog28
-rw-r--r--gcc/config/i386/i386.c494
-rw-r--r--gcc/config/i386/i386.h17
-rw-r--r--gcc/config/i386/i386.md59
-rw-r--r--gcc/config/i386/linux.h4
-rw-r--r--gcc/config/i386/linux64.h4
-rw-r--r--gcc/doc/invoke.texi13
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