/* True for mips16 instructions that jump to an absolute address. */
unsigned int mips16_absolute_jump_p : 1;
+
+ /* True if this instruction is complete. */
+ unsigned int complete_p : 1;
};
/* The ABI to use. */
/* MIPS ISA we are using for this output file. */
static int file_mips_isa = ISA_UNKNOWN;
-/* True if -mips16 was passed or implied by arguments passed on the
- command line (e.g., by -march). */
+/* True if any MIPS16 code was produced. */
static int file_ase_mips16;
#define ISA_SUPPORTS_MIPS16E (mips_opts.isa == ISA_MIPS32 \
/* ...likewise -mfix-24k. */
static int mips_fix_24k;
+/* ...likewise -mfix-cn63xxp1 */
+static bfd_boolean mips_fix_cn63xxp1;
+
/* 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
but it's not clear that it would actually improve performance. */
-#define RELAX_BRANCH_ENCODE(uncond, likely, link, toofar) \
- ((relax_substateT) \
- (0xc0000000 \
- | ((toofar) ? 1 : 0) \
- | ((link) ? 2 : 0) \
- | ((likely) ? 4 : 0) \
- | ((uncond) ? 8 : 0)))
+#define RELAX_BRANCH_ENCODE(at, uncond, likely, link, toofar) \
+ ((relax_substateT) \
+ (0xc0000000 \
+ | ((at) & 0x1f) \
+ | ((toofar) ? 0x20 : 0) \
+ | ((link) ? 0x40 : 0) \
+ | ((likely) ? 0x80 : 0) \
+ | ((uncond) ? 0x100 : 0)))
#define RELAX_BRANCH_P(i) (((i) & 0xf0000000) == 0xc0000000)
-#define RELAX_BRANCH_UNCOND(i) (((i) & 8) != 0)
-#define RELAX_BRANCH_LIKELY(i) (((i) & 4) != 0)
-#define RELAX_BRANCH_LINK(i) (((i) & 2) != 0)
-#define RELAX_BRANCH_TOOFAR(i) (((i) & 1) != 0)
+#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_AT(i) ((i) & 0x1f)
/* For mips16 code, we use an entirely different form of relaxation.
mips16 supports two versions of most instructions which take
static void macro_end (void);
static void macro (struct mips_cl_insn * ip);
static void mips16_macro (struct mips_cl_insn * ip);
-#ifdef LOSING_COMPILER
-static void macro2 (struct mips_cl_insn * ip);
-#endif
static void mips_ip (char *str, struct mips_cl_insn * ip);
static void mips16_ip (char *str, struct mips_cl_insn * ip);
static void mips16_immed
{"origin", s_org, 0},
{"repeat", s_rept, 0},
+ /* For MIPS this is non-standard, but we define it for consistency. */
+ {"sbss", s_change_sec, 'B'},
+
/* These pseudo-ops are defined in read.c, but must be overridden
here for one reason or another. */
{"align", s_align, 0},
{ NULL, NULL, 0 },
};
+/* Export the ABI address size for use by TC_ADDRESS_BYTES for the
+ purpose of the `.dc.a' internal pseudo-op. */
+
+int
+mips_address_bytes (void)
+{
+ return HAVE_64BIT_ADDRESSES ? 8 : 4;
+}
+
extern void pop_insert (const pseudo_typeS *);
void
/* The default target format to use. */
+#if defined (TE_FreeBSD)
+#define ELF_TARGET(PREFIX, ENDIAN) PREFIX "trad" ENDIAN "mips-freebsd"
+#elif defined (TE_TMIPS)
+#define ELF_TARGET(PREFIX, ENDIAN) PREFIX "trad" ENDIAN "mips"
+#else
+#define ELF_TARGET(PREFIX, ENDIAN) PREFIX ENDIAN "mips"
+#endif
+
const char *
mips_target_format (void)
{
? "elf32-bigmips-vxworks"
: "elf32-littlemips-vxworks");
#endif
-#ifdef TE_TMIPS
- /* This is traditional mips. */
return (target_big_endian
? (HAVE_64BIT_OBJECTS
- ? "elf64-tradbigmips"
+ ? ELF_TARGET ("elf64-", "big")
: (HAVE_NEWABI
- ? "elf32-ntradbigmips" : "elf32-tradbigmips"))
+ ? ELF_TARGET ("elf32-n", "big")
+ : ELF_TARGET ("elf32-", "big")))
: (HAVE_64BIT_OBJECTS
- ? "elf64-tradlittlemips"
+ ? ELF_TARGET ("elf64-", "little")
: (HAVE_NEWABI
- ? "elf32-ntradlittlemips" : "elf32-tradlittlemips")));
-#else
- return (target_big_endian
- ? (HAVE_64BIT_OBJECTS
- ? "elf64-bigmips"
- : (HAVE_NEWABI
- ? "elf32-nbigmips" : "elf32-bigmips"))
- : (HAVE_64BIT_OBJECTS
- ? "elf64-littlemips"
- : (HAVE_NEWABI
- ? "elf32-nlittlemips" : "elf32-littlemips")));
-#endif
+ ? ELF_TARGET ("elf32-n", "little")
+ : ELF_TARGET ("elf32-", "little"))));
default:
abort ();
return NULL;
insn->fixed_p = (mips_opts.noreorder > 0);
insn->noreorder_p = (mips_opts.noreorder > 0);
insn->mips16_absolute_jump_p = 0;
+ insn->complete_p = 0;
}
/* Record the current MIPS16 mode in now_seg. */
void
md_mips_end (void)
{
+ mips_emit_delays ();
if (! ECOFF_DEBUGGING)
md_obj_end ();
}
&& fixp->fx_offset == fixp->fx_next->fx_offset);
}
-/* See whether instruction IP reads register REG. CLASS is the type
- of register. */
-
-static int
-insn_uses_reg (const struct mips_cl_insn *ip, unsigned int reg,
- enum mips_regclass regclass)
-{
- if (regclass == MIPS16_REG)
- {
- gas_assert (mips_opts.mips16);
- reg = mips16_to_32_reg_map[reg];
- regclass = MIPS_GR_REG;
- }
-
- /* Don't report on general register ZERO, since it never changes. */
- if (regclass == MIPS_GR_REG && reg == ZERO)
- return 0;
-
- if (regclass == MIPS_FP_REG)
- {
- gas_assert (! mips_opts.mips16);
- /* If we are called with either $f0 or $f1, we must check $f0.
- This is not optimal, because it will introduce an unnecessary
- NOP between "lwc1 $f0" and "swc1 $f1". To fix this we would
- need to distinguish reading both $f0 and $f1 or just one of
- them. Note that we don't have to check the other way,
- because there is no instruction that sets both $f0 and $f1
- and requires a delay. */
- if ((ip->insn_mo->pinfo & INSN_READ_FPR_S)
- && ((EXTRACT_OPERAND (FS, *ip) & ~(unsigned) 1)
- == (reg &~ (unsigned) 1)))
- return 1;
- if ((ip->insn_mo->pinfo & INSN_READ_FPR_T)
- && ((EXTRACT_OPERAND (FT, *ip) & ~(unsigned) 1)
- == (reg &~ (unsigned) 1)))
- return 1;
- }
- else if (! mips_opts.mips16)
- {
- if ((ip->insn_mo->pinfo & INSN_READ_GPR_S)
- && EXTRACT_OPERAND (RS, *ip) == reg)
- return 1;
- if ((ip->insn_mo->pinfo & INSN_READ_GPR_T)
- && EXTRACT_OPERAND (RT, *ip) == reg)
- return 1;
- }
- else
- {
- if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_X)
- && mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RX, *ip)] == reg)
- return 1;
- if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_Y)
- && mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RY, *ip)] == reg)
- return 1;
- if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_Z)
- && (mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (MOVE32Z, *ip)]
- == reg))
- return 1;
- if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_T) && reg == TREG)
- return 1;
- if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_SP) && reg == SP)
- return 1;
- if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_31) && reg == RA)
- return 1;
- if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_GPR_X)
- && MIPS16_EXTRACT_OPERAND (REGR32, *ip) == reg)
- return 1;
- }
-
- return 0;
-}
-
/* This function returns true if modifying a register requires a
delay. */
mips_relax.sequence = 0;
}
+/* Return the mask of core registers that IP reads. */
+
+static unsigned int
+gpr_read_mask (const struct mips_cl_insn *ip)
+{
+ unsigned long pinfo, pinfo2;
+ unsigned int mask;
+
+ mask = 0;
+ pinfo = ip->insn_mo->pinfo;
+ pinfo2 = ip->insn_mo->pinfo2;
+ if (mips_opts.mips16)
+ {
+ if (pinfo & MIPS16_INSN_READ_X)
+ mask |= 1 << mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RX, *ip)];
+ if (pinfo & MIPS16_INSN_READ_Y)
+ mask |= 1 << mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RY, *ip)];
+ if (pinfo & MIPS16_INSN_READ_T)
+ mask |= 1 << TREG;
+ if (pinfo & MIPS16_INSN_READ_SP)
+ mask |= 1 << SP;
+ if (pinfo & MIPS16_INSN_READ_31)
+ mask |= 1 << RA;
+ if (pinfo & MIPS16_INSN_READ_Z)
+ mask |= 1 << (mips16_to_32_reg_map
+ [MIPS16_EXTRACT_OPERAND (MOVE32Z, *ip)]);
+ if (pinfo & MIPS16_INSN_READ_GPR_X)
+ mask |= 1 << MIPS16_EXTRACT_OPERAND (REGR32, *ip);
+ }
+ else
+ {
+ if (pinfo2 & INSN2_READ_GPR_D)
+ mask |= 1 << EXTRACT_OPERAND (RD, *ip);
+ if (pinfo & INSN_READ_GPR_T)
+ mask |= 1 << EXTRACT_OPERAND (RT, *ip);
+ if (pinfo & INSN_READ_GPR_S)
+ mask |= 1 << EXTRACT_OPERAND (RS, *ip);
+ if (pinfo2 & INSN2_READ_GPR_Z)
+ mask |= 1 << EXTRACT_OPERAND (RZ, *ip);
+ }
+ return mask & ~0;
+}
+
+/* Return the mask of core registers that IP writes. */
+
+static unsigned int
+gpr_write_mask (const struct mips_cl_insn *ip)
+{
+ unsigned long pinfo, pinfo2;
+ unsigned int mask;
+
+ mask = 0;
+ pinfo = ip->insn_mo->pinfo;
+ pinfo2 = ip->insn_mo->pinfo2;
+ if (mips_opts.mips16)
+ {
+ if (pinfo & MIPS16_INSN_WRITE_X)
+ mask |= 1 << mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RX, *ip)];
+ if (pinfo & MIPS16_INSN_WRITE_Y)
+ mask |= 1 << mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RY, *ip)];
+ if (pinfo & MIPS16_INSN_WRITE_Z)
+ mask |= 1 << mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RZ, *ip)];
+ if (pinfo & MIPS16_INSN_WRITE_T)
+ mask |= 1 << TREG;
+ if (pinfo & MIPS16_INSN_WRITE_SP)
+ mask |= 1 << SP;
+ if (pinfo & MIPS16_INSN_WRITE_31)
+ mask |= 1 << RA;
+ if (pinfo & MIPS16_INSN_WRITE_GPR_Y)
+ mask |= 1 << MIPS16OP_EXTRACT_REG32R (ip->insn_opcode);
+ }
+ else
+ {
+ if (pinfo & INSN_WRITE_GPR_D)
+ mask |= 1 << EXTRACT_OPERAND (RD, *ip);
+ if (pinfo & INSN_WRITE_GPR_T)
+ mask |= 1 << EXTRACT_OPERAND (RT, *ip);
+ if (pinfo & INSN_WRITE_GPR_31)
+ mask |= 1 << RA;
+ if (pinfo2 & INSN2_WRITE_GPR_Z)
+ mask |= 1 << EXTRACT_OPERAND (RZ, *ip);
+ }
+ return mask & ~0;
+}
+
+/* Return the mask of floating-point registers that IP reads. */
+
+static unsigned int
+fpr_read_mask (const struct mips_cl_insn *ip)
+{
+ unsigned long pinfo, pinfo2;
+ unsigned int mask;
+
+ mask = 0;
+ pinfo = ip->insn_mo->pinfo;
+ pinfo2 = ip->insn_mo->pinfo2;
+ if (!mips_opts.mips16)
+ {
+ if (pinfo & INSN_READ_FPR_S)
+ mask |= 1 << EXTRACT_OPERAND (FS, *ip);
+ if (pinfo & INSN_READ_FPR_T)
+ mask |= 1 << EXTRACT_OPERAND (FT, *ip);
+ if (pinfo & INSN_READ_FPR_R)
+ mask |= 1 << EXTRACT_OPERAND (FR, *ip);
+ if (pinfo2 & INSN2_READ_FPR_Z)
+ mask |= 1 << EXTRACT_OPERAND (FZ, *ip);
+ }
+ /* Conservatively treat all operands to an FP_D instruction are doubles.
+ (This is overly pessimistic for things like cvt.d.s.) */
+ if (HAVE_32BIT_FPRS && (pinfo & FP_D))
+ mask |= mask << 1;
+ return mask;
+}
+
+/* Return the mask of floating-point registers that IP writes. */
+
+static unsigned int
+fpr_write_mask (const struct mips_cl_insn *ip)
+{
+ unsigned long pinfo, pinfo2;
+ unsigned int mask;
+
+ mask = 0;
+ pinfo = ip->insn_mo->pinfo;
+ pinfo2 = ip->insn_mo->pinfo2;
+ if (!mips_opts.mips16)
+ {
+ if (pinfo & INSN_WRITE_FPR_D)
+ mask |= 1 << EXTRACT_OPERAND (FD, *ip);
+ if (pinfo & INSN_WRITE_FPR_S)
+ mask |= 1 << EXTRACT_OPERAND (FS, *ip);
+ if (pinfo & INSN_WRITE_FPR_T)
+ mask |= 1 << EXTRACT_OPERAND (FT, *ip);
+ if (pinfo2 & INSN2_WRITE_FPR_Z)
+ mask |= 1 << EXTRACT_OPERAND (FZ, *ip);
+ }
+ /* Conservatively treat all operands to an FP_D instruction are doubles.
+ (This is overly pessimistic for things like cvt.s.d.) */
+ if (HAVE_32BIT_FPRS && (pinfo & FP_D))
+ mask |= mask << 1;
+ return mask;
+}
+
/* Classify an instruction according to the FIX_VR4120_* enumeration.
Return NUM_FIX_VR4120_CLASSES if the instruction isn't affected
by VR4120 errata. */
const struct mips_cl_insn *insn2)
{
unsigned long pinfo1, pinfo2;
+ unsigned int mask;
/* This function needs to know which pinfo flags are set for INSN2
and which registers INSN2 uses. The former is stored in PINFO2 and
- the latter is tested via INSN2_USES_REG. If INSN2 is null, PINFO2
- will have every flag set and INSN2_USES_REG will always return true. */
+ the latter is tested via INSN2_USES_GPR. If INSN2 is null, PINFO2
+ will have every flag set and INSN2_USES_GPR will always return true. */
pinfo1 = insn1->insn_mo->pinfo;
pinfo2 = insn2 ? insn2->insn_mo->pinfo : ~0U;
-#define INSN2_USES_REG(REG, CLASS) \
- (insn2 == NULL || insn_uses_reg (insn2, REG, CLASS))
+#define INSN2_USES_GPR(REG) \
+ (insn2 == NULL || (gpr_read_mask (insn2) & (1U << (REG))) != 0)
/* For most targets, write-after-read dependencies on the HI and LO
registers must be separated by at least two instructions. */
between an mfhi or mflo and any instruction that uses the result. */
if (mips_7000_hilo_fix
&& MF_HILO_INSN (pinfo1)
- && INSN2_USES_REG (EXTRACT_OPERAND (RD, *insn1), MIPS_GR_REG))
+ && INSN2_USES_GPR (EXTRACT_OPERAND (RD, *insn1)))
return 2;
/* If we're working around 24K errata, one instruction is required
|| (!cop_interlocks && (pinfo1 & INSN_LOAD_COPROC_DELAY)))
{
know (pinfo1 & INSN_WRITE_GPR_T);
- if (INSN2_USES_REG (EXTRACT_OPERAND (RT, *insn1), MIPS_GR_REG))
+ if (INSN2_USES_GPR (EXTRACT_OPERAND (RT, *insn1)))
return 1;
}
/* Handle cases where INSN1 writes to a known general coprocessor
register. There must be a one instruction delay before INSN2
if INSN2 reads that register, otherwise no delay is needed. */
- if (pinfo1 & INSN_WRITE_FPR_T)
+ mask = fpr_write_mask (insn1);
+ if (mask != 0)
{
- if (INSN2_USES_REG (EXTRACT_OPERAND (FT, *insn1), MIPS_FP_REG))
- return 1;
- }
- else if (pinfo1 & INSN_WRITE_FPR_S)
- {
- if (INSN2_USES_REG (EXTRACT_OPERAND (FS, *insn1), MIPS_FP_REG))
+ if (!insn2 || (mask & fpr_read_mask (insn2)) != 0)
return 1;
}
else
return 1;
}
-#undef INSN2_USES_REG
+#undef INSN2_USES_GPR
return 0;
}
/* Return the number of nops that would be needed to work around the
VR4130 mflo/mfhi errata if instruction INSN immediately followed
- the MAX_VR4130_NOPS instructions described by HIST. */
+ the MAX_VR4130_NOPS instructions described by HIST. Ignore hazards
+ that are contained within the first IGNORE instructions of HIST. */
static int
-nops_for_vr4130 (const struct mips_cl_insn *hist,
+nops_for_vr4130 (int ignore, const struct mips_cl_insn *hist,
const struct mips_cl_insn *insn)
{
- int i, j, reg;
+ int i, j;
+ unsigned int mask;
/* Check if the instruction writes to HI or LO. MTHI and MTLO
are not affected by the errata. */
if (MF_HILO_INSN (hist[i].insn_mo->pinfo))
{
/* Extract the destination register. */
- if (mips_opts.mips16)
- reg = mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RX, hist[i])];
- else
- reg = EXTRACT_OPERAND (RD, hist[i]);
+ mask = gpr_write_mask (&hist[i]);
/* No nops are needed if INSN reads that register. */
- if (insn != NULL && insn_uses_reg (insn, reg, MIPS_GR_REG))
+ if (insn != NULL && (gpr_read_mask (insn) & mask) != 0)
return 0;
/* ...or if any of the intervening instructions do. */
for (j = 0; j < i; j++)
- if (insn_uses_reg (&hist[j], reg, MIPS_GR_REG))
+ if (gpr_read_mask (&hist[j]) & mask)
return 0;
- return MAX_VR4130_NOPS - i;
+ if (i >= ignore)
+ return MAX_VR4130_NOPS - i;
}
return 0;
}
+#define BASE_REG_EQ(INSN1, INSN2) \
+ ((((INSN1) >> OP_SH_RS) & OP_MASK_RS) \
+ == (((INSN2) >> OP_SH_RS) & OP_MASK_RS))
+
+/* Return the minimum alignment for this store instruction. */
+
+static int
+fix_24k_align_to (const struct mips_opcode *mo)
+{
+ if (strcmp (mo->name, "sh") == 0)
+ return 2;
+
+ if (strcmp (mo->name, "swc1") == 0
+ || strcmp (mo->name, "swc2") == 0
+ || strcmp (mo->name, "sw") == 0
+ || strcmp (mo->name, "sc") == 0
+ || strcmp (mo->name, "s.s") == 0)
+ return 4;
+
+ if (strcmp (mo->name, "sdc1") == 0
+ || strcmp (mo->name, "sdc2") == 0
+ || strcmp (mo->name, "s.d") == 0)
+ return 8;
+
+ /* sb, swl, swr */
+ return 1;
+}
+
+struct fix_24k_store_info
+ {
+ /* Immediate offset, if any, for this store instruction. */
+ short off;
+ /* Alignment required by this store instruction. */
+ int align_to;
+ /* True for register offsets. */
+ int register_offset;
+ };
+
+/* Comparison function used by qsort. */
+
+static int
+fix_24k_sort (const void *a, const void *b)
+{
+ const struct fix_24k_store_info *pos1 = a;
+ const struct fix_24k_store_info *pos2 = b;
+
+ return (pos1->off - pos2->off);
+}
+
+/* INSN is a store instruction. Try to record the store information
+ in STINFO. Return false if the information isn't known. */
+
+static bfd_boolean
+fix_24k_record_store_info (struct fix_24k_store_info *stinfo,
+ const struct mips_cl_insn *insn)
+{
+ /* The instruction must have a known offset. */
+ if (!insn->complete_p || !strstr (insn->insn_mo->args, "o("))
+ return FALSE;
+
+ stinfo->off = (insn->insn_opcode >> OP_SH_IMMEDIATE) & OP_MASK_IMMEDIATE;
+ stinfo->align_to = fix_24k_align_to (insn->insn_mo);
+ return TRUE;
+}
+
+/* Return the number of nops that would be needed to work around the 24k
+ "lost data on stores during refill" errata if instruction INSN
+ immediately followed the 2 instructions described by HIST.
+ Ignore hazards that are contained within the first IGNORE
+ instructions of HIST.
+
+ Problem: The FSB (fetch store buffer) acts as an intermediate buffer
+ for the data cache refills and store data. The following describes
+ the scenario where the store data could be lost.
+
+ * A data cache miss, due to either a load or a store, causing fill
+ data to be supplied by the memory subsystem
+ * The first three doublewords of fill data are returned and written
+ into the cache
+ * A sequence of four stores occurs in consecutive cycles around the
+ final doubleword of the fill:
+ * Store A
+ * Store B
+ * Store C
+ * Zero, One or more instructions
+ * Store D
+
+ The four stores A-D must be to different doublewords of the line that
+ is being filled. The fourth instruction in the sequence above permits
+ the fill of the final doubleword to be transferred from the FSB into
+ the cache. In the sequence above, the stores may be either integer
+ (sb, sh, sw, swr, swl, sc) or coprocessor (swc1/swc2, sdc1/sdc2,
+ swxc1, sdxc1, suxc1) stores, as long as the four stores are to
+ different doublewords on the line. If the floating point unit is
+ running in 1:2 mode, it is not possible to create the sequence above
+ using only floating point store instructions.
+
+ In this case, the cache line being filled is incorrectly marked
+ invalid, thereby losing the data from any store to the line that
+ occurs between the original miss and the completion of the five
+ cycle sequence shown above.
+
+ The workarounds are:
+
+ * Run the data cache in write-through mode.
+ * Insert a non-store instruction between
+ Store A and Store B or Store B and Store C. */
+
+static int
+nops_for_24k (int ignore, const struct mips_cl_insn *hist,
+ const struct mips_cl_insn *insn)
+{
+ struct fix_24k_store_info pos[3];
+ int align, i, base_offset;
+
+ if (ignore >= 2)
+ return 0;
+
+ /* If the previous instruction wasn't a store, there's nothing to
+ worry about. */
+ if ((hist[0].insn_mo->pinfo & INSN_STORE_MEMORY) == 0)
+ return 0;
+
+ /* If the instructions after the previous one are unknown, we have
+ to assume the worst. */
+ if (!insn)
+ return 1;
+
+ /* Check whether we are dealing with three consecutive stores. */
+ if ((insn->insn_mo->pinfo & INSN_STORE_MEMORY) == 0
+ || (hist[1].insn_mo->pinfo & INSN_STORE_MEMORY) == 0)
+ return 0;
+
+ /* If we don't know the relationship between the store addresses,
+ assume the worst. */
+ if (!BASE_REG_EQ (insn->insn_opcode, hist[0].insn_opcode)
+ || !BASE_REG_EQ (insn->insn_opcode, hist[1].insn_opcode))
+ return 1;
+
+ if (!fix_24k_record_store_info (&pos[0], insn)
+ || !fix_24k_record_store_info (&pos[1], &hist[0])
+ || !fix_24k_record_store_info (&pos[2], &hist[1]))
+ return 1;
+
+ qsort (&pos, 3, sizeof (struct fix_24k_store_info), fix_24k_sort);
+
+ /* Pick a value of ALIGN and X such that all offsets are adjusted by
+ X bytes and such that the base register + X is known to be aligned
+ to align bytes. */
+
+ if (((insn->insn_opcode >> OP_SH_RS) & OP_MASK_RS) == SP)
+ align = 8;
+ else
+ {
+ align = pos[0].align_to;
+ base_offset = pos[0].off;
+ for (i = 1; i < 3; i++)
+ if (align < pos[i].align_to)
+ {
+ align = pos[i].align_to;
+ base_offset = pos[i].off;
+ }
+ for (i = 0; i < 3; i++)
+ pos[i].off -= base_offset;
+ }
+
+ pos[0].off &= ~align + 1;
+ pos[1].off &= ~align + 1;
+ pos[2].off &= ~align + 1;
+
+ /* If any two stores write to the same chunk, they also write to the
+ same doubleword. The offsets are still sorted at this point. */
+ if (pos[0].off == pos[1].off || pos[1].off == pos[2].off)
+ return 0;
+
+ /* A range of at least 9 bytes is needed for the stores to be in
+ non-overlapping doublewords. */
+ if (pos[2].off - pos[0].off <= 8)
+ return 0;
+
+ if (pos[2].off - pos[1].off >= 24
+ || pos[1].off - pos[0].off >= 24
+ || pos[2].off - pos[0].off >= 32)
+ return 0;
+
+ return 1;
+}
+
/* Return the number of nops that would be needed if instruction INSN
immediately followed the MAX_NOPS instructions given by HIST,
- where HIST[0] is the most recent instruction. If INSN is null,
- return the worse-case number of nops for any instruction. */
+ where HIST[0] is the most recent instruction. Ignore hazards
+ between INSN and the first IGNORE instructions in HIST.
+
+ If INSN is null, return the worse-case number of nops for any
+ instruction. */
static int
-nops_for_insn (const struct mips_cl_insn *hist,
+nops_for_insn (int ignore, const struct mips_cl_insn *hist,
const struct mips_cl_insn *insn)
{
int i, nops, tmp_nops;
nops = 0;
- for (i = 0; i < MAX_DELAY_NOPS; i++)
+ for (i = ignore; i < MAX_DELAY_NOPS; i++)
{
tmp_nops = insns_between (hist + i, insn) - i;
if (tmp_nops > nops)
if (mips_fix_vr4130)
{
- tmp_nops = nops_for_vr4130 (hist, insn);
+ tmp_nops = nops_for_vr4130 (ignore, hist, insn);
+ if (tmp_nops > nops)
+ nops = tmp_nops;
+ }
+
+ if (mips_fix_24k)
+ {
+ tmp_nops = nops_for_24k (ignore, hist, insn);
if (tmp_nops > nops)
nops = tmp_nops;
}
/* The variable arguments provide NUM_INSNS extra instructions that
might be added to HIST. Return the largest number of nops that
- would be needed after the extended sequence. */
+ would be needed after the extended sequence, ignoring hazards
+ in the first IGNORE instructions. */
static int
-nops_for_sequence (int num_insns, const struct mips_cl_insn *hist, ...)
+nops_for_sequence (int num_insns, int ignore,
+ const struct mips_cl_insn *hist, ...)
{
va_list args;
struct mips_cl_insn buffer[MAX_NOPS];
while (cursor > buffer)
*--cursor = *va_arg (args, const struct mips_cl_insn *);
- nops = nops_for_insn (buffer, NULL);
+ nops = nops_for_insn (ignore, buffer, NULL);
va_end (args);
return nops;
}
worst-case delay for the branch target. */
static int
-nops_for_insn_or_target (const struct mips_cl_insn *hist,
+nops_for_insn_or_target (int ignore, const struct mips_cl_insn *hist,
const struct mips_cl_insn *insn)
{
int nops, tmp_nops;
- nops = nops_for_insn (hist, insn);
+ nops = nops_for_insn (ignore, hist, insn);
if (insn->insn_mo->pinfo & (INSN_UNCOND_BRANCH_DELAY
| INSN_COND_BRANCH_DELAY
| INSN_COND_BRANCH_LIKELY))
{
- tmp_nops = nops_for_sequence (2, hist, insn, NOP_INSN);
+ tmp_nops = nops_for_sequence (2, ignore ? ignore + 2 : 0,
+ hist, insn, NOP_INSN);
if (tmp_nops > nops)
nops = tmp_nops;
}
&& (insn->insn_mo->pinfo & (MIPS16_INSN_UNCOND_BRANCH
| MIPS16_INSN_COND_BRANCH)))
{
- tmp_nops = nops_for_sequence (1, hist, insn);
+ tmp_nops = nops_for_sequence (1, ignore ? ignore + 1 : 0, hist, insn);
if (tmp_nops > nops)
nops = tmp_nops;
}
bfd_reloc_code_real_type *reloc_type)
{
unsigned long prev_pinfo, pinfo;
+ unsigned long prev_pinfo2, pinfo2;
relax_stateT prev_insn_frag_type = 0;
bfd_boolean relaxed_branch = FALSE;
segment_info_type *si = seg_info (now_seg);
/* Mark instruction labels in mips16 mode. */
mips16_mark_labels ();
+ file_ase_mips16 |= mips_opts.mips16;
+
prev_pinfo = history[0].insn_mo->pinfo;
+ prev_pinfo2 = history[0].insn_mo->pinfo2;
pinfo = ip->insn_mo->pinfo;
+ pinfo2 = ip->insn_mo->pinfo2;
+
+ if (address_expr == NULL)
+ ip->complete_p = 1;
+ else if (*reloc_type <= BFD_RELOC_UNUSED
+ && address_expr->X_op == O_constant)
+ {
+ unsigned int tmp;
+
+ ip->complete_p = 1;
+ switch (*reloc_type)
+ {
+ case BFD_RELOC_32:
+ ip->insn_opcode |= address_expr->X_add_number;
+ break;
+
+ case BFD_RELOC_MIPS_HIGHEST:
+ tmp = (address_expr->X_add_number + 0x800080008000ull) >> 48;
+ ip->insn_opcode |= tmp & 0xffff;
+ break;
+
+ case BFD_RELOC_MIPS_HIGHER:
+ tmp = (address_expr->X_add_number + 0x80008000ull) >> 32;
+ ip->insn_opcode |= tmp & 0xffff;
+ break;
+
+ case BFD_RELOC_HI16_S:
+ tmp = (address_expr->X_add_number + 0x8000) >> 16;
+ ip->insn_opcode |= tmp & 0xffff;
+ break;
+
+ case BFD_RELOC_HI16:
+ ip->insn_opcode |= (address_expr->X_add_number >> 16) & 0xffff;
+ break;
+
+ case BFD_RELOC_UNUSED:
+ case BFD_RELOC_LO16:
+ case BFD_RELOC_MIPS_GOT_DISP:
+ ip->insn_opcode |= address_expr->X_add_number & 0xffff;
+ break;
+
+ case BFD_RELOC_MIPS_JMP:
+ if ((address_expr->X_add_number & 3) != 0)
+ as_bad (_("jump to misaligned address (0x%lx)"),
+ (unsigned long) address_expr->X_add_number);
+ ip->insn_opcode |= (address_expr->X_add_number >> 2) & 0x3ffffff;
+ ip->complete_p = 0;
+ break;
+
+ case BFD_RELOC_MIPS16_JMP:
+ if ((address_expr->X_add_number & 3) != 0)
+ as_bad (_("jump to misaligned address (0x%lx)"),
+ (unsigned long) address_expr->X_add_number);
+ ip->insn_opcode |=
+ (((address_expr->X_add_number & 0x7c0000) << 3)
+ | ((address_expr->X_add_number & 0xf800000) >> 7)
+ | ((address_expr->X_add_number & 0x3fffc) >> 2));
+ ip->complete_p = 0;
+ break;
+
+ case BFD_RELOC_16_PCREL_S2:
+ if ((address_expr->X_add_number & 3) != 0)
+ as_bad (_("branch to misaligned address (0x%lx)"),
+ (unsigned long) address_expr->X_add_number);
+ if (mips_relax_branch)
+ goto need_reloc;
+ if ((address_expr->X_add_number + 0x20000) & ~0x3ffff)
+ as_bad (_("branch address range overflow (0x%lx)"),
+ (unsigned long) address_expr->X_add_number);
+ ip->insn_opcode |= (address_expr->X_add_number >> 2) & 0xffff;
+ ip->complete_p = 0;
+ break;
+
+ default:
+ internalError ();
+ }
+ }
if (mips_relax.sequence != 2 && !mips_opts.noreorder)
{
benefit hand written assembly code, and does not seem worth
it. */
int nops = (mips_optimize == 0
- ? nops_for_insn (history, NULL)
- : nops_for_insn_or_target (history, ip));
+ ? nops_for_insn (0, history, NULL)
+ : nops_for_insn_or_target (0, history, ip));
if (nops > 0)
{
fragS *old_frag;
}
else if (mips_relax.sequence != 2 && prev_nop_frag != NULL)
{
- /* Work out how many nops in prev_nop_frag are needed by IP. */
- int nops = nops_for_insn_or_target (history, ip);
+ int nops;
+
+ /* Work out how many nops in prev_nop_frag are needed by IP,
+ ignoring hazards generated by the first prev_nop_frag_since
+ instructions. */
+ nops = nops_for_insn_or_target (prev_nop_frag_since, history, ip);
gas_assert (nops <= prev_nop_frag_holds);
/* Enforce NOPS as a minimum. */
out that the branch was out-of-range, we'll get an error. */
&& !mips_opts.warn_about_macros
&& (mips_opts.at || mips_pic == NO_PIC)
+ /* Don't relax BPOSGE32/64 as they have no complementing branches. */
+ && !(ip->insn_mo->membership & (INSN_DSP64 | INSN_DSP))
&& !mips_opts.mips16)
{
relaxed_branch = TRUE;
: (pinfo & INSN_COND_BRANCH_LIKELY) ? 1
: 0)), 4,
RELAX_BRANCH_ENCODE
- (pinfo & INSN_UNCOND_BRANCH_DELAY,
+ (AT,
+ pinfo & INSN_UNCOND_BRANCH_DELAY,
pinfo & INSN_COND_BRANCH_LIKELY,
pinfo & INSN_WRITE_GPR_31,
0),
if (address_expr != NULL && *reloc_type <= BFD_RELOC_UNUSED)
{
- if (address_expr->X_op == O_constant)
- {
- unsigned int tmp;
-
- switch (*reloc_type)
- {
- case BFD_RELOC_32:
- ip->insn_opcode |= address_expr->X_add_number;
- break;
-
- case BFD_RELOC_MIPS_HIGHEST:
- tmp = (address_expr->X_add_number + 0x800080008000ull) >> 48;
- ip->insn_opcode |= tmp & 0xffff;
- break;
-
- case BFD_RELOC_MIPS_HIGHER:
- tmp = (address_expr->X_add_number + 0x80008000ull) >> 32;
- ip->insn_opcode |= tmp & 0xffff;
- break;
-
- case BFD_RELOC_HI16_S:
- tmp = (address_expr->X_add_number + 0x8000) >> 16;
- ip->insn_opcode |= tmp & 0xffff;
- break;
-
- case BFD_RELOC_HI16:
- ip->insn_opcode |= (address_expr->X_add_number >> 16) & 0xffff;
- break;
-
- case BFD_RELOC_UNUSED:
- case BFD_RELOC_LO16:
- case BFD_RELOC_MIPS_GOT_DISP:
- ip->insn_opcode |= address_expr->X_add_number & 0xffff;
- break;
-
- case BFD_RELOC_MIPS_JMP:
- if ((address_expr->X_add_number & 3) != 0)
- as_bad (_("jump to misaligned address (0x%lx)"),
- (unsigned long) address_expr->X_add_number);
- ip->insn_opcode |= (address_expr->X_add_number >> 2) & 0x3ffffff;
- break;
-
- case BFD_RELOC_MIPS16_JMP:
- if ((address_expr->X_add_number & 3) != 0)
- as_bad (_("jump to misaligned address (0x%lx)"),
- (unsigned long) address_expr->X_add_number);
- ip->insn_opcode |=
- (((address_expr->X_add_number & 0x7c0000) << 3)
- | ((address_expr->X_add_number & 0xf800000) >> 7)
- | ((address_expr->X_add_number & 0x3fffc) >> 2));
- break;
-
- case BFD_RELOC_16_PCREL_S2:
- if ((address_expr->X_add_number & 3) != 0)
- as_bad (_("branch to misaligned address (0x%lx)"),
- (unsigned long) address_expr->X_add_number);
- if (mips_relax_branch)
- goto need_reloc;
- if ((address_expr->X_add_number + 0x20000) & ~0x3ffff)
- as_bad (_("branch address range overflow (0x%lx)"),
- (unsigned long) address_expr->X_add_number);
- ip->insn_opcode |= (address_expr->X_add_number >> 2) & 0xffff;
- break;
-
- default:
- internalError ();
- }
- }
- else if (*reloc_type < BFD_RELOC_UNUSED)
+ if (!ip->complete_p
+ && *reloc_type < BFD_RELOC_UNUSED)
need_reloc:
{
reloc_howto_type *howto;
install_insn (ip);
/* Update the register mask information. */
- if (! mips_opts.mips16)
- {
- if (pinfo & INSN_WRITE_GPR_D)
- mips_gprmask |= 1 << EXTRACT_OPERAND (RD, *ip);
- if ((pinfo & (INSN_WRITE_GPR_T | INSN_READ_GPR_T)) != 0)
- mips_gprmask |= 1 << EXTRACT_OPERAND (RT, *ip);
- if (pinfo & INSN_READ_GPR_S)
- mips_gprmask |= 1 << EXTRACT_OPERAND (RS, *ip);
- if (pinfo & INSN_WRITE_GPR_31)
- mips_gprmask |= 1 << RA;
- if (pinfo & INSN_WRITE_FPR_D)
- mips_cprmask[1] |= 1 << EXTRACT_OPERAND (FD, *ip);
- if ((pinfo & (INSN_WRITE_FPR_S | INSN_READ_FPR_S)) != 0)
- mips_cprmask[1] |= 1 << EXTRACT_OPERAND (FS, *ip);
- if ((pinfo & (INSN_WRITE_FPR_T | INSN_READ_FPR_T)) != 0)
- mips_cprmask[1] |= 1 << EXTRACT_OPERAND (FT, *ip);
- if ((pinfo & INSN_READ_FPR_R) != 0)
- mips_cprmask[1] |= 1 << EXTRACT_OPERAND (FR, *ip);
- if (pinfo & INSN_COP)
- {
- /* We don't keep enough information to sort these cases out.
- The itbl support does keep this information however, although
- we currently don't support itbl fprmats as part of the cop
- instruction. May want to add this support in the future. */
- }
- /* Never set the bit for $0, which is always zero. */
- mips_gprmask &= ~1 << 0;
- }
- else
- {
- if (pinfo & (MIPS16_INSN_WRITE_X | MIPS16_INSN_READ_X))
- mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (RX, *ip);
- if (pinfo & (MIPS16_INSN_WRITE_Y | MIPS16_INSN_READ_Y))
- mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (RY, *ip);
- if (pinfo & MIPS16_INSN_WRITE_Z)
- mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (RZ, *ip);
- if (pinfo & (MIPS16_INSN_WRITE_T | MIPS16_INSN_READ_T))
- mips_gprmask |= 1 << TREG;
- if (pinfo & (MIPS16_INSN_WRITE_SP | MIPS16_INSN_READ_SP))
- mips_gprmask |= 1 << SP;
- if (pinfo & (MIPS16_INSN_WRITE_31 | MIPS16_INSN_READ_31))
- mips_gprmask |= 1 << RA;
- if (pinfo & MIPS16_INSN_WRITE_GPR_Y)
- mips_gprmask |= 1 << MIPS16OP_EXTRACT_REG32R (ip->insn_opcode);
- if (pinfo & MIPS16_INSN_READ_Z)
- mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (MOVE32Z, *ip);
- if (pinfo & MIPS16_INSN_READ_GPR_X)
- mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (REGR32, *ip);
- }
+ mips_gprmask |= gpr_read_mask (ip) | gpr_write_mask (ip);
+ mips_cprmask[1] |= fpr_read_mask (ip) | fpr_write_mask (ip);
if (mips_relax.sequence != 2 && !mips_opts.noreorder)
{
&& prev_insn_frag_type == rs_machine_dependent)
/* Check for conflicts between the branch and the instructions
before the candidate delay slot. */
- || nops_for_insn (history + 1, ip) > 0
+ || nops_for_insn (0, history + 1, ip) > 0
/* Check for conflicts between the swapped sequence and the
target of the branch. */
- || nops_for_sequence (2, history + 1, ip, history) > 0
+ || nops_for_sequence (2, 0, history + 1, ip, history) > 0
/* We do not swap with a trap instruction, since it
complicates trap handlers to have the trap
instruction be in a delay slot. */
|| (prev_pinfo & INSN_TRAP)
/* If the branch reads a register that the previous
instruction sets, we can not swap. */
- || (! mips_opts.mips16
- && (prev_pinfo & INSN_WRITE_GPR_T)
- && insn_uses_reg (ip, EXTRACT_OPERAND (RT, history[0]),
- MIPS_GR_REG))
- || (! mips_opts.mips16
- && (prev_pinfo & INSN_WRITE_GPR_D)
- && insn_uses_reg (ip, EXTRACT_OPERAND (RD, history[0]),
- MIPS_GR_REG))
- || (mips_opts.mips16
- && (((prev_pinfo & MIPS16_INSN_WRITE_X)
- && (insn_uses_reg
- (ip, MIPS16_EXTRACT_OPERAND (RX, history[0]),
- MIPS16_REG)))
- || ((prev_pinfo & MIPS16_INSN_WRITE_Y)
- && (insn_uses_reg
- (ip, MIPS16_EXTRACT_OPERAND (RY, history[0]),
- MIPS16_REG)))
- || ((prev_pinfo & MIPS16_INSN_WRITE_Z)
- && (insn_uses_reg
- (ip, MIPS16_EXTRACT_OPERAND (RZ, history[0]),
- MIPS16_REG)))
- || ((prev_pinfo & MIPS16_INSN_WRITE_T)
- && insn_uses_reg (ip, TREG, MIPS_GR_REG))
- || ((prev_pinfo & MIPS16_INSN_WRITE_31)
- && insn_uses_reg (ip, RA, MIPS_GR_REG))
- || ((prev_pinfo & MIPS16_INSN_WRITE_GPR_Y)
- && insn_uses_reg (ip,
- MIPS16OP_EXTRACT_REG32R
- (history[0].insn_opcode),
- MIPS_GR_REG))))
+ || (gpr_read_mask (ip) & gpr_write_mask (&history[0])) != 0
/* If the branch writes a register that the previous
- instruction sets, we can not swap (we know that
- branches write only to RD or to $31). */
- || (! mips_opts.mips16
- && (prev_pinfo & INSN_WRITE_GPR_T)
- && (((pinfo & INSN_WRITE_GPR_D)
- && (EXTRACT_OPERAND (RT, history[0])
- == EXTRACT_OPERAND (RD, *ip)))
- || ((pinfo & INSN_WRITE_GPR_31)
- && EXTRACT_OPERAND (RT, history[0]) == RA)))
- || (! mips_opts.mips16
- && (prev_pinfo & INSN_WRITE_GPR_D)
- && (((pinfo & INSN_WRITE_GPR_D)
- && (EXTRACT_OPERAND (RD, history[0])
- == EXTRACT_OPERAND (RD, *ip)))
- || ((pinfo & INSN_WRITE_GPR_31)
- && EXTRACT_OPERAND (RD, history[0]) == RA)))
- || (mips_opts.mips16
- && (pinfo & MIPS16_INSN_WRITE_31)
- && ((prev_pinfo & MIPS16_INSN_WRITE_31)
- || ((prev_pinfo & MIPS16_INSN_WRITE_GPR_Y)
- && (MIPS16OP_EXTRACT_REG32R (history[0].insn_opcode)
- == RA))))
+ instruction sets, we can not swap. */
+ || (gpr_write_mask (ip) & gpr_write_mask (&history[0])) != 0
/* If the branch writes a register that the previous
- instruction reads, we can not swap (we know that
- branches only write to RD or to $31). */
- || (! mips_opts.mips16
- && (pinfo & INSN_WRITE_GPR_D)
- && insn_uses_reg (&history[0],
- EXTRACT_OPERAND (RD, *ip),
- MIPS_GR_REG))
- || (! mips_opts.mips16
- && (pinfo & INSN_WRITE_GPR_31)
- && insn_uses_reg (&history[0], RA, MIPS_GR_REG))
- || (mips_opts.mips16
- && (pinfo & MIPS16_INSN_WRITE_31)
- && insn_uses_reg (&history[0], RA, MIPS_GR_REG))
+ instruction reads, we can not swap. */
+ || (gpr_write_mask (ip) & gpr_read_mask (&history[0])) != 0
/* If one instruction sets a condition code and the
other one uses a condition code, we can not swap. */
|| ((pinfo & INSN_READ_COND_CODE)
{
if (! mips_opts.noreorder)
{
- int nops = nops_for_insn (history, NULL);
+ int nops = nops_for_insn (0, history, NULL);
if (nops > 0)
{
while (nops-- > 0)
/* Insert any nops that might be needed between the .set noreorder
block and the previous instructions. We will later remove any
nops that turn out not to be needed. */
- nops = nops_for_insn (history, NULL);
+ nops = nops_for_insn (0, history, NULL);
if (nops > 0)
{
if (mips_optimize != 0)
case 'i':
case 'j':
- case 'o':
macro_read_relocs (&args, r);
gas_assert (*r == BFD_RELOC_GPREL16
- || *r == BFD_RELOC_MIPS_LITERAL
- || *r == BFD_RELOC_MIPS_HIGHER
- || *r == BFD_RELOC_HI16_S
- || *r == BFD_RELOC_LO16
- || *r == BFD_RELOC_MIPS_GOT16
- || *r == BFD_RELOC_MIPS_CALL16
- || *r == BFD_RELOC_MIPS_GOT_DISP
- || *r == BFD_RELOC_MIPS_GOT_PAGE
- || *r == BFD_RELOC_MIPS_GOT_OFST
- || *r == BFD_RELOC_MIPS_GOT_LO16
- || *r == BFD_RELOC_MIPS_CALL_LO16);
+ || *r == BFD_RELOC_MIPS_HIGHER
+ || *r == BFD_RELOC_HI16_S
+ || *r == BFD_RELOC_LO16
+ || *r == BFD_RELOC_MIPS_GOT_OFST);
+ continue;
+
+ case 'o':
+ macro_read_relocs (&args, r);
continue;
case 'u':
macro_read_relocs (&args, r);
gas_assert (ep != NULL
- && (ep->X_op == O_constant
- || (ep->X_op == O_symbol
- && (*r == BFD_RELOC_MIPS_HIGHEST
- || *r == BFD_RELOC_HI16_S
- || *r == BFD_RELOC_HI16
- || *r == BFD_RELOC_GPREL16
- || *r == BFD_RELOC_MIPS_GOT_HI16
- || *r == BFD_RELOC_MIPS_CALL_HI16))));
+ && (ep->X_op == O_constant
+ || (ep->X_op == O_symbol
+ && (*r == BFD_RELOC_MIPS_HIGHEST
+ || *r == BFD_RELOC_HI16_S
+ || *r == BFD_RELOC_HI16
+ || *r == BFD_RELOC_GPREL16
+ || *r == BFD_RELOC_MIPS_GOT_HI16
+ || *r == BFD_RELOC_MIPS_CALL_HI16))));
continue;
case 'p':
gas_assert (! mips_opts.mips16);
- treg = (ip->insn_opcode >> 16) & 0x1f;
- dreg = (ip->insn_opcode >> 11) & 0x1f;
- sreg = breg = (ip->insn_opcode >> 21) & 0x1f;
+ treg = EXTRACT_OPERAND (RT, *ip);
+ dreg = EXTRACT_OPERAND (RD, *ip);
+ sreg = breg = EXTRACT_OPERAND (RS, *ip);
mask = ip->insn_mo->mask;
expr1.X_op = O_constant;
expr1.X_add_number = 8;
macro_build (&expr1, "bgez", "s,p", sreg);
if (dreg == sreg)
- macro_build (NULL, "nop", "", 0);
+ macro_build (NULL, "nop", "");
else
move_register (dreg, sreg);
macro_build (NULL, dbl ? "dsub" : "sub", "d,v,t", dreg, 0, sreg);
break;
default:
macro_build (NULL, "balign", "t,s,2", treg, sreg,
- (int)imm_expr.X_add_number);
+ (int) imm_expr.X_add_number);
break;
}
break;
beq_i:
if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
{
- macro_build (&offset_expr, s, "s,t,p", sreg, 0);
+ macro_build (&offset_expr, s, "s,t,p", sreg, ZERO);
break;
}
used_at = 1;
}
used_at = 1;
macro_build (NULL, "slt", "d,v,t", AT, sreg, treg);
- macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
+ macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, ZERO);
break;
case M_BGTL_I:
likely = 1;
case M_BGT_I:
- /* check for > max integer */
+ /* Check for > max integer. */
maxnum = 0x7fffffff;
if (HAVE_64BIT_GPRS && sizeof (maxnum) > 4)
{
&& (HAVE_32BIT_GPRS || sizeof (maxnum) > 4))
{
do_false:
- /* result is always false */
+ /* Result is always false. */
if (! likely)
- macro_build (NULL, "nop", "", 0);
+ macro_build (NULL, "nop", "");
else
- macro_build (&offset_expr, "bnel", "s,t,p", 0, 0);
+ macro_build (&offset_expr, "bnel", "s,t,p", ZERO, ZERO);
break;
}
if (imm_expr.X_op != O_constant)
}
used_at = 1;
set_at (sreg, 0);
- macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
+ macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, ZERO);
break;
case M_BGEUL:
if (sreg == 0)
{
macro_build (&offset_expr, likely ? "beql" : "beq",
- "s,t,p", 0, treg);
+ "s,t,p", ZERO, treg);
break;
}
used_at = 1;
macro_build (NULL, "sltu", "d,v,t", AT, sreg, treg);
- macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
+ macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, ZERO);
break;
case M_BGTUL_I:
if (sreg == 0
|| (HAVE_32BIT_GPRS
&& imm_expr.X_op == O_constant
- && imm_expr.X_add_number == (offsetT) 0xffffffff))
+ && imm_expr.X_add_number == -1))
goto do_false;
if (imm_expr.X_op != O_constant)
as_bad (_("Unsupported large constant"));
if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
{
macro_build (&offset_expr, likely ? "bnel" : "bne",
- "s,t,p", sreg, 0);
+ "s,t,p", sreg, ZERO);
break;
}
used_at = 1;
set_at (sreg, 1);
- macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
+ macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, ZERO);
break;
case M_BGTL:
}
used_at = 1;
macro_build (NULL, "slt", "d,v,t", AT, treg, sreg);
- macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
+ macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, ZERO);
break;
case M_BGTUL:
if (treg == 0)
{
macro_build (&offset_expr, likely ? "bnel" : "bne",
- "s,t,p", sreg, 0);
+ "s,t,p", sreg, ZERO);
break;
}
if (sreg == 0)
goto do_false;
used_at = 1;
macro_build (NULL, "sltu", "d,v,t", AT, treg, sreg);
- macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
+ macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, ZERO);
break;
case M_BLEL:
}
used_at = 1;
macro_build (NULL, "slt", "d,v,t", AT, treg, sreg);
- macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
+ macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, ZERO);
break;
case M_BLEL_I:
}
used_at = 1;
set_at (sreg, 0);
- macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
+ macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, ZERO);
break;
case M_BLEUL:
if (treg == 0)
{
macro_build (&offset_expr, likely ? "beql" : "beq",
- "s,t,p", sreg, 0);
+ "s,t,p", sreg, ZERO);
break;
}
if (sreg == 0)
goto do_true;
used_at = 1;
macro_build (NULL, "sltu", "d,v,t", AT, treg, sreg);
- macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
+ macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, ZERO);
break;
case M_BLEUL_I:
if (sreg == 0
|| (HAVE_32BIT_GPRS
&& imm_expr.X_op == O_constant
- && imm_expr.X_add_number == (offsetT) 0xffffffff))
+ && imm_expr.X_add_number == -1))
goto do_true;
if (imm_expr.X_op != O_constant)
as_bad (_("Unsupported large constant"));
if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
{
macro_build (&offset_expr, likely ? "beql" : "beq",
- "s,t,p", sreg, 0);
+ "s,t,p", sreg, ZERO);
break;
}
used_at = 1;
set_at (sreg, 1);
- macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
+ macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, ZERO);
break;
case M_BLTL:
}
used_at = 1;
macro_build (NULL, "slt", "d,v,t", AT, sreg, treg);
- macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
+ macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, ZERO);
break;
case M_BLTUL:
if (sreg == 0)
{
macro_build (&offset_expr, likely ? "bnel" : "bne",
- "s,t,p", 0, treg);
+ "s,t,p", ZERO, treg);
break;
}
used_at = 1;
macro_build (NULL, "sltu", "d,v,t", AT, sreg, treg);
- macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
+ macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, ZERO);
break;
case M_DEXT:
{
- unsigned long pos;
- unsigned long size;
+ /* Use unsigned arithmetic. */
+ addressT pos;
+ addressT size;
- if (imm_expr.X_op != O_constant || imm2_expr.X_op != O_constant)
+ if (imm_expr.X_op != O_constant || imm2_expr.X_op != O_constant)
{
as_bad (_("Unsupported large constant"));
pos = size = 1;
}
else
{
- pos = (unsigned long) imm_expr.X_add_number;
- size = (unsigned long) imm2_expr.X_add_number;
+ pos = imm_expr.X_add_number;
+ size = imm2_expr.X_add_number;
}
if (pos > 63)
{
- as_bad (_("Improper position (%lu)"), pos);
+ as_bad (_("Improper position (%lu)"), (unsigned long) pos);
pos = 1;
}
- if (size == 0 || size > 64
- || (pos + size - 1) > 63)
+ if (size == 0 || size > 64 || (pos + size - 1) > 63)
{
as_bad (_("Improper extract size (%lu, position %lu)"),
- size, pos);
+ (unsigned long) size, (unsigned long) pos);
size = 1;
}
s = "dextm";
fmt = "t,r,+A,+G";
}
- macro_build ((expressionS *) NULL, s, fmt, treg, sreg, pos, size - 1);
+ macro_build ((expressionS *) NULL, s, fmt, treg, sreg, (int) pos,
+ (int) (size - 1));
}
break;
case M_DINS:
{
- unsigned long pos;
- unsigned long size;
+ /* Use unsigned arithmetic. */
+ addressT pos;
+ addressT size;
- if (imm_expr.X_op != O_constant || imm2_expr.X_op != O_constant)
+ if (imm_expr.X_op != O_constant || imm2_expr.X_op != O_constant)
{
as_bad (_("Unsupported large constant"));
pos = size = 1;
}
else
{
- pos = (unsigned long) imm_expr.X_add_number;
- size = (unsigned long) imm2_expr.X_add_number;
+ pos = imm_expr.X_add_number;
+ size = imm2_expr.X_add_number;
}
if (pos > 63)
{
- as_bad (_("Improper position (%lu)"), pos);
+ as_bad (_("Improper position (%lu)"), (unsigned long) pos);
pos = 1;
}
- if (size == 0 || size > 64
- || (pos + size - 1) > 63)
+ if (size == 0 || size > 64 || (pos + size - 1) > 63)
{
as_bad (_("Improper insert size (%lu, position %lu)"),
- size, pos);
+ (unsigned long) size, (unsigned long) pos);
size = 1;
}
{
as_warn (_("Divide by zero."));
if (mips_trap)
- macro_build (NULL, "teq", "s,t,q", 0, 0, 7);
+ macro_build (NULL, "teq", "s,t,q", ZERO, ZERO, 7);
else
macro_build (NULL, "break", "c", 7);
break;
start_noreorder ();
if (mips_trap)
{
- macro_build (NULL, "teq", "s,t,q", treg, 0, 7);
+ macro_build (NULL, "teq", "s,t,q", treg, ZERO, 7);
macro_build (NULL, dbl ? "ddiv" : "div", "z,s,t", sreg, treg);
}
else
{
expr1.X_add_number = 8;
- macro_build (&expr1, "bne", "s,t,p", treg, 0);
+ macro_build (&expr1, "bne", "s,t,p", treg, ZERO);
macro_build (NULL, dbl ? "ddiv" : "div", "z,s,t", sreg, treg);
macro_build (NULL, "break", "c", 7);
}
{
expr1.X_add_number = 8;
macro_build (&expr1, "bne", "s,t,p", sreg, AT);
- macro_build (NULL, "nop", "", 0);
+ macro_build (NULL, "nop", "");
/* We want to close the noreorder block as soon as possible, so
that later insns are available for delay slot filling. */
{
as_warn (_("Divide by zero."));
if (mips_trap)
- macro_build (NULL, "teq", "s,t,q", 0, 0, 7);
+ macro_build (NULL, "teq", "s,t,q", ZERO, ZERO, 7);
else
macro_build (NULL, "break", "c", 7);
break;
if (strcmp (s2, "mflo") == 0)
move_register (dreg, sreg);
else
- move_register (dreg, 0);
+ move_register (dreg, ZERO);
break;
}
if (imm_expr.X_op == O_constant
macro_build (NULL, dbl ? "dneg" : "neg", "d,w", dreg, sreg);
}
else
- move_register (dreg, 0);
+ move_register (dreg, ZERO);
break;
}
start_noreorder ();
if (mips_trap)
{
- macro_build (NULL, "teq", "s,t,q", treg, 0, 7);
+ macro_build (NULL, "teq", "s,t,q", treg, ZERO, 7);
macro_build (NULL, s, "z,s,t", sreg, treg);
/* We want to close the noreorder block as soon as possible, so
that later insns are available for delay slot filling. */
else
{
expr1.X_add_number = 8;
- macro_build (&expr1, "bne", "s,t,p", treg, 0);
+ macro_build (&expr1, "bne", "s,t,p", treg, ZERO);
macro_build (NULL, s, "z,s,t", sreg, treg);
/* We want to close the noreorder block as soon as possible, so
if (dbl && HAVE_32BIT_GPRS)
as_warn (_("dla used to load 32-bit register"));
- if (! dbl && HAVE_64BIT_OBJECTS)
+ if (!dbl && HAVE_64BIT_OBJECTS)
as_warn (_("la used to load 64-bit address"));
if (offset_expr.X_op == O_constant
if (offset_expr.X_op != O_symbol
&& offset_expr.X_op != O_constant)
{
- as_bad (_("expression too complex"));
+ as_bad (_("Expression too complex"));
offset_expr.X_op = O_constant;
}
relax_switch ();
}
if (!IS_SEXT_32BIT_NUM (offset_expr.X_add_number))
- as_bad (_("offset too large"));
+ as_bad (_("Offset too large"));
macro_build_lui (&offset_expr, tempreg);
macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
tempreg, tempreg, BFD_RELOC_LO16);
unsigned long temp = (treg << 16) | (0x01);
macro_build (NULL, "c2", "C", temp);
}
- /* AT is not used, just return */
- return;
+ break;
case M_MSGLD:
{
unsigned long temp = (0x02);
macro_build (NULL, "c2", "C", temp);
}
- /* AT is not used, just return */
- return;
+ break;
case M_MSGLD_T:
{
unsigned long temp = (treg << 16) | (0x02);
macro_build (NULL, "c2", "C", temp);
}
- /* AT is not used, just return */
- return;
+ break;
case M_MSGWAIT:
macro_build (NULL, "c2", "C", 3);
- /* AT is not used, just return */
- return;
+ break;
case M_MSGWAIT_T:
{
unsigned long temp = (treg << 16) | 0x03;
macro_build (NULL, "c2", "C", temp);
}
- /* AT is not used, just return */
- return;
+ break;
case M_J_A:
/* The j instruction may not be used in PIC code, since it
as_warn (_("No .cprestore pseudo-op used in PIC code"));
else
{
- if (! mips_frame_reg_valid)
+ if (!mips_frame_reg_valid)
{
as_warn (_("No .frame pseudo-op used in PIC code"));
/* Quiet this warning. */
mips_frame_reg_valid = 1;
}
- if (! mips_cprestore_valid)
+ if (!mips_cprestore_valid)
{
as_warn (_("No .cprestore pseudo-op used in PIC code"));
/* Quiet this warning. */
GOT_DISP. */
if (HAVE_NEWABI)
{
- if (! mips_big_got)
+ if (!mips_big_got)
{
relax_start (offset_expr.X_add_symbol);
macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
else
{
relax_start (offset_expr.X_add_symbol);
- if (! mips_big_got)
+ if (!mips_big_got)
{
macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
PIC_CALL_REG, BFD_RELOC_MIPS_CALL16,
as_warn (_("No .cprestore pseudo-op used in PIC code"));
else
{
- if (! mips_frame_reg_valid)
+ if (!mips_frame_reg_valid)
{
as_warn (_("No .frame pseudo-op used in PIC code"));
/* Quiet this warning. */
mips_frame_reg_valid = 1;
}
- if (! mips_cprestore_valid)
+ if (!mips_cprestore_valid)
{
as_warn (_("No .cprestore pseudo-op used in PIC code"));
/* Quiet this warning. */
case M_CACHE_AB:
s = "cache";
goto st;
+ case M_PREF_AB:
+ s = "pref";
+ goto st;
case M_SDC1_AB:
s = "sdc1";
coproc = 1;
&& NO_ISA_COP (mips_opts.arch)
&& (ip->insn_mo->pinfo2 & (INSN2_M_FP_S | INSN2_M_FP_D)) == 0)
{
- as_bad (_("opcode not supported on this processor: %s"),
+ as_bad (_("Opcode not supported on this processor: %s"),
mips_cpu_info_from_arch (mips_opts.arch)->name);
break;
}
|| mask == M_L_DAB
|| mask == M_S_DAB)
fmt = "T,o(b)";
- else if (mask == M_CACHE_AB)
+ else if (mask == M_CACHE_AB || mask == M_PREF_AB)
fmt = "k,o(b)";
else if (coproc)
fmt = "E,o(b)";
if (offset_expr.X_op != O_constant
&& offset_expr.X_op != O_symbol)
{
- as_bad (_("expression too complex"));
+ as_bad (_("Expression too complex"));
offset_expr.X_op = O_constant;
}
is in non PIC code. */
if (offset_expr.X_op == O_constant)
{
- expr1.X_add_number = ((offset_expr.X_add_number + 0x8000)
- & ~(bfd_vma) 0xffff);
+ expr1.X_add_number = offset_expr.X_add_number;
normalize_address_expr (&expr1);
- load_register (tempreg, &expr1, HAVE_64BIT_ADDRESSES);
- if (breg != 0)
- macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
- tempreg, tempreg, breg);
- macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_LO16, tempreg);
+ if (!IS_SEXT_16BIT_NUM (expr1.X_add_number))
+ {
+ expr1.X_add_number = ((expr1.X_add_number + 0x8000)
+ & ~(bfd_vma) 0xffff);
+ load_register (tempreg, &expr1, HAVE_64BIT_ADDRESSES);
+ if (breg != 0)
+ macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
+ tempreg, tempreg, breg);
+ breg = tempreg;
+ }
+ macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_LO16, breg);
}
else if (mips_pic == NO_PIC)
{
else
{
gas_assert (offset_expr.X_op == O_symbol
- && strcmp (segment_name (S_GET_SEGMENT
- (offset_expr.X_add_symbol)),
- ".lit4") == 0
- && offset_expr.X_add_number == 0);
+ && strcmp (segment_name (S_GET_SEGMENT
+ (offset_expr.X_add_symbol)),
+ ".lit4") == 0
+ && offset_expr.X_add_number == 0);
macro_build (&offset_expr, "lwc1", "T,o(b)", treg,
BFD_RELOC_MIPS_LITERAL, mips_gp_register);
break;
}
gas_assert (offset_expr.X_op == O_symbol
- && offset_expr.X_add_number == 0);
+ && offset_expr.X_add_number == 0);
s = segment_name (S_GET_SEGMENT (offset_expr.X_add_symbol));
if (strcmp (s, ".lit8") == 0)
{
target_big_endian ? treg : treg + 1, r, breg);
break;
+ case M_S_DOB:
+ gas_assert (mips_opts.isa == ISA_MIPS1);
+ /* Even on a big endian machine $fn comes before $fn+1. We have
+ to adjust when storing to memory. */
+ macro_build (&offset_expr, "swc1", "T,o(b)",
+ target_big_endian ? treg + 1 : treg, BFD_RELOC_LO16, breg);
+ offset_expr.X_add_number += 4;
+ macro_build (&offset_expr, "swc1", "T,o(b)",
+ target_big_endian ? treg : treg + 1, BFD_RELOC_LO16, breg);
+ break;
+
case M_L_DAB:
/*
* The MIPS assembler seems to check for X_add_number not
if (offset_expr.X_op != O_symbol
&& offset_expr.X_op != O_constant)
{
- as_bad (_("expression too complex"));
+ as_bad (_("Expression too complex"));
offset_expr.X_op = O_constant;
}
to adjust when loading from memory. We set coproc if we must
load $fn+1 first. */
/* Itbl support may require additional care here. */
- if (! target_big_endian)
+ if (!target_big_endian)
coproc = 0;
- if (mips_pic == NO_PIC
- || offset_expr.X_op == O_constant)
+ if (mips_pic == NO_PIC || offset_expr.X_op == O_constant)
{
/* If this is a reference to a GP relative symbol, we want
<op> $treg,<sym>($gp) (BFD_RELOC_GPREL16)
relax_switch ();
- /* We just generated two relocs. When tc_gen_reloc
- handles this case, it will skip the first reloc and
- handle the second. The second reloc already has an
- extra addend of 4, which we added above. We must
- subtract it out, and then subtract another 4 to make
- the first reloc come out right. The second reloc
- will come out right because we are going to add 4 to
- offset_expr when we build its instruction below.
-
- If we have a symbol, then we don't want to include
- the offset, because it will wind up being included
- when we generate the reloc. */
-
- if (offset_expr.X_op == O_constant)
- offset_expr.X_add_number -= 8;
- else
- {
- offset_expr.X_add_number = -4;
- offset_expr.X_op = O_constant;
- }
+ offset_expr.X_add_number -= 4;
}
used_at = 1;
macro_build_lui (&offset_expr, AT);
break;
case M_LD_OB:
- s = "lw";
+ s = HAVE_64BIT_GPRS ? "ld" : "lw";
goto sd_ob;
case M_SD_OB:
- s = "sw";
+ s = HAVE_64BIT_GPRS ? "sd" : "sw";
sd_ob:
- gas_assert (HAVE_32BIT_ADDRESSES);
- macro_build (&offset_expr, s, "t,o(b)", treg, BFD_RELOC_LO16, breg);
- offset_expr.X_add_number += 4;
- macro_build (&offset_expr, s, "t,o(b)", treg + 1, BFD_RELOC_LO16, breg);
+ macro_build (&offset_expr, s, "t,o(b)", treg,
+ -1, offset_reloc[0], offset_reloc[1], offset_reloc[2],
+ breg);
+ if (!HAVE_64BIT_GPRS)
+ {
+ offset_expr.X_add_number += 4;
+ macro_build (&offset_expr, s, "t,o(b)", treg + 1,
+ -1, offset_reloc[0], offset_reloc[1], offset_reloc[2],
+ breg);
+ }
break;
/* New code added to support COPZ instructions.
move_register (dreg, sreg);
break;
-#ifdef LOSING_COMPILER
- default:
- /* Try and see if this is a new itbl instruction.
- This code builds table entries out of the macros in mip_opcodes.
- FIXME: For now we just assemble the expression and pass it's
- value along as a 32-bit immediate.
- We may want to have the assembler assemble this value,
- so that we gain the assembler's knowledge of delay slots,
- symbols, etc.
- Would it be more efficient to use mask (id) here? */
- if (itbl_have_entries
- && (immed_expr = itbl_assemble (ip->insn_mo->name, "")))
- {
- s = ip->insn_mo->name;
- s2 = "cop3";
- coproc = ITBL_DECODE_PNUM (immed_expr);;
- macro_build (&immed_expr, s, "C");
- break;
- }
- macro2 (ip);
- break;
- }
- if (!mips_opts.at && used_at)
- as_bad (_("Macro used $at after \".set noat\""));
-}
-
-static void
-macro2 (struct mips_cl_insn *ip)
-{
- unsigned int treg, sreg, dreg, breg;
- unsigned int tempreg;
- int mask;
- int used_at;
- expressionS expr1;
- const char *s;
- const char *s2;
- const char *fmt;
- int likely = 0;
- int dbl = 0;
- int coproc = 0;
- int lr = 0;
- int imm = 0;
- int off;
- offsetT maxnum;
- bfd_reloc_code_real_type r;
-
- treg = (ip->insn_opcode >> 16) & 0x1f;
- dreg = (ip->insn_opcode >> 11) & 0x1f;
- sreg = breg = (ip->insn_opcode >> 21) & 0x1f;
- mask = ip->insn_mo->mask;
-
- expr1.X_op = O_constant;
- expr1.X_op_symbol = NULL;
- expr1.X_add_symbol = NULL;
- expr1.X_add_number = 1;
-
- switch (mask)
- {
-#endif /* LOSING_COMPILER */
-
case M_DMUL:
dbl = 1;
case M_MUL:
{
expr1.X_add_number = 8;
macro_build (&expr1, "beq", "s,t,p", dreg, AT);
- macro_build (NULL, "nop", "", 0);
+ macro_build (NULL, "nop", "");
macro_build (NULL, "break", "c", 6);
}
end_noreorder ();
macro_build (NULL, "mfhi", "d", AT);
macro_build (NULL, "mflo", "d", dreg);
if (mips_trap)
- macro_build (NULL, "tne", "s,t,q", AT, 0, 6);
+ macro_build (NULL, "tne", "s,t,q", AT, ZERO, 6);
else
{
expr1.X_add_number = 8;
- macro_build (&expr1, "beq", "s,t,p", AT, 0);
- macro_build (NULL, "nop", "", 0);
+ macro_build (&expr1, "beq", "s,t,p", AT, ZERO);
+ macro_build (NULL, "nop", "");
macro_build (NULL, "break", "c", 6);
}
end_noreorder ();
break;
}
used_at = 1;
- macro_build (NULL, "dsubu", "d,v,t", AT, 0, treg);
+ macro_build (NULL, "dsubu", "d,v,t", AT, ZERO, treg);
macro_build (NULL, "dsrlv", "d,t,s", AT, sreg, AT);
macro_build (NULL, "dsllv", "d,t,s", dreg, sreg, treg);
macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
break;
}
used_at = 1;
- macro_build (NULL, "subu", "d,v,t", AT, 0, treg);
+ macro_build (NULL, "subu", "d,v,t", AT, ZERO, treg);
macro_build (NULL, "srlv", "d,t,s", AT, sreg, AT);
macro_build (NULL, "sllv", "d,t,s", dreg, sreg, treg);
macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
break;
}
used_at = 1;
- macro_build (NULL, "dsubu", "d,v,t", AT, 0, treg);
+ macro_build (NULL, "dsubu", "d,v,t", AT, ZERO, treg);
macro_build (NULL, "dsllv", "d,t,s", AT, sreg, AT);
macro_build (NULL, "dsrlv", "d,t,s", dreg, sreg, treg);
macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
break;
}
used_at = 1;
- macro_build (NULL, "subu", "d,v,t", AT, 0, treg);
+ macro_build (NULL, "subu", "d,v,t", AT, ZERO, treg);
macro_build (NULL, "sllv", "d,t,s", AT, sreg, AT);
macro_build (NULL, "srlv", "d,t,s", dreg, sreg, treg);
macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
}
break;
- case M_S_DOB:
- gas_assert (mips_opts.isa == ISA_MIPS1);
- /* Even on a big endian machine $fn comes before $fn+1. We have
- to adjust when storing to memory. */
- macro_build (&offset_expr, "swc1", "T,o(b)",
- target_big_endian ? treg + 1 : treg, BFD_RELOC_LO16, breg);
- offset_expr.X_add_number += 4;
- macro_build (&offset_expr, "swc1", "T,o(b)",
- target_big_endian ? treg : treg + 1, BFD_RELOC_LO16, breg);
- break;
-
case M_SEQ:
if (sreg == 0)
macro_build (&expr1, "sltiu", "t,r,j", dreg, treg, BFD_RELOC_LO16);
ulh:
used_at = 1;
if (offset_expr.X_add_number >= 0x7fff)
- as_bad (_("operand overflow"));
- if (! target_big_endian)
+ as_bad (_("Operand overflow"));
+ if (!target_big_endian)
++offset_expr.X_add_number;
macro_build (&offset_expr, s, "t,o(b)", AT, BFD_RELOC_LO16, breg);
- if (! target_big_endian)
+ if (!target_big_endian)
--offset_expr.X_add_number;
else
++offset_expr.X_add_number;
off = 3;
ulw:
if (offset_expr.X_add_number >= 0x8000 - off)
- as_bad (_("operand overflow"));
+ as_bad (_("Operand overflow"));
if (treg != breg)
tempreg = treg;
else
used_at = 1;
tempreg = AT;
}
- if (! target_big_endian)
+ if (!target_big_endian)
offset_expr.X_add_number += off;
macro_build (&offset_expr, s, "t,o(b)", tempreg, BFD_RELOC_LO16, breg);
- if (! target_big_endian)
+ if (!target_big_endian)
offset_expr.X_add_number -= off;
else
offset_expr.X_add_number += off;
macro_build (&offset_expr, s2, "t,o(b)", tempreg, BFD_RELOC_LO16, breg);
- /* If necessary, move the result in tempreg the final destination. */
+ /* If necessary, move the result in tempreg to the final destination. */
if (treg == tempreg)
break;
/* Protect second load's delay slot. */
load_address (AT, &offset_expr, &used_at);
if (breg != 0)
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, AT, breg);
- if (! target_big_endian)
+ if (!target_big_endian)
expr1.X_add_number = off;
else
expr1.X_add_number = 0;
macro_build (&expr1, s, "t,o(b)", treg, BFD_RELOC_LO16, AT);
- if (! target_big_endian)
+ if (!target_big_endian)
expr1.X_add_number = 0;
else
expr1.X_add_number = off;
case M_USH:
used_at = 1;
if (offset_expr.X_add_number >= 0x7fff)
- as_bad (_("operand overflow"));
+ as_bad (_("Operand overflow"));
if (target_big_endian)
++offset_expr.X_add_number;
macro_build (&offset_expr, "sb", "t,o(b)", treg, BFD_RELOC_LO16, breg);
off = 3;
usw:
if (offset_expr.X_add_number >= 0x8000 - off)
- as_bad (_("operand overflow"));
- if (! target_big_endian)
+ as_bad (_("Operand overflow"));
+ if (!target_big_endian)
offset_expr.X_add_number += off;
macro_build (&offset_expr, s, "t,o(b)", treg, BFD_RELOC_LO16, breg);
- if (! target_big_endian)
+ if (!target_big_endian)
offset_expr.X_add_number -= off;
else
offset_expr.X_add_number += off;
load_address (AT, &offset_expr, &used_at);
if (breg != 0)
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, AT, breg);
- if (! target_big_endian)
+ if (!target_big_endian)
expr1.X_add_number = off;
else
expr1.X_add_number = 0;
macro_build (&expr1, s, "t,o(b)", treg, BFD_RELOC_LO16, AT);
- if (! target_big_endian)
+ if (!target_big_endian)
expr1.X_add_number = 0;
else
expr1.X_add_number = off;
load_address (AT, &offset_expr, &used_at);
if (breg != 0)
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, AT, breg);
- if (! target_big_endian)
+ if (!target_big_endian)
expr1.X_add_number = 0;
macro_build (&expr1, "sb", "t,o(b)", treg, BFD_RELOC_LO16, AT);
macro_build (NULL, "srl", "d,w,<", treg, treg, 8);
- if (! target_big_endian)
+ if (!target_big_endian)
expr1.X_add_number = 1;
else
expr1.X_add_number = 0;
macro_build (&expr1, "sb", "t,o(b)", treg, BFD_RELOC_LO16, AT);
- if (! target_big_endian)
+ if (!target_big_endian)
expr1.X_add_number = 0;
else
expr1.X_add_number = 1;
case 'Q': USE_BITS (OP_MASK_SEQI, OP_SH_SEQI); break;
case 's': USE_BITS (OP_MASK_CINSLM1, OP_SH_CINSLM1); break;
case 'S': USE_BITS (OP_MASK_CINSLM1, OP_SH_CINSLM1); break;
+ case 'z': USE_BITS (OP_MASK_RZ, OP_SH_RZ); break;
+ case 'Z': USE_BITS (OP_MASK_FZ, OP_SH_FZ); break;
+ case 'a': USE_BITS (OP_MASK_OFFSET_A, OP_SH_OFFSET_A); break;
+ case 'b': USE_BITS (OP_MASK_OFFSET_B, OP_SH_OFFSET_B); break;
+ case 'c': USE_BITS (OP_MASK_OFFSET_C, OP_SH_OFFSET_C); break;
default:
as_bad (_("internal: bad mips opcode (unknown extension operand type `+%c'): %s %s"),
struct mips_opcode *insn;
char *argsStart;
unsigned int regno;
- unsigned int lastregno = 0;
+ unsigned int lastregno;
unsigned int lastpos = 0;
unsigned int limlo, limhi;
char *s_reset;
/* If we did not find a '.', then we can quit now. */
if (*s != '.')
{
- insn_error = _("unrecognized opcode");
+ insn_error = _("Unrecognized opcode");
return;
}
*s++ = '\0';
if ((insn = (struct mips_opcode *) hash_find (op_hash, str)) == NULL)
{
- insn_error = _("unrecognized opcode");
+ insn_error = _("Unrecognized opcode");
return;
}
}
return;
break;
- case '2': /* dsp 2-bit unsigned immediate in bit 11 */
+ case '2': /* DSP 2-bit unsigned immediate in bit 11. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if ((unsigned long) imm_expr.X_add_number != 1
s = expr_end;
continue;
- case '3': /* dsp 3-bit unsigned immediate in bit 21 */
+ case '3': /* DSP 3-bit unsigned immediate in bit 21. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if (imm_expr.X_add_number & ~OP_MASK_SA3)
s = expr_end;
continue;
- case '4': /* dsp 4-bit unsigned immediate in bit 21 */
+ case '4': /* DSP 4-bit unsigned immediate in bit 21. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if (imm_expr.X_add_number & ~OP_MASK_SA4)
s = expr_end;
continue;
- case '5': /* dsp 8-bit unsigned immediate in bit 16 */
+ case '5': /* DSP 8-bit unsigned immediate in bit 16. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if (imm_expr.X_add_number & ~OP_MASK_IMM8)
s = expr_end;
continue;
- case '6': /* dsp 5-bit unsigned immediate in bit 21 */
+ case '6': /* DSP 5-bit unsigned immediate in bit 21. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if (imm_expr.X_add_number & ~OP_MASK_RS)
s = expr_end;
continue;
- case '7': /* four dsp accumulators in bits 11,12 */
+ case '7': /* Four DSP accumulators in bits 11,12. */
if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
s[3] >= '0' && s[3] <= '3')
{
as_bad (_("Invalid dsp acc register"));
break;
- case '8': /* dsp 6-bit unsigned immediate in bit 11 */
+ case '8': /* DSP 6-bit unsigned immediate in bit 11. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if (imm_expr.X_add_number & ~OP_MASK_WRDSP)
s = expr_end;
continue;
- case '9': /* four dsp accumulators in bits 21,22 */
+ case '9': /* Four DSP accumulators in bits 21,22. */
if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
s[3] >= '0' && s[3] <= '3')
{
as_bad (_("Invalid dsp acc register"));
break;
- case '0': /* dsp 6-bit signed immediate in bit 20 */
+ case '0': /* DSP 6-bit signed immediate in bit 20. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
min_range = -((OP_MASK_DSPSFT + 1) >> 1);
s = expr_end;
continue;
- case '\'': /* dsp 6-bit unsigned immediate in bit 16 */
+ case '\'': /* DSP 6-bit unsigned immediate in bit 16. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if (imm_expr.X_add_number & ~OP_MASK_RDDSP)
s = expr_end;
continue;
- case ':': /* dsp 7-bit signed immediate in bit 19 */
+ case ':': /* DSP 7-bit signed immediate in bit 19. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
min_range = -((OP_MASK_DSPSFT_7 + 1) >> 1);
s = expr_end;
continue;
- case '@': /* dsp 10-bit signed immediate in bit 16 */
+ case '@': /* DSP 10-bit signed immediate in bit 16. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
min_range = -((OP_MASK_IMM10 + 1) >> 1);
s = expr_end;
continue;
- case '*': /* four dsp accumulators in bits 18,19 */
+ case '*': /* Four DSP accumulators in bits 18,19. */
if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
s[3] >= '0' && s[3] <= '3')
{
as_bad (_("Invalid dsp/smartmips acc register"));
break;
- case '&': /* four dsp accumulators in bits 13,14 */
+ case '&': /* Four DSP accumulators in bits 13,14. */
if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
s[3] >= '0' && s[3] <= '3')
{
we must have a left paren. */
/* This is dependent on the next operand specifier
is a base register specification. */
- gas_assert (args[1] == 'b' || args[1] == '5'
- || args[1] == '-' || args[1] == '4');
+ gas_assert (args[1] == 'b');
if (*s == '\0')
return;
- case ')': /* these must match exactly */
+ case ')': /* These must match exactly. */
case '[':
case ']':
if (*s++ == *args)
imm->desc ? imm->desc : ip->insn_mo->name,
(unsigned long) imm_expr.X_add_number,
(unsigned long) imm_expr.X_add_number);
- imm_expr.X_add_number &= imm->mask;
+ imm_expr.X_add_number &= imm->mask;
}
ip->insn_opcode |= ((unsigned long) imm_expr.X_add_number
<< imm->shift);
s = expr_end;
}
continue;
-
+
case 'A': /* ins/ext position, becomes LSB. */
limlo = 0;
limhi = 31;
limlo = 32;
limhi = 63;
goto do_lsb;
-do_lsb:
+ do_lsb:
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if ((unsigned long) imm_expr.X_add_number < limlo
limlo = 33;
limhi = 64;
goto do_msb;
-do_msb:
+ do_msb:
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
/* Check for negative input so that small negative numbers
limlo = 33;
limhi = 64;
goto do_msbd;
-do_msbd:
+ do_msbd:
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
/* Check for negative input so that small negative numbers
s = expr_end;
continue;
+ case 'a': /* 8-bit signed offset in bit 6 */
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ min_range = -((OP_MASK_OFFSET_A + 1) >> 1);
+ max_range = ((OP_MASK_OFFSET_A + 1) >> 1) - 1;
+ if (imm_expr.X_add_number < min_range
+ || imm_expr.X_add_number > max_range)
+ {
+ as_bad (_("Offset not in range %ld..%ld (%ld)"),
+ (long) min_range, (long) max_range,
+ (long) imm_expr.X_add_number);
+ }
+ INSERT_OPERAND (OFFSET_A, *ip, imm_expr.X_add_number);
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ continue;
+
+ case 'b': /* 8-bit signed offset in bit 3 */
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ min_range = -((OP_MASK_OFFSET_B + 1) >> 1);
+ max_range = ((OP_MASK_OFFSET_B + 1) >> 1) - 1;
+ if (imm_expr.X_add_number < min_range
+ || imm_expr.X_add_number > max_range)
+ {
+ as_bad (_("Offset not in range %ld..%ld (%ld)"),
+ (long) min_range, (long) max_range,
+ (long) imm_expr.X_add_number);
+ }
+ INSERT_OPERAND (OFFSET_B, *ip, imm_expr.X_add_number);
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ continue;
+
+ case 'c': /* 9-bit signed offset in bit 6 */
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ min_range = -((OP_MASK_OFFSET_C + 1) >> 1);
+ max_range = ((OP_MASK_OFFSET_C + 1) >> 1) - 1;
+ /* We check the offset range before adjusted. */
+ min_range <<= 4;
+ max_range <<= 4;
+ if (imm_expr.X_add_number < min_range
+ || imm_expr.X_add_number > max_range)
+ {
+ as_bad (_("Offset not in range %ld..%ld (%ld)"),
+ (long) min_range, (long) max_range,
+ (long) imm_expr.X_add_number);
+ }
+ if (imm_expr.X_add_number & 0xf)
+ {
+ as_bad (_("Offset not 16 bytes alignment (%ld)"),
+ (long) imm_expr.X_add_number);
+ }
+ /* Right shift 4 bits to adjust the offset operand. */
+ INSERT_OPERAND (OFFSET_C, *ip, imm_expr.X_add_number >> 4);
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ continue;
+
+ case 'z':
+ if (!reg_lookup (&s, RTYPE_NUM | RTYPE_GP, ®no))
+ break;
+ if (regno == AT && mips_opts.at)
+ {
+ if (mips_opts.at == ATREG)
+ as_warn (_("used $at without \".set noat\""));
+ else
+ as_warn (_("used $%u with \".set at=$%u\""),
+ regno, mips_opts.at);
+ }
+ INSERT_OPERAND (RZ, *ip, regno);
+ continue;
+
+ case 'Z':
+ if (!reg_lookup (&s, RTYPE_FPU, ®no))
+ break;
+ INSERT_OPERAND (FZ, *ip, regno);
+ continue;
+
default:
- as_bad (_("internal: bad mips opcode (unknown extension operand type `+%c'): %s %s"),
- *args, insn->name, insn->args);
+ as_bad (_("Internal error: bad mips opcode "
+ "(unknown extension operand type `+%c'): %s %s"),
+ *args, insn->name, insn->args);
/* Further processing is fruitless. */
return;
}
s = expr_end;
continue;
- case 'k': /* cache code */
- case 'h': /* prefx code */
- case '1': /* sync type */
+ case 'k': /* CACHE code. */
+ case 'h': /* PREFX code. */
+ case '1': /* SYNC type. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if ((unsigned long) imm_expr.X_add_number > 31)
ip->insn_mo->name,
(unsigned long) imm_expr.X_add_number);
if (*args == 'k')
- INSERT_OPERAND (CACHE, *ip, imm_expr.X_add_number);
+ {
+ if (mips_fix_cn63xxp1 && strcmp ("pref", insn->name) == 0)
+ switch (imm_expr.X_add_number)
+ {
+ case 5:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+ case 31: /* These are ok. */
+ break;
+
+ default: /* The rest must be changed to 28. */
+ imm_expr.X_add_number = 28;
+ break;
+ }
+ INSERT_OPERAND (CACHE, *ip, imm_expr.X_add_number);
+ }
else if (*args == 'h')
INSERT_OPERAND (PREFX, *ip, imm_expr.X_add_number);
else
s = expr_end;
continue;
- case 'c': /* break code */
+ case 'c': /* BREAK code. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if ((unsigned long) imm_expr.X_add_number > OP_MASK_CODE)
s = expr_end;
continue;
- case 'q': /* lower break code */
+ case 'q': /* Lower BREAK code. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if ((unsigned long) imm_expr.X_add_number > OP_MASK_CODE2)
s = expr_end;
continue;
- case 'B': /* 20-bit syscall/break code. */
+ case 'B': /* 20-bit SYSCALL/BREAK code. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if ((unsigned long) imm_expr.X_add_number > OP_MASK_CODE20)
s = expr_end;
continue;
- case 'C': /* Coprocessor code */
+ case 'C': /* Coprocessor code. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if ((unsigned long) imm_expr.X_add_number > OP_MASK_COPZ)
s = expr_end;
continue;
- case 'J': /* 19-bit wait code. */
+ case 'J': /* 19-bit WAIT code. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if ((unsigned long) imm_expr.X_add_number > OP_MASK_CODE19)
else
break;
- case 'b': /* base register */
- case 'd': /* destination register */
- case 's': /* source register */
- case 't': /* target register */
- case 'r': /* both target and source */
- case 'v': /* both dest and source */
- case 'w': /* both dest and target */
- case 'E': /* coprocessor target register */
- case 'K': /* 'rdhwr' destination register */
- case 'x': /* ignore register name */
- case 'z': /* must be zero register */
- case 'U': /* destination register (clo/clz). */
- case 'g': /* coprocessor destination register */
- s_reset = s;
+ case 'b': /* Base register. */
+ case 'd': /* Destination register. */
+ case 's': /* Source register. */
+ case 't': /* Target register. */
+ case 'r': /* Both target and source. */
+ case 'v': /* Both dest and source. */
+ case 'w': /* Both dest and target. */
+ case 'E': /* Coprocessor target register. */
+ case 'K': /* RDHWR destination register. */
+ case 'x': /* Ignore register name. */
+ case 'z': /* Must be zero register. */
+ case 'U': /* Destination register (CLO/CLZ). */
+ case 'g': /* Coprocessor destination register. */
+ s_reset = s;
if (*args == 'E' || *args == 'K')
ok = reg_lookup (&s, RTYPE_NUM, ®no);
else
if (regno == AT && mips_opts.at)
{
if (mips_opts.at == ATREG)
- as_warn (_("used $at without \".set noat\""));
+ as_warn (_("Used $at without \".set noat\""));
else
- as_warn (_("used $%u with \".set at=$%u\""),
+ as_warn (_("Used $%u with \".set at=$%u\""),
regno, mips_opts.at);
}
}
if (c == 's' && !strncmp (ip->insn_mo->name, "jalr", 4))
{
if (regno == lastregno)
- {
- insn_error = _("source and destination must be different");
+ {
+ insn_error
+ = _("Source and destination must be different");
continue;
- }
+ }
if (regno == 31 && lastregno == 0xffffffff)
- {
- insn_error = _("a destination register must be supplied");
+ {
+ insn_error
+ = _("A destination register must be supplied");
continue;
- }
+ }
}
- /* Now that we have assembled one operand, we use the args string
- * to figure out where it goes in the instruction. */
+ /* Now that we have assembled one operand, we use the args
+ string to figure out where it goes in the instruction. */
switch (c)
{
case 'r':
INSERT_OPERAND (RS, *ip, regno);
break;
case 'd':
- case 'G':
case 'K':
case 'g':
INSERT_OPERAND (RD, *ip, regno);
is $0. This only matches $0, and is checked
outside the switch. */
break;
- case 'D':
- /* Itbl operand; not yet implemented. FIXME ?? */
- break;
- /* What about all other operands like 'i', which
- can be specified in the opcode table? */
}
lastregno = regno;
continue;
case 'Y': /* MDMX source register. */
case 'Z': /* MDMX target register. */
is_mdmx = 1;
- case 'D': /* floating point destination register */
- case 'S': /* floating point source register */
- case 'T': /* floating point target register */
- case 'R': /* floating point source register */
+ case 'D': /* Floating point destination register. */
+ case 'S': /* Floating point source register. */
+ case 'T': /* Floating point target register. */
+ case 'R': /* Floating point source register. */
case 'V':
case 'W':
rtype = RTYPE_FPU;
{
if ((regno & 1) != 0
&& HAVE_32BIT_FPRS
- && ! mips_oddfpreg_ok (ip->insn_mo, argnum))
+ && !mips_oddfpreg_ok (ip->insn_mo, argnum))
as_warn (_("Float register should be even, was %d"),
regno);
ip->insn_opcode |= (MDMX_FMTSEL_VEC_OB <<
OP_SH_VSEL);
}
- /* Fall through */
+ /* Fall through. */
case 'W':
case 'T':
case 'Z':
|| (temp[2] == 0 && temp[3] == 0))))
{
imm_expr.X_op = O_constant;
- if (! target_big_endian)
+ if (!target_big_endian)
imm_expr.X_add_number = bfd_getl32 (temp);
else
imm_expr.X_add_number = bfd_getb32 (temp);
}
else if (length > 4
- && ! mips_disable_float_construction
+ && !mips_disable_float_construction
/* Constants can only be constructed in GPRs and
copied to FPRs if the GPRs are at least as wide
as the FPRs. Force the constant into memory if
we are using 64-bit FPRs but the GPRs are only
32 bits wide. */
&& (using_gprs
- || ! (HAVE_64BIT_FPRS && HAVE_32BIT_GPRS))
+ || !(HAVE_64BIT_FPRS && HAVE_32BIT_GPRS))
&& ((temp[0] == 0 && temp[1] == 0)
|| (temp[2] == 0 && temp[3] == 0))
&& ((temp[4] == 0 && temp[5] == 0)
|| (temp[6] == 0 && temp[7] == 0)))
{
/* The value is simple enough to load with a couple of
- instructions. If using 32-bit registers, set
- imm_expr to the high order 32 bits and offset_expr to
- the low order 32 bits. Otherwise, set imm_expr to
- the entire 64 bit constant. */
+ instructions. If using 32-bit registers, set
+ imm_expr to the high order 32 bits and offset_expr to
+ the low order 32 bits. Otherwise, set imm_expr to
+ the entire 64 bit constant. */
if (using_gprs ? HAVE_32BIT_GPRS : HAVE_32BIT_FPRS)
{
imm_expr.X_op = O_constant;
offset_expr.X_op = O_constant;
- if (! target_big_endian)
+ if (!target_big_endian)
{
imm_expr.X_add_number = bfd_getl32 (temp + 4);
offset_expr.X_add_number = bfd_getl32 (temp);
else if (sizeof (imm_expr.X_add_number) > 4)
{
imm_expr.X_op = O_constant;
- if (! target_big_endian)
+ if (!target_big_endian)
imm_expr.X_add_number = bfd_getl64 (temp);
else
imm_expr.X_add_number = bfd_getb64 (temp);
{
imm_expr.X_op = O_big;
imm_expr.X_add_number = 4;
- if (! target_big_endian)
+ if (!target_big_endian)
{
generic_bignum[0] = bfd_getl16 (temp);
generic_bignum[1] = bfd_getl16 (temp + 2);
}
continue;
- case 'i': /* 16 bit unsigned immediate */
- case 'j': /* 16 bit signed immediate */
+ case 'i': /* 16-bit unsigned immediate. */
+ case 'j': /* 16-bit signed immediate. */
*imm_reloc = BFD_RELOC_LO16;
if (my_getSmallExpression (&imm_expr, imm_reloc, s) == 0)
{
break;
if (imm_expr.X_op == O_constant
|| imm_expr.X_op == O_big)
- as_bad (_("expression out of range"));
+ as_bad (_("Expression out of range"));
}
}
s = expr_end;
continue;
- case 'o': /* 16 bit offset */
+ case 'o': /* 16-bit offset. */
+ offset_reloc[0] = BFD_RELOC_LO16;
+ offset_reloc[1] = BFD_RELOC_UNUSED;
+ offset_reloc[2] = BFD_RELOC_UNUSED;
+
/* Check whether there is only a single bracketed expression
left. If so, it must be the base register and the
constant must be zero. */
s = expr_end;
continue;
- case 'p': /* pc relative offset */
+ case 'p': /* PC-relative offset. */
*offset_reloc = BFD_RELOC_16_PCREL_S2;
my_getExpression (&offset_expr, s);
s = expr_end;
continue;
- case 'u': /* upper 16 bits */
+ case 'u': /* Upper 16 bits. */
if (my_getSmallExpression (&imm_expr, imm_reloc, s) == 0
&& imm_expr.X_op == O_constant
&& (imm_expr.X_add_number < 0
|| imm_expr.X_add_number >= 0x10000))
- as_bad (_("lui expression not in range 0..65535"));
+ as_bad (_("lui expression (%lu) not in range 0..65535"),
+ (unsigned long) imm_expr.X_add_number);
s = expr_end;
continue;
- case 'a': /* 26 bit address */
+ case 'a': /* 26-bit address. */
my_getExpression (&offset_expr, s);
s = expr_end;
*offset_reloc = BFD_RELOC_MIPS_JMP;
continue;
- case 'N': /* 3 bit branch condition code */
- case 'M': /* 3 bit compare condition code */
+ case 'N': /* 3-bit branch condition code. */
+ case 'M': /* 3-bit compare condition code. */
rtype = RTYPE_CCC;
- if (ip->insn_mo->pinfo & (FP_D| FP_S))
+ if (ip->insn_mo->pinfo & (FP_D | FP_S))
rtype |= RTYPE_FCC;
if (!reg_lookup (&s, rtype, ®no))
break;
- if ((strcmp(str + strlen(str) - 3, ".ps") == 0
- || strcmp(str + strlen(str) - 5, "any2f") == 0
- || strcmp(str + strlen(str) - 5, "any2t") == 0)
+ if ((strcmp (str + strlen (str) - 3, ".ps") == 0
+ || strcmp (str + strlen (str) - 5, "any2f") == 0
+ || strcmp (str + strlen (str) - 5, "any2t") == 0)
&& (regno & 1) != 0)
- as_warn (_("Condition code register should be even for %s, was %d"),
+ as_warn (_("Condition code register should be even for %s, "
+ "was %d"),
str, regno);
- if ((strcmp(str + strlen(str) - 5, "any4f") == 0
- || strcmp(str + strlen(str) - 5, "any4t") == 0)
+ if ((strcmp (str + strlen (str) - 5, "any4f") == 0
+ || strcmp (str + strlen (str) - 5, "any4t") == 0)
&& (regno & 3) != 0)
- as_warn (_("Condition code register should be 0 or 4 for %s, was %d"),
+ as_warn (_("Condition code register should be 0 or 4 for %s, "
+ "was %d"),
str, regno);
if (*args == 'N')
INSERT_OPERAND (BCC, *ip, regno);
c = 8; /* Invalid sel value. */
if (c > 7)
- as_bad (_("invalid coprocessor sub-selection value (0-7)"));
+ as_bad (_("Invalid coprocessor sub-selection value (0-7)"));
ip->insn_opcode |= c;
continue;
continue;
default:
- as_bad (_("bad char = '%c'\n"), *args);
+ as_bad (_("Bad char = '%c'\n"), *args);
internalError ();
}
break;
{
++insn;
s = argsStart;
- insn_error = _("illegal operands");
+ insn_error = _("Illegal operands");
continue;
}
if (save_c)
*(--argsStart) = save_c;
- insn_error = _("illegal operands");
+ insn_error = _("Illegal operands");
return;
}
}
my_getExpression (expressionS *ep, char *str)
{
char *save_in;
- valueT val;
save_in = input_line_pointer;
input_line_pointer = str;
expression (ep);
expr_end = input_line_pointer;
input_line_pointer = save_in;
-
- /* If we are in mips16 mode, and this is an expression based on `.',
- then we bump the value of the symbol by 1 since that is how other
- text symbols are handled. We don't bother to handle complex
- expressions, just `.' plus or minus a constant. */
- if (mips_opts.mips16
- && ep->X_op == O_symbol
- && strcmp (S_GET_NAME (ep->X_add_symbol), FAKE_LABEL_NAME) == 0
- && S_GET_SEGMENT (ep->X_add_symbol) == now_seg
- && symbol_get_frag (ep->X_add_symbol) == frag_now
- && symbol_constant_p (ep->X_add_symbol)
- && (val = S_GET_VALUE (ep->X_add_symbol)) == frag_now_fix ())
- S_SET_VALUE (ep->X_add_symbol, val + 1);
}
char *
list = bfd_target_list ();
for (l = list; *l != NULL; l++)
-#ifdef TE_TMIPS
- /* This is traditional mips */
- if (strcmp (*l, "elf64-tradbigmips") == 0
- || strcmp (*l, "elf64-tradlittlemips") == 0)
-#else
- if (strcmp (*l, "elf64-bigmips") == 0
- || strcmp (*l, "elf64-littlemips") == 0)
-#endif
+ if (strcmp (*l, ELF_TARGET ("elf64-", "big")) == 0
+ || strcmp (*l, ELF_TARGET ("elf64-", "little")) == 0)
break;
yes = (*l != NULL);
free (list);
OPTION_NO_FIX_VR4120,
OPTION_FIX_VR4130,
OPTION_NO_FIX_VR4130,
+ OPTION_FIX_CN63XXP1,
+ OPTION_NO_FIX_CN63XXP1,
OPTION_TRAP,
OPTION_BREAK,
OPTION_EB,
{"mno-fix-vr4130", no_argument, NULL, OPTION_NO_FIX_VR4130},
{"mfix-24k", no_argument, NULL, OPTION_FIX_24K},
{"mno-fix-24k", no_argument, NULL, OPTION_NO_FIX_24K},
+ {"mfix-cn63xxp1", no_argument, NULL, OPTION_FIX_CN63XXP1},
+ {"mno-fix-cn63xxp1", no_argument, NULL, OPTION_NO_FIX_CN63XXP1},
/* Miscellaneous options. */
{"trap", no_argument, NULL, OPTION_TRAP},
mips_fix_vr4130 = 0;
break;
+ case OPTION_FIX_CN63XXP1:
+ mips_fix_cn63xxp1 = TRUE;
+ break;
+
+ case OPTION_NO_FIX_CN63XXP1:
+ mips_fix_cn63xxp1 = FALSE;
+ break;
+
case OPTION_RELAX_BRANCH:
mips_relax_branch = 1;
break;
mips_cpu_info_from_isa (mips_opts.isa)->name);
file_mips_isa = mips_opts.isa;
- file_ase_mips16 = mips_opts.mips16;
file_ase_mips3d = mips_opts.ase_mips3d;
file_ase_mdmx = mips_opts.ase_mdmx;
file_ase_smartmips = mips_opts.ase_smartmips;
return;
gas_assert (fixP->fx_size == 4
- || fixP->fx_r_type == BFD_RELOC_16
- || fixP->fx_r_type == BFD_RELOC_64
- || fixP->fx_r_type == BFD_RELOC_CTOR
- || fixP->fx_r_type == BFD_RELOC_MIPS_SUB
- || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
- || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY
- || fixP->fx_r_type == BFD_RELOC_MIPS_TLS_DTPREL64);
+ || fixP->fx_r_type == BFD_RELOC_16
+ || fixP->fx_r_type == BFD_RELOC_64
+ || fixP->fx_r_type == BFD_RELOC_CTOR
+ || fixP->fx_r_type == BFD_RELOC_MIPS_SUB
+ || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+ || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY
+ || fixP->fx_r_type == BFD_RELOC_MIPS_TLS_DTPREL64);
buf = (bfd_byte *) (fixP->fx_frag->fr_literal + fixP->fx_where);
}
demand_empty_rest_of_line ();
break;
+
+ case 'B':
+ seg = subseg_new (".sbss", (subsegT) get_absolute_expression ());
+ if (IS_ELF)
+ {
+ bfd_set_section_flags (stdoutput, seg, SEC_ALLOC);
+ if (strncmp (TARGET_OS, "elf", 3) != 0)
+ record_alignment (seg, 4);
+ }
+ demand_empty_rest_of_line ();
+ break;
}
auto_align = 1;
mips_emit_delays ();
if (log_size > 0 && auto_align)
mips_align (log_size, 0, label);
- mips_clear_insn_labels ();
cons (1 << log_size);
+ mips_clear_insn_labels ();
}
static void
mips_align (2, 0, label);
}
- mips_clear_insn_labels ();
-
float_cons (type);
+ mips_clear_insn_labels ();
}
/* Handle .globl. We need to override it because on Irix 5 you are
mips_emit_delays ();
if (auto_align)
mips_align (2, 0, label);
- mips_clear_insn_labels ();
expression (&ex);
+ mips_clear_insn_labels ();
if (ex.X_op != O_symbol || ex.X_add_number != 0)
{
mips_emit_delays ();
if (auto_align)
mips_align (3, 0, label);
- mips_clear_insn_labels ();
expression (&ex);
+ mips_clear_insn_labels ();
if (ex.X_op != O_symbol || ex.X_add_number != 0)
{
if (fragp && update && toofar != RELAX_BRANCH_TOOFAR (fragp->fr_subtype))
fragp->fr_subtype
- = RELAX_BRANCH_ENCODE (RELAX_BRANCH_UNCOND (fragp->fr_subtype),
+ = RELAX_BRANCH_ENCODE (RELAX_BRANCH_AT (fragp->fr_subtype),
+ RELAX_BRANCH_UNCOND (fragp->fr_subtype),
RELAX_BRANCH_LIKELY (fragp->fr_subtype),
RELAX_BRANCH_LINK (fragp->fr_subtype),
toofar);
&& (S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_MERGE) != 0)
return 0;
- /* There is no place to store an in-place offset for JALR relocations. */
- if (fixp->fx_r_type == BFD_RELOC_MIPS_JALR && HAVE_IN_PLACE_ADDENDS)
+ /* There is no place to store an in-place offset for JALR relocations.
+ Likewise an in-range offset of PC-relative relocations may overflow
+ the in-place relocatable field if recalculated against the start
+ address of the symbol's containing section. */
+ if (HAVE_IN_PLACE_ADDENDS
+ && (fixp->fx_pcrel || fixp->fx_r_type == BFD_RELOC_MIPS_JALR))
return 0;
#ifdef OBJ_ELF
int i;
as_warn_where (fragp->fr_file, fragp->fr_line,
- _("relaxed out-of-range branch into a jump"));
+ _("Relaxed out-of-range branch into a jump"));
if (RELAX_BRANCH_UNCOND (fragp->fr_subtype))
goto uncond;
}
else
{
+ unsigned long at = RELAX_BRANCH_AT (fragp->fr_subtype);
+
/* lw/ld $at, <sym>($gp) R_MIPS_GOT16 */
- insn = HAVE_64BIT_ADDRESSES ? 0xdf810000 : 0x8f810000;
+ insn = HAVE_64BIT_ADDRESSES ? 0xdf800000 : 0x8f800000;
+ insn |= at << OP_SH_RT;
exp.X_op = O_symbol;
exp.X_add_symbol = fragp->fr_symbol;
exp.X_add_number = fragp->fr_offset;
}
/* d/addiu $at, $at, <sym> R_MIPS_LO16 */
- insn = HAVE_64BIT_ADDRESSES ? 0x64210000 : 0x24210000;
+ insn = HAVE_64BIT_ADDRESSES ? 0x64000000 : 0x24000000;
+ insn |= at << OP_SH_RS | at << OP_SH_RT;
fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
4, &exp, FALSE, BFD_RELOC_LO16);
/* j(al)r $at. */
if (RELAX_BRANCH_LINK (fragp->fr_subtype))
- insn = 0x0020f809;
+ insn = 0x0000f809;
else
- insn = 0x00200008;
+ insn = 0x00000008;
+ insn |= at << OP_SH_RS;
md_number_to_chars ((char *) buf, insn, 4);
buf += 4;
ext = FALSE;
}
- resolve_symbol_value (fragp->fr_symbol);
- val = S_GET_VALUE (fragp->fr_symbol);
+ val = resolve_symbol_value (fragp->fr_symbol);
if (op->pcrel)
{
addressT addr;
#endif
-/* This function is called whenever a label is defined. It is used
- when handling branch delays; if a branch has a label, we assume we
- can not move it. */
+/* This function is called whenever a label is defined, including fake
+ labels instantiated off the dot special symbol. It is used when
+ handling branch delays; if a branch has a label, we assume we cannot
+ move it. This also bumps the value of the symbol by 1 in compressed
+ code. */
void
-mips_define_label (symbolS *sym)
+mips_record_label (symbolS *sym)
{
segment_info_type *si = seg_info (now_seg);
struct insn_label_list *l;
l->label = sym;
l->next = si->label_list;
si->label_list = l;
+}
+/* This function is called as tc_frob_label() whenever a label is defined
+ and adds a DWARF-2 record we only want for true labels. */
+
+void
+mips_define_label (symbolS *sym)
+{
+ mips_record_label (sym);
#ifdef OBJ_ELF
dwarf2_emit_label (sym);
#endif
/* Broadcom SB-1A CPU core */
{ "sb1a", MIPS_CPU_ASE_MIPS3D | MIPS_CPU_ASE_MDMX,
ISA_MIPS64, CPU_SB1 },
+
+ { "loongson3a", 0, ISA_MIPS64, CPU_LOONGSON_3A },
/* MIPS 64 Release 2 */
-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\
+-mfix-cn63xxp1 work around CN63XXP1 PREF errata\n\
-mgp32 use 32-bit GPRs, regardless of the chosen ISA\n\
-mfp32 use 32-bit FPRs, regardless of the chosen ISA\n\
-msym32 assume all symbols have 32-bit values\n\