/* 1 if -msingle-float, 0 if -mdouble-float. The default is 0. */
static int file_mips_single_float = 0;
+/* True if -mnan=2008, false if -mnan=legacy. */
+static bfd_boolean mips_flag_nan2008 = FALSE;
+
static struct mips_set_options mips_opts =
{
/* isa */ ISA_UNKNOWN, /* ase */ 0, /* mips16 */ -1, /* micromips */ -1,
static void s_ehword (int);
static void s_cpadd (int);
static void s_insn (int);
+static void s_nan (int);
static void md_obj_begin (void);
static void md_obj_end (void);
static void s_mips_ent (int);
OPTION_PDR,
OPTION_NO_PDR,
OPTION_MVXWORKS_PIC,
+ OPTION_NAN,
OPTION_END_OF_ENUM
};
{"mpdr", no_argument, NULL, OPTION_PDR},
{"mno-pdr", no_argument, NULL, OPTION_NO_PDR},
{"mvxworks-pic", no_argument, NULL, OPTION_MVXWORKS_PIC},
+ {"mnan", required_argument, NULL, OPTION_NAN},
{NULL, no_argument, NULL, 0}
};
{"ehword", s_ehword, 0},
{"cpadd", s_cpadd, 0},
{"insn", s_insn, 0},
+ {"nan", s_nan, 0},
/* Relatively generic pseudo-ops that happen to be used on MIPS
chips. */
\f
static char *expr_end;
-/* Expressions which appear in instructions. These are set by
- mips_ip. */
+/* Expressions which appear in macro instructions. These are set by
+ mips_ip and read by macro. */
static expressionS imm_expr;
static expressionS imm2_expr;
-static expressionS offset_expr;
-/* Relocs associated with imm_expr and offset_expr. */
+/* The relocatable field in an instruction and the relocs associated
+ with it. These variables are used for instructions like LUI and
+ JAL as well as true offsets. They are also used for address
+ operands in macros. */
-static bfd_reloc_code_real_type imm_reloc[3]
- = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
+static expressionS offset_expr;
static bfd_reloc_code_real_type offset_reloc[3]
= {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
imm_expr.X_op = O_absent;
imm2_expr.X_op = O_absent;
offset_expr.X_op = O_absent;
- imm_reloc[0] = BFD_RELOC_UNUSED;
- imm_reloc[1] = BFD_RELOC_UNUSED;
- imm_reloc[2] = BFD_RELOC_UNUSED;
offset_reloc[0] = BFD_RELOC_UNUSED;
offset_reloc[1] = BFD_RELOC_UNUSED;
offset_reloc[2] = BFD_RELOC_UNUSED;
}
else
{
- if (imm_expr.X_op != O_absent)
- append_insn (&insn, &imm_expr, imm_reloc, FALSE);
- else if (offset_expr.X_op != O_absent)
+ if (offset_expr.X_op != O_absent)
append_insn (&insn, &offset_expr, offset_reloc, FALSE);
else
append_insn (&insn, NULL, unused_reloc, FALSE);
return reloc == BFD_RELOC_MIPS_JALR || reloc == BFD_RELOC_MICROMIPS_JALR;
}
+static inline bfd_boolean
+gprel16_reloc_p (bfd_reloc_code_real_type reloc)
+{
+ return (reloc == BFD_RELOC_GPREL16 || reloc == BFD_RELOC_MIPS16_GPREL
+ || reloc == BFD_RELOC_MICROMIPS_GPREL16);
+}
+
/* Return true if RELOC is a PC-relative relocation that does not have
full address range. */
if (next >= 0)
r[0] = (bfd_reloc_code_real_type) next;
else
- for (i = 0; i < 3; i++)
- r[i] = (bfd_reloc_code_real_type) va_arg (*args, int);
+ {
+ for (i = 0; i < 3; i++)
+ r[i] = (bfd_reloc_code_real_type) va_arg (*args, int);
+ /* This function is only used for 16-bit relocation fields.
+ To make the macro code simpler, treat an unrelocated value
+ in the same way as BFD_RELOC_LO16. */
+ if (r[0] == BFD_RELOC_UNUSED)
+ r[0] = BFD_RELOC_LO16;
+ }
}
/* Build an instruction created by a macro expansion. This is passed
case 'C':
gas_assert (!mips_opts.micromips);
- INSERT_OPERAND (0, COPZ, insn, va_arg (args, unsigned long));
+ INSERT_OPERAND (0, COPZ, insn, va_arg (args, int));
continue;
case 'k':
INSERT_OPERAND (mips_opts.micromips,
- CACHE, insn, va_arg (args, unsigned long));
+ CACHE, insn, va_arg (args, int));
continue;
case '|':
case '\\':
INSERT_OPERAND (mips_opts.micromips,
- 3BITPOS, insn, va_arg (args, unsigned int));
+ 3BITPOS, insn, va_arg (args, int));
continue;
case '~':
INSERT_OPERAND (mips_opts.micromips,
- OFFSET12, insn, va_arg (args, unsigned long));
+ OFFSET12, insn, va_arg (args, int));
continue;
case 'N':
MIPS16_INSERT_OPERAND (REGR32, insn, va_arg (*args, int));
continue;
- case 'Y':
- {
- int regno;
-
- regno = va_arg (*args, int);
- regno = ((regno & 7) << 2) | ((regno & 0x18) >> 3);
- MIPS16_INSERT_OPERAND (REG32R, insn, regno);
- }
- continue;
-
case '<':
case '>':
case '4':
macro_build (ep, br, "s,t,p", sreg, treg);
}
+/* Return the high part that should be loaded in order to make the low
+ part of VALUE accessible using an offset of OFFBITS bits. */
+
+static offsetT
+offset_high_part (offsetT value, unsigned int offbits)
+{
+ offsetT bias;
+ addressT low_mask;
+
+ if (offbits == 0)
+ return value;
+ bias = 1 << (offbits - 1);
+ low_mask = bias * 2 - 1;
+ return (value + bias) & ~low_mask;
+}
+
+/* Return true if the value stored in offset_expr and offset_reloc
+ fits into a signed offset of OFFBITS bits. RANGE is the maximum
+ amount that the caller wants to add without inducing overflow
+ and ALIGN is the known alignment of the value in bytes. */
+
+static bfd_boolean
+small_offset_p (unsigned int range, unsigned int align, unsigned int offbits)
+{
+ if (offbits == 16)
+ {
+ /* Accept any relocation operator if overflow isn't a concern. */
+ if (range < align && *offset_reloc != BFD_RELOC_UNUSED)
+ return TRUE;
+
+ /* These relocations are guaranteed not to overflow in correct links. */
+ if (*offset_reloc == BFD_RELOC_MIPS_LITERAL
+ || gprel16_reloc_p (*offset_reloc))
+ return TRUE;
+ }
+ if (offset_expr.X_op == O_constant
+ && offset_high_part (offset_expr.X_add_number, offbits) == 0
+ && offset_high_part (offset_expr.X_add_number + range, offbits) == 0)
+ return TRUE;
+ return FALSE;
+}
+
/*
* Build macros
* This routine implements the seemingly endless macro or synthesized
int imm = 0;
int ust = 0;
int lp = 0;
- int ab = 0;
+ bfd_boolean large_offset;
int off;
- bfd_reloc_code_real_type r;
int hold_mips_optimize;
+ unsigned int align;
gas_assert (! mips_opts.mips16);
expr1.X_op_symbol = NULL;
expr1.X_add_symbol = NULL;
expr1.X_add_number = 1;
+ align = 1;
switch (mask)
{
if (!dbl && HAVE_64BIT_OBJECTS)
as_warn (_("la used to load 64-bit address"));
- if (offset_expr.X_op == O_constant
- && offset_expr.X_add_number >= -0x8000
- && offset_expr.X_add_number < 0x8000)
+ if (small_offset_p (0, align, 16))
{
- macro_build (&offset_expr, ADDRESS_ADDI_INSN,
- "t,r,j", treg, sreg, BFD_RELOC_LO16);
+ macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j", treg, breg,
+ -1, offset_reloc[0], offset_reloc[1], offset_reloc[2]);
break;
}
case M_MSGSND:
gas_assert (!mips_opts.micromips);
- {
- unsigned long temp = (treg << 16) | (0x01);
- macro_build (NULL, "c2", "C", temp);
- }
+ macro_build (NULL, "c2", "C", (treg << 16) | 0x01);
break;
case M_MSGLD:
gas_assert (!mips_opts.micromips);
- {
- unsigned long temp = (0x02);
- macro_build (NULL, "c2", "C", temp);
- }
+ macro_build (NULL, "c2", "C", 0x02);
break;
case M_MSGLD_T:
gas_assert (!mips_opts.micromips);
- {
- unsigned long temp = (treg << 16) | (0x02);
- macro_build (NULL, "c2", "C", temp);
- }
+ macro_build (NULL, "c2", "C", (treg << 16) | 0x02);
break;
case M_MSGWAIT:
case M_MSGWAIT_T:
gas_assert (!mips_opts.micromips);
- {
- unsigned long temp = (treg << 16) | 0x03;
- macro_build (NULL, "c2", "C", temp);
- }
+ macro_build (NULL, "c2", "C", (treg << 16) | 0x03);
break;
case M_J_A:
break;
case M_LBUE_AB:
- ab = 1;
- case M_LBUE_OB:
s = "lbue";
fmt = "t,+j(b)";
offbits = 9;
goto ld_st;
case M_LHUE_AB:
- ab = 1;
- case M_LHUE_OB:
s = "lhue";
fmt = "t,+j(b)";
offbits = 9;
goto ld_st;
case M_LBE_AB:
- ab = 1;
- case M_LBE_OB:
s = "lbe";
fmt = "t,+j(b)";
offbits = 9;
goto ld_st;
case M_LHE_AB:
- ab = 1;
- case M_LHE_OB:
s = "lhe";
fmt = "t,+j(b)";
offbits = 9;
goto ld_st;
case M_LLE_AB:
- ab = 1;
- case M_LLE_OB:
s = "lle";
fmt = "t,+j(b)";
offbits = 9;
goto ld_st;
case M_LWE_AB:
- ab = 1;
- case M_LWE_OB:
s = "lwe";
fmt = "t,+j(b)";
offbits = 9;
goto ld_st;
case M_LWLE_AB:
- ab = 1;
- case M_LWLE_OB:
s = "lwle";
fmt = "t,+j(b)";
offbits = 9;
goto ld_st;
case M_LWRE_AB:
- ab = 1;
- case M_LWRE_OB:
s = "lwre";
fmt = "t,+j(b)";
offbits = 9;
goto ld_st;
case M_SBE_AB:
- ab = 1;
- case M_SBE_OB:
s = "sbe";
fmt = "t,+j(b)";
offbits = 9;
goto ld_st;
case M_SCE_AB:
- ab = 1;
- case M_SCE_OB:
s = "sce";
fmt = "t,+j(b)";
offbits = 9;
goto ld_st;
case M_SHE_AB:
- ab = 1;
- case M_SHE_OB:
s = "she";
fmt = "t,+j(b)";
offbits = 9;
goto ld_st;
case M_SWE_AB:
- ab = 1;
- case M_SWE_OB:
s = "swe";
fmt = "t,+j(b)";
offbits = 9;
goto ld_st;
case M_SWLE_AB:
- ab = 1;
- case M_SWLE_OB:
s = "swle";
fmt = "t,+j(b)";
offbits = 9;
goto ld_st;
case M_SWRE_AB:
- ab = 1;
- case M_SWRE_OB:
s = "swre";
fmt = "t,+j(b)";
offbits = 9;
goto ld_st;
case M_ACLR_AB:
- ab = 1;
- case M_ACLR_OB:
s = "aclr";
treg = EXTRACT_OPERAND (mips_opts.micromips, 3BITPOS, *ip);
fmt = "\\,~(b)";
offbits = 12;
goto ld_st;
case M_ASET_AB:
- ab = 1;
- case M_ASET_OB:
s = "aset";
treg = EXTRACT_OPERAND (mips_opts.micromips, 3BITPOS, *ip);
fmt = "\\,~(b)";
offbits = 12;
goto ld_st;
case M_LB_AB:
- ab = 1;
s = "lb";
fmt = "t,o(b)";
goto ld;
case M_LBU_AB:
- ab = 1;
s = "lbu";
fmt = "t,o(b)";
goto ld;
case M_LH_AB:
- ab = 1;
s = "lh";
fmt = "t,o(b)";
goto ld;
case M_LHU_AB:
- ab = 1;
s = "lhu";
fmt = "t,o(b)";
goto ld;
case M_LW_AB:
- ab = 1;
s = "lw";
fmt = "t,o(b)";
goto ld;
case M_LWC0_AB:
- ab = 1;
gas_assert (!mips_opts.micromips);
s = "lwc0";
fmt = "E,o(b)";
coproc = 1;
goto ld_st;
case M_LWC1_AB:
- ab = 1;
s = "lwc1";
fmt = "T,o(b)";
/* Itbl support may require additional care here. */
coproc = 1;
goto ld_st;
case M_LWC2_AB:
- ab = 1;
- case M_LWC2_OB:
s = "lwc2";
fmt = COP12_FMT;
offbits = (mips_opts.micromips ? 12 : 16);
coproc = 1;
goto ld_st;
case M_LWC3_AB:
- ab = 1;
gas_assert (!mips_opts.micromips);
s = "lwc3";
fmt = "E,o(b)";
coproc = 1;
goto ld_st;
case M_LWL_AB:
- ab = 1;
- case M_LWL_OB:
s = "lwl";
fmt = MEM12_FMT;
offbits = (mips_opts.micromips ? 12 : 16);
goto ld_st;
case M_LWR_AB:
- ab = 1;
- case M_LWR_OB:
s = "lwr";
fmt = MEM12_FMT;
offbits = (mips_opts.micromips ? 12 : 16);
goto ld_st;
case M_LDC1_AB:
- ab = 1;
s = "ldc1";
fmt = "T,o(b)";
/* Itbl support may require additional care here. */
coproc = 1;
goto ld_st;
case M_LDC2_AB:
- ab = 1;
- case M_LDC2_OB:
s = "ldc2";
fmt = COP12_FMT;
offbits = (mips_opts.micromips ? 12 : 16);
coproc = 1;
goto ld_st;
case M_LQC2_AB:
- ab = 1;
s = "lqc2";
fmt = "E,o(b)";
/* Itbl support may require additional care here. */
coproc = 1;
goto ld_st;
case M_LDC3_AB:
- ab = 1;
s = "ldc3";
fmt = "E,o(b)";
/* Itbl support may require additional care here. */
coproc = 1;
goto ld_st;
case M_LDL_AB:
- ab = 1;
- case M_LDL_OB:
s = "ldl";
fmt = MEM12_FMT;
offbits = (mips_opts.micromips ? 12 : 16);
goto ld_st;
case M_LDR_AB:
- ab = 1;
- case M_LDR_OB:
s = "ldr";
fmt = MEM12_FMT;
offbits = (mips_opts.micromips ? 12 : 16);
goto ld_st;
case M_LL_AB:
- ab = 1;
- case M_LL_OB:
s = "ll";
fmt = MEM12_FMT;
offbits = (mips_opts.micromips ? 12 : 16);
goto ld;
case M_LLD_AB:
- ab = 1;
- case M_LLD_OB:
s = "lld";
fmt = MEM12_FMT;
offbits = (mips_opts.micromips ? 12 : 16);
goto ld;
case M_LWU_AB:
- ab = 1;
- case M_LWU_OB:
s = "lwu";
fmt = MEM12_FMT;
offbits = (mips_opts.micromips ? 12 : 16);
goto ld;
case M_LWP_AB:
- ab = 1;
- case M_LWP_OB:
gas_assert (mips_opts.micromips);
s = "lwp";
fmt = "t,~(b)";
lp = 1;
goto ld;
case M_LDP_AB:
- ab = 1;
- case M_LDP_OB:
gas_assert (mips_opts.micromips);
s = "ldp";
fmt = "t,~(b)";
lp = 1;
goto ld;
case M_LWM_AB:
- ab = 1;
- case M_LWM_OB:
gas_assert (mips_opts.micromips);
s = "lwm";
fmt = "n,~(b)";
offbits = 12;
goto ld_st;
case M_LDM_AB:
- ab = 1;
- case M_LDM_OB:
gas_assert (mips_opts.micromips);
s = "ldm";
fmt = "n,~(b)";
goto ld_noat;
case M_SB_AB:
- ab = 1;
s = "sb";
fmt = "t,o(b)";
goto ld_st;
case M_SH_AB:
- ab = 1;
s = "sh";
fmt = "t,o(b)";
goto ld_st;
case M_SW_AB:
- ab = 1;
s = "sw";
fmt = "t,o(b)";
goto ld_st;
case M_SWC0_AB:
- ab = 1;
gas_assert (!mips_opts.micromips);
s = "swc0";
fmt = "E,o(b)";
coproc = 1;
goto ld_st;
case M_SWC1_AB:
- ab = 1;
s = "swc1";
fmt = "T,o(b)";
/* Itbl support may require additional care here. */
coproc = 1;
goto ld_st;
case M_SWC2_AB:
- ab = 1;
- case M_SWC2_OB:
s = "swc2";
fmt = COP12_FMT;
offbits = (mips_opts.micromips ? 12 : 16);
coproc = 1;
goto ld_st;
case M_SWC3_AB:
- ab = 1;
gas_assert (!mips_opts.micromips);
s = "swc3";
fmt = "E,o(b)";
coproc = 1;
goto ld_st;
case M_SWL_AB:
- ab = 1;
- case M_SWL_OB:
s = "swl";
fmt = MEM12_FMT;
offbits = (mips_opts.micromips ? 12 : 16);
goto ld_st;
case M_SWR_AB:
- ab = 1;
- case M_SWR_OB:
s = "swr";
fmt = MEM12_FMT;
offbits = (mips_opts.micromips ? 12 : 16);
goto ld_st;
case M_SC_AB:
- ab = 1;
- case M_SC_OB:
s = "sc";
fmt = MEM12_FMT;
offbits = (mips_opts.micromips ? 12 : 16);
goto ld_st;
case M_SCD_AB:
- ab = 1;
- case M_SCD_OB:
s = "scd";
fmt = MEM12_FMT;
offbits = (mips_opts.micromips ? 12 : 16);
goto ld_st;
case M_CACHE_AB:
- ab = 1;
- case M_CACHE_OB:
s = "cache";
fmt = mips_opts.micromips ? "k,~(b)" : "k,o(b)";
offbits = (mips_opts.micromips ? 12 : 16);
goto ld_st;
case M_CACHEE_AB:
- ab = 1;
- case M_CACHEE_OB:
s = "cachee";
fmt = "k,+j(b)";
offbits = 9;
goto ld_st;
case M_PREF_AB:
- ab = 1;
- case M_PREF_OB:
s = "pref";
fmt = !mips_opts.micromips ? "k,o(b)" : "k,~(b)";
offbits = (mips_opts.micromips ? 12 : 16);
goto ld_st;
case M_PREFE_AB:
- ab = 1;
- case M_PREFE_OB:
s = "prefe";
fmt = "k,+j(b)";
offbits = 9;
goto ld_st;
case M_SDC1_AB:
- ab = 1;
s = "sdc1";
fmt = "T,o(b)";
coproc = 1;
/* Itbl support may require additional care here. */
goto ld_st;
case M_SDC2_AB:
- ab = 1;
- case M_SDC2_OB:
s = "sdc2";
fmt = COP12_FMT;
offbits = (mips_opts.micromips ? 12 : 16);
coproc = 1;
goto ld_st;
case M_SQC2_AB:
- ab = 1;
s = "sqc2";
fmt = "E,o(b)";
/* Itbl support may require additional care here. */
coproc = 1;
goto ld_st;
case M_SDC3_AB:
- ab = 1;
gas_assert (!mips_opts.micromips);
s = "sdc3";
fmt = "E,o(b)";
coproc = 1;
goto ld_st;
case M_SDL_AB:
- ab = 1;
- case M_SDL_OB:
s = "sdl";
fmt = MEM12_FMT;
offbits = (mips_opts.micromips ? 12 : 16);
goto ld_st;
case M_SDR_AB:
- ab = 1;
- case M_SDR_OB:
s = "sdr";
fmt = MEM12_FMT;
offbits = (mips_opts.micromips ? 12 : 16);
goto ld_st;
case M_SWP_AB:
- ab = 1;
- case M_SWP_OB:
gas_assert (mips_opts.micromips);
s = "swp";
fmt = "t,~(b)";
offbits = 12;
goto ld_st;
case M_SDP_AB:
- ab = 1;
- case M_SDP_OB:
gas_assert (mips_opts.micromips);
s = "sdp";
fmt = "t,~(b)";
offbits = 12;
goto ld_st;
case M_SWM_AB:
- ab = 1;
- case M_SWM_OB:
gas_assert (mips_opts.micromips);
s = "swm";
fmt = "n,~(b)";
offbits = 12;
goto ld_st;
case M_SDM_AB:
- ab = 1;
- case M_SDM_OB:
gas_assert (mips_opts.micromips);
s = "sdm";
fmt = "n,~(b)";
ld_st:
tempreg = AT;
- used_at = 1;
ld_noat:
+ if (small_offset_p (0, align, 16))
+ {
+ /* The first case exists for M_LD_AB and M_SD_AB, which are
+ macros for o32 but which should act like normal instructions
+ otherwise. */
+ if (offbits == 16)
+ macro_build (&offset_expr, s, fmt, treg, -1, offset_reloc[0],
+ offset_reloc[1], offset_reloc[2], breg);
+ else if (small_offset_p (0, align, offbits))
+ {
+ if (offbits == 0)
+ macro_build (NULL, s, fmt, treg, breg);
+ else
+ macro_build (NULL, s, fmt, treg,
+ (int) offset_expr.X_add_number, breg);
+ }
+ else
+ {
+ if (tempreg == AT)
+ used_at = 1;
+ macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
+ tempreg, breg, -1, offset_reloc[0],
+ offset_reloc[1], offset_reloc[2]);
+ if (offbits == 0)
+ macro_build (NULL, s, fmt, treg, tempreg);
+ else
+ macro_build (NULL, s, fmt, treg, 0, tempreg);
+ }
+ break;
+ }
+
+ if (tempreg == AT)
+ used_at = 1;
+
if (offset_expr.X_op != O_constant
&& offset_expr.X_op != O_symbol)
{
is in non PIC code. */
if (offset_expr.X_op == O_constant)
{
- int hipart = 0;
+ expr1.X_add_number = offset_high_part (offset_expr.X_add_number,
+ offbits == 0 ? 16 : offbits);
+ offset_expr.X_add_number -= expr1.X_add_number;
- expr1.X_add_number = offset_expr.X_add_number;
- normalize_address_expr (&expr1);
- if ((offbits == 0 || offbits == 16)
- && !IS_SEXT_16BIT_NUM (expr1.X_add_number))
- {
- expr1.X_add_number = ((expr1.X_add_number + 0x8000)
- & ~(bfd_vma) 0xffff);
- hipart = 1;
- }
- else if (offbits == 12 && !IS_SEXT_12BIT_NUM (expr1.X_add_number))
- {
- expr1.X_add_number = ((expr1.X_add_number + 0x800)
- & ~(bfd_vma) 0xfff);
- hipart = 1;
- }
- else if (offbits == 9 && !IS_SEXT_9BIT_NUM (expr1.X_add_number))
- {
- expr1.X_add_number = ((expr1.X_add_number + 0x100)
- & ~(bfd_vma) 0x1ff);
- hipart = 1;
- }
- if (hipart)
- {
- load_register (tempreg, &expr1, HAVE_64BIT_ADDRESSES);
- if (breg != 0)
- macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
- tempreg, tempreg, breg);
- breg = tempreg;
- }
+ load_register (tempreg, &expr1, HAVE_64BIT_ADDRESSES);
+ if (breg != 0)
+ macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
+ tempreg, tempreg, breg);
if (offbits == 0)
{
- if (offset_expr.X_add_number == 0)
- tempreg = breg;
- else
+ if (offset_expr.X_add_number != 0)
macro_build (&offset_expr, ADDRESS_ADDI_INSN,
- "t,r,j", tempreg, breg, BFD_RELOC_LO16);
+ "t,r,j", tempreg, tempreg, BFD_RELOC_LO16);
macro_build (NULL, s, fmt, treg, tempreg);
}
else if (offbits == 16)
- macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_LO16, breg);
+ macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_LO16, tempreg);
else
- macro_build (NULL, s, fmt,
- treg, (unsigned long) offset_expr.X_add_number, breg);
+ macro_build (NULL, s, fmt, treg,
+ (int) offset_expr.X_add_number, tempreg);
}
else if (offbits != 16)
{
/* The offset field is too narrow to be used for a low-part
relocation, so load the whole address into the auxillary
- register. In the case of "A(b)" addresses, we first load
- absolute address "A" into the register and then add base
- register "b". In the case of "o(b)" addresses, we simply
- need to add 16-bit offset "o" to base register "b", and
- offset_reloc already contains the relocations associated
- with "o". */
- if (ab)
- {
- load_address (tempreg, &offset_expr, &used_at);
- if (breg != 0)
- macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
- tempreg, tempreg, breg);
- }
- else
- macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
- tempreg, breg, -1,
- offset_reloc[0], offset_reloc[1], offset_reloc[2]);
- expr1.X_add_number = 0;
+ register. */
+ load_address (tempreg, &offset_expr, &used_at);
+ if (breg != 0)
+ macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
+ tempreg, tempreg, breg);
if (offbits == 0)
macro_build (NULL, s, fmt, treg, tempreg);
else
- macro_build (NULL, s, fmt,
- treg, (unsigned long) expr1.X_add_number, tempreg);
+ macro_build (NULL, s, fmt, treg, 0, tempreg);
}
else if (mips_pic == NO_PIC)
{
&& offset_expr.X_add_number == 0);
s = segment_name (S_GET_SEGMENT (offset_expr.X_add_symbol));
if (strcmp (s, ".lit8") == 0)
- {
- if (CPU_HAS_LDC1_SDC1 (mips_opts.arch) || mips_opts.micromips)
- {
- macro_build (&offset_expr, "ldc1", "T,o(b)", treg,
- BFD_RELOC_MIPS_LITERAL, mips_gp_register);
- break;
- }
- breg = mips_gp_register;
- r = BFD_RELOC_MIPS_LITERAL;
- goto dob;
+ {
+ breg = mips_gp_register;
+ offset_reloc[0] = BFD_RELOC_MIPS_LITERAL;
+ offset_reloc[1] = BFD_RELOC_UNUSED;
+ offset_reloc[2] = BFD_RELOC_UNUSED;
}
else
{
macro_build_lui (&offset_expr, AT);
}
- if (CPU_HAS_LDC1_SDC1 (mips_opts.arch) || mips_opts.micromips)
- {
- macro_build (&offset_expr, "ldc1", "T,o(b)",
- treg, BFD_RELOC_LO16, AT);
- break;
- }
breg = AT;
- r = BFD_RELOC_LO16;
- goto dob;
- }
-
- case M_L_DOB:
- /* Even on a big endian machine $fn comes before $fn+1. We have
- to adjust when loading from memory. */
- r = BFD_RELOC_LO16;
- dob:
- gas_assert (!mips_opts.micromips);
- gas_assert (!CPU_HAS_LDC1_SDC1 (mips_opts.arch));
- macro_build (&offset_expr, "lwc1", "T,o(b)",
- target_big_endian ? treg + 1 : treg, r, breg);
- /* FIXME: A possible overflow which I don't know how to deal
- with. */
- offset_expr.X_add_number += 4;
- macro_build (&offset_expr, "lwc1", "T,o(b)",
- target_big_endian ? treg : treg + 1, r, breg);
- break;
-
- case M_S_DOB:
- gas_assert (!mips_opts.micromips);
- gas_assert (!CPU_HAS_LDC1_SDC1 (mips_opts.arch));
- /* 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;
+ offset_reloc[0] = BFD_RELOC_LO16;
+ offset_reloc[1] = BFD_RELOC_UNUSED;
+ offset_reloc[2] = BFD_RELOC_UNUSED;
+ }
+ align = 8;
+ /* Fall through */
case M_L_DAB:
- gas_assert (!mips_opts.micromips);
/*
* The MIPS assembler seems to check for X_add_number not
* being double aligned and generating:
s = "sw";
ldd_std:
+ /* Even on a big endian machine $fn comes before $fn+1. We have
+ 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)
+ coproc = 0;
+
+ if (small_offset_p (0, align, 16))
+ {
+ ep = &offset_expr;
+ if (!small_offset_p (4, align, 16))
+ {
+ macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j", AT, breg,
+ -1, offset_reloc[0], offset_reloc[1],
+ offset_reloc[2]);
+ expr1.X_add_number = 0;
+ ep = &expr1;
+ breg = AT;
+ used_at = 1;
+ offset_reloc[0] = BFD_RELOC_LO16;
+ offset_reloc[1] = BFD_RELOC_UNUSED;
+ offset_reloc[2] = BFD_RELOC_UNUSED;
+ }
+ if (strcmp (s, "lw") == 0 && treg == breg)
+ {
+ ep->X_add_number += 4;
+ macro_build (ep, s, fmt, treg + 1, -1, offset_reloc[0],
+ offset_reloc[1], offset_reloc[2], breg);
+ ep->X_add_number -= 4;
+ macro_build (ep, s, fmt, treg, -1, offset_reloc[0],
+ offset_reloc[1], offset_reloc[2], breg);
+ }
+ else
+ {
+ macro_build (ep, s, fmt, coproc ? treg + 1 : treg, -1,
+ offset_reloc[0], offset_reloc[1], offset_reloc[2],
+ breg);
+ ep->X_add_number += 4;
+ macro_build (ep, s, fmt, coproc ? treg : treg + 1, -1,
+ offset_reloc[0], offset_reloc[1], offset_reloc[2],
+ breg);
+ }
+ break;
+ }
+
if (offset_expr.X_op != O_symbol
&& offset_expr.X_op != O_constant)
{
as_bad (_("Number (0x%s) larger than 32 bits"), value);
}
- /* Even on a big endian machine $fn comes before $fn+1. We have
- 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)
- coproc = 0;
-
if (mips_pic == NO_PIC || offset_expr.X_op == O_constant)
{
/* If this is a reference to a GP relative symbol, we want
offset_expr.X_add_number -= 4;
}
used_at = 1;
- macro_build_lui (&offset_expr, AT);
+ if (offset_high_part (offset_expr.X_add_number, 16)
+ != offset_high_part (offset_expr.X_add_number + 4, 16))
+ {
+ load_address (AT, &offset_expr, &used_at);
+ offset_expr.X_op = O_constant;
+ offset_expr.X_add_number = 0;
+ }
+ else
+ macro_build_lui (&offset_expr, AT);
if (breg != 0)
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, breg, AT);
/* Itbl support may require additional care here. */
abort ();
break;
-
- case M_LD_OB:
- s = HAVE_64BIT_GPRS ? "ld" : "lw";
- goto sd_ob;
- case M_SD_OB:
- s = HAVE_64BIT_GPRS ? "sd" : "sw";
- sd_ob:
- 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;
-
case M_SAA_AB:
- ab = 1;
- case M_SAA_OB:
s = "saa";
offbits = 0;
fmt = "t,(b)";
goto ld_st;
case M_SAAD_AB:
- ab = 1;
- case M_SAAD_OB:
s = "saad";
offbits = 0;
fmt = "t,(b)";
gas_assert (!mips_opts.micromips);
/* For now we just do C (same as Cz). The parameter will be
stored in insn_opcode by mips_ip. */
- macro_build (NULL, s, "C", ip->insn_opcode);
+ macro_build (NULL, s, "C", (int) ip->insn_opcode);
break;
case M_MOVE:
end_noreorder ();
break;
- case M_ULH_A:
- ab = 1;
- case M_ULH:
+ case M_ULH_AB:
s = "lb";
s2 = "lbu";
off = 1;
goto uld_st;
- case M_ULHU_A:
- ab = 1;
- case M_ULHU:
+ case M_ULHU_AB:
s = "lbu";
s2 = "lbu";
off = 1;
goto uld_st;
- case M_ULW_A:
- ab = 1;
- case M_ULW:
+ case M_ULW_AB:
s = "lwl";
s2 = "lwr";
offbits = (mips_opts.micromips ? 12 : 16);
off = 3;
goto uld_st;
- case M_ULD_A:
- ab = 1;
- case M_ULD:
+ case M_ULD_AB:
s = "ldl";
s2 = "ldr";
offbits = (mips_opts.micromips ? 12 : 16);
off = 7;
goto uld_st;
- case M_USH_A:
- ab = 1;
- case M_USH:
+ case M_USH_AB:
s = "sb";
s2 = "sb";
off = 1;
ust = 1;
goto uld_st;
- case M_USW_A:
- ab = 1;
- case M_USW:
+ case M_USW_AB:
s = "swl";
s2 = "swr";
offbits = (mips_opts.micromips ? 12 : 16);
off = 3;
ust = 1;
goto uld_st;
- case M_USD_A:
- ab = 1;
- case M_USD:
+ case M_USD_AB:
s = "sdl";
s2 = "sdr";
offbits = (mips_opts.micromips ? 12 : 16);
ust = 1;
uld_st:
- if (!ab && offset_expr.X_add_number >= 0x8000 - off)
- as_bad (_("Operand overflow"));
-
+ large_offset = !small_offset_p (off, align, offbits);
ep = &offset_expr;
expr1.X_add_number = 0;
- if (ab)
+ if (large_offset)
{
used_at = 1;
tempreg = AT;
- load_address (tempreg, ep, &used_at);
- if (breg != 0)
- macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
- tempreg, tempreg, breg);
- breg = tempreg;
- tempreg = treg;
- ep = &expr1;
- }
- else if (offbits == 12
- && (offset_expr.X_op != O_constant
- || !IS_SEXT_12BIT_NUM (offset_expr.X_add_number)
- || !IS_SEXT_12BIT_NUM (offset_expr.X_add_number + off)))
- {
- used_at = 1;
- tempreg = AT;
- macro_build (ep, ADDRESS_ADDI_INSN, "t,r,j", tempreg, breg,
- -1, offset_reloc[0], offset_reloc[1], offset_reloc[2]);
+ if (small_offset_p (0, align, 16))
+ macro_build (ep, ADDRESS_ADDI_INSN, "t,r,j", tempreg, breg, -1,
+ offset_reloc[0], offset_reloc[1], offset_reloc[2]);
+ else
+ {
+ load_address (tempreg, ep, &used_at);
+ if (breg != 0)
+ macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
+ tempreg, tempreg, breg);
+ }
+ offset_reloc[0] = BFD_RELOC_LO16;
+ offset_reloc[1] = BFD_RELOC_UNUSED;
+ offset_reloc[2] = BFD_RELOC_UNUSED;
breg = tempreg;
tempreg = treg;
ep = &expr1;
if (!target_big_endian)
ep->X_add_number += off;
- if (offbits != 12)
- macro_build (ep, s, "t,o(b)", tempreg, BFD_RELOC_LO16, breg);
+ if (offbits == 12)
+ macro_build (NULL, s, "t,~(b)", tempreg, (int) ep->X_add_number, breg);
else
- macro_build (NULL, s, "t,~(b)",
- tempreg, (unsigned long) ep->X_add_number, breg);
+ macro_build (ep, s, "t,o(b)", tempreg, -1,
+ offset_reloc[0], offset_reloc[1], offset_reloc[2], breg);
if (!target_big_endian)
ep->X_add_number -= off;
else
ep->X_add_number += off;
- if (offbits != 12)
- macro_build (ep, s2, "t,o(b)", tempreg, BFD_RELOC_LO16, breg);
- else
+ if (offbits == 12)
macro_build (NULL, s2, "t,~(b)",
- tempreg, (unsigned long) ep->X_add_number, breg);
+ tempreg, (int) ep->X_add_number, breg);
+ else
+ macro_build (ep, s2, "t,o(b)", tempreg, -1,
+ offset_reloc[0], offset_reloc[1], offset_reloc[2], breg);
/* If necessary, move the result in tempreg to the final destination. */
if (!ust && treg != tempreg)
used_at = 1;
if (target_big_endian == ust)
ep->X_add_number += off;
- tempreg = ust || ab ? treg : AT;
- macro_build (ep, s, "t,o(b)", tempreg, BFD_RELOC_LO16, breg);
+ tempreg = ust || large_offset ? treg : AT;
+ macro_build (ep, s, "t,o(b)", tempreg, -1,
+ offset_reloc[0], offset_reloc[1], offset_reloc[2], breg);
/* For halfword transfers we need a temporary register to shuffle
bytes. Unfortunately for M_USH_A we have none available before
the next store as AT holds the base address. We deal with this
case by clobbering TREG and then restoring it as with ULH. */
- tempreg = ust == ab ? treg : AT;
+ tempreg = ust == large_offset ? treg : AT;
if (ust)
macro_build (NULL, "srl", SHFT_FMT, tempreg, treg, 8);
ep->X_add_number -= off;
else
ep->X_add_number += off;
- macro_build (ep, s2, "t,o(b)", tempreg, BFD_RELOC_LO16, breg);
+ macro_build (ep, s2, "t,o(b)", tempreg, -1,
+ offset_reloc[0], offset_reloc[1], offset_reloc[2], breg);
/* For M_USH_A re-retrieve the LSB. */
- if (ust && ab)
+ if (ust && large_offset)
{
if (target_big_endian)
ep->X_add_number += off;
else
ep->X_add_number -= off;
- macro_build (&expr1, "lbu", "t,o(b)", AT, BFD_RELOC_LO16, AT);
+ macro_build (&expr1, "lbu", "t,o(b)", AT, -1,
+ offset_reloc[0], offset_reloc[1], offset_reloc[2], AT);
}
/* For ULH and M_USH_A OR the LSB in. */
- if (!ust || ab)
+ if (!ust || large_offset)
{
- tempreg = !ab ? AT : treg;
+ tempreg = !large_offset ? AT : treg;
macro_build (NULL, "sll", SHFT_FMT, tempreg, tempreg, 8);
macro_build (NULL, "or", "d,v,t", treg, treg, AT);
}
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;
+ case 'i': USE_BITS (OP_MASK_TARGET, OP_SH_TARGET); break;
case 'j': USE_BITS (OP_MASK_EVAOFFSET, OP_SH_EVAOFFSET); break;
default:
USE_BITS (OP_MASK_RT, OP_SH_RT); break;
case 'e': USE_BITS (OP_MASK_VECBYTE, OP_SH_VECBYTE); break;
case '%': USE_BITS (OP_MASK_VECALIGN, OP_SH_VECALIGN); break;
- case '[': break;
- case ']': break;
case '1': USE_BITS (OP_MASK_STYPE, OP_SH_STYPE); break;
case '2': USE_BITS (OP_MASK_BP, OP_SH_BP); break;
case '3': USE_BITS (OP_MASK_SA3, OP_SH_SA3); break;
case 'F': USE_BITS (INSMSB); break;
case 'G': USE_BITS (EXTMSBD); break;
case 'H': USE_BITS (EXTMSBD); break;
+ case 'i': USE_BITS (TARGET); break;
case 'j': USE_BITS (EVAOFFSET); break;
default:
as_bad (_("Internal error: bad mips opcode "
&& ep->X_add_number < max << bit);
}
-/* This routine assembles an instruction into its binary format. As a
- side effect, it sets one of the global variables imm_reloc or
- offset_reloc to the type of relocation to do if one of the operands
- is an address expression. */
+/* Assemble an instruction into its binary format. If the instruction
+ is a macro, set imm_expr, imm2_expr and offset_expr to the values
+ associated with "I", "+I" and "A" operands respectively. Otherwise
+ store the value of the relocatable field (if any) in offset_expr.
+ In both cases set offset_reloc to the relocation operators applied
+ to offset_expr. */
static void
mips_ip (char *str, struct mips_cl_insn *ip)
return;
}
+ imm_expr.X_op = O_absent;
+ imm2_expr.X_op = O_absent;
+ offset_expr.X_op = O_absent;
+ offset_reloc[0] = BFD_RELOC_UNUSED;
+ offset_reloc[1] = BFD_RELOC_UNUSED;
+ offset_reloc[2] = BFD_RELOC_UNUSED;
+
create_insn (ip, insn);
insn_error = NULL;
argnum = 1;
continue;
break;
- case '[': /* These must match exactly. */
- case ']':
- gas_assert (!mips_opts.micromips);
- if (*s++ == *args)
- continue;
- break;
-
case '+': /* Opcode extension character. */
switch (*++args)
{
(unsigned long) imm_expr.X_add_number);
imm_expr.X_add_number = 0;
}
- /* Make the pos explicit to simplify +S. */
- lastpos = imm_expr.X_add_number + 32;
+ lastpos = imm_expr.X_add_number;
INSERT_OPERAND (0, CINSPOS, *ip, imm_expr.X_add_number);
imm_expr.X_op = O_absent;
s = expr_end;
continue;
case 's':
- /* cins and exts length-minus-one field. */
+ /* cins32 and exts32 length-minus-one field. */
gas_assert (!mips_opts.micromips);
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
- if ((unsigned long) imm_expr.X_add_number > 31)
+ if ((unsigned long) imm_expr.X_add_number > 31
+ || (unsigned long) imm_expr.X_add_number + lastpos > 31)
{
as_bad (_("Improper size (%lu)"),
(unsigned long) imm_expr.X_add_number);
continue;
case 'S':
- /* cins32/exts32 and cins/exts aliasing cint32/exts32
- length-minus-one field. */
+ /* cins/exts length-minus-one field. */
gas_assert (!mips_opts.micromips);
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
- if ((long) imm_expr.X_add_number < 0
+ if ((unsigned long) imm_expr.X_add_number > 31
|| (unsigned long) imm_expr.X_add_number + lastpos > 63)
{
as_bad (_("Improper size (%lu)"),
INSERT_OPERAND (0, FZ, *ip, regno);
continue;
+ case 'i':
+ goto jump;
+
case 'j':
{
int shift = 8;
size_t i;
+ bfd_reloc_code_real_type r[3];
+
/* Check whether there is only a single bracketed expression
left. If so, it must be the base register and the
constant must be zero. */
/* If this value won't fit into the offset, then go find
a macro that will generate a 16- or 32-bit offset code
pattern. */
- i = my_getSmallExpression (&imm_expr, imm_reloc, s);
+ i = my_getSmallExpression (&imm_expr, r, s);
if ((i == 0 && (imm_expr.X_op != O_constant
|| imm_expr.X_add_number >= 1 << shift
|| imm_expr.X_add_number < -1 << shift))
{
int shift = *args == '.' ? 9 : 11;
size_t i;
+ bfd_reloc_code_real_type r[3];
/* Check whether there is only a single bracketed expression
left. If so, it must be the base register and the
/* If this value won't fit into the offset, then go find
a macro that will generate a 16- or 32-bit offset code
pattern. */
- i = my_getSmallExpression (&imm_expr, imm_reloc, s);
+ i = my_getSmallExpression (&imm_expr, r, s);
if ((i == 0 && (imm_expr.X_op != O_constant
|| imm_expr.X_add_number >= 1 << shift
|| imm_expr.X_add_number < -1 << shift))
case 'X': /* MDMX destination register. */
case 'Y': /* MDMX source register. */
case 'Z': /* MDMX target register. */
- is_mdmx = 1;
+ is_mdmx = !(insn->membership & INSN_5400);
case 'W':
gas_assert (!mips_opts.micromips);
case 'D': /* Floating point destination register. */
/* This is like 'Z', but also needs to fix the MDMX
vector/scalar select bits. Note that the
scalar immediate case is handled above. */
+ if ((ip->insn_mo->membership & INSN_5400)
+ && strcmp (insn->name, "rzu.ob") == 0)
+ as_bad (_("Operand %d of `%s' must be an immediate"),
+ argnum, ip->insn_mo->name);
+
if (*s == '[')
{
int is_qh = (ip->insn_opcode & (1 << OP_SH_VSEL));
s++;
}
else
- {
+ {
+ if ((ip->insn_mo->membership & INSN_5400)
+ && (strcmp (insn->name, "sll.ob") == 0
+ || strcmp (insn->name, "srl.ob") == 0))
+ as_bad (_("Operand %d of `%s' must be scalar"),
+ argnum, ip->insn_mo->name);
+
if (ip->insn_opcode & (OP_MASK_VSEL << OP_SH_VSEL))
ip->insn_opcode |= (MDMX_FMTSEL_VEC_QH
<< OP_SH_VSEL);
continue;
case 'A':
- my_getExpression (&offset_expr, s);
- normalize_address_expr (&offset_expr);
- *imm_reloc = BFD_RELOC_32;
- s = expr_end;
+ my_getSmallExpression (&offset_expr, offset_reloc, s);
+ if (offset_expr.X_op == O_register)
+ {
+ /* Assume that the offset has been elided and that what
+ we saw was a base register. The match will fail later
+ if that assumption turns out to be wrong. */
+ offset_expr.X_op = O_constant;
+ offset_expr.X_add_number = 0;
+ }
+ else
+ {
+ normalize_address_expr (&offset_expr);
+ s = expr_end;
+ }
continue;
case 'F':
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)
+ *offset_reloc = BFD_RELOC_LO16;
+ if (my_getSmallExpression (&offset_expr, offset_reloc, s) == 0)
{
int more;
offsetT minval, maxval;
else
minval = -0x8000, maxval = 0xffff;
- if (imm_expr.X_op != O_constant
- || imm_expr.X_add_number < minval
- || imm_expr.X_add_number > maxval)
+ if (offset_expr.X_op != O_constant
+ || offset_expr.X_add_number < minval
+ || offset_expr.X_add_number > maxval)
{
if (more)
break;
- if (imm_expr.X_op == O_constant
- || imm_expr.X_op == O_big)
+ if (offset_expr.X_op == O_constant
+ || offset_expr.X_op == O_big)
as_bad (_("Expression out of range"));
}
}
continue;
case 'u': /* Upper 16 bits. */
- *imm_reloc = BFD_RELOC_LO16;
- 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))
+ *offset_reloc = BFD_RELOC_LO16;
+ if (my_getSmallExpression (&offset_expr, offset_reloc, s) == 0
+ && offset_expr.X_op == O_constant
+ && (offset_expr.X_add_number < 0
+ || offset_expr.X_add_number >= 0x10000))
as_bad (_("lui expression (%lu) not in range 0..65535"),
- (unsigned long) imm_expr.X_add_number);
+ (unsigned long) offset_expr.X_add_number);
s = expr_end;
continue;
case 'a': /* 26-bit address. */
+ jump:
*offset_reloc = BFD_RELOC_MIPS_JMP;
my_getExpression (&offset_expr, s);
s = expr_end;
#define SKIP_SPACE_TABS(S) { while (*(S) == ' ' || *(S) == '\t') ++(S); }
-/* This routine assembles an instruction into its binary format when
- assembling for the mips16. As a side effect, it sets one of the
- global variables imm_reloc or offset_reloc to the type of relocation
- to do if one of the operands is an address expression. It also sets
- forced_insn_length to the resulting instruction size in bytes if the
- user explicitly requested a small or extended instruction. */
+/* As for mips_ip, but used when assembling MIPS16 code.
+ Also set forced_insn_length to the resulting instruction size in
+ bytes if the user explicitly requested a small or extended instruction. */
static void
mips16_ip (char *str, struct mips_cl_insn *ip)
for (;;)
{
bfd_boolean ok;
+ char relax_char;
gas_assert (strcmp (insn->name, str) == 0);
create_insn (ip, insn);
imm_expr.X_op = O_absent;
- imm_reloc[0] = BFD_RELOC_UNUSED;
- imm_reloc[1] = BFD_RELOC_UNUSED;
- imm_reloc[2] = BFD_RELOC_UNUSED;
imm2_expr.X_op = O_absent;
offset_expr.X_op = O_absent;
offset_reloc[0] = BFD_RELOC_UNUSED;
offset_reloc[1] = BFD_RELOC_UNUSED;
offset_reloc[2] = BFD_RELOC_UNUSED;
+ relax_char = 0;
for (args = insn->args; 1; ++args)
{
int c;
offsetT value;
/* Stuff the immediate value in now, if we can. */
- if (imm_expr.X_op == O_constant
- && *imm_reloc > BFD_RELOC_UNUSED
- && insn->pinfo != INSN_MACRO
- && calculate_reloc (*offset_reloc,
- imm_expr.X_add_number, &value))
+ if (insn->pinfo == INSN_MACRO)
+ {
+ gas_assert (relax_char == 0);
+ gas_assert (*offset_reloc == BFD_RELOC_UNUSED);
+ }
+ else if (relax_char
+ && offset_expr.X_op == O_constant
+ && calculate_reloc (*offset_reloc,
+ offset_expr.X_add_number,
+ &value))
{
- mips16_immed (NULL, 0, *imm_reloc - BFD_RELOC_UNUSED,
- *offset_reloc, value, forced_insn_length,
- &ip->insn_opcode);
- imm_expr.X_op = O_absent;
- *imm_reloc = BFD_RELOC_UNUSED;
+ mips16_immed (NULL, 0, relax_char, *offset_reloc, value,
+ forced_insn_length, &ip->insn_opcode);
+ offset_expr.X_op = O_absent;
*offset_reloc = BFD_RELOC_UNUSED;
}
+ else if (relax_char && *offset_reloc != BFD_RELOC_UNUSED)
+ {
+ if (forced_insn_length == 2)
+ as_bad (_("invalid unextended operand value"));
+ forced_insn_length = 4;
+ ip->insn_opcode |= MIPS16_EXTEND;
+ }
+ else if (relax_char)
+ *offset_reloc = (int) BFD_RELOC_UNUSED + relax_char;
return;
}
case 'U':
case 'k':
case 'K':
- i = my_getSmallExpression (&imm_expr, imm_reloc, s);
+ i = my_getSmallExpression (&offset_expr, offset_reloc, s);
if (i > 0)
{
- if (imm_expr.X_op != O_constant)
- {
- forced_insn_length = 4;
- ip->insn_opcode |= MIPS16_EXTEND;
- }
- else
- {
- /* We need to relax this instruction. */
- *offset_reloc = *imm_reloc;
- *imm_reloc = (int) BFD_RELOC_UNUSED + c;
- }
+ relax_char = c;
s = expr_end;
continue;
}
- *imm_reloc = BFD_RELOC_UNUSED;
+ *offset_reloc = BFD_RELOC_UNUSED;
/* Fall through. */
case '<':
case '>':
case ']':
case '4':
case '8':
- my_getExpression (&imm_expr, s);
- if (imm_expr.X_op == O_register)
+ my_getExpression (&offset_expr, s);
+ if (offset_expr.X_op == O_register)
{
/* What we thought was an expression turned out to
be a register. */
/* It looks like the expression was omitted
before a register indirection, which means
that the expression is implicitly zero. We
- still set up imm_expr, so that we handle
+ still set up offset_expr, so that we handle
explicit extensions correctly. */
- imm_expr.X_op = O_constant;
- imm_expr.X_add_number = 0;
- *imm_reloc = (int) BFD_RELOC_UNUSED + c;
+ offset_expr.X_op = O_constant;
+ offset_expr.X_add_number = 0;
+ relax_char = c;
continue;
}
}
/* We need to relax this instruction. */
- *imm_reloc = (int) BFD_RELOC_UNUSED + c;
+ relax_char = c;
s = expr_end;
continue;
break;
/* We need to relax this instruction. */
- *offset_reloc = (int) BFD_RELOC_UNUSED + c;
+ relax_char = c;
s = expr_end;
continue;
s = expr_end;
continue;
+ case 'I':
+ my_getExpression (&imm_expr, s);
+ if (imm_expr.X_op != O_big
+ && imm_expr.X_op != O_constant)
+ insn_error = _("absolute expression required");
+ if (HAVE_32BIT_GPRS)
+ normalize_constant_expr (&imm_expr);
+ s = expr_end;
+ continue;
+
case 'a': /* 26 bit address */
+ case 'i':
my_getExpression (&offset_expr, s);
s = expr_end;
*offset_reloc = BFD_RELOC_MIPS16_JMP;
mips_pic = VXWORKS_PIC;
break;
+ case OPTION_NAN:
+ if (strcmp (arg, "2008") == 0)
+ mips_flag_nan2008 = TRUE;
+ else if (strcmp (arg, "legacy") == 0)
+ mips_flag_nan2008 = FALSE;
+ else
+ {
+ as_fatal (_("Invalid NaN setting -mnan=%s"), arg);
+ return 0;
+ }
+ break;
+
default:
return 0;
}
demand_empty_rest_of_line ();
}
+/* Handle the .nan pseudo-op. */
+
+static void
+s_nan (int ignore ATTRIBUTE_UNUSED)
+{
+ static const char str_legacy[] = "legacy";
+ static const char str_2008[] = "2008";
+ size_t i;
+
+ for (i = 0; !is_end_of_line[(unsigned char) input_line_pointer[i]]; i++);
+
+ if (i == sizeof (str_2008) - 1
+ && memcmp (input_line_pointer, str_2008, i) == 0)
+ mips_flag_nan2008 = TRUE;
+ else if (i == sizeof (str_legacy) - 1
+ && memcmp (input_line_pointer, str_legacy, i) == 0)
+ mips_flag_nan2008 = FALSE;
+ else
+ as_bad (_("Bad .nan directive"));
+
+ input_line_pointer += i;
+ demand_empty_rest_of_line ();
+}
+
/* Handle a .stab[snd] directive. Ideally these directives would be
implemented in a transparent way, so that removing them would not
have any effect on the generated instructions. However, s_stab
if (mips_32bitmode)
elf_elfheader (stdoutput)->e_flags |= EF_MIPS_32BITMODE;
+ if (mips_flag_nan2008)
+ elf_elfheader (stdoutput)->e_flags |= EF_MIPS_NAN2008;
+
#if 0 /* XXX FIXME */
/* 32 bit code with 64 bit FP registers. */
if (!file_mips_fp32 && ABI_NEEDS_32BIT_REGS (mips_abi))
-msingle-float only allow 32-bit floating-point operations\n\
-mdouble-float allow 32-bit and 64-bit floating-point operations\n\
--[no-]construct-floats [dis]allow floating point values to be constructed\n\
---[no-]relax-branch [dis]allow out-of-range branches to be relaxed\n"
- ));
+--[no-]relax-branch [dis]allow out-of-range branches to be relaxed\n\
+-mnan=ENCODING select an IEEE 754 NaN encoding convention, either of:\n"));
+
+ first = 1;
+
+ show (stream, "legacy", &column, &first);
+ show (stream, "2008", &column, &first);
+
+ fputc ('\n', stream);
+
fprintf (stream, _("\
-KPIC, -call_shared generate SVR4 position independent code\n\
-call_nonpic generate non-PIC code that can operate with DSOs\n\