rtx ix86_compare_op0 = NULL_RTX;
rtx ix86_compare_op1 = NULL_RTX;
+/* The encoding characters for the four TLS models present in ELF. */
+
+static char const tls_model_chars[] = "GLil";
+
#define MAX_386_STACK_LOCALS 3
/* Size of the register save area. */
#define X86_64_VARARGS_SIZE (REGPARM_MAX * UNITS_PER_WORD + SSE_REGPARM_MAX * 16)
struct machine_function
{
rtx stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS];
+ const char *some_ld_name;
int save_varrargs_registers;
int accesses_prev_frame;
};
/* Asm dialect. */
const char *ix86_asm_string;
enum asm_dialect ix86_asm_dialect = ASM_ATT;
+/* TLS dialext. */
+const char *ix86_tls_dialect_string;
+enum tls_dialect ix86_tls_dialect = TLS_DIALECT_GNU;
/* Which unit we are generating floating point math for. */
enum fpmath_unit ix86_fpmath;
static int internal_label_prefix_len;
\f
static int local_symbolic_operand PARAMS ((rtx, enum machine_mode));
-static const char *get_pic_label_name PARAMS ((void));
+static int tls_symbolic_operand_1 PARAMS ((rtx, enum tls_model));
static void output_pic_addr_const PARAMS ((FILE *, rtx, int));
static void put_condition_code PARAMS ((enum rtx_code, enum machine_mode,
int, int, FILE *));
+static const char *get_some_local_dynamic_name PARAMS ((void));
+static int get_some_local_dynamic_name_1 PARAMS ((rtx *, void *));
+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 gen_push PARAMS ((rtx));
static int memory_address_length PARAMS ((rtx addr));
static int ix86_flags_dependant PARAMS ((rtx, rtx, enum attr_type));
static int ix86_decompose_address PARAMS ((rtx, struct ix86_address *));
-static void i386_encode_section_info PARAMS ((tree, int)) ATTRIBUTE_UNUSED;
+static void ix86_encode_section_info PARAMS ((tree, int)) ATTRIBUTE_UNUSED;
+static const char *ix86_strip_name_encoding PARAMS ((const char *))
+ ATTRIBUTE_UNUSED;
struct builtin_description;
static rtx ix86_expand_sse_comi PARAMS ((const struct builtin_description *,
#define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD \
ia32_multipass_dfa_lookahead
+#ifdef HAVE_AS_TLS
+#undef TARGET_HAVE_TLS
+#define TARGET_HAVE_TLS true
+#endif
+
struct gcc_target targetm = TARGET_INITIALIZER;
\f
/* Sometimes certain combinations of command options do not make
ix86_branch_cost = i;
}
+ if (ix86_tls_dialect_string)
+ {
+ if (strcmp (ix86_tls_dialect_string, "gnu") == 0)
+ ix86_tls_dialect = TLS_DIALECT_GNU;
+ else if (strcmp (ix86_tls_dialect_string, "sun") == 0)
+ ix86_tls_dialect = TLS_DIALECT_SUN;
+ else
+ error ("bad value (%s) for -mtls-dialect= switch",
+ ix86_tls_dialect_string);
+ }
+
/* Keep nonleaf frame pointers. */
if (TARGET_OMIT_LEAF_FRAME_POINTER)
flag_omit_frame_pointer = 1;
return 0;
}
+/* Test for various thread-local symbols. See ix86_encode_section_info. */
+
+int
+tls_symbolic_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ const char *symbol_str;
+
+ if (GET_CODE (op) != SYMBOL_REF)
+ return 0;
+ symbol_str = XSTR (op, 0);
+
+ if (symbol_str[0] != '%')
+ return 0;
+ return strchr (tls_model_chars, symbol_str[1]) - tls_model_chars + 1;
+}
+
+static int
+tls_symbolic_operand_1 (op, kind)
+ rtx op;
+ enum tls_model kind;
+{
+ const char *symbol_str;
+
+ if (GET_CODE (op) != SYMBOL_REF)
+ return 0;
+ symbol_str = XSTR (op, 0);
+
+ return symbol_str[0] == '%' && symbol_str[1] == tls_model_chars[kind];
+}
+
+int
+global_dynamic_symbolic_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ return tls_symbolic_operand_1 (op, TLS_MODEL_GLOBAL_DYNAMIC);
+}
+
+int
+local_dynamic_symbolic_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ return tls_symbolic_operand_1 (op, TLS_MODEL_LOCAL_DYNAMIC);
+}
+
+int
+initial_exec_symbolic_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ return tls_symbolic_operand_1 (op, TLS_MODEL_INITIAL_EXEC);
+}
+
+int
+local_exec_symbolic_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ return tls_symbolic_operand_1 (op, TLS_MODEL_LOCAL_EXEC);
+}
+
/* Test for a valid operand for a call instruction. Don't allow the
arg pointer register or virtual regs since they may decay into
reg + const, which the patterns can't handle. */
\f
static char pic_label_name[32];
-static const char *
-get_pic_label_name ()
-{
- if (! pic_label_name[0])
- ASM_GENERATE_INTERNAL_LABEL (pic_label_name, "LPR", 0);
- return pic_label_name;
-}
-
/* This function generates code for -fpic that loads %ebx with
the return address of the caller and then returns. */
{
rtx xops[2];
- if (! TARGET_DEEP_BRANCH_PREDICTION || pic_label_name[0] == 0)
+ if (pic_label_name[0] == 0)
return;
/* ??? Binutils 2.10 and earlier has a linkonce elimination bug related
}
else
{
- xops[2] = gen_rtx_SYMBOL_REF (Pmode, get_pic_label_name ());
+ if (! pic_label_name[0])
+ ASM_GENERATE_INTERNAL_LABEL (pic_label_name, "LPR", 0);
+
+ xops[2] = gen_rtx_SYMBOL_REF (Pmode, pic_label_name);
xops[2] = gen_rtx_MEM (QImode, xops[2]);
output_asm_insn ("call\t%X2", xops);
}
return term;
}
\f
+/* Determine if a given RTX is a valid constant. We already know this
+ satisfies CONSTANT_P. */
+
+bool
+legitimate_constant_p (x)
+ rtx x;
+{
+ rtx inner;
+
+ switch (GET_CODE (x))
+ {
+ case SYMBOL_REF:
+ /* TLS symbols are not constant. */
+ if (tls_symbolic_operand (x, Pmode))
+ return false;
+ break;
+
+ case CONST:
+ inner = XEXP (x, 0);
+
+ /* Offsets of TLS symbols are never valid.
+ Discourage CSE from creating them. */
+ if (GET_CODE (inner) == PLUS
+ && tls_symbolic_operand (XEXP (inner, 0), Pmode))
+ return false;
+
+ /* Only some unspecs are valid as "constants". */
+ if (GET_CODE (inner) == UNSPEC)
+ switch (XINT (inner, 1))
+ {
+ case UNSPEC_TPOFF:
+ return local_exec_symbolic_operand (XVECEXP (inner, 0, 0), Pmode);
+ case UNSPEC_TP:
+ return true;
+ default:
+ return false;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ /* Otherwise we handle everything else in the move patterns. */
+ return true;
+}
+
+/* Determine if a given RTX is a valid constant address. */
+
+bool
+constant_address_p (x)
+ rtx x;
+{
+ switch (GET_CODE (x))
+ {
+ case LABEL_REF:
+ case CONST_INT:
+ return true;
+
+ case CONST_DOUBLE:
+ return TARGET_64BIT;
+
+ case CONST:
+ case SYMBOL_REF:
+ return !flag_pic && legitimate_constant_p (x);
+
+ default:
+ return false;
+ }
+}
+
+/* Nonzero if the constant value X is a legitimate general operand
+ when generating PIC code. It is given that flag_pic is on and
+ that X satisfies CONSTANT_P or is a CONST_DOUBLE. */
+
+bool
+legitimate_pic_operand_p (x)
+ rtx x;
+{
+ rtx inner;
+
+ switch (GET_CODE (x))
+ {
+ case CONST:
+ inner = XEXP (x, 0);
+
+ /* Only some unspecs are valid as "constants". */
+ if (GET_CODE (inner) == UNSPEC)
+ switch (XINT (inner, 1))
+ {
+ case UNSPEC_TPOFF:
+ return local_exec_symbolic_operand (XVECEXP (inner, 0, 0), Pmode);
+ case UNSPEC_TP:
+ return true;
+ default:
+ return false;
+ }
+ /* FALLTHRU */
+
+ case SYMBOL_REF:
+ case LABEL_REF:
+ return legitimate_pic_address_disp_p (x);
+
+ default:
+ return true;
+ }
+}
+
/* Determine if a given CONST RTX is a valid memory displacement
in PIC mode. */
legitimate_pic_address_disp_p (disp)
register rtx disp;
{
+ bool saw_plus;
+
/* In 64bit mode we can allow direct addresses of symbols and labels
when they are not dynamic symbols. */
if (TARGET_64BIT)
return 1;
}
+ saw_plus = false;
if (GET_CODE (disp) == PLUS)
{
if (GET_CODE (XEXP (disp, 1)) != CONST_INT)
return 0;
disp = XEXP (disp, 0);
+ saw_plus = true;
}
if (GET_CODE (disp) != UNSPEC)
return 0;
- /* Must be @GOT or @GOTOFF. */
switch (XINT (disp, 1))
{
case UNSPEC_GOT:
+ if (saw_plus)
+ return false;
return GET_CODE (XVECEXP (disp, 0, 0)) == SYMBOL_REF;
case UNSPEC_GOTOFF:
return local_symbolic_operand (XVECEXP (disp, 0, 0), Pmode);
+ case UNSPEC_GOTTPOFF:
+ if (saw_plus)
+ return false;
+ return initial_exec_symbolic_operand (XVECEXP (disp, 0, 0), Pmode);
+ case UNSPEC_NTPOFF:
+ /* ??? Could support offset here. */
+ if (saw_plus)
+ return false;
+ return local_exec_symbolic_operand (XVECEXP (disp, 0, 0), Pmode);
+ case UNSPEC_DTPOFF:
+ /* ??? Could support offset here. */
+ if (saw_plus)
+ return false;
+ return local_dynamic_symbolic_operand (XVECEXP (disp, 0, 0), Pmode);
}
return 0;
{
reason_rtx = disp;
- if (!CONSTANT_ADDRESS_P (disp))
- {
- reason = "displacement is not constant";
- goto report_error;
- }
-
if (TARGET_64BIT)
{
if (!x86_64_sign_extended_value (disp))
}
}
- if (flag_pic && SYMBOLIC_CONST (disp))
+ if (GET_CODE (disp) == CONST
+ && GET_CODE (XEXP (disp, 0)) == UNSPEC)
+ switch (XINT (XEXP (disp, 0), 1))
+ {
+ case UNSPEC_GOT:
+ case UNSPEC_GOTOFF:
+ case UNSPEC_GOTPCREL:
+ if (!flag_pic)
+ abort ();
+ goto is_legitimate_pic;
+
+ case UNSPEC_GOTTPOFF:
+ case UNSPEC_NTPOFF:
+ case UNSPEC_DTPOFF:
+ break;
+
+ default:
+ reason = "invalid address unspec";
+ goto report_error;
+ }
+
+ else if (flag_pic && SYMBOLIC_CONST (disp))
{
+ is_legitimate_pic:
if (TARGET_64BIT && (index || base))
{
reason = "non-constant pic memory reference";
goto report_error;
}
}
+ else if (!CONSTANT_ADDRESS_P (disp))
+ {
+ reason = "displacement is not constant";
+ goto report_error;
+ }
}
/* Everything looks valid. */
return new;
}
-/* If using PIC, mark a SYMBOL_REF for a non-global symbol so that we
- may access it directly in the GOT. */
-
static void
-i386_encode_section_info (decl, first)
+ix86_encode_section_info (decl, first)
tree decl;
int first ATTRIBUTE_UNUSED;
{
+ bool local_p = (*targetm.binds_local_p) (decl);
+ rtx rtl, symbol;
+
+ rtl = DECL_P (decl) ? DECL_RTL (decl) : TREE_CST_RTL (decl);
+ if (GET_CODE (rtl) != MEM)
+ return;
+ symbol = XEXP (rtl, 0);
+ if (GET_CODE (symbol) != SYMBOL_REF)
+ return;
+
+ /* For basic x86, if using PIC, mark a SYMBOL_REF for a non-global
+ symbol so that we may access it directly in the GOT. */
+
if (flag_pic)
+ SYMBOL_REF_FLAG (symbol) = local_p;
+
+ /* For ELF, encode thread-local data with %[GLil] for "global dynamic",
+ "local dynamic", "initial exec" or "local exec" TLS models
+ respectively. */
+
+ if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
{
- rtx rtl = DECL_P (decl) ? DECL_RTL (decl) : TREE_CST_RTL (decl);
+ const char *symbol_str;
+ char *newstr;
+ size_t len;
+ enum tls_model kind;
+
+ if (!flag_pic)
+ {
+ if (local_p)
+ kind = TLS_MODEL_LOCAL_EXEC;
+ else
+ kind = TLS_MODEL_INITIAL_EXEC;
+ }
+ /* Local dynamic is inefficient when we're not combining the
+ parts of the address. */
+ else if (optimize && local_p)
+ kind = TLS_MODEL_LOCAL_DYNAMIC;
+ else
+ kind = TLS_MODEL_GLOBAL_DYNAMIC;
+ if (kind < flag_tls_default)
+ kind = flag_tls_default;
+
+ symbol_str = XSTR (symbol, 0);
- if (GET_CODE (rtl) == MEM && GET_CODE (XEXP (rtl, 0)) == SYMBOL_REF)
- SYMBOL_REF_FLAG (XEXP (rtl, 0)) = (*targetm.binds_local_p) (decl);
+ if (symbol_str[0] == '%')
+ {
+ if (symbol_str[1] == tls_model_chars[kind])
+ return;
+ symbol_str += 2;
+ }
+ len = strlen (symbol_str) + 1;
+ newstr = alloca (len + 2);
+
+ newstr[0] = '%';
+ newstr[1] = tls_model_chars[kind];
+ memcpy (newstr + 2, symbol_str, len);
+
+ XSTR (symbol, 0) = ggc_alloc_string (newstr, len + 2 - 1);
}
}
+
+/* Undo the above when printing symbol names. */
+
+static const char *
+ix86_strip_name_encoding (str)
+ const char *str;
+{
+ if (str[0] == '%')
+ str += 2;
+ if (str [0] == '*')
+ str += 1;
+ return str;
+}
\f
+/* 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_CONST (Pmode, tp);
+ tp = force_reg (Pmode, tp);
+
+ return tp;
+}
+
/* Try machine-dependent ways of modifying an illegitimate address
to be legitimate. If we find one, return the new, valid address.
This macro is used in only one place: `memory_address' in explow.c.
debug_rtx (x);
}
+ /* Note that tls_symbolic_operand return is biased by 1 to return true. */
+ log = tls_symbolic_operand (x, mode);
+ if (log)
+ {
+ rtx dest, base, off, pic;
+
+ switch (log - 1)
+ {
+ case TLS_MODEL_GLOBAL_DYNAMIC:
+ dest = gen_reg_rtx (Pmode);
+ emit_insn (gen_tls_global_dynamic (dest, x));
+ break;
+
+ case TLS_MODEL_LOCAL_DYNAMIC:
+ base = gen_reg_rtx (Pmode);
+ emit_insn (gen_tls_local_dynamic_base (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 (flag_pic)
+ {
+ current_function_uses_pic_offset_table = 1;
+ pic = pic_offset_table_rtx;
+ }
+ else
+ {
+ pic = gen_reg_rtx (Pmode);
+ emit_insn (gen_set_got (pic));
+ }
+
+ base = get_thread_pointer ();
+
+ off = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_GOTTPOFF);
+ off = gen_rtx_CONST (Pmode, off);
+ 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 ());
+
+ /* Damn Sun for specifing a set of dynamic relocations without
+ considering the two-operand nature of the architecture!
+ We'd be much better off with a "GOTNTPOFF" relocation that
+ already contained the negated constant. */
+ /* ??? Using negl and reg+reg addressing appears to be a lose
+ size-wise. The negl is two bytes, just like the extra movl
+ incurred by the two-operand subl, but reg+reg addressing
+ uses the two-byte modrm form, unlike plain reg. */
+
+ dest = gen_reg_rtx (Pmode);
+ 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_GNU_TLS ? UNSPEC_NTPOFF : UNSPEC_TPOFF);
+ off = gen_rtx_CONST (Pmode, off);
+
+ if (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);
case UNSPEC_GOTOFF:
fputs ("@GOTOFF", file);
break;
- case UNSPEC_PLT:
- fputs ("@PLT", file);
- break;
case UNSPEC_GOTPCREL:
fputs ("@GOTPCREL(%RIP)", file);
break;
+ case UNSPEC_GOTTPOFF:
+ fputs ("@GOTTPOFF", file);
+ break;
+ case UNSPEC_TPOFF:
+ fputs ("@TPOFF", file);
+ break;
+ case UNSPEC_NTPOFF:
+ fputs ("@NTPOFF", file);
+ break;
+ case UNSPEC_DTPOFF:
+ fputs ("@DTPOFF", file);
+ break;
default:
output_operand_lossage ("invalid UNSPEC as operand");
break;
}
}
+/* Locate some local-dynamic symbol still in use by this function
+ so that we can print its name in some tls_local_dynamic_base
+ pattern. */
+
+static const char *
+get_some_local_dynamic_name ()
+{
+ rtx insn;
+
+ if (cfun->machine->some_ld_name)
+ return cfun->machine->some_ld_name;
+
+ for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
+ if (INSN_P (insn)
+ && for_each_rtx (&PATTERN (insn), get_some_local_dynamic_name_1, 0))
+ return cfun->machine->some_ld_name;
+
+ abort ();
+}
+
+static int
+get_some_local_dynamic_name_1 (px, data)
+ rtx *px;
+ void *data ATTRIBUTE_UNUSED;
+{
+ rtx x = *px;
+
+ if (GET_CODE (x) == SYMBOL_REF
+ && local_dynamic_symbolic_operand (x, Pmode))
+ {
+ cfun->machine->some_ld_name = XSTR (x, 0);
+ return 1;
+ }
+
+ return 0;
+}
+
/* Meaning of CODE:
L,W,B,Q,S,T -- print the opcode suffix for specified size of operand.
C -- print opcode suffix for set/cmov insn.
D -- print condition for SSE cmp instruction.
P -- if PIC, print an @PLT suffix.
X -- don't print any sort of PIC '@' suffix for a symbol.
+ & -- print some in-use local-dynamic symbol name.
*/
void
putc ('*', file);
return;
+ case '&':
+ assemble_name (file, get_some_local_dynamic_name ());
+ return;
+
case 'A':
if (ASSEMBLER_DIALECT == ASM_ATT)
putc ('*', file);
REAL_VALUE_TO_DECIMAL (r, "%.22e", dstr);
fprintf (file, "%s", dstr);
}
+
+ else if (GET_CODE (x) == CONST
+ && GET_CODE (XEXP (x, 0)) == UNSPEC
+ && XINT (XEXP (x, 0), 1) == UNSPEC_TP)
+ {
+ if (ASSEMBLER_DIALECT == ASM_INTEL)
+ fputs ("DWORD PTR ", file);
+ if (ASSEMBLER_DIALECT == ASM_ATT || USER_LABEL_PREFIX[0] == 0)
+ putc ('%', file);
+ fputs ("gs:0", file);
+ }
+
else
{
if (code != 'P')
}
}
}
+
+bool
+output_addr_const_extra (file, x)
+ FILE *file;
+ rtx x;
+{
+ rtx op;
+
+ if (GET_CODE (x) != UNSPEC)
+ return false;
+
+ op = XVECEXP (x, 0, 0);
+ switch (XINT (x, 1))
+ {
+ case UNSPEC_GOTTPOFF:
+ output_addr_const (file, op);
+ fputs ("@GOTTPOFF", file);
+ break;
+ case UNSPEC_TPOFF:
+ output_addr_const (file, op);
+ fputs ("@TPOFF", file);
+ break;
+ case UNSPEC_NTPOFF:
+ output_addr_const (file, op);
+ fputs ("@NTPOFF", file);
+ break;
+ case UNSPEC_DTPOFF:
+ output_addr_const (file, op);
+ fputs ("@DTPOFF", file);
+ break;
+
+ default:
+ return false;
+ }
+
+ return true;
+}
\f
/* Split one or more DImode RTL references into pairs of SImode
references. The RTL can be REG, offsettable MEM, integer constant, or
emit_insn (tmp);
}
+/* X is an unchanging MEM. If it is a constant pool reference, return
+ the constant pool rtx, else NULL. */
+
+static rtx
+maybe_get_pool_constant (x)
+ rtx x;
+{
+ x = XEXP (x, 0);
+
+ if (flag_pic)
+ {
+ if (GET_CODE (x) != PLUS)
+ return NULL_RTX;
+ if (XEXP (x, 0) != pic_offset_table_rtx)
+ return NULL_RTX;
+ x = XEXP (x, 1);
+ if (GET_CODE (x) != CONST)
+ return NULL_RTX;
+ x = XEXP (x, 0);
+ if (GET_CODE (x) != UNSPEC)
+ return NULL_RTX;
+ if (XINT (x, 1) != UNSPEC_GOTOFF)
+ return NULL_RTX;
+ x = XVECEXP (x, 0, 0);
+ }
+
+ if (GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x))
+ return get_pool_constant (x);
+
+ return NULL_RTX;
+}
+
void
ix86_expand_move (mode, operands)
enum machine_mode mode;
rtx operands[];
{
int strict = (reload_in_progress || reload_completed);
- rtx insn;
+ rtx insn, op0, op1, tmp;
+
+ op0 = operands[0];
+ op1 = operands[1];
+
+ /* ??? We have a slight problem. We need to say that tls symbols are
+ not legitimate constants so that reload does not helpfully reload
+ these constants from a REG_EQUIV, which we cannot handle. (Recall
+ that general- and local-dynamic address resolution requires a
+ function call.)
- if (flag_pic && mode == Pmode && symbolic_operand (operands[1], Pmode))
+ However, if we say that tls symbols are not legitimate constants,
+ then emit_move_insn helpfully drop them into the constant pool.
+
+ It is far easier to work around emit_move_insn than reload. Recognize
+ the MEM that we would have created and extract the symbol_ref. */
+
+ if (mode == Pmode
+ && GET_CODE (op1) == MEM
+ && RTX_UNCHANGING_P (op1))
{
- /* Emit insns to move operands[1] into operands[0]. */
+ tmp = maybe_get_pool_constant (op1);
+ /* Note that we only care about symbolic constants here, which
+ unlike CONST_INT will always have a proper mode. */
+ if (tmp && GET_MODE (tmp) == Pmode)
+ op1 = tmp;
+ }
- if (GET_CODE (operands[0]) == MEM)
- operands[1] = force_reg (Pmode, 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 (GET_CODE (op0) == MEM)
+ op1 = force_reg (Pmode, op1);
else
{
- rtx temp = operands[0];
+ rtx temp = op0;
if (GET_CODE (temp) != REG)
temp = gen_reg_rtx (Pmode);
- temp = legitimize_pic_address (operands[1], temp);
- if (temp == operands[0])
+ temp = legitimize_pic_address (op1, temp);
+ if (temp == op0)
return;
- operands[1] = temp;
+ op1 = temp;
}
}
else
{
- if (GET_CODE (operands[0]) == MEM
+ if (GET_CODE (op0) == MEM
&& (PUSH_ROUNDING (GET_MODE_SIZE (mode)) != GET_MODE_SIZE (mode)
- || !push_operand (operands[0], mode))
- && GET_CODE (operands[1]) == MEM)
- operands[1] = force_reg (mode, operands[1]);
+ || !push_operand (op0, mode))
+ && GET_CODE (op1) == MEM)
+ op1 = force_reg (mode, op1);
- if (push_operand (operands[0], mode)
- && ! general_no_elim_operand (operands[1], mode))
- operands[1] = copy_to_mode_reg (mode, operands[1]);
+ if (push_operand (op0, mode)
+ && ! general_no_elim_operand (op1, mode))
+ op1 = copy_to_mode_reg (mode, op1);
/* Force large constants in 64bit compilation into register
to get them CSEed. */
if (TARGET_64BIT && mode == DImode
- && immediate_operand (operands[1], mode)
- && !x86_64_zero_extended_value (operands[1])
- && !register_operand (operands[0], mode)
+ && immediate_operand (op1, mode)
+ && !x86_64_zero_extended_value (op1)
+ && !register_operand (op0, mode)
&& optimize && !reload_completed && !reload_in_progress)
- operands[1] = copy_to_mode_reg (mode, operands[1]);
+ op1 = copy_to_mode_reg (mode, op1);
if (FLOAT_MODE_P (mode))
{
if (strict)
;
- else if (GET_CODE (operands[1]) == CONST_DOUBLE
- && register_operand (operands[0], mode))
- operands[1] = validize_mem (force_const_mem (mode, operands[1]));
+ else if (GET_CODE (op1) == CONST_DOUBLE
+ && register_operand (op0, mode))
+ op1 = validize_mem (force_const_mem (mode, op1));
}
}
- insn = gen_rtx_SET (VOIDmode, operands[0], operands[1]);
+ insn = gen_rtx_SET (VOIDmode, op0, op1);
emit_insn (insn);
}
if (size < 2 || size > 3)
abort ();
- /* Optimize constant pool reference to immediates. This is used by fp moves,
- that force all constants to memory to allow combining. */
-
- if (GET_CODE (operand) == MEM
- && GET_CODE (XEXP (operand, 0)) == SYMBOL_REF
- && CONSTANT_POOL_ADDRESS_P (XEXP (operand, 0)))
- operand = get_pool_constant (XEXP (operand, 0));
+ /* Optimize constant pool reference to immediates. This is used by fp
+ moves, that force all constants to memory to allow combining. */
+ if (GET_CODE (operand) == MEM && RTX_UNCHANGING_P (operand))
+ {
+ rtx tmp = maybe_get_pool_constant (operand);
+ if (tmp)
+ operand = tmp;
+ }
if (GET_CODE (operand) == MEM && !offsettable_memref_p (operand))
{
return ix86_stack_locals[(int) mode][n];
}
+
+/* Construct the SYMBOL_REF for the tls_get_addr function. */
+
+rtx
+ix86_tls_get_addr ()
+{
+ static rtx symbol;
+
+ if (!symbol)
+ {
+ symbol = gen_rtx_SYMBOL_REF (Pmode, (TARGET_GNU_TLS
+ ? "___tls_get_addr"
+ : "__tls_get_addr"));
+ ggc_add_rtx_root (&symbol, 1);
+ }
+
+ return symbol;
+}
\f
/* Calculate the length of the memory address in the instruction
encoding. Does not include the one-byte modrm, opcode, or prefix. */
echo $ac_n "checking assembler leb128 support""... $ac_c" 1>&6
-echo "configure:7228: checking assembler leb128 support" >&5
+echo "configure:7248: checking assembler leb128 support" >&5
gcc_cv_as_leb128=no
if test x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x; then
if test "$gcc_cv_gas_major_version" -eq 2 -a "$gcc_cv_gas_minor_version" -ge 11 -o "$gcc_cv_gas_major_version" -gt 2 && grep 'obj_format = elf' ../gas/Makefile > /dev/null; then
echo "$ac_t""$gcc_cv_as_leb128" 1>&6
echo $ac_n "checking assembler eh_frame optimization""... $ac_c" 1>&6
-echo "configure:7273: checking assembler eh_frame optimization" >&5
+echo "configure:7293: checking assembler eh_frame optimization" >&5
gcc_cv_as_eh_frame=no
if test x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x; then
if test "$gcc_cv_gas_major_version" -eq 2 -a "$gcc_cv_gas_minor_version" -ge 12 -o "$gcc_cv_gas_major_version" -gt 2 && grep 'obj_format = elf' ../gas/Makefile > /dev/null; then
echo "$ac_t""$gcc_cv_as_eh_frame" 1>&6
echo $ac_n "checking assembler section merging support""... $ac_c" 1>&6
-echo "configure:7354: checking assembler section merging support" >&5
+echo "configure:7374: checking assembler section merging support" >&5
gcc_cv_as_shf_merge=no
if test x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x; then
if test "$gcc_cv_gas_major_version" -eq 2 -a "$gcc_cv_gas_minor_version" -ge 12 -o "$gcc_cv_gas_major_version" -gt 2 && grep 'obj_format = elf' ../gas/Makefile > /dev/null; then
fi
echo "$ac_t""$gcc_cv_as_shf_merge" 1>&6
+echo $ac_n "checking assembler thread-local storage support""... $ac_c" 1>&6
+echo "configure:7397: checking assembler thread-local storage support" >&5
+gcc_cv_as_tls=no
+conftest_s=
+tls_first_major=
+tls_first_minor=
+case "$target" in
+ i[34567]86-*-*)
+ conftest_s='
+ .section ".tdata","awT",@progbits
+foo: .long 25
+ .text
+ movl %gs:0, %eax
+ leal foo@TLSGD(,%ebx,1), %eax
+ leal foo@TLSLDM(%ebx), %eax
+ leal foo@DTPOFF(%eax), %edx
+ movl foo@GOTTPOFF(%ebx), %eax
+ subl foo@GOTTPOFF(%ebx), %eax
+ movl $foo@TPOFF, %eax
+ subl $foo@TPOFF, %eax
+ leal foo@NTPOFF(%ecx), %eax'
+ tls_first_major=2
+ tls_first_minor=13
+ ;;
+esac
+if test -z "$tls_first_major"; then
+ :
+elif test x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x
+then
+ if test "$gcc_cv_gas_major_version" -eq "$tls_first_major" \
+ -a "$gcc_cv_gas_minor_version" -ge "$tls_first_minor" \
+ -o "$gcc_cv_gas_major_version" -gt "$tls_first_major"; then
+ gcc_cv_as_tls=yes
+ fi
+elif test x$gcc_cv_as != x; then
+ echo "$conftest_s" > conftest.s
+ if $gcc_cv_as --fatal-warnings -o conftest.o conftest.s > /dev/null 2>&1
+ then
+ gcc_cv_as_tls=yes
+ fi
+ rm -f conftest.s conftest.o
+fi
+if test "$gcc_cv_as_tls" = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_AS_TLS 1
+EOF
+
+fi
+echo "$ac_t""$gcc_cv_as_tls" 1>&6
+
case "$target" in
# All TARGET_ABI_OSF targets.
alpha*-*-osf* | alpha*-*-linux* | alpha*-*-*bsd*)
echo $ac_n "checking assembler supports explicit relocations""... $ac_c" 1>&6
-echo "configure:7380: checking assembler supports explicit relocations" >&5
+echo "configure:7450: checking assembler supports explicit relocations" >&5
if eval "test \"`echo '$''{'gcc_cv_as_explicit_relocs'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
;;
sparc*-*-*)
echo $ac_n "checking assembler .register pseudo-op support""... $ac_c" 1>&6
-echo "configure:7430: checking assembler .register pseudo-op support" >&5
+echo "configure:7500: checking assembler .register pseudo-op support" >&5
if eval "test \"`echo '$''{'gcc_cv_as_register_pseudo_op'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
fi
echo $ac_n "checking assembler supports -relax""... $ac_c" 1>&6
-echo "configure:7458: checking assembler supports -relax" >&5
+echo "configure:7528: checking assembler supports -relax" >&5
if eval "test \"`echo '$''{'gcc_cv_as_relax_opt'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
fi
echo $ac_n "checking assembler and linker support unaligned pc related relocs""... $ac_c" 1>&6
-echo "configure:7486: checking assembler and linker support unaligned pc related relocs" >&5
+echo "configure:7556: checking assembler and linker support unaligned pc related relocs" >&5
if eval "test \"`echo '$''{'gcc_cv_as_sparc_ua_pcrel'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
fi
echo $ac_n "checking assembler and linker support unaligned pc related relocs against hidden symbols""... $ac_c" 1>&6
-echo "configure:7513: checking assembler and linker support unaligned pc related relocs against hidden symbols" >&5
+echo "configure:7583: checking assembler and linker support unaligned pc related relocs against hidden symbols" >&5
if eval "test \"`echo '$''{'gcc_cv_as_sparc_ua_pcrel_hidden'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
if test "x$gcc_cv_as_flags64" != xno; then
echo $ac_n "checking for assembler offsetable %lo() support""... $ac_c" 1>&6
-echo "configure:7554: checking for assembler offsetable %lo() support" >&5
+echo "configure:7624: checking for assembler offsetable %lo() support" >&5
if eval "test \"`echo '$''{'gcc_cv_as_offsetable_lo10'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
i[34567]86-*-* | x86_64-*-*)
echo $ac_n "checking assembler instructions""... $ac_c" 1>&6
-echo "configure:7594: checking assembler instructions" >&5
+echo "configure:7664: checking assembler instructions" >&5
gcc_cv_as_instructions=
if test x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x; then
if test "$gcc_cv_gas_major_version" -eq 2 -a "$gcc_cv_gas_minor_version" -ge 9 -o "$gcc_cv_gas_major_version" -gt 2; then
echo "$ac_t""$gcc_cv_as_instructions" 1>&6
echo $ac_n "checking assembler GOTOFF in data directives""... $ac_c" 1>&6
-echo "configure:7621: checking assembler GOTOFF in data directives" >&5
+echo "configure:7691: checking assembler GOTOFF in data directives" >&5
gcc_cv_as_gotoff_in_data=no
if test x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x
then
esac
echo $ac_n "checking assembler dwarf2 debug_line support""... $ac_c" 1>&6
-echo "configure:7651: checking assembler dwarf2 debug_line support" >&5
+echo "configure:7721: checking assembler dwarf2 debug_line support" >&5
gcc_cv_as_dwarf2_debug_line=no
# ??? Not all targets support dwarf2 debug_line, even within a version
# of gas. Moreover, we need to emit a valid instruction to trigger any
echo "$ac_t""$gcc_cv_as_dwarf2_debug_line" 1>&6
echo $ac_n "checking assembler --gdwarf2 support""... $ac_c" 1>&6
-echo "configure:7707: checking assembler --gdwarf2 support" >&5
+echo "configure:7777: checking assembler --gdwarf2 support" >&5
gcc_cv_as_gdwarf2_flag=no
if test x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x;
then
echo "$ac_t""$gcc_cv_as_gdwarf2_flag" 1>&6
echo $ac_n "checking assembler --gstabs support""... $ac_c" 1>&6
-echo "configure:7736: checking assembler --gstabs support" >&5
+echo "configure:7806: checking assembler --gstabs support" >&5
gcc_cv_as_gstabs_flag=no
if test x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x;
then
echo "$ac_t""$gcc_cv_as_gstabs_flag" 1>&6
echo $ac_n "checking linker PT_GNU_EH_FRAME support""... $ac_c" 1>&6
-echo "configure:7764: checking linker PT_GNU_EH_FRAME support" >&5
+echo "configure:7834: checking linker PT_GNU_EH_FRAME support" >&5
gcc_cv_ld_eh_frame_hdr=no
if test x$gcc_cv_gld_major_version != x -a x$gcc_cv_gld_minor_version != x; then
if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 12 -o "$gcc_cv_gld_major_version" -gt 2 && grep 'EMUL = elf' ../ld/Makefile > /dev/null; then
echo $ac_n "checking whether to enable maintainer-specific portions of Makefiles""... $ac_c" 1>&6
-echo "configure:7927: checking whether to enable maintainer-specific portions of Makefiles" >&5
+echo "configure:7997: checking whether to enable maintainer-specific portions of Makefiles" >&5
# Check whether --enable-maintainer-mode or --disable-maintainer-mode was given.
if test "${enable_maintainer_mode+set}" = set; then
enableval="$enable_maintainer_mode"