|
|
|
@ -141,6 +141,12 @@ struct mips_cl_insn
|
|
|
|
|
extension. */
|
|
|
|
|
unsigned long insn_opcode;
|
|
|
|
|
|
|
|
|
|
/* The name if this is an label. */
|
|
|
|
|
char label[16];
|
|
|
|
|
|
|
|
|
|
/* The target label name if this is an branch. */
|
|
|
|
|
char target[16];
|
|
|
|
|
|
|
|
|
|
/* The frag that contains the instruction. */
|
|
|
|
|
struct frag *frag;
|
|
|
|
|
|
|
|
|
@ -511,7 +517,7 @@ static int mips_32bitmode = 0;
|
|
|
|
|
/* True if CPU has a ror instruction. */
|
|
|
|
|
#define CPU_HAS_ROR(CPU) CPU_HAS_DROR (CPU)
|
|
|
|
|
|
|
|
|
|
/* True if CPU is in the Octeon family */
|
|
|
|
|
/* True if CPU is in the Octeon family. */
|
|
|
|
|
#define CPU_IS_OCTEON(CPU) ((CPU) == CPU_OCTEON || (CPU) == CPU_OCTEONP \
|
|
|
|
|
|| (CPU) == CPU_OCTEON2 || (CPU) == CPU_OCTEON3)
|
|
|
|
|
|
|
|
|
@ -660,7 +666,7 @@ static int g_switch_seen = 0;
|
|
|
|
|
fixed it for the non-PIC mode. KR 95/04/07 */
|
|
|
|
|
static int nopic_need_relax (symbolS *, int);
|
|
|
|
|
|
|
|
|
|
/* handle of the OPCODE hash table */
|
|
|
|
|
/* Handle of the OPCODE hash table. */
|
|
|
|
|
static struct hash_control *op_hash = NULL;
|
|
|
|
|
|
|
|
|
|
/* The opcode hash table we use for the mips16. */
|
|
|
|
@ -670,12 +676,12 @@ static struct hash_control *mips16_op_hash = NULL;
|
|
|
|
|
static struct hash_control *micromips_op_hash = NULL;
|
|
|
|
|
|
|
|
|
|
/* This array holds the chars that always start a comment. If the
|
|
|
|
|
pre-processor is disabled, these aren't very useful */
|
|
|
|
|
pre-processor is disabled, these aren't very useful. */
|
|
|
|
|
const char comment_chars[] = "#";
|
|
|
|
|
|
|
|
|
|
/* This array holds the chars that only start a comment at the beginning of
|
|
|
|
|
a line. If the line seems to have the form '# 123 filename'
|
|
|
|
|
.line and .file directives will appear in the pre-processed output */
|
|
|
|
|
.line and .file directives will appear in the pre-processed output. */
|
|
|
|
|
/* Note that input_file.c hand checks for '#' at the beginning of the
|
|
|
|
|
first line of the input file. This is because the compiler outputs
|
|
|
|
|
#NO_APP at the beginning of its output. */
|
|
|
|
@ -685,22 +691,22 @@ const char line_comment_chars[] = "#";
|
|
|
|
|
/* This array holds machine specific line separator characters. */
|
|
|
|
|
const char line_separator_chars[] = ";";
|
|
|
|
|
|
|
|
|
|
/* Chars that can be used to separate mant from exp in floating point nums */
|
|
|
|
|
/* Chars that can be used to separate mant from exp in floating point nums. */
|
|
|
|
|
const char EXP_CHARS[] = "eE";
|
|
|
|
|
|
|
|
|
|
/* Chars that mean this number is a floating point constant */
|
|
|
|
|
/* As in 0f12.456 */
|
|
|
|
|
/* or 0d1.2345e12 */
|
|
|
|
|
/* Chars that mean this number is a floating point constant.
|
|
|
|
|
As in 0f12.456
|
|
|
|
|
or 0d1.2345e12. */
|
|
|
|
|
const char FLT_CHARS[] = "rRsSfFdDxXpP";
|
|
|
|
|
|
|
|
|
|
/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
|
|
|
|
|
changed in read.c . Ideally it shouldn't have to know about it at all,
|
|
|
|
|
but nothing is ideal around here.
|
|
|
|
|
*/
|
|
|
|
|
but nothing is ideal around here. */
|
|
|
|
|
|
|
|
|
|
/* Types of printf format used for instruction-related error messages.
|
|
|
|
|
"I" means int ("%d") and "S" means string ("%s"). */
|
|
|
|
|
enum mips_insn_error_format {
|
|
|
|
|
"I" means int ("%d") and "S" means string ("%s"). */
|
|
|
|
|
enum mips_insn_error_format
|
|
|
|
|
{
|
|
|
|
|
ERR_FMT_PLAIN,
|
|
|
|
|
ERR_FMT_I,
|
|
|
|
|
ERR_FMT_SS,
|
|
|
|
@ -708,7 +714,8 @@ enum mips_insn_error_format {
|
|
|
|
|
|
|
|
|
|
/* Information about an error that was found while assembling the current
|
|
|
|
|
instruction. */
|
|
|
|
|
struct mips_insn_error {
|
|
|
|
|
struct mips_insn_error
|
|
|
|
|
{
|
|
|
|
|
/* We sometimes need to match an instruction against more than one
|
|
|
|
|
opcode table entry. Errors found during this matching are reported
|
|
|
|
|
against a particular syntactic argument rather than against the
|
|
|
|
@ -727,7 +734,8 @@ struct mips_insn_error {
|
|
|
|
|
/* The printf()-style message, including its format and arguments. */
|
|
|
|
|
enum mips_insn_error_format format;
|
|
|
|
|
const char *msg;
|
|
|
|
|
union {
|
|
|
|
|
union
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
const char *ss[2];
|
|
|
|
|
} u;
|
|
|
|
@ -786,16 +794,20 @@ static int mips_debug = 0;
|
|
|
|
|
/* The maximum number of NOPs needed for any purpose. */
|
|
|
|
|
#define MAX_NOPS 4
|
|
|
|
|
|
|
|
|
|
/* The maximum range of context length of ll/sc. */
|
|
|
|
|
#define MAX_LLSC_RANGE 20
|
|
|
|
|
|
|
|
|
|
/* A list of previous instructions, with index 0 being the most recent.
|
|
|
|
|
We need to look back MAX_NOPS instructions when filling delay slots
|
|
|
|
|
or working around processor errata. We need to look back one
|
|
|
|
|
instruction further if we're thinking about using history[0] to
|
|
|
|
|
fill a branch delay slot. */
|
|
|
|
|
static struct mips_cl_insn history[1 + MAX_NOPS];
|
|
|
|
|
static struct mips_cl_insn history[1 + MAX_NOPS + MAX_LLSC_RANGE];
|
|
|
|
|
|
|
|
|
|
/* Arrays of operands for each instruction. */
|
|
|
|
|
#define MAX_OPERANDS 6
|
|
|
|
|
struct mips_operand_array {
|
|
|
|
|
struct mips_operand_array
|
|
|
|
|
{
|
|
|
|
|
const struct mips_operand *operand[MAX_OPERANDS];
|
|
|
|
|
};
|
|
|
|
|
static struct mips_operand_array *mips_operands;
|
|
|
|
@ -808,6 +820,9 @@ static struct mips_cl_insn mips16_nop_insn;
|
|
|
|
|
static struct mips_cl_insn micromips_nop16_insn;
|
|
|
|
|
static struct mips_cl_insn micromips_nop32_insn;
|
|
|
|
|
|
|
|
|
|
/* Sync instructions used by insert sync. */
|
|
|
|
|
static struct mips_cl_insn sync_insn;
|
|
|
|
|
|
|
|
|
|
/* The appropriate nop for the current mode. */
|
|
|
|
|
#define NOP_INSN (mips_opts.mips16 \
|
|
|
|
|
? &mips16_nop_insn \
|
|
|
|
@ -943,6 +958,9 @@ static bfd_boolean mips_fix_cn63xxp1;
|
|
|
|
|
static bfd_boolean mips_fix_r5900;
|
|
|
|
|
static bfd_boolean mips_fix_r5900_explicit;
|
|
|
|
|
|
|
|
|
|
/* ...likewise -mfix-loongson3-llsc. */
|
|
|
|
|
static bfd_boolean mips_fix_loongson3_llsc = DEFAULT_MIPS_FIX_LOONGSON3_LLSC;
|
|
|
|
|
|
|
|
|
|
/* We don't relax branches by default, since this causes us to expand
|
|
|
|
|
`la .l2 - .l1' if there's a branch between .l1 and .l2, because we
|
|
|
|
|
fail to compute the offset before expanding the macro to the most
|
|
|
|
@ -1482,6 +1500,8 @@ enum options
|
|
|
|
|
OPTION_NO_FIX_24K,
|
|
|
|
|
OPTION_FIX_RM7000,
|
|
|
|
|
OPTION_NO_FIX_RM7000,
|
|
|
|
|
OPTION_FIX_LOONGSON3_LLSC,
|
|
|
|
|
OPTION_NO_FIX_LOONGSON3_LLSC,
|
|
|
|
|
OPTION_FIX_LOONGSON2F_JUMP,
|
|
|
|
|
OPTION_NO_FIX_LOONGSON2F_JUMP,
|
|
|
|
|
OPTION_FIX_LOONGSON2F_NOP,
|
|
|
|
@ -1628,6 +1648,8 @@ struct option md_longopts[] =
|
|
|
|
|
{"mfix7000", no_argument, NULL, OPTION_M7000_HILO_FIX},
|
|
|
|
|
{"no-fix-7000", no_argument, NULL, OPTION_MNO_7000_HILO_FIX},
|
|
|
|
|
{"mno-fix7000", no_argument, NULL, OPTION_MNO_7000_HILO_FIX},
|
|
|
|
|
{"mfix-loongson3-llsc", no_argument, NULL, OPTION_FIX_LOONGSON3_LLSC},
|
|
|
|
|
{"mno-fix-loongson3-llsc", no_argument, NULL, OPTION_NO_FIX_LOONGSON3_LLSC},
|
|
|
|
|
{"mfix-loongson2f-jump", no_argument, NULL, OPTION_FIX_LOONGSON2F_JUMP},
|
|
|
|
|
{"mno-fix-loongson2f-jump", no_argument, NULL, OPTION_NO_FIX_LOONGSON2F_JUMP},
|
|
|
|
|
{"mfix-loongson2f-nop", no_argument, NULL, OPTION_FIX_LOONGSON2F_NOP},
|
|
|
|
@ -2774,7 +2796,7 @@ struct regname {
|
|
|
|
|
{"$ta2", RTYPE_GP | 14}, /* alias for $t6 */ \
|
|
|
|
|
{"$ta3", RTYPE_GP | 15} /* alias for $t7 */
|
|
|
|
|
|
|
|
|
|
/* Remaining symbolic register names */
|
|
|
|
|
/* Remaining symbolic register names. */
|
|
|
|
|
#define SYMBOLIC_REGISTER_NAMES \
|
|
|
|
|
{"$zero", RTYPE_GP | 0}, \
|
|
|
|
|
{"$at", RTYPE_GP | 1}, \
|
|
|
|
@ -2809,8 +2831,8 @@ struct regname {
|
|
|
|
|
{"$pc", RTYPE_PC | 0}
|
|
|
|
|
|
|
|
|
|
#define MDMX_VECTOR_REGISTER_NAMES \
|
|
|
|
|
/* {"$v0", RTYPE_VEC | 0}, clash with REG 2 above */ \
|
|
|
|
|
/* {"$v1", RTYPE_VEC | 1}, clash with REG 3 above */ \
|
|
|
|
|
/* {"$v0", RTYPE_VEC | 0}, Clash with REG 2 above. */ \
|
|
|
|
|
/* {"$v1", RTYPE_VEC | 1}, Clash with REG 3 above. */ \
|
|
|
|
|
{"$v2", RTYPE_VEC | 2}, \
|
|
|
|
|
{"$v3", RTYPE_VEC | 3}, \
|
|
|
|
|
{"$v4", RTYPE_VEC | 4}, \
|
|
|
|
@ -3671,6 +3693,7 @@ md_begin (void)
|
|
|
|
|
if (!validate_mips_insn (&mips_opcodes[i], 0xffffffff,
|
|
|
|
|
decode_mips_operand, &mips_operands[i]))
|
|
|
|
|
broken = 1;
|
|
|
|
|
|
|
|
|
|
if (nop_insn.insn_mo == NULL && strcmp (name, "nop") == 0)
|
|
|
|
|
{
|
|
|
|
|
create_insn (&nop_insn, mips_opcodes + i);
|
|
|
|
@ -3678,6 +3701,10 @@ md_begin (void)
|
|
|
|
|
nop_insn.insn_opcode = LOONGSON2F_NOP_INSN;
|
|
|
|
|
nop_insn.fixed_p = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sync_insn.insn_mo == NULL && strcmp (name, "sync") == 0)
|
|
|
|
|
create_insn (&sync_insn, mips_opcodes + i);
|
|
|
|
|
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
while ((i < NUMOPCODES) && !strcmp (mips_opcodes[i].name, name));
|
|
|
|
@ -3833,7 +3860,7 @@ md_begin (void)
|
|
|
|
|
|
|
|
|
|
/* The ABI says this section should be loaded so that the
|
|
|
|
|
running program can access it. However, we don't load it
|
|
|
|
|
if we are configured for an embedded target */
|
|
|
|
|
if we are configured for an embedded target. */
|
|
|
|
|
flags = SEC_READONLY | SEC_DATA;
|
|
|
|
|
if (strncmp (TARGET_OS, "elf", 3) != 0)
|
|
|
|
|
flags |= SEC_ALLOC | SEC_LOAD;
|
|
|
|
@ -6859,6 +6886,103 @@ fix_loongson2f (struct mips_cl_insn * ip)
|
|
|
|
|
fix_loongson2f_jump (ip);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Fix loongson3 llsc errata: Insert sync before ll/lld. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
fix_loongson3_llsc (struct mips_cl_insn * ip)
|
|
|
|
|
{
|
|
|
|
|
gas_assert (!HAVE_CODE_COMPRESSION);
|
|
|
|
|
|
|
|
|
|
/* If is an local label and the insn is not sync,
|
|
|
|
|
look forward that whether an branch between ll/sc jump to here
|
|
|
|
|
if so, insert a sync. */
|
|
|
|
|
if (seg_info (now_seg)->label_list
|
|
|
|
|
&& S_IS_LOCAL (seg_info (now_seg)->label_list->label)
|
|
|
|
|
&& (strcmp (ip->insn_mo->name, "sync") != 0))
|
|
|
|
|
{
|
|
|
|
|
const char *label_name = S_GET_NAME (seg_info (now_seg)->label_list->label);
|
|
|
|
|
unsigned long lookback = ARRAY_SIZE (history);
|
|
|
|
|
unsigned long i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < lookback; i++)
|
|
|
|
|
{
|
|
|
|
|
if (streq (history[i].insn_mo->name, "ll")
|
|
|
|
|
|| streq (history[i].insn_mo->name, "lld"))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (streq (history[i].insn_mo->name, "sc")
|
|
|
|
|
|| streq (history[i].insn_mo->name, "scd"))
|
|
|
|
|
{
|
|
|
|
|
unsigned long j;
|
|
|
|
|
|
|
|
|
|
for (j = i + 1; j < lookback; j++)
|
|
|
|
|
{
|
|
|
|
|
if (streq (history[i].insn_mo->name, "ll")
|
|
|
|
|
|| streq (history[i].insn_mo->name, "lld"))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (delayed_branch_p (&history[j]))
|
|
|
|
|
{
|
|
|
|
|
if (streq (history[j].target, label_name))
|
|
|
|
|
{
|
|
|
|
|
add_fixed_insn (&sync_insn);
|
|
|
|
|
insert_into_history (0, 1, &sync_insn);
|
|
|
|
|
i = lookback;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* If we find a sc, we look forward to look for an branch insn,
|
|
|
|
|
and see whether it jump back and out of ll/sc. */
|
|
|
|
|
else if (streq(ip->insn_mo->name, "sc") || streq(ip->insn_mo->name, "scd"))
|
|
|
|
|
{
|
|
|
|
|
unsigned long lookback = ARRAY_SIZE (history) - 1;
|
|
|
|
|
unsigned long i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < lookback; i++)
|
|
|
|
|
{
|
|
|
|
|
if (streq (history[i].insn_mo->name, "ll")
|
|
|
|
|
|| streq (history[i].insn_mo->name, "lld"))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (delayed_branch_p (&history[i]))
|
|
|
|
|
{
|
|
|
|
|
unsigned long j;
|
|
|
|
|
|
|
|
|
|
for (j = i + 1; j < lookback; j++)
|
|
|
|
|
{
|
|
|
|
|
if (streq (history[j].insn_mo->name, "ll")
|
|
|
|
|
|| streq (history[i].insn_mo->name, "lld"))
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (; j < lookback; j++)
|
|
|
|
|
{
|
|
|
|
|
if (history[j].label[0] != '\0'
|
|
|
|
|
&& streq (history[j].label, history[i].target)
|
|
|
|
|
&& strcmp (history[j+1].insn_mo->name, "sync") != 0)
|
|
|
|
|
{
|
|
|
|
|
add_fixed_insn (&sync_insn);
|
|
|
|
|
insert_into_history (++j, 1, &sync_insn);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Skip if there is a sync before ll/lld. */
|
|
|
|
|
if ((strcmp (ip->insn_mo->name, "ll") == 0
|
|
|
|
|
|| strcmp (ip->insn_mo->name, "lld") == 0)
|
|
|
|
|
&& (strcmp (history[0].insn_mo->name, "sync") != 0))
|
|
|
|
|
{
|
|
|
|
|
add_fixed_insn (&sync_insn);
|
|
|
|
|
insert_into_history (0, 1, &sync_insn);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* IP is a branch that has a delay slot, and we need to fill it
|
|
|
|
|
automatically. Return true if we can do that by swapping IP
|
|
|
|
|
with the previous instruction.
|
|
|
|
@ -7316,6 +7440,15 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
|
|
|
|
|
if (mips_fix_loongson2f && !HAVE_CODE_COMPRESSION)
|
|
|
|
|
fix_loongson2f (ip);
|
|
|
|
|
|
|
|
|
|
ip->target[0] = '\0';
|
|
|
|
|
if (offset_expr.X_op == O_symbol)
|
|
|
|
|
strncpy (ip->target, S_GET_NAME (offset_expr.X_add_symbol), 15);
|
|
|
|
|
ip->label[0] = '\0';
|
|
|
|
|
if (seg_info (now_seg)->label_list)
|
|
|
|
|
strncpy (ip->label, S_GET_NAME (seg_info (now_seg)->label_list->label), 15);
|
|
|
|
|
if (mips_fix_loongson3_llsc && !HAVE_CODE_COMPRESSION)
|
|
|
|
|
fix_loongson3_llsc (ip);
|
|
|
|
|
|
|
|
|
|
file_ase_mips16 |= mips_opts.mips16;
|
|
|
|
|
file_ase_micromips |= mips_opts.micromips;
|
|
|
|
|
|
|
|
|
@ -10361,7 +10494,7 @@ macro (struct mips_cl_insn *ip, char *str)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
++imm_expr.X_add_number;
|
|
|
|
|
/* FALLTHROUGH */
|
|
|
|
|
/* Fall through. */
|
|
|
|
|
case M_BGE_I:
|
|
|
|
|
case M_BGEL_I:
|
|
|
|
|
if (mask == M_BGEL_I)
|
|
|
|
@ -10381,7 +10514,7 @@ macro (struct mips_cl_insn *ip, char *str)
|
|
|
|
|
if (imm_expr.X_add_number <= GPR_SMIN)
|
|
|
|
|
{
|
|
|
|
|
do_true:
|
|
|
|
|
/* result is always true */
|
|
|
|
|
/* Result is always true. */
|
|
|
|
|
as_warn (_("branch %s is always true"), ip->insn_mo->name);
|
|
|
|
|
macro_build (&offset_expr, "b", "p");
|
|
|
|
|
break;
|
|
|
|
@ -10419,7 +10552,7 @@ macro (struct mips_cl_insn *ip, char *str)
|
|
|
|
|
&& imm_expr.X_add_number == -1))
|
|
|
|
|
goto do_false;
|
|
|
|
|
++imm_expr.X_add_number;
|
|
|
|
|
/* FALLTHROUGH */
|
|
|
|
|
/* Fall through. */
|
|
|
|
|
case M_BGEU_I:
|
|
|
|
|
case M_BGEUL_I:
|
|
|
|
|
if (mask == M_BGEUL_I)
|
|
|
|
@ -10497,7 +10630,7 @@ macro (struct mips_cl_insn *ip, char *str)
|
|
|
|
|
if (imm_expr.X_add_number >= GPR_SMAX)
|
|
|
|
|
goto do_true;
|
|
|
|
|
++imm_expr.X_add_number;
|
|
|
|
|
/* FALLTHROUGH */
|
|
|
|
|
/* Fall through. */
|
|
|
|
|
case M_BLT_I:
|
|
|
|
|
case M_BLTL_I:
|
|
|
|
|
if (mask == M_BLTL_I)
|
|
|
|
@ -10542,7 +10675,7 @@ macro (struct mips_cl_insn *ip, char *str)
|
|
|
|
|
&& imm_expr.X_add_number == -1))
|
|
|
|
|
goto do_true;
|
|
|
|
|
++imm_expr.X_add_number;
|
|
|
|
|
/* FALLTHROUGH */
|
|
|
|
|
/* Fall through. */
|
|
|
|
|
case M_BLTU_I:
|
|
|
|
|
case M_BLTUL_I:
|
|
|
|
|
if (mask == M_BLTUL_I)
|
|
|
|
@ -12633,20 +12766,18 @@ macro (struct mips_cl_insn *ip, char *str)
|
|
|
|
|
offset_reloc[2] = BFD_RELOC_UNUSED;
|
|
|
|
|
}
|
|
|
|
|
align = 8;
|
|
|
|
|
/* Fall through */
|
|
|
|
|
/* Fall through. */
|
|
|
|
|
|
|
|
|
|
case M_L_DAB:
|
|
|
|
|
/*
|
|
|
|
|
* The MIPS assembler seems to check for X_add_number not
|
|
|
|
|
* being double aligned and generating:
|
|
|
|
|
* lui at,%hi(foo+1)
|
|
|
|
|
* addu at,at,v1
|
|
|
|
|
* addiu at,at,%lo(foo+1)
|
|
|
|
|
* lwc1 f2,0(at)
|
|
|
|
|
* lwc1 f3,4(at)
|
|
|
|
|
* But, the resulting address is the same after relocation so why
|
|
|
|
|
* generate the extra instruction?
|
|
|
|
|
*/
|
|
|
|
|
/* The MIPS assembler seems to check for X_add_number not
|
|
|
|
|
being double aligned and generating:
|
|
|
|
|
lui at,%hi(foo+1)
|
|
|
|
|
addu at,at,v1
|
|
|
|
|
addiu at,at,%lo(foo+1)
|
|
|
|
|
lwc1 f2,0(at)
|
|
|
|
|
lwc1 f3,4(at)
|
|
|
|
|
But, the resulting address is the same after relocation so why
|
|
|
|
|
generate the extra instruction? */
|
|
|
|
|
/* Itbl support may require additional care here. */
|
|
|
|
|
coproc = 1;
|
|
|
|
|
fmt = "T,o(b)";
|
|
|
|
@ -13369,7 +13500,7 @@ macro (struct mips_cl_insn *ip, char *str)
|
|
|
|
|
macro_build (&expr1, "xori", "t,r,i", op[0], op[0], BFD_RELOC_LO16);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case M_SGE_I: /* X >= I <==> not (X < I) */
|
|
|
|
|
case M_SGE_I: /* X >= I <==> not (X < I). */
|
|
|
|
|
case M_SGEU_I:
|
|
|
|
|
if (imm_expr.X_add_number >= -0x8000
|
|
|
|
|
&& imm_expr.X_add_number < 0x8000)
|
|
|
|
@ -13385,7 +13516,7 @@ macro (struct mips_cl_insn *ip, char *str)
|
|
|
|
|
macro_build (&expr1, "xori", "t,r,i", op[0], op[0], BFD_RELOC_LO16);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case M_SGT: /* X > Y <==> Y < X */
|
|
|
|
|
case M_SGT: /* X > Y <==> Y < X. */
|
|
|
|
|
s = "slt";
|
|
|
|
|
goto sgt;
|
|
|
|
|
case M_SGTU:
|
|
|
|
@ -13394,7 +13525,7 @@ macro (struct mips_cl_insn *ip, char *str)
|
|
|
|
|
macro_build (NULL, s, "d,v,t", op[0], op[2], op[1]);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case M_SGT_I: /* X > I <==> I < X */
|
|
|
|
|
case M_SGT_I: /* X > I <==> I < X. */
|
|
|
|
|
s = "slt";
|
|
|
|
|
goto sgti;
|
|
|
|
|
case M_SGTU_I:
|
|
|
|
@ -13405,7 +13536,7 @@ macro (struct mips_cl_insn *ip, char *str)
|
|
|
|
|
macro_build (NULL, s, "d,v,t", op[0], AT, op[1]);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case M_SLE: /* X <= Y <==> Y >= X <==> not (Y < X) */
|
|
|
|
|
case M_SLE: /* X <= Y <==> Y >= X <==> not (Y < X). */
|
|
|
|
|
s = "slt";
|
|
|
|
|
goto sle;
|
|
|
|
|
case M_SLEU:
|
|
|
|
@ -14731,6 +14862,14 @@ md_parse_option (int c, const char *arg)
|
|
|
|
|
mips_fix_rm7000 = 0;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OPTION_FIX_LOONGSON3_LLSC:
|
|
|
|
|
mips_fix_loongson3_llsc = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OPTION_NO_FIX_LOONGSON3_LLSC:
|
|
|
|
|
mips_fix_loongson3_llsc = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OPTION_FIX_LOONGSON2F_JUMP:
|
|
|
|
|
mips_fix_loongson2f_jump = TRUE;
|
|
|
|
|
break;
|
|
|
|
@ -14999,7 +15138,7 @@ mips_after_parse_args (void)
|
|
|
|
|
const struct mips_cpu_info *arch_info = 0;
|
|
|
|
|
const struct mips_cpu_info *tune_info = 0;
|
|
|
|
|
|
|
|
|
|
/* GP relative stuff not working for PE */
|
|
|
|
|
/* GP relative stuff not working for PE. */
|
|
|
|
|
if (strncmp (TARGET_OS, "pe", 2) == 0)
|
|
|
|
|
{
|
|
|
|
|
if (g_switch_seen && g_switch_value != 0)
|
|
|
|
@ -15078,7 +15217,7 @@ mips_after_parse_args (void)
|
|
|
|
|
void
|
|
|
|
|
mips_init_after_args (void)
|
|
|
|
|
{
|
|
|
|
|
/* initialize opcodes */
|
|
|
|
|
/* Initialize opcodes. */
|
|
|
|
|
bfd_mips_num_opcodes = bfd_mips_num_builtin_opcodes;
|
|
|
|
|
mips_opcodes = (struct mips_opcode *) mips_builtin_opcodes;
|
|
|
|
|
}
|
|
|
|
@ -15087,6 +15226,7 @@ long
|
|
|
|
|
md_pcrel_from (fixS *fixP)
|
|
|
|
|
{
|
|
|
|
|
valueT addr = fixP->fx_where + fixP->fx_frag->fr_address;
|
|
|
|
|
|
|
|
|
|
switch (fixP->fx_r_type)
|
|
|
|
|
{
|
|
|
|
|
case BFD_RELOC_MICROMIPS_7_PCREL_S1:
|
|
|
|
@ -19703,7 +19843,7 @@ s_mips_mask (int reg_type)
|
|
|
|
|
gcc's mips_cpu_info_table[]. */
|
|
|
|
|
static const struct mips_cpu_info mips_cpu_info_table[] =
|
|
|
|
|
{
|
|
|
|
|
/* Entries for generic ISAs */
|
|
|
|
|
/* Entries for generic ISAs. */
|
|
|
|
|
{ "mips1", MIPS_CPU_IS_ISA, 0, ISA_MIPS1, CPU_R3000 },
|
|
|
|
|
{ "mips2", MIPS_CPU_IS_ISA, 0, ISA_MIPS2, CPU_R6000 },
|
|
|
|
|
{ "mips3", MIPS_CPU_IS_ISA, 0, ISA_MIPS3, CPU_R4000 },
|
|
|
|
@ -19742,7 +19882,7 @@ static const struct mips_cpu_info mips_cpu_info_table[] =
|
|
|
|
|
{ "orion", 0, 0, ISA_MIPS3, CPU_R4600 },
|
|
|
|
|
{ "r4650", 0, 0, ISA_MIPS3, CPU_R4650 },
|
|
|
|
|
{ "r5900", 0, 0, ISA_MIPS3, CPU_R5900 },
|
|
|
|
|
/* ST Microelectronics Loongson 2E and 2F cores */
|
|
|
|
|
/* ST Microelectronics Loongson 2E and 2F cores. */
|
|
|
|
|
{ "loongson2e", 0, 0, ISA_MIPS3, CPU_LOONGSON_2E },
|
|
|
|
|
{ "loongson2f", 0, ASE_LOONGSON_MMI, ISA_MIPS3, CPU_LOONGSON_2F },
|
|
|
|
|
|
|
|
|
@ -19821,12 +19961,12 @@ static const struct mips_cpu_info mips_cpu_info_table[] =
|
|
|
|
|
{ "1004kf2_1", 0, ASE_DSP | ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 },
|
|
|
|
|
{ "1004kf", 0, ASE_DSP | ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 },
|
|
|
|
|
{ "1004kf1_1", 0, ASE_DSP | ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 },
|
|
|
|
|
/* interaptiv is the new name for 1004kf */
|
|
|
|
|
/* interaptiv is the new name for 1004kf. */
|
|
|
|
|
{ "interaptiv", 0, ASE_DSP | ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 },
|
|
|
|
|
{ "interaptiv-mr2", 0,
|
|
|
|
|
ASE_DSP | ASE_EVA | ASE_MT | ASE_MIPS16E2 | ASE_MIPS16E2_MT,
|
|
|
|
|
ISA_MIPS32R3, CPU_INTERAPTIV_MR2 },
|
|
|
|
|
/* M5100 family */
|
|
|
|
|
/* M5100 family. */
|
|
|
|
|
{ "m5100", 0, ASE_MCU, ISA_MIPS32R5, CPU_MIPS32R5 },
|
|
|
|
|
{ "m5101", 0, ASE_MCU, ISA_MIPS32R5, CPU_MIPS32R5 },
|
|
|
|
|
/* P5600 with EVA and Virtualization ASEs, other ASEs are optional. */
|
|
|
|
@ -19838,14 +19978,14 @@ static const struct mips_cpu_info mips_cpu_info_table[] =
|
|
|
|
|
{ "20kc", 0, ASE_MIPS3D, ISA_MIPS64, CPU_MIPS64 },
|
|
|
|
|
{ "25kf", 0, ASE_MIPS3D, ISA_MIPS64, CPU_MIPS64 },
|
|
|
|
|
|
|
|
|
|
/* Broadcom SB-1 CPU core */
|
|
|
|
|
/* Broadcom SB-1 CPU core. */
|
|
|
|
|
{ "sb1", 0, ASE_MIPS3D | ASE_MDMX, ISA_MIPS64, CPU_SB1 },
|
|
|
|
|
/* Broadcom SB-1A CPU core */
|
|
|
|
|
/* Broadcom SB-1A CPU core. */
|
|
|
|
|
{ "sb1a", 0, ASE_MIPS3D | ASE_MDMX, ISA_MIPS64, CPU_SB1 },
|
|
|
|
|
|
|
|
|
|
/* MIPS 64 Release 2 */
|
|
|
|
|
/* Loongson CPU core */
|
|
|
|
|
/* -march=loongson3a is an alias of -march=gs464 for compatibility */
|
|
|
|
|
/* MIPS 64 Release 2. */
|
|
|
|
|
/* Loongson CPU core. */
|
|
|
|
|
/* -march=loongson3a is an alias of -march=gs464 for compatibility. */
|
|
|
|
|
{ "loongson3a", 0, ASE_LOONGSON_MMI | ASE_LOONGSON_CAM | ASE_LOONGSON_EXT,
|
|
|
|
|
ISA_MIPS64R2, CPU_GS464 },
|
|
|
|
|
{ "gs464", 0, ASE_LOONGSON_MMI | ASE_LOONGSON_CAM | ASE_LOONGSON_EXT,
|
|
|
|
@ -19855,7 +19995,7 @@ static const struct mips_cpu_info mips_cpu_info_table[] =
|
|
|
|
|
{ "gs264e", 0, ASE_LOONGSON_MMI | ASE_LOONGSON_CAM | ASE_LOONGSON_EXT
|
|
|
|
|
| ASE_LOONGSON_EXT2 | ASE_MSA | ASE_MSA64, ISA_MIPS64R2, CPU_GS264E },
|
|
|
|
|
|
|
|
|
|
/* Cavium Networks Octeon CPU core */
|
|
|
|
|
/* Cavium Networks Octeon CPU core. */
|
|
|
|
|
{ "octeon", 0, 0, ISA_MIPS64R2, CPU_OCTEON },
|
|
|
|
|
{ "octeon+", 0, 0, ISA_MIPS64R2, CPU_OCTEONP },
|
|
|
|
|
{ "octeon2", 0, 0, ISA_MIPS64R2, CPU_OCTEON2 },
|
|
|
|
@ -19869,11 +20009,11 @@ static const struct mips_cpu_info mips_cpu_info_table[] =
|
|
|
|
|
MIPS64R2 rather than MIPS64. */
|
|
|
|
|
{ "xlp", 0, 0, ISA_MIPS64R2, CPU_XLR },
|
|
|
|
|
|
|
|
|
|
/* MIPS 64 Release 6 */
|
|
|
|
|
/* MIPS 64 Release 6. */
|
|
|
|
|
{ "i6400", 0, ASE_MSA, ISA_MIPS64R6, CPU_MIPS64R6},
|
|
|
|
|
{ "p6600", 0, ASE_VIRT | ASE_MSA, ISA_MIPS64R6, CPU_MIPS64R6},
|
|
|
|
|
|
|
|
|
|
/* End marker */
|
|
|
|
|
/* End marker. */
|
|
|
|
|
{ NULL, 0, 0, 0, 0 }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
@ -20140,9 +20280,20 @@ MIPS options:\n\
|
|
|
|
|
fprintf (stream, _("\
|
|
|
|
|
-minsn32 only generate 32-bit microMIPS instructions\n\
|
|
|
|
|
-mno-insn32 generate all microMIPS instructions\n"));
|
|
|
|
|
#if DEFAULT_MIPS_FIX_LOONGSON3_LLSC
|
|
|
|
|
fprintf (stream, _("\
|
|
|
|
|
-mfix-loongson3-llsc work around Loongson3 LL/SC errata, default\n\
|
|
|
|
|
-mno-fix-loongson3-llsc disable work around Loongson3 LL/SC errata\n"));
|
|
|
|
|
#else
|
|
|
|
|
fprintf (stream, _("\
|
|
|
|
|
-mfix-loongson3-llsc work around Loongson3 LL/SC errata\n\
|
|
|
|
|
-mno-fix-loongson3-llsc disable work around Loongson3 LL/SC errata, default\n"));
|
|
|
|
|
#endif
|
|
|
|
|
fprintf (stream, _("\
|
|
|
|
|
-mfix-loongson2f-jump work around Loongson2F JUMP instructions\n\
|
|
|
|
|
-mfix-loongson2f-nop work around Loongson2F NOP errata\n\
|
|
|
|
|
-mfix-loongson3-llsc work around Loongson3 LL/SC errata\n\
|
|
|
|
|
-mno-fix-loongson3-llsc disable work around Loongson3 LL/SC errata\n\
|
|
|
|
|
-mfix-vr4120 work around certain VR4120 errata\n\
|
|
|
|
|
-mfix-vr4130 work around VR4130 mflo/mfhi errata\n\
|
|
|
|
|
-mfix-24k insert a nop after ERET and DERET instructions\n\
|
|
|
|
|