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));
{
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 *));
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
/* 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)
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)
{
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;
out->index = index;
out->disp = disp;
out->scale = scale;
+ out->seg = seg;
return retval;
}
/* 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
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";
return new;
}
\f
-/* 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
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);
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];
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 ();
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
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)
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
return;
op1 = temp;
}
+#endif /* TARGET_MACHO */
}
else
{
}
}
- insn = gen_rtx_SET (VOIDmode, op0, op1);
-
- emit_insn (insn);
+ emit_insn (gen_rtx_SET (VOIDmode, op0, op1));
}
void
*total = COSTS_N_INSNS (ix86_cost->fsqrt);
return false;
+ case UNSPEC:
+ if (XINT (x, 1) == UNSPEC_TP)
+ *total = 0;
+ return false;
+
default:
return false;
}