ADDRESS_CONST_INT,
ADDRESS_SYMBOLIC,
ADDRESS_GOTOFF,
- ADDRESS_PLT
+ ADDRESS_PLT,
+ ADDRESS_TLS
};
/* Classifies symbols
SYMBOL_TYPE_GENERAL
};
+/* TLS Address Type. */
+enum tls_reloc {
+ TLS_GD,
+ TLS_LDM,
+ TLS_DTPREL,
+ TLS_IE,
+ TLS_LE
+};
+
/* Classification of a MicroBlaze address. */
struct microblaze_address_info
{
rtx offset; /* Contains valid values on ADDRESS_CONST_INT and ADDRESS_REG. */
rtx symbol; /* Contains valid values on ADDRESS_SYMBOLIC. */
enum microblaze_symbol_type symbol_type;
+ enum tls_reloc tls_type;
};
/* Structure to be filled in by compute_frame_size with register
section *sdata2_section;
+#ifdef HAVE_AS_TLS
+#undef TARGET_HAVE_TLS
+#define TARGET_HAVE_TLS true
+#endif
+
/* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */
static bool
microblaze_const_double_ok (rtx op, enum machine_mode mode)
plus0 = XEXP (addr, 0);
plus1 = XEXP (addr, 1);
+ if (GET_CODE (plus0) != REG)
+ return 0;
+
if (GET_CODE (plus0) == REG && GET_CODE (plus1) == CONST_INT
&& SMALL_INT (plus1))
{
&& microblaze_regno_ok_for_base_p (REGNO (x), strict));
}
+/* Build the SYMBOL_REF for __tls_get_addr. */
+
+static GTY(()) rtx tls_get_addr_libfunc;
+
+static rtx
+get_tls_get_addr (void)
+{
+ if (!tls_get_addr_libfunc)
+ tls_get_addr_libfunc = init_one_libfunc ("__tls_get_addr");
+ return tls_get_addr_libfunc;
+}
+
+/* Return TRUE if X is a thread-local symbol. */
+bool
+microblaze_tls_symbol_p (rtx x)
+{
+ if (!TARGET_HAVE_TLS)
+ return false;
+
+ if (GET_CODE (x) != SYMBOL_REF)
+ return false;
+
+ return SYMBOL_REF_TLS_MODEL (x) != 0;
+}
+
+static int
+microblaze_tls_operand_p_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
+{
+ if (GET_CODE (*x) == SYMBOL_REF)
+ return SYMBOL_REF_TLS_MODEL (*x) != 0;
+
+ /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are
+ TLS offsets, not real symbol references. */
+ if (GET_CODE (*x) == UNSPEC && XINT (*x, 1) == UNSPEC_TLS)
+ return -1;
+
+ return 0;
+}
+
+/* Return TRUE if X contains any TLS symbol references. */
+
+bool
+microblaze_tls_referenced_p (rtx x)
+{
+ if (!TARGET_HAVE_TLS)
+ return false;
+
+ return for_each_rtx (&x, microblaze_tls_operand_p_1, NULL);
+}
+
+bool
+microblaze_cannot_force_const_mem (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x)
+{
+ return microblaze_tls_referenced_p(x);
+}
+
+/* Return TRUE if X references a SYMBOL_REF. */
+int
+symbol_mentioned_p (rtx x)
+{
+ const char * fmt;
+ int i;
+
+ if (GET_CODE (x) == SYMBOL_REF)
+ return 1;
+
+ /* UNSPEC entries for a symbol include the SYMBOL_REF, but they
+ are constant offsets, not symbols. */
+ if (GET_CODE (x) == UNSPEC)
+ return 0;
+
+ fmt = GET_RTX_FORMAT (GET_CODE (x));
+
+ for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'E')
+ {
+ int j;
+
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ if (symbol_mentioned_p (XVECEXP (x, i, j)))
+ return 1;
+ }
+ else if (fmt[i] == 'e' && symbol_mentioned_p (XEXP (x, i)))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Return TRUE if X references a LABEL_REF. */
+int
+label_mentioned_p (rtx x)
+{
+ const char * fmt;
+ int i;
+
+ if (GET_CODE (x) == LABEL_REF)
+ return 1;
+
+ /* UNSPEC entries for a symbol include a LABEL_REF for the referencing
+ instruction, but they are constant offsets, not symbols. */
+ if (GET_CODE (x) == UNSPEC)
+ return 0;
+
+ fmt = GET_RTX_FORMAT (GET_CODE (x));
+ for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'E')
+ {
+ int j;
+
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ if (label_mentioned_p (XVECEXP (x, i, j)))
+ return 1;
+ }
+ else if (fmt[i] == 'e' && label_mentioned_p (XEXP (x, i)))
+ return 1;
+ }
+
+ return 0;
+}
+
+int
+tls_mentioned_p (rtx x)
+{
+ switch (GET_CODE (x))
+ {
+ case CONST:
+ return tls_mentioned_p (XEXP (x, 0));
+
+ case UNSPEC:
+ if (XINT (x, 1) == UNSPEC_TLS)
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+static rtx
+load_tls_operand (rtx x, rtx reg)
+{
+ rtx tmp;
+
+ if (reg == NULL_RTX)
+ reg = gen_reg_rtx (Pmode);
+
+ tmp = gen_rtx_CONST (Pmode, x);
+
+ emit_insn (gen_rtx_SET (VOIDmode, reg,
+ gen_rtx_PLUS (Pmode, pic_offset_table_rtx, tmp)));
+
+ return reg;
+}
+
+static rtx
+microblaze_call_tls_get_addr (rtx x, rtx reg, rtx *valuep, int reloc)
+{
+ rtx insns, tls_entry;
+
+ df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
+
+ start_sequence ();
+
+ tls_entry = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (reloc)),
+ UNSPEC_TLS);
+
+ reg = load_tls_operand (tls_entry, reg);
+
+ *valuep = emit_library_call_value (get_tls_get_addr (), NULL_RTX,
+ LCT_PURE, /* LCT_CONST? */
+ Pmode, 1, reg, Pmode);
+
+ insns = get_insns ();
+ end_sequence ();
+
+ return insns;
+}
+
+rtx
+microblaze_legitimize_tls_address(rtx x, rtx reg)
+{
+ rtx dest, insns, ret, eqv, addend;
+ enum tls_model model;
+ model = SYMBOL_REF_TLS_MODEL (x);
+
+ switch (model)
+ {
+ case TLS_MODEL_LOCAL_DYNAMIC:
+ case TLS_MODEL_GLOBAL_DYNAMIC:
+ case TLS_MODEL_INITIAL_EXEC:
+ insns = microblaze_call_tls_get_addr (x, reg, &ret, TLS_GD);
+ dest = gen_reg_rtx (Pmode);
+ emit_libcall_block (insns, dest, ret, x);
+ break;
+
+ case TLS_MODEL_LOCAL_EXEC:
+ insns = microblaze_call_tls_get_addr (x, reg, &ret, TLS_LDM);
+
+ /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
+ share the LDM result with other LD model accesses. */
+ eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const1_rtx), UNSPEC_TLS);
+ dest = gen_reg_rtx (Pmode);
+ emit_libcall_block (insns, dest, ret, eqv);
+
+ /* Load the addend. */
+ addend = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (TLS_DTPREL)),
+ UNSPEC_TLS);
+ addend = force_reg (SImode, gen_rtx_CONST (SImode, addend));
+ dest = gen_rtx_PLUS (Pmode, dest, addend);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ return dest;
+}
+
static bool
microblaze_classify_unspec (struct microblaze_address_info *info, rtx x)
{
{
info->type = ADDRESS_PLT;
}
+ else if (XINT (x, 1) == UNSPEC_TLS)
+ {
+ info->type = ADDRESS_TLS;
+ info->tls_type = tls_reloc INTVAL(XVECEXP(x, 0, 1));
+ }
else
{
return false;
get_base_reg (rtx x)
{
tree decl;
- int base_reg = (flag_pic ? MB_ABI_PIC_ADDR_REGNUM : MB_ABI_BASE_REGNUM);
+ int base_reg;
+
+ if (!flag_pic || microblaze_tls_symbol_p(x))
+ base_reg = MB_ABI_BASE_REGNUM;
+ else if (flag_pic)
+ base_reg = MB_ABI_PIC_ADDR_REGNUM;
if (TARGET_XLGPOPT
&& GET_CODE (x) == SYMBOL_REF
}
else if (GET_CODE (xplus1) == UNSPEC)
{
+ /* Need offsettable address. */
+ if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
+ return false;
+
return microblaze_classify_unspec (info, xplus1);
}
else if ((GET_CODE (xplus1) == SYMBOL_REF ||
- GET_CODE (xplus1) == LABEL_REF) && flag_pic == 2)
- {
- return false;
- }
- else if (GET_CODE (xplus1) == SYMBOL_REF ||
- GET_CODE (xplus1) == LABEL_REF ||
- GET_CODE (xplus1) == CONST)
+ GET_CODE (xplus1) == LABEL_REF))
{
- if (GET_CODE (XEXP (xplus1, 0)) == UNSPEC)
- return microblaze_classify_unspec (info, XEXP (xplus1, 0));
- else if (flag_pic == 2)
- {
- return false;
- }
+ if (flag_pic == 2 || microblaze_tls_symbol_p(xplus1))
+ return false;
info->type = ADDRESS_SYMBOLIC;
info->symbol = xplus1;
info->symbol_type = SYMBOL_TYPE_GENERAL;
return true;
}
+ else if (GET_CODE (xplus1) == CONST)
+ {
+ rtx xconst0 = XEXP(xplus1, 0);
+
+ /* base + unspec. */
+ if (GET_CODE (xconst0) == UNSPEC)
+ {
+ /* Need offsettable address. */
+ if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
+ return false;
+ return microblaze_classify_unspec(info, xconst0);
+ }
+
+ /* for (plus x const_int) just look at x. */
+ if (GET_CODE (xconst0) == PLUS
+ && GET_CODE (XEXP (xconst0, 1)) == CONST_INT
+ && SMALL_INT (XEXP (xconst0, 1)))
+ {
+ /* This is ok as info->symbol is set to xplus1 the full
+ const-expression below. */
+ xconst0 = XEXP (xconst0, 0);
+ }
+
+ if (GET_CODE (xconst0) == SYMBOL_REF
+ || GET_CODE (xconst0) == LABEL_REF)
+ {
+ if (flag_pic == 2 || microblaze_tls_symbol_p(xconst0))
+ return false;
+
+ info->type = ADDRESS_SYMBOLIC;
+ info->symbol = xplus1;
+ info->symbol_type = SYMBOL_TYPE_GENERAL;
+ return true;
+ }
+
+ /* Not base + symbol || base + UNSPEC. */
+ return false;
+
+ }
else if (GET_CODE (xplus1) == REG
&& microblaze_valid_index_register_p (xplus1, mode,
strict)
if (GET_CODE (x) == CONST)
{
- return !(flag_pic && pic_address_needs_scratch (x));
- }
- else if (flag_pic == 2)
- {
- return false;
+ if (GET_CODE (XEXP (x, 0)) == UNSPEC)
+ {
+ info->regA = gen_rtx_raw_REG (mode,
+ get_base_reg (XVECEXP (XEXP (x,0), 0, 0)));
+ return microblaze_classify_unspec (info, XEXP (x, 0));
+ }
+ return !(flag_pic && pic_address_needs_scratch (x));
}
+ if (flag_pic == 2)
+ return false;
+ else if (microblaze_tls_symbol_p(x))
+ return false;
+
return true;
}
int
microblaze_legitimate_pic_operand (rtx x)
{
- struct microblaze_address_info addr;
-
- if (pic_address_needs_scratch (x))
+ if (flag_pic == 2 && (symbol_mentioned_p(x) || label_mentioned_p(x)))
return 0;
- if (!microblaze_valid_pic_const(x))
+
+ if (microblaze_tls_referenced_p(x))
return 0;
return 1;
return result;
}
- if (code0 == REG && REG_OK_FOR_BASE_P (xplus0) && flag_pic == 2)
+ if (code0 == REG && REG_OK_FOR_BASE_P (xplus0))
{
if (reload_in_progress)
df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
}
if (code1 == SYMBOL_REF)
{
- result =
- gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xplus1), UNSPEC_GOTOFF);
- result = gen_rtx_CONST (Pmode, result);
- result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result);
- result = gen_const_mem (Pmode, result);
- result = gen_rtx_PLUS (Pmode, xplus0, result);
- return result;
+ if (microblaze_tls_symbol_p(xplus1))
+ {
+ rtx tls_ref, reg;
+ reg = gen_reg_rtx (Pmode);
+
+ tls_ref = microblaze_legitimize_tls_address (xplus1,
+ NULL_RTX);
+ emit_move_insn (reg, tls_ref);
+
+ result = gen_rtx_PLUS (Pmode, xplus0, reg);
+
+ return result;
+ }
+ else if (flag_pic == 2)
+ {
+ rtx pic_ref, reg;
+ reg = gen_reg_rtx (Pmode);
+
+ pic_ref = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xplus1),
+ UNSPEC_GOTOFF);
+ pic_ref = gen_rtx_CONST (Pmode, pic_ref);
+ pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pic_ref);
+ pic_ref = gen_const_mem (Pmode, pic_ref);
+ emit_move_insn (reg, pic_ref);
+ result = gen_rtx_PLUS (Pmode, xplus0, reg);
+ return result;
+ }
}
}
}
if (GET_CODE (xinsn) == SYMBOL_REF)
{
- if (reload_in_progress)
- df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
- result = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xinsn), UNSPEC_GOTOFF);
- result = gen_rtx_CONST (Pmode, result);
- result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result);
- result = gen_const_mem (Pmode, result);
- return result;
+ rtx reg;
+ if (microblaze_tls_symbol_p(xinsn))
+ {
+ reg = microblaze_legitimize_tls_address (xinsn, NULL_RTX);
+ }
+ else
+ {
+ rtx pic_ref;
+
+ if (reload_in_progress)
+ df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
+
+ pic_ref = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xinsn), UNSPEC_GOTOFF);
+ pic_ref = gen_rtx_CONST (Pmode, pic_ref);
+ pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pic_ref);
+ pic_ref = gen_const_mem (Pmode, pic_ref);
+ reg = pic_ref;
+ }
+ return reg;
}
return x;
else
return 2;
case ADDRESS_REG_INDEX:
- case ADDRESS_SYMBOLIC:
return 1;
+ case ADDRESS_SYMBOLIC:
case ADDRESS_GOTOFF:
return 2;
+ case ADDRESS_TLS:
+ switch (addr.tls_type)
+ {
+ case TLS_GD:
+ return 2;
+ case TLS_LDM:
+ return 2;
+ case TLS_DTPREL:
+ return 1;
+ default :
+ abort();
+ }
default:
break;
}
int
pic_address_needs_scratch (rtx x)
{
- /* An address which is a symbolic plus a non SMALL_INT needs a temp reg. */
- if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS
- && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
- && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
- && (flag_pic == 2 || !SMALL_INT (XEXP (XEXP (x, 0), 1))))
- return 1;
+ if (GET_CODE (x) == CONST && GET_CODE (XEXP (x,0)) == PLUS)
+ {
+ rtx p0, p1;
+ p0 = XEXP (XEXP (x, 0), 0);
+ p1 = XEXP (XEXP (x, 0), 1);
+
+ if ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
+ && (GET_CODE (p1) == CONST_INT)
+ && (flag_pic == 2 || microblaze_tls_symbol_p (p0) || !SMALL_INT (p1)))
+ return 1;
+ }
return 0;
}
case ADDRESS_CONST_INT:
case ADDRESS_SYMBOLIC:
case ADDRESS_GOTOFF:
+ case ADDRESS_TLS:
fputs ("i", file);
break;
case ADDRESS_REG_INDEX:
else if (letter == 't')
fputs (code == EQ ? "t" : "f", file);
- else if (code == CONST && GET_CODE (XEXP (op, 0)) == REG)
+ else if (code == CONST
+ && ((GET_CODE (XEXP (op, 0)) == REG)
+ || (GET_CODE (XEXP (op, 0)) == UNSPEC)))
{
print_operand (file, XEXP (op, 0), letter);
}
+ else if (code == CONST
+ && (GET_CODE (XEXP (op, 0)) == PLUS)
+ && (GET_CODE (XEXP (XEXP (op, 0), 0)) == REG)
+ && (GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST))
+ {
+ print_operand_address (file, XEXP (op, 0));
+ }
else if (letter == 'm')
fprintf (file, HOST_WIDE_INT_PRINT_DEC, (1L << INTVAL (op)));
else
case ADDRESS_SYMBOLIC:
case ADDRESS_GOTOFF:
case ADDRESS_PLT:
+ case ADDRESS_TLS:
if (info.regA)
fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
output_addr_const (file, info.symbol);
{
fputs ("@PLT", file);
}
+ else if (type == ADDRESS_TLS)
+ {
+ switch (info.tls_type)
+ {
+ case TLS_GD:
+ fputs ("@TLSGD", file);
+ break;
+ case TLS_LDM:
+ fputs ("@TLSLDM", file);
+ break;
+ case TLS_DTPREL:
+ fputs ("@TLSDTPREL", file);
+ break;
+ default :
+ abort();
+ break;
+ }
+ }
break;
case ADDRESS_INVALID:
fatal_insn ("invalid address", addr);
}
}
- if (flag_pic == 2 && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM))
+ if ((flag_pic == 2 || TLS_NEEDS_GOT )
+ && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM))
{
SET_REGNO (pic_offset_table_rtx, MB_ABI_PIC_ADDR_REGNUM);
emit_insn (gen_set_got (pic_offset_table_rtx)); /* setting GOT. */
bool
microblaze_expand_move (enum machine_mode mode, rtx operands[])
{
+ rtx op0, op1;
+
+ op0 = operands[0];
+ op1 = operands[1];
+
+ if (!register_operand (op0, SImode)
+ && !register_operand (op1, SImode)
+ && (GET_CODE (op1) != CONST_INT || INTVAL (op1) != 0))
+ {
+ rtx temp = force_reg (SImode, op1);
+ emit_move_insn (op0, temp);
+ return true;
+ }
/* If operands[1] is a constant address invalid for pic, then we need to
handle it just like LEGITIMIZE_ADDRESS does. */
- if (flag_pic)
+ if (GET_CODE (op1) == SYMBOL_REF || GET_CODE (op1) == LABEL_REF)
{
- if (GET_CODE (operands[0]) == MEM)
+ rtx result;
+ if (microblaze_tls_symbol_p(op1))
{
- rtx addr = XEXP (operands[0], 0);
- if (GET_CODE (addr) == SYMBOL_REF)
- {
- rtx ptr_reg, result;
-
- if (reload_in_progress)
- df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
-
- addr = expand_pic_symbol_ref (mode, addr);
- ptr_reg = gen_reg_rtx (Pmode);
- emit_move_insn (ptr_reg, addr);
- result = gen_rtx_MEM (mode, ptr_reg);
- operands[0] = result;
- }
+ result = microblaze_legitimize_tls_address (op1, NULL_RTX);
+ emit_move_insn (op0, result);
+ return true;
}
- if (GET_CODE (operands[1]) == SYMBOL_REF
- || GET_CODE (operands[1]) == LABEL_REF)
+ else if (flag_pic)
{
- rtx result;
if (reload_in_progress)
df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
- result = expand_pic_symbol_ref (mode, operands[1]);
- if (GET_CODE (operands[0]) != REG)
- {
- rtx ptr_reg = gen_reg_rtx (Pmode);
- emit_move_insn (ptr_reg, result);
- emit_move_insn (operands[0], ptr_reg);
- }
- else
- {
- emit_move_insn (operands[0], result);
- }
+ result = expand_pic_symbol_ref (mode, op1);
+ emit_move_insn (op0, result);
return true;
}
- else if (GET_CODE (operands[1]) == MEM &&
- GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF)
- {
- rtx result;
- rtx ptr_reg;
- if (reload_in_progress)
- df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
- result = expand_pic_symbol_ref (mode, XEXP (operands[1], 0));
+ }
+ /* Handle Case of (const (plus symbol const_int)). */
+ if (GET_CODE (op1) == CONST && GET_CODE (XEXP (op1,0)) == PLUS)
+ {
+ rtx p0, p1;
- ptr_reg = gen_reg_rtx (Pmode);
+ p0 = XEXP (XEXP (op1, 0), 0);
+ p1 = XEXP (XEXP (op1, 0), 1);
- emit_move_insn (ptr_reg, result);
- result = gen_rtx_MEM (mode, ptr_reg);
- emit_move_insn (operands[0], result);
- return true;
- }
- else if (pic_address_needs_scratch (operands[1]))
+ if ((GET_CODE (p1) == CONST_INT)
+ && ((GET_CODE (p0) == UNSPEC)
+ || ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
+ && (flag_pic == 2 || microblaze_tls_symbol_p (p0)
+ || !SMALL_INT (p1)))))
{
- rtx temp = force_reg (SImode, XEXP (XEXP (operands[1], 0), 0));
- rtx temp2 = XEXP (XEXP (operands[1], 0), 1);
+ rtx temp = force_reg (SImode, p0);
+ rtx temp2 = p1;
- if (reload_in_progress)
+ if (flag_pic && reload_in_progress)
df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
- emit_move_insn (operands[0], gen_rtx_PLUS (SImode, temp, temp2));
+ emit_move_insn (op0, gen_rtx_PLUS (SImode, temp, temp2));
return true;
}
}
-
- if ((reload_in_progress | reload_completed) == 0
- && !register_operand (operands[0], SImode)
- && !register_operand (operands[1], SImode)
- && (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0))
- {
- rtx temp = force_reg (SImode, operands[1]);
- emit_move_insn (operands[0], temp);
- return true;
- }
return false;
}
At present, GAS doesn't understand li.[sd], so don't allow it
to be generated at present. */
static bool
-microblaze_legitimate_constant_p (enum machine_mode mode, rtx x)
+microblaze_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x)
{
- return GET_CODE (x) != CONST_DOUBLE || microblaze_const_double_ok (x, mode);
+
+ if (microblaze_cannot_force_const_mem(mode, x))
+ return false;
+
+ if (GET_CODE (x) == CONST_DOUBLE)
+ {
+ return microblaze_const_double_ok (x, GET_MODE (x));
+ }
+
+ /* Handle Case of (const (plus unspec const_int)). */
+ if (GET_CODE (x) == CONST && GET_CODE (XEXP (x,0)) == PLUS)
+ {
+ rtx p0, p1;
+
+ p0 = XEXP (XEXP (x, 0), 0);
+ p1 = XEXP (XEXP (x, 0), 1);
+
+ if (GET_CODE(p1) == CONST_INT)
+ {
+ /* Const offset from UNSPEC is not supported. */
+ if ((GET_CODE (p0) == UNSPEC))
+ return false;
+
+ if ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
+ && (microblaze_tls_symbol_p (p0) || !SMALL_INT (p1)))
+ return false;
+ }
+ }
+
+ return true;
}
+
\f
#undef TARGET_ENCODE_SECTION_INFO
#define TARGET_ENCODE_SECTION_INFO microblaze_encode_section_info
#undef TARGET_RTX_COSTS
#define TARGET_RTX_COSTS microblaze_rtx_costs
+#undef TARGET_CANNOT_FORCE_CONST_MEM
+#define TARGET_CANNOT_FORCE_CONST_MEM microblaze_cannot_force_const_mem
+
#undef TARGET_ADDRESS_COST
#define TARGET_ADDRESS_COST microblaze_address_cost