can be extracted using RELAX_FIRST() and RELAX_SECOND(). In addition,
the subtype has the following flags:
+ RELAX_PIC
+ Set if generating PIC code.
+
RELAX_USE_SECOND
Set if it has been decided that we should use the second
sequence instead of the first.
The code and fixups for the unwanted alternative are discarded
by md_convert_frag. */
-#define RELAX_ENCODE(FIRST, SECOND) (((FIRST) << 8) | (SECOND))
+#define RELAX_ENCODE(FIRST, SECOND, PIC) \
+ (((FIRST) << 8) | (SECOND) | ((PIC) ? 0x10000 : 0))
#define RELAX_FIRST(X) (((X) >> 8) & 0xff)
#define RELAX_SECOND(X) ((X) & 0xff)
-#define RELAX_USE_SECOND 0x10000
-#define RELAX_SECOND_LONGER 0x20000
-#define RELAX_NOMACRO 0x40000
-#define RELAX_DELAY_SLOT 0x80000
-#define RELAX_DELAY_SLOT_16BIT 0x100000
-#define RELAX_DELAY_SLOT_SIZE_FIRST 0x200000
-#define RELAX_DELAY_SLOT_SIZE_SECOND 0x400000
+#define RELAX_PIC(X) (((X) & 0x10000) != 0)
+#define RELAX_USE_SECOND 0x20000
+#define RELAX_SECOND_LONGER 0x40000
+#define RELAX_NOMACRO 0x80000
+#define RELAX_DELAY_SLOT 0x100000
+#define RELAX_DELAY_SLOT_16BIT 0x200000
+#define RELAX_DELAY_SLOT_SIZE_FIRST 0x400000
+#define RELAX_DELAY_SLOT_SIZE_SECOND 0x800000
/* Branch without likely bit. If label is out of range, we turn:
but it's not clear that it would actually improve performance. */
-#define RELAX_BRANCH_ENCODE(at, uncond, likely, link, toofar) \
+#define RELAX_BRANCH_ENCODE(at, pic, \
+ uncond, likely, link, toofar) \
((relax_substateT) \
(0xc0000000 \
| ((at) & 0x1f) \
- | ((toofar) ? 0x20 : 0) \
- | ((link) ? 0x40 : 0) \
- | ((likely) ? 0x80 : 0) \
- | ((uncond) ? 0x100 : 0)))
+ | ((pic) ? 0x20 : 0) \
+ | ((toofar) ? 0x40 : 0) \
+ | ((link) ? 0x80 : 0) \
+ | ((likely) ? 0x100 : 0) \
+ | ((uncond) ? 0x200 : 0)))
#define RELAX_BRANCH_P(i) (((i) & 0xf0000000) == 0xc0000000)
-#define RELAX_BRANCH_UNCOND(i) (((i) & 0x100) != 0)
-#define RELAX_BRANCH_LIKELY(i) (((i) & 0x80) != 0)
-#define RELAX_BRANCH_LINK(i) (((i) & 0x40) != 0)
-#define RELAX_BRANCH_TOOFAR(i) (((i) & 0x20) != 0)
+#define RELAX_BRANCH_UNCOND(i) (((i) & 0x200) != 0)
+#define RELAX_BRANCH_LIKELY(i) (((i) & 0x100) != 0)
+#define RELAX_BRANCH_LINK(i) (((i) & 0x80) != 0)
+#define RELAX_BRANCH_TOOFAR(i) (((i) & 0x40) != 0)
+#define RELAX_BRANCH_PIC(i) (((i) & 0x20) != 0)
#define RELAX_BRANCH_AT(i) ((i) & 0x1f)
/* For mips16 code, we use an entirely different form of relaxation.
store whether this is known to be a branch to a different section,
whether we have tried to relax this frag yet, and whether we have
ever extended a PC relative fragment because of a shift count. */
-#define RELAX_MIPS16_ENCODE(type, small, ext, dslot, jal_dslot) \
+#define RELAX_MIPS16_ENCODE(type, e2, pic, sym32, nomacro, \
+ small, ext, \
+ dslot, jal_dslot) \
(0x80000000 \
| ((type) & 0xff) \
- | ((small) ? 0x100 : 0) \
- | ((ext) ? 0x200 : 0) \
- | ((dslot) ? 0x400 : 0) \
- | ((jal_dslot) ? 0x800 : 0))
+ | ((e2) ? 0x100 : 0) \
+ | ((pic) ? 0x200 : 0) \
+ | ((sym32) ? 0x400 : 0) \
+ | ((nomacro) ? 0x800 : 0) \
+ | ((small) ? 0x1000 : 0) \
+ | ((ext) ? 0x2000 : 0) \
+ | ((dslot) ? 0x4000 : 0) \
+ | ((jal_dslot) ? 0x8000 : 0))
+
#define RELAX_MIPS16_P(i) (((i) & 0xc0000000) == 0x80000000)
#define RELAX_MIPS16_TYPE(i) ((i) & 0xff)
-#define RELAX_MIPS16_USER_SMALL(i) (((i) & 0x100) != 0)
-#define RELAX_MIPS16_USER_EXT(i) (((i) & 0x200) != 0)
-#define RELAX_MIPS16_DSLOT(i) (((i) & 0x400) != 0)
-#define RELAX_MIPS16_JAL_DSLOT(i) (((i) & 0x800) != 0)
-#define RELAX_MIPS16_EXTENDED(i) (((i) & 0x1000) != 0)
-#define RELAX_MIPS16_MARK_EXTENDED(i) ((i) | 0x1000)
-#define RELAX_MIPS16_CLEAR_EXTENDED(i) ((i) &~ 0x1000)
-#define RELAX_MIPS16_LONG_BRANCH(i) (((i) & 0x2000) != 0)
-#define RELAX_MIPS16_MARK_LONG_BRANCH(i) ((i) | 0x2000)
-#define RELAX_MIPS16_CLEAR_LONG_BRANCH(i) ((i) &~ 0x2000)
+#define RELAX_MIPS16_E2(i) (((i) & 0x100) != 0)
+#define RELAX_MIPS16_PIC(i) (((i) & 0x200) != 0)
+#define RELAX_MIPS16_SYM32(i) (((i) & 0x400) != 0)
+#define RELAX_MIPS16_NOMACRO(i) (((i) & 0x800) != 0)
+#define RELAX_MIPS16_USER_SMALL(i) (((i) & 0x1000) != 0)
+#define RELAX_MIPS16_USER_EXT(i) (((i) & 0x2000) != 0)
+#define RELAX_MIPS16_DSLOT(i) (((i) & 0x4000) != 0)
+#define RELAX_MIPS16_JAL_DSLOT(i) (((i) & 0x8000) != 0)
+
+#define RELAX_MIPS16_EXTENDED(i) (((i) & 0x10000) != 0)
+#define RELAX_MIPS16_MARK_EXTENDED(i) ((i) | 0x10000)
+#define RELAX_MIPS16_CLEAR_EXTENDED(i) ((i) & ~0x10000)
+#define RELAX_MIPS16_ALWAYS_EXTENDED(i) (((i) & 0x20000) != 0)
+#define RELAX_MIPS16_MARK_ALWAYS_EXTENDED(i) ((i) | 0x20000)
+#define RELAX_MIPS16_CLEAR_ALWAYS_EXTENDED(i) ((i) & ~0x20000)
+#define RELAX_MIPS16_MACRO(i) (((i) & 0x40000) != 0)
+#define RELAX_MIPS16_MARK_MACRO(i) ((i) | 0x40000)
+#define RELAX_MIPS16_CLEAR_MACRO(i) ((i) & ~0x40000)
/* For microMIPS code, we use relaxation similar to one we use for
MIPS16 code. Some instructions that take immediate values support
instructions is enabled, and whether the displacement of a branch is
too large to fit as an immediate argument of a 16-bit and a 32-bit
branch, respectively. */
-#define RELAX_MICROMIPS_ENCODE(type, at, insn32, \
+#define RELAX_MICROMIPS_ENCODE(type, at, insn32, pic, \
uncond, compact, link, nods, \
relax32, toofar16, toofar32) \
(0x40000000 \
| ((type) & 0xff) \
| (((at) & 0x1f) << 8) \
| ((insn32) ? 0x2000 : 0) \
- | ((uncond) ? 0x4000 : 0) \
- | ((compact) ? 0x8000 : 0) \
- | ((link) ? 0x10000 : 0) \
- | ((nods) ? 0x20000 : 0) \
- | ((relax32) ? 0x40000 : 0) \
- | ((toofar16) ? 0x80000 : 0) \
- | ((toofar32) ? 0x100000 : 0))
+ | ((pic) ? 0x4000 : 0) \
+ | ((uncond) ? 0x8000 : 0) \
+ | ((compact) ? 0x10000 : 0) \
+ | ((link) ? 0x20000 : 0) \
+ | ((nods) ? 0x40000 : 0) \
+ | ((relax32) ? 0x80000 : 0) \
+ | ((toofar16) ? 0x100000 : 0) \
+ | ((toofar32) ? 0x200000 : 0))
#define RELAX_MICROMIPS_P(i) (((i) & 0xc0000000) == 0x40000000)
#define RELAX_MICROMIPS_TYPE(i) ((i) & 0xff)
#define RELAX_MICROMIPS_AT(i) (((i) >> 8) & 0x1f)
#define RELAX_MICROMIPS_INSN32(i) (((i) & 0x2000) != 0)
-#define RELAX_MICROMIPS_UNCOND(i) (((i) & 0x4000) != 0)
-#define RELAX_MICROMIPS_COMPACT(i) (((i) & 0x8000) != 0)
-#define RELAX_MICROMIPS_LINK(i) (((i) & 0x10000) != 0)
-#define RELAX_MICROMIPS_NODS(i) (((i) & 0x20000) != 0)
-#define RELAX_MICROMIPS_RELAX32(i) (((i) & 0x40000) != 0)
-
-#define RELAX_MICROMIPS_TOOFAR16(i) (((i) & 0x80000) != 0)
-#define RELAX_MICROMIPS_MARK_TOOFAR16(i) ((i) | 0x80000)
-#define RELAX_MICROMIPS_CLEAR_TOOFAR16(i) ((i) & ~0x80000)
-#define RELAX_MICROMIPS_TOOFAR32(i) (((i) & 0x100000) != 0)
-#define RELAX_MICROMIPS_MARK_TOOFAR32(i) ((i) | 0x100000)
-#define RELAX_MICROMIPS_CLEAR_TOOFAR32(i) ((i) & ~0x100000)
+#define RELAX_MICROMIPS_PIC(i) (((i) & 0x4000) != 0)
+#define RELAX_MICROMIPS_UNCOND(i) (((i) & 0x8000) != 0)
+#define RELAX_MICROMIPS_COMPACT(i) (((i) & 0x10000) != 0)
+#define RELAX_MICROMIPS_LINK(i) (((i) & 0x20000) != 0)
+#define RELAX_MICROMIPS_NODS(i) (((i) & 0x40000) != 0)
+#define RELAX_MICROMIPS_RELAX32(i) (((i) & 0x80000) != 0)
+
+#define RELAX_MICROMIPS_TOOFAR16(i) (((i) & 0x100000) != 0)
+#define RELAX_MICROMIPS_MARK_TOOFAR16(i) ((i) | 0x100000)
+#define RELAX_MICROMIPS_CLEAR_TOOFAR16(i) ((i) & ~0x100000)
+#define RELAX_MICROMIPS_TOOFAR32(i) (((i) & 0x200000) != 0)
+#define RELAX_MICROMIPS_MARK_TOOFAR32(i) ((i) | 0x200000)
+#define RELAX_MICROMIPS_CLEAR_TOOFAR32(i) ((i) & ~0x200000)
/* Sign-extend 16-bit value X. */
#define SEXT_16BIT(X) ((((X) + 0x8000) & 0xffff) - 0x8000)
static void mips16_macro (struct mips_cl_insn * ip);
static void mips_ip (char *str, struct mips_cl_insn * ip);
static void mips16_ip (char *str, struct mips_cl_insn * ip);
+static unsigned long mips16_immed_extend (offsetT, unsigned int);
static void mips16_immed
(const char *, unsigned int, int, bfd_reloc_code_real_type, offsetT,
unsigned int, unsigned long *);
OPTION_NO_MICROMIPS,
OPTION_MCU,
OPTION_NO_MCU,
+ OPTION_MIPS16E2,
+ OPTION_NO_MIPS16E2,
OPTION_COMPAT_ARCH_BASE,
OPTION_M4650,
OPTION_NO_M4650,
{"mno-msa", no_argument, NULL, OPTION_NO_MSA},
{"mxpa", no_argument, NULL, OPTION_XPA},
{"mno-xpa", no_argument, NULL, OPTION_NO_XPA},
+ {"mmips16e2", no_argument, NULL, OPTION_MIPS16E2},
+ {"mno-mips16e2", no_argument, NULL, OPTION_NO_MIPS16E2},
/* Old-style architecture options. Don't add more of these. */
{"m4650", no_argument, NULL, OPTION_M4650},
{ "xpa", ASE_XPA, 0,
OPTION_XPA, OPTION_NO_XPA,
- 2, 2, -1, -1,
+ 2, 2, 2, 2,
-1 },
+
+ { "mips16e2", ASE_MIPS16E2, 0,
+ OPTION_MIPS16E2, OPTION_NO_MIPS16E2,
+ 2, 2, -1, -1,
+ 6 },
};
/* The set of ASEs that require -mfp64. */
mask = mips_ase_mask (ase->flags);
opts->ase &= ~mask;
+
+ /* Clear combination ASE flags, which need to be recalculated based on
+ updated regular ASE settings. */
+ opts->ase &= ~(ASE_MIPS16E2_MT | ASE_XPA_VIRT);
+
if (enabled_p)
opts->ase |= ase->flags;
+
+ /* The Virtualization ASE has eXtended Physical Addressing (XPA)
+ instructions which are only valid when both ASEs are enabled.
+ This sets the ASE_XPA_VIRT flag when both ASEs are present. */
+ if ((opts->ase & (ASE_XPA | ASE_VIRT)) == (ASE_XPA | ASE_VIRT))
+ {
+ opts->ase |= ASE_XPA_VIRT;
+ mask |= ASE_XPA_VIRT;
+ }
+ if ((opts->ase & (ASE_MIPS16E2 | ASE_MT)) == (ASE_MIPS16E2 | ASE_MT))
+ {
+ opts->ase |= ASE_MIPS16E2_MT;
+ mask |= ASE_MIPS16E2_MT;
+ }
+
return mask;
}
insn_insert_operand (struct mips_cl_insn *insn,
const struct mips_operand *operand, unsigned int uval)
{
- insn->insn_opcode = mips_insert_operand (operand, insn->insn_opcode, uval);
+ if (mips_opts.mips16
+ && operand->type == OP_INT && operand->lsb == 0
+ && mips_opcode_32bit_p (insn->insn_mo))
+ insn->insn_opcode |= mips16_immed_extend (uval, operand->size);
+ else
+ insn->insn_opcode = mips_insert_operand (operand, insn->insn_opcode, uval);
}
/* Extract the value of OPERAND from INSN. */
static bfd_boolean
is_opcode_valid_16 (const struct mips_opcode *mo)
{
- return opcode_is_member (mo, mips_opts.isa, 0, mips_opts.arch);
+ int isa = mips_opts.isa;
+ int ase = mips_opts.ase;
+ unsigned int i;
+
+ if (ISA_HAS_64BIT_REGS (isa))
+ for (i = 0; i < ARRAY_SIZE (mips_ases); i++)
+ if ((ase & mips_ases[i].flags) == mips_ases[i].flags)
+ ase |= mips_ases[i].flags64;
+
+ return opcode_is_member (mo, isa, ase, mips_opts.arch);
}
/* Return TRUE if the size of the microMIPS opcode MO matches one
}
gas_assert (opno < MAX_OPERANDS);
operands->operand[opno] = operand;
- if (operand && operand->type != OP_VU0_MATCH_SUFFIX)
+ if (!decode_operand && operand
+ && operand->type == OP_INT && operand->lsb == 0
+ && mips_opcode_32bit_p (opcode))
+ used_bits |= mips16_immed_extend (-1, operand->size);
+ else if (operand && operand->type != OP_VU0_MATCH_SUFFIX)
{
used_bits = mips_insert_operand (operand, used_bits, -1);
if (operand->type == OP_MDMX_IMM_REG)
used_bits &= ~(1 << (operand->lsb + 5));
if (operand->type == OP_ENTRY_EXIT_LIST)
used_bits &= ~(mask & 0x700);
+ /* interAptiv MR2 SAVE/RESTORE instructions have a discontiguous
+ operand field that cannot be fully described with LSB/SIZE. */
+ if (operand->type == OP_SAVE_RESTORE_LIST && operand->lsb == 6)
+ used_bits &= ~0x6000;
}
/* Skip prefix characters. */
if (decode_operand && (*s == '+' || *s == 'm' || *s == '-'))
{
mips_macro_warning.first_frag = frag_now;
frag_var (rs_machine_dependent, 0, 0,
- RELAX_ENCODE (mips_relax.sizes[0], mips_relax.sizes[1]),
+ RELAX_ENCODE (mips_relax.sizes[0], mips_relax.sizes[1],
+ mips_pic != NO_PIC),
mips_relax.symbol, 0, (char *) mips_relax.first_fixup);
memset (&mips_relax.sizes, 0, sizeof (mips_relax.sizes));
case OP_IMM_INDEX:
abort ();
+ case OP_REG28:
+ return 1 << 28;
+
case OP_REG:
case OP_OPTIONAL_REG:
{
/* Try to get a constant expression from the next tokens in ARG. Consume
the tokens and return return true on success, storing the constant value
- in *VALUE. Use FALLBACK as the value if the match succeeded with an
- error. */
+ in *VALUE. */
static bfd_boolean
match_const_int (struct mips_arg_info *arg, offsetT *value)
*value = ex.X_add_number;
else
{
- match_not_constant (arg);
+ if (r[0] == BFD_RELOC_UNUSED && ex.X_op == O_big)
+ match_out_of_range (arg);
+ else
+ match_not_constant (arg);
return FALSE;
}
return TRUE;
if (!match_expression (arg, &offset_expr, offset_reloc))
return FALSE;
+ if (offset_expr.X_op == O_big)
+ {
+ match_out_of_range (arg);
+ return FALSE;
+ }
+
if (offset_reloc[0] != BFD_RELOC_UNUSED)
/* Relocation operators were used. Accept the argument and
leave the relocation value in offset_expr and offset_relocs
/* Accept non-constant operands if no later alternative matches,
leaving it for the caller to process. */
if (!arg->lax_match)
- return FALSE;
+ {
+ match_not_constant (arg);
+ return FALSE;
+ }
offset_reloc[0] = BFD_RELOC_LO16;
return TRUE;
}
{
max_val = ((1 << operand_base->size) - 1) << operand->shift;
if (!arg->lax_match && sval <= max_val)
- return FALSE;
+ {
+ match_out_of_range (arg);
+ return FALSE;
+ }
}
}
else
return TRUE;
}
+/* Encode regular MIPS SAVE/RESTORE instruction operands according to
+ the argument register mask AMASK, the number of static registers
+ saved NSREG, the $ra, $s0 and $s1 register specifiers RA, S0 and S1
+ respectively, and the frame size FRAME_SIZE. */
+
+static unsigned int
+mips_encode_save_restore (unsigned int amask, unsigned int nsreg,
+ unsigned int ra, unsigned int s0, unsigned int s1,
+ unsigned int frame_size)
+{
+ return ((nsreg << 23) | ((frame_size & 0xf0) << 15) | (amask << 15)
+ | (ra << 12) | (s0 << 11) | (s1 << 10) | ((frame_size & 0xf) << 6));
+}
+
+/* Encode MIPS16 SAVE/RESTORE instruction operands according to the
+ argument register mask AMASK, the number of static registers saved
+ NSREG, the $ra, $s0 and $s1 register specifiers RA, S0 and S1
+ respectively, and the frame size FRAME_SIZE. */
+
+static unsigned int
+mips16_encode_save_restore (unsigned int amask, unsigned int nsreg,
+ unsigned int ra, unsigned int s0, unsigned int s1,
+ unsigned int frame_size)
+{
+ unsigned int args;
+
+ args = (ra << 6) | (s0 << 5) | (s1 << 4) | (frame_size & 0xf);
+ if (nsreg || amask || frame_size == 0 || frame_size > 16)
+ args |= (MIPS16_EXTEND | (nsreg << 24) | (amask << 16)
+ | ((frame_size & 0xf0) << 16));
+ return args;
+}
+
/* OP_SAVE_RESTORE_LIST matcher. */
static bfd_boolean
{
unsigned int opcode, args, statics, sregs;
unsigned int num_frame_sizes, num_args, num_statics, num_sregs;
+ unsigned int arg_mask, ra, s0, s1;
offsetT frame_size;
opcode = arg->insn->insn_opcode;
args = 0;
statics = 0;
sregs = 0;
+ ra = 0;
+ s0 = 0;
+ s1 = 0;
do
{
unsigned int regno1, regno2;
sregs |= 1 << 8;
else if (regno1 == 31)
/* Add $ra to insn. */
- opcode |= 0x40;
+ ra = 1;
else
return FALSE;
regno1 += 1;
return FALSE;
else if (args == 0xf)
/* All $a0-$a3 are args. */
- opcode |= MIPS16_ALL_ARGS << 16;
+ arg_mask = MIPS_SVRS_ALL_ARGS;
else if (statics == 0xf)
/* All $a0-$a3 are statics. */
- opcode |= MIPS16_ALL_STATICS << 16;
+ arg_mask = MIPS_SVRS_ALL_STATICS;
else
{
/* Count arg registers. */
return FALSE;
/* Encode args/statics. */
- opcode |= ((num_args << 2) | num_statics) << 16;
+ arg_mask = (num_args << 2) | num_statics;
}
/* Encode $s0/$s1. */
if (sregs & (1 << 0)) /* $s0 */
- opcode |= 0x20;
+ s0 = 1;
if (sregs & (1 << 1)) /* $s1 */
- opcode |= 0x10;
+ s1 = 1;
sregs >>= 2;
/* Encode $s2-$s8. */
}
if (sregs != 0)
return FALSE;
- opcode |= num_sregs << 24;
/* Encode frame size. */
if (num_frame_sizes == 0)
set_insn_error (arg->argnum, _("invalid frame size"));
return FALSE;
}
- if (frame_size != 128 || (opcode >> 16) != 0)
- {
- frame_size /= 8;
- opcode |= (((frame_size & 0xf0) << 16)
- | (frame_size & 0x0f));
- }
+ frame_size /= 8;
/* Finally build the instruction. */
- if ((opcode >> 16) != 0 || frame_size == 0)
- opcode |= MIPS16_EXTEND;
+ if (mips_opts.mips16)
+ opcode |= mips16_encode_save_restore (arg_mask, num_sregs, ra, s0, s1,
+ frame_size);
+ else if (!mips_opts.micromips)
+ opcode |= mips_encode_save_restore (arg_mask, num_sregs, ra, s0, s1,
+ frame_size);
+ else
+ abort ();
+
arg->insn->insn_opcode = opcode;
return TRUE;
}
return FALSE;
}
+/* OP_REG28 matcher. */
+
+static bfd_boolean
+match_reg28_operand (struct mips_arg_info *arg)
+{
+ unsigned int regno;
+
+ if (arg->token->type == OT_REG
+ && match_regno (arg, OP_REG_GP, arg->token->u.regno, ®no)
+ && regno == GP)
+ {
+ ++arg->token;
+ return TRUE;
+ }
+ return FALSE;
+}
+
/* OP_NON_ZERO_REG matcher. */
static bfd_boolean
return match_reg (arg, OP_REG_GP, ®no) && regno == other_regno;
}
-/* Read a floating-point constant from S for LI.S or LI.D. LENGTH is
- the length of the value in bytes (4 for float, 8 for double) and
- USING_GPRS says whether the destination is a GPR rather than an FPR.
+/* Try to match a floating-point constant from ARG for LI.S or LI.D.
+ LENGTH is the length of the value in bytes (4 for float, 8 for double)
+ and USING_GPRS says whether the destination is a GPR rather than an FPR.
Return the constant in IMM and OFFSET as follows:
return TRUE;
}
-/* S is the text seen for ARG. Match it against OPERAND. Return the end
- of the argument text if the match is successful, otherwise return null. */
+/* Try to match a token from ARG against OPERAND. Consume the token
+ and return true on success, otherwise return false. */
static bfd_boolean
match_operand (struct mips_arg_info *arg,
case OP_PC:
return match_pc_operand (arg);
+ case OP_REG28:
+ return match_reg28_operand (arg);
+
case OP_VU0_SUFFIX:
return match_vu0_suffix_operand (arg, operand, FALSE);
break;
}
}
- if (rv == FALSE)
+ if (!rv)
{
/* Insert nop after branch to fix short loop. */
return FALSE;
: branch_likely_p (ip) ? 1
: 0)), 4,
RELAX_BRANCH_ENCODE
- (AT,
+ (AT, mips_pic != NO_PIC,
uncond_branch_p (ip),
branch_likely_p (ip),
pinfo & INSN_WRITE_GPR_31,
length32 = relaxed_micromips_32bit_branch_length (NULL, NULL, uncond);
add_relaxed_insn (ip, length32, relax16 ? 2 : 4,
RELAX_MICROMIPS_ENCODE (type, AT, mips_opts.insn32,
+ mips_pic != NO_PIC,
uncond, compact, al, nods,
relax32, 0, 0),
address_expr->X_add_symbol,
else
{
symbol = make_expr_symbol (address_expr);
+ symbol_append (symbol, symbol_lastP, &symbol_rootP, &symbol_lastP);
offset = 0;
}
- add_relaxed_insn (ip, 4, 0,
+ add_relaxed_insn (ip, 12, 0,
RELAX_MIPS16_ENCODE
(*reloc_type - BFD_RELOC_UNUSED,
+ mips_opts.ase & ASE_MIPS16E2,
+ mips_pic != NO_PIC,
+ HAVE_32BIT_SYMBOLS,
+ mips_opts.warn_about_macros,
require_unextended, require_extended,
delayed_branch_p (&history[0]),
history[0].mips16_absolute_jump_p),
address_expr,
howto0 && howto0->pc_relative,
final_type[0]);
+ /* Record non-PIC mode in `fx_tcbit2' for `md_apply_fix'. */
+ ip->fixp[0]->fx_tcbit2 = mips_pic == NO_PIC;
/* Tag symbols that have a R_MIPS16_26 relocation against them. */
if (final_type[0] == BFD_RELOC_MIPS16_JMP && ip->fixp[0]->fx_addsy)
const char *args;
const struct mips_operand *operand;
const struct mips_operand *ext_operand;
+ bfd_boolean pcrel = FALSE;
int required_insn_length;
struct mips_arg_info arg;
int relax_char;
}
else if (relax_char
&& offset_expr.X_op == O_constant
+ && !pcrel
&& calculate_reloc (*offset_reloc,
offset_expr.X_add_number,
&value))
{
if (required_insn_length == 2)
set_insn_error (0, _("invalid unextended operand value"));
- else
+ else if (!mips_opcode_32bit_p (opcode))
{
forced_insn_length = 4;
insn->insn_opcode |= MIPS16_EXTEND;
case 'A':
case 'B':
case 'E':
+ case 'V':
+ case 'u':
relax_char = c;
break;
if (!operand)
abort ();
- if (operand->type != OP_PCREL)
+ if (operand->type == OP_PCREL)
+ pcrel = TRUE;
+ else
{
ext_operand = decode_mips16_operand (c, TRUE);
if (operand != ext_operand)
continue;
}
- /* We need the OT_INTEGER check because some MIPS16
- immediate variants are listed before the register ones. */
- if (arg.token->type != OT_INTEGER
- || !match_expression (&arg, &offset_expr, offset_reloc))
+ if (!match_expression (&arg, &offset_expr, offset_reloc))
return FALSE;
/* '8' is used for SLTI(U) and has traditionally not
been allowed to take relocation operators. */
if (offset_reloc[0] != BFD_RELOC_UNUSED
&& (ext_operand->size != 16 || c == '8'))
- return FALSE;
+ {
+ match_not_constant (&arg);
+ return FALSE;
+ }
+
+ if (offset_expr.X_op == O_big)
+ {
+ match_out_of_range (&arg);
+ return FALSE;
+ }
relax_char = c;
continue;
struct mips_operand_token *tokens;
unsigned int l;
- for (s = str; ISLOWER (*s); ++s)
+ for (s = str; *s != '\0' && *s != '.' && *s != ' '; ++s)
;
end = s;
c = *end;
break;
else if (*s++ == ' ')
break;
- /* Fall through. */
- default:
set_insn_error (0, _("unrecognized opcode"));
return;
}
mips16_immed_extend (offsetT val, unsigned int nbits)
{
int extval;
- if (nbits == 16)
+
+ extval = 0;
+ val &= (1U << nbits) - 1;
+ if (nbits == 16 || nbits == 9)
{
extval = ((val >> 11) & 0x1f) | (val & 0x7e0);
val &= 0x1f;
extval = ((val >> 11) & 0xf) | (val & 0x7f0);
val &= 0xf;
}
- else
+ else if (nbits == 6)
{
extval = ((val & 0x1f) << 6) | (val & 0x20);
val = 0;
{"%got_lo", BFD_RELOC_MIPS_GOT_LO16},
{"%got", BFD_RELOC_MIPS_GOT16},
{"%gp_rel", BFD_RELOC_GPREL16},
+ {"%gprel", BFD_RELOC_GPREL16},
{"%half", BFD_RELOC_16},
{"%highest", BFD_RELOC_MIPS_HIGHEST},
{"%higher", BFD_RELOC_MIPS_HIGHER},
static const struct percent_op_match mips16_percent_op[] =
{
{"%lo", BFD_RELOC_MIPS16_LO16},
+ {"%gp_rel", BFD_RELOC_MIPS16_GPREL},
{"%gprel", BFD_RELOC_MIPS16_GPREL},
{"%got", BFD_RELOC_MIPS16_GOT16},
{"%call16", BFD_RELOC_MIPS16_CALL16},
insn |= (*valP >> 2) & 0xffff;
write_insn (buf, insn);
}
- else if (mips_pic == NO_PIC
+ else if (fixP->fx_tcbit2
&& fixP->fx_done
&& fixP->fx_frag->fr_address >= text_section->vma
&& (fixP->fx_frag->fr_address
if (section_type == SHT_MIPS_DWARF)
section_type = SHT_PROGBITS;
- obj_elf_change_section (section_name, section_type, section_flag,
+ obj_elf_change_section (section_name, section_type, 0, section_flag,
section_entry_size, 0, 0, 0);
if (now_seg->name != section_name)
/* A global or weak symbol is treated as external. */
&& (!S_IS_WEAK (sym) && !S_IS_EXTERNAL (sym)));
}
+\f
+/* Given a MIPS16 variant frag FRAGP and PC-relative operand PCREL_OP
+ convert a section-relative value VAL to the equivalent PC-relative
+ value. */
+static offsetT
+mips16_pcrel_val (fragS *fragp, const struct mips_pcrel_operand *pcrel_op,
+ offsetT val, long stretch)
+{
+ fragS *sym_frag;
+ addressT addr;
+
+ gas_assert (pcrel_op->root.root.type == OP_PCREL);
+
+ sym_frag = symbol_get_frag (fragp->fr_symbol);
+
+ /* If the relax_marker of the symbol fragment differs from the
+ relax_marker of this fragment, we have not yet adjusted the
+ symbol fragment fr_address. We want to add in STRETCH in
+ order to get a better estimate of the address. This
+ particularly matters because of the shift bits. */
+ if (stretch != 0 && sym_frag->relax_marker != fragp->relax_marker)
+ {
+ fragS *f;
+
+ /* Adjust stretch for any alignment frag. Note that if have
+ been expanding the earlier code, the symbol may be
+ defined in what appears to be an earlier frag. FIXME:
+ This doesn't handle the fr_subtype field, which specifies
+ a maximum number of bytes to skip when doing an
+ alignment. */
+ for (f = fragp; f != NULL && f != sym_frag; f = f->fr_next)
+ {
+ if (f->fr_type == rs_align || f->fr_type == rs_align_code)
+ {
+ if (stretch < 0)
+ stretch = -(-stretch & ~((1 << (int) f->fr_offset) - 1));
+ else
+ stretch &= ~((1 << (int) f->fr_offset) - 1);
+ if (stretch == 0)
+ break;
+ }
+ }
+ if (f != NULL)
+ val += stretch;
+ }
+
+ addr = fragp->fr_address + fragp->fr_fix;
+
+ /* The base address rules are complicated. The base address of
+ a branch is the following instruction. The base address of a
+ PC relative load or add is the instruction itself, but if it
+ is in a delay slot (in which case it can not be extended) use
+ the address of the instruction whose delay slot it is in. */
+ if (pcrel_op->include_isa_bit)
+ {
+ addr += 2;
+
+ /* If we are currently assuming that this frag should be
+ extended, then the current address is two bytes higher. */
+ if (RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
+ addr += 2;
+
+ /* Ignore the low bit in the target, since it will be set
+ for a text label. */
+ val &= -2;
+ }
+ else if (RELAX_MIPS16_JAL_DSLOT (fragp->fr_subtype))
+ addr -= 4;
+ else if (RELAX_MIPS16_DSLOT (fragp->fr_subtype))
+ addr -= 2;
+
+ val -= addr & -(1 << pcrel_op->align_log2);
+
+ return val;
+}
/* Given a mips16 variant frag FRAGP, return non-zero if it needs an
extended opcode. SEC is the section the frag is in. */
static int
mips16_extended_frag (fragS *fragp, asection *sec, long stretch)
{
- int type;
const struct mips_int_operand *operand;
offsetT val;
segT symsec;
- fragS *sym_frag;
+ int type;
if (RELAX_MIPS16_USER_SMALL (fragp->fr_subtype))
return 0;
: !bfd_is_abs_section (symsec)))
return 1;
- sym_frag = symbol_get_frag (fragp->fr_symbol);
val = S_GET_VALUE (fragp->fr_symbol) + fragp->fr_offset;
if (operand->root.type == OP_PCREL)
{
const struct mips_pcrel_operand *pcrel_op;
- addressT addr;
offsetT maxtiny;
- if (RELAX_MIPS16_LONG_BRANCH (fragp->fr_subtype))
+ if (RELAX_MIPS16_ALWAYS_EXTENDED (fragp->fr_subtype))
return 1;
pcrel_op = (const struct mips_pcrel_operand *) operand;
-
- /* If the relax_marker of the symbol fragment differs from the
- relax_marker of this fragment, we have not yet adjusted the
- symbol fragment fr_address. We want to add in STRETCH in
- order to get a better estimate of the address. This
- particularly matters because of the shift bits. */
- if (stretch != 0
- && sym_frag->relax_marker != fragp->relax_marker)
- {
- fragS *f;
-
- /* Adjust stretch for any alignment frag. Note that if have
- been expanding the earlier code, the symbol may be
- defined in what appears to be an earlier frag. FIXME:
- This doesn't handle the fr_subtype field, which specifies
- a maximum number of bytes to skip when doing an
- alignment. */
- for (f = fragp; f != NULL && f != sym_frag; f = f->fr_next)
- {
- if (f->fr_type == rs_align || f->fr_type == rs_align_code)
- {
- if (stretch < 0)
- stretch = - ((- stretch)
- & ~ ((1 << (int) f->fr_offset) - 1));
- else
- stretch &= ~ ((1 << (int) f->fr_offset) - 1);
- if (stretch == 0)
- break;
- }
- }
- if (f != NULL)
- val += stretch;
- }
-
- addr = fragp->fr_address + fragp->fr_fix;
-
- /* The base address rules are complicated. The base address of
- a branch is the following instruction. The base address of a
- PC relative load or add is the instruction itself, but if it
- is in a delay slot (in which case it can not be extended) use
- the address of the instruction whose delay slot it is in. */
- if (pcrel_op->include_isa_bit)
- {
- addr += 2;
-
- /* If we are currently assuming that this frag should be
- extended, then, the current address is two bytes
- higher. */
- if (RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
- addr += 2;
-
- /* Ignore the low bit in the target, since it will be set
- for a text label. */
- val &= -2;
- }
- else if (RELAX_MIPS16_JAL_DSLOT (fragp->fr_subtype))
- addr -= 4;
- else if (RELAX_MIPS16_DSLOT (fragp->fr_subtype))
- addr -= 2;
-
- val -= addr & -(1 << pcrel_op->align_log2);
+ val = mips16_pcrel_val (fragp, pcrel_op, val, stretch);
/* If any of the shifted bits are set, we must use an extended
opcode. If the address depends on the size of this
if ((val & ((1 << operand->shift) - 1)) != 0)
{
fragp->fr_subtype =
- RELAX_MIPS16_MARK_LONG_BRANCH (fragp->fr_subtype);
+ RELAX_MIPS16_MARK_ALWAYS_EXTENDED (fragp->fr_subtype);
return 1;
}
&& ! RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
{
fragp->fr_subtype =
- RELAX_MIPS16_MARK_LONG_BRANCH (fragp->fr_subtype);
+ RELAX_MIPS16_MARK_ALWAYS_EXTENDED (fragp->fr_subtype);
return 1;
}
}
return !mips16_immed_in_range_p (operand, BFD_RELOC_UNUSED, val);
}
+/* Given a MIPS16 variant frag FRAGP, return non-zero if it needs
+ macro expansion. SEC is the section the frag is in. We only
+ support PC-relative instructions (LA, DLA, LW, LD) here, in
+ non-PIC code using 32-bit addressing. */
+
+static int
+mips16_macro_frag (fragS *fragp, asection *sec, long stretch)
+{
+ const struct mips_pcrel_operand *pcrel_op;
+ const struct mips_int_operand *operand;
+ offsetT val;
+ segT symsec;
+ int type;
+
+ gas_assert (!RELAX_MIPS16_USER_SMALL (fragp->fr_subtype));
+
+ if (RELAX_MIPS16_USER_EXT (fragp->fr_subtype))
+ return 0;
+ if (!RELAX_MIPS16_SYM32 (fragp->fr_subtype))
+ return 0;
+
+ type = RELAX_MIPS16_TYPE (fragp->fr_subtype);
+ switch (type)
+ {
+ case 'A':
+ case 'B':
+ case 'E':
+ symsec = S_GET_SEGMENT (fragp->fr_symbol);
+ if (bfd_is_abs_section (symsec))
+ return 1;
+ if (RELAX_MIPS16_PIC (fragp->fr_subtype))
+ return 0;
+ if (S_FORCE_RELOC (fragp->fr_symbol, TRUE) || sec != symsec)
+ return 1;
+
+ operand = mips16_immed_operand (type, TRUE);
+ val = S_GET_VALUE (fragp->fr_symbol) + fragp->fr_offset;
+ pcrel_op = (const struct mips_pcrel_operand *) operand;
+ val = mips16_pcrel_val (fragp, pcrel_op, val, stretch);
+
+ return !mips16_immed_in_range_p (operand, BFD_RELOC_UNUSED, val);
+
+ default:
+ return 0;
+ }
+}
+
/* Compute the length of a branch sequence, and adjust the
RELAX_BRANCH_TOOFAR bit accordingly. If FRAGP is NULL, the
worst-case length is computed, with UPDATE being used to indicate
if (fragp && update && toofar != RELAX_BRANCH_TOOFAR (fragp->fr_subtype))
fragp->fr_subtype
= RELAX_BRANCH_ENCODE (RELAX_BRANCH_AT (fragp->fr_subtype),
+ RELAX_BRANCH_PIC (fragp->fr_subtype),
RELAX_BRANCH_UNCOND (fragp->fr_subtype),
RELAX_BRANCH_LIKELY (fragp->fr_subtype),
RELAX_BRANCH_LINK (fragp->fr_subtype),
if (fragp ? RELAX_BRANCH_LIKELY (fragp->fr_subtype) : (update > 0))
length += 8;
- if (mips_pic != NO_PIC)
+ if (!fragp || RELAX_BRANCH_PIC (fragp->fr_subtype))
{
/* Additional space for PIC loading of target address. */
length += 8;
{
bfd_boolean insn32 = TRUE;
bfd_boolean nods = TRUE;
+ bfd_boolean pic = TRUE;
bfd_boolean al = TRUE;
int short_insn_size;
bfd_boolean toofar;
{
insn32 = RELAX_MICROMIPS_INSN32 (fragp->fr_subtype);
nods = RELAX_MICROMIPS_NODS (fragp->fr_subtype);
+ pic = RELAX_MICROMIPS_PIC (fragp->fr_subtype);
al = RELAX_MICROMIPS_LINK (fragp->fr_subtype);
}
short_insn_size = insn32 ? 4 : 2;
# compact && (!PIC || insn32)
0:
*/
- if ((mips_pic == NO_PIC || insn32) && (!compact_known || compact))
+ if ((!pic || insn32) && (!compact_known || compact))
length += short_insn_size;
/* If assembling PIC code, we further turn:
d/addiu at, %lo(label) # 4 bytes
jr/c at # 2/4 bytes
*/
- if (mips_pic != NO_PIC)
+ if (pic)
length += 4 + short_insn_size;
/* Add an extra nop if the jump has no compact form and we need
to fill the delay slot. */
- if ((mips_pic == NO_PIC || al) && nods)
+ if ((!pic || al) && nods)
length += (fragp
? frag_branch_delay_slot_size (fragp, al, short_insn_size)
: short_insn_size);
}
if (RELAX_MIPS16_P (fragp->fr_subtype))
- /* We don't want to modify the EXTENDED bit here; it might get us
- into infinite loops. We change it only in mips_relax_frag(). */
- return (RELAX_MIPS16_EXTENDED (fragp->fr_subtype) ? 4 : 2);
+ {
+ /* We don't want to modify the EXTENDED bit here; it might get us
+ into infinite loops. We change it only in mips_relax_frag(). */
+ if (RELAX_MIPS16_MACRO (fragp->fr_subtype))
+ return RELAX_MIPS16_E2 (fragp->fr_subtype) ? 8 : 12;
+ else
+ return RELAX_MIPS16_EXTENDED (fragp->fr_subtype) ? 4 : 2;
+ }
if (RELAX_MICROMIPS_P (fragp->fr_subtype))
{
return length;
}
- if (mips_pic == NO_PIC)
- change = nopic_need_relax (fragp->fr_symbol, 0);
- else if (mips_pic == SVR4_PIC)
- change = pic_need_relax (fragp->fr_symbol);
- else if (mips_pic == VXWORKS_PIC)
+ if (mips_pic == VXWORKS_PIC)
/* For vxworks, GOT16 relocations never have a corresponding LO16. */
change = 0;
+ else if (RELAX_PIC (fragp->fr_subtype))
+ change = pic_need_relax (fragp->fr_symbol);
else
- abort ();
+ change = nopic_need_relax (fragp->fr_symbol, 0);
if (change)
{
if (! RELAX_MIPS16_P (fragp->fr_subtype))
return 0;
- if (mips16_extended_frag (fragp, sec, stretch))
+ if (!mips16_extended_frag (fragp, sec, stretch))
{
- if (RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
+ if (RELAX_MIPS16_MACRO (fragp->fr_subtype))
+ {
+ fragp->fr_subtype = RELAX_MIPS16_CLEAR_MACRO (fragp->fr_subtype);
+ return RELAX_MIPS16_E2 (fragp->fr_subtype) ? -6 : -10;
+ }
+ else if (RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
+ {
+ fragp->fr_subtype = RELAX_MIPS16_CLEAR_EXTENDED (fragp->fr_subtype);
+ return -2;
+ }
+ else
+ return 0;
+ }
+ else if (!mips16_macro_frag (fragp, sec, stretch))
+ {
+ if (RELAX_MIPS16_MACRO (fragp->fr_subtype))
+ {
+ fragp->fr_subtype = RELAX_MIPS16_CLEAR_MACRO (fragp->fr_subtype);
+ fragp->fr_subtype = RELAX_MIPS16_MARK_EXTENDED (fragp->fr_subtype);
+ return RELAX_MIPS16_E2 (fragp->fr_subtype) ? -4 : -8;
+ }
+ else if (!RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
+ {
+ fragp->fr_subtype = RELAX_MIPS16_MARK_EXTENDED (fragp->fr_subtype);
+ return 2;
+ }
+ else
return 0;
- fragp->fr_subtype = RELAX_MIPS16_MARK_EXTENDED (fragp->fr_subtype);
- return 2;
}
else
{
- if (! RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
+ if (RELAX_MIPS16_MACRO (fragp->fr_subtype))
return 0;
- fragp->fr_subtype = RELAX_MIPS16_CLEAR_EXTENDED (fragp->fr_subtype);
- return -2;
+ else if (RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
+ {
+ fragp->fr_subtype = RELAX_MIPS16_CLEAR_EXTENDED (fragp->fr_subtype);
+ fragp->fr_subtype = RELAX_MIPS16_MARK_MACRO (fragp->fr_subtype);
+ return RELAX_MIPS16_E2 (fragp->fr_subtype) ? 4 : 8;
+ }
+ else
+ {
+ fragp->fr_subtype = RELAX_MIPS16_MARK_MACRO (fragp->fr_subtype);
+ return RELAX_MIPS16_E2 (fragp->fr_subtype) ? 6 : 10;
+ }
}
return 0;
}
uncond:
- if (mips_pic == NO_PIC)
+ if (!RELAX_BRANCH_PIC (fragp->fr_subtype))
{
/* j or jal. */
insn = (RELAX_BRANCH_LINK (fragp->fr_subtype)
bfd_boolean compact = RELAX_MICROMIPS_COMPACT (fragp->fr_subtype);
bfd_boolean insn32 = RELAX_MICROMIPS_INSN32 (fragp->fr_subtype);
bfd_boolean nods = RELAX_MICROMIPS_NODS (fragp->fr_subtype);
+ bfd_boolean pic = RELAX_MICROMIPS_PIC (fragp->fr_subtype);
bfd_boolean al = RELAX_MICROMIPS_LINK (fragp->fr_subtype);
int type = RELAX_MICROMIPS_TYPE (fragp->fr_subtype);
bfd_boolean short_ds;
}
}
- if (mips_pic == NO_PIC)
+ if (!pic)
{
unsigned long jal = (short_ds || nods
? 0x74000000 : 0xf4000000); /* jal/s */
const struct mips_int_operand *operand;
offsetT val;
char *buf;
- unsigned int user_length, length;
+ unsigned int user_length;
bfd_boolean need_reloc;
unsigned long insn;
+ bfd_boolean mac;
bfd_boolean ext;
segT symsec;
type = RELAX_MIPS16_TYPE (fragp->fr_subtype);
operand = mips16_immed_operand (type, FALSE);
+ mac = RELAX_MIPS16_MACRO (fragp->fr_subtype);
ext = RELAX_MIPS16_EXTENDED (fragp->fr_subtype);
val = resolve_symbol_value (fragp->fr_symbol) + fragp->fr_offset;
symsec = S_GET_SEGMENT (fragp->fr_symbol);
need_reloc = (S_FORCE_RELOC (fragp->fr_symbol, TRUE)
- || (operand->root.type == OP_PCREL
+ || (operand->root.type == OP_PCREL && !mac
? asec != symsec
: !bfd_is_abs_section (symsec)));
- if (operand->root.type == OP_PCREL)
+ if (operand->root.type == OP_PCREL && !mac)
{
const struct mips_pcrel_operand *pcrel_op;
- addressT addr;
pcrel_op = (const struct mips_pcrel_operand *) operand;
- addr = fragp->fr_address + fragp->fr_fix;
- /* The rules for the base address of a PC relative reloc are
- complicated; see mips16_extended_frag. */
- if (pcrel_op->include_isa_bit)
+ if (pcrel_op->include_isa_bit && !need_reloc)
{
- if (!need_reloc)
- {
- if (!ELF_ST_IS_MIPS16 (S_GET_OTHER (fragp->fr_symbol)))
- as_bad_where (fragp->fr_file, fragp->fr_line,
- _("branch to a symbol in another ISA mode"));
- else if ((fragp->fr_offset & 0x1) != 0)
- as_bad_where (fragp->fr_file, fragp->fr_line,
- _("branch to misaligned address (0x%lx)"),
- (long) val);
- }
- addr += 2;
- if (ext)
- addr += 2;
- /* Ignore the low bit in the target, since it will be
- set for a text label. */
- val &= -2;
+ if (!ELF_ST_IS_MIPS16 (S_GET_OTHER (fragp->fr_symbol)))
+ as_bad_where (fragp->fr_file, fragp->fr_line,
+ _("branch to a symbol in another ISA mode"));
+ else if ((fragp->fr_offset & 0x1) != 0)
+ as_bad_where (fragp->fr_file, fragp->fr_line,
+ _("branch to misaligned address (0x%lx)"),
+ (long) val);
}
- else if (RELAX_MIPS16_JAL_DSLOT (fragp->fr_subtype))
- addr -= 4;
- else if (RELAX_MIPS16_DSLOT (fragp->fr_subtype))
- addr -= 2;
- addr &= -(1 << pcrel_op->align_log2);
- val -= addr;
+ val = mips16_pcrel_val (fragp, pcrel_op, val, 0);
/* Make sure the section winds up with the alignment we have
assumed. */
record_alignment (asec, operand->shift);
}
- if (ext
- && (RELAX_MIPS16_JAL_DSLOT (fragp->fr_subtype)
- || RELAX_MIPS16_DSLOT (fragp->fr_subtype)))
+ if (RELAX_MIPS16_JAL_DSLOT (fragp->fr_subtype)
+ || RELAX_MIPS16_DSLOT (fragp->fr_subtype))
+ {
+ if (mac)
+ as_warn_where (fragp->fr_file, fragp->fr_line,
+ _("macro instruction expanded into multiple "
+ "instructions in a branch delay slot"));
+ else if (ext)
+ as_warn_where (fragp->fr_file, fragp->fr_line,
+ _("extended instruction in a branch delay slot"));
+ }
+ else if (RELAX_MIPS16_NOMACRO (fragp->fr_subtype) && mac)
as_warn_where (fragp->fr_file, fragp->fr_line,
- _("extended instruction in delay slot"));
+ _("macro instruction expanded into multiple "
+ "instructions"));
buf = fragp->fr_literal + fragp->fr_fix;
else
user_length = 0;
- if (need_reloc)
+ if (mac)
{
- bfd_reloc_code_real_type reloc = BFD_RELOC_NONE;
- expressionS exp;
- fixS *fixp;
+ unsigned long reg;
+ unsigned long new;
+ unsigned long op;
+ bfd_boolean e2;
+
+ gas_assert (type == 'A' || type == 'B' || type == 'E');
+ gas_assert (RELAX_MIPS16_SYM32 (fragp->fr_subtype));
+
+ e2 = RELAX_MIPS16_E2 (fragp->fr_subtype);
+
+ if (need_reloc)
+ {
+ fixS *fixp;
+
+ gas_assert (!RELAX_MIPS16_PIC (fragp->fr_subtype));
+
+ fixp = fix_new (fragp, buf - fragp->fr_literal, 4,
+ fragp->fr_symbol, fragp->fr_offset,
+ FALSE, BFD_RELOC_MIPS16_HI16_S);
+ fixp->fx_file = fragp->fr_file;
+ fixp->fx_line = fragp->fr_line;
+
+ fixp = fix_new (fragp, buf - fragp->fr_literal + (e2 ? 4 : 8), 4,
+ fragp->fr_symbol, fragp->fr_offset,
+ FALSE, BFD_RELOC_MIPS16_LO16);
+ fixp->fx_file = fragp->fr_file;
+ fixp->fx_line = fragp->fr_line;
- switch (type)
+ val = 0;
+ }
+
+ switch (insn & 0xf800)
{
- case 'p':
- case 'q':
- reloc = BFD_RELOC_MIPS16_16_PCREL_S1;
+ case 0x0800: /* ADDIU */
+ reg = (insn >> 8) & 0x7;
+ op = 0xf0004800 | (reg << 8);
break;
- default:
- as_bad_where (fragp->fr_file, fragp->fr_line,
- _("unsupported relocation"));
+ case 0xb000: /* LW */
+ reg = (insn >> 8) & 0x7;
+ op = 0xf0009800 | (reg << 8) | (reg << 5);
+ break;
+ case 0xf800: /* I64 */
+ reg = (insn >> 5) & 0x7;
+ switch (insn & 0x0700)
+ {
+ case 0x0400: /* LD */
+ op = 0xf0003800 | (reg << 8) | (reg << 5);
+ break;
+ case 0x0600: /* DADDIU */
+ op = 0xf000fd00 | (reg << 5);
+ break;
+ default:
+ abort ();
+ }
break;
+ default:
+ abort ();
}
- if (reloc == BFD_RELOC_NONE)
- ;
- else if (ext)
+
+ new = (e2 ? 0xf0006820 : 0xf0006800) | (reg << 8); /* LUI/LI */
+ new |= mips16_immed_extend ((val + 0x8000) >> 16, 16);
+ buf = write_compressed_insn (buf, new, 4);
+ if (!e2)
{
- exp.X_op = O_symbol;
- exp.X_add_symbol = fragp->fr_symbol;
- exp.X_add_number = fragp->fr_offset;
+ new = 0xf4003000 | (reg << 8) | (reg << 5); /* SLL */
+ buf = write_compressed_insn (buf, new, 4);
+ }
+ op |= mips16_immed_extend (val, 16);
+ buf = write_compressed_insn (buf, op, 4);
- fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 2, &exp,
- TRUE, reloc);
+ fragp->fr_fix += e2 ? 8 : 12;
+ }
+ else
+ {
+ unsigned int length = ext ? 4 : 2;
- fixp->fx_file = fragp->fr_file;
- fixp->fx_line = fragp->fr_line;
+ if (need_reloc)
+ {
+ bfd_reloc_code_real_type reloc = BFD_RELOC_NONE;
+ expressionS exp;
+ fixS *fixp;
- /* These relocations can have an addend that won't fit
- in 2 octets. */
- fixp->fx_no_overflow = 1;
+ switch (type)
+ {
+ case 'p':
+ case 'q':
+ reloc = BFD_RELOC_MIPS16_16_PCREL_S1;
+ break;
+ default:
+ break;
+ }
+ if (mac || reloc == BFD_RELOC_NONE)
+ as_bad_where (fragp->fr_file, fragp->fr_line,
+ _("unsupported relocation"));
+ else if (ext)
+ {
+ exp.X_op = O_symbol;
+ exp.X_add_symbol = fragp->fr_symbol;
+ exp.X_add_number = fragp->fr_offset;
+
+ fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp,
+ TRUE, reloc);
+
+ fixp->fx_file = fragp->fr_file;
+ fixp->fx_line = fragp->fr_line;
+ }
+ else
+ as_bad_where (fragp->fr_file, fragp->fr_line,
+ _("invalid unextended operand value"));
}
else
- as_bad_where (fragp->fr_file, fragp->fr_line,
- _("invalid unextended operand value"));
- }
- else
- mips16_immed (fragp->fr_file, fragp->fr_line, type,
- BFD_RELOC_UNUSED, val, user_length, &insn);
+ mips16_immed (fragp->fr_file, fragp->fr_line, type,
+ BFD_RELOC_UNUSED, val, user_length, &insn);
- length = (ext ? 4 : 2);
- gas_assert (mips16_opcode_length (insn) == length);
- write_compressed_insn (buf, insn, length);
- fragp->fr_fix += length;
+ gas_assert (mips16_opcode_length (insn) == length);
+ write_compressed_insn (buf, insn, length);
+ fragp->fr_fix += length;
+ }
}
else
{
ext_ases |= AFL_ASE_MSA;
if (ase & ASE_XPA)
ext_ases |= AFL_ASE_XPA;
+ if (ase & ASE_MIPS16E2)
+ ext_ases |= file_ase_mips16 ? AFL_ASE_MIPS16E2 : 0;
return ext_ases;
}
cur_proc_ptr->func_end_sym = exp->X_add_symbol;
}
+#ifdef md_flush_pending_output
+ md_flush_pending_output ();
+#endif
+
/* Generate a .pdr section. */
if (!ECOFF_DEBUGGING && mips_flag_pdr)
{
expressionS exp;
char *fragp;
-#ifdef md_flush_pending_output
- md_flush_pending_output ();
-#endif
-
gas_assert (pdr_seg);
subseg_set (pdr_seg, 0);
{ "1004kf1_1", 0, ASE_DSP | ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 },
/* 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", 0, ASE_MCU, ISA_MIPS32R5, CPU_MIPS32R5 },
{ "m5101", 0, ASE_MCU, ISA_MIPS32R5, CPU_MIPS32R5 },