/* 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);
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':
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:
macro_build (NULL, s, fmt, treg, breg);
else
macro_build (NULL, s, fmt, treg,
- (unsigned long) offset_expr.X_add_number, breg);
+ (int) offset_expr.X_add_number, breg);
}
else
{
if (offbits == 0)
macro_build (NULL, s, fmt, treg, tempreg);
else
- macro_build (NULL, s, fmt, treg, 0L, tempreg);
+ macro_build (NULL, s, fmt, treg, 0, tempreg);
}
break;
}
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, tempreg);
+ (int) offset_expr.X_add_number, tempreg);
}
else if (offbits != 16)
{
if (offbits == 0)
macro_build (NULL, s, fmt, treg, tempreg);
else
- macro_build (NULL, s, fmt, treg, 0L, tempreg);
+ macro_build (NULL, s, fmt, treg, 0, tempreg);
}
else if (mips_pic == NO_PIC)
{
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:
if (!target_big_endian)
ep->X_add_number += off;
if (offbits == 12)
- macro_build (NULL, s, "t,~(b)",
- tempreg, (unsigned long) ep->X_add_number, breg);
+ macro_build (NULL, s, "t,~(b)", tempreg, (int) ep->X_add_number, breg);
else
macro_build (ep, s, "t,o(b)", tempreg, -1,
offset_reloc[0], offset_reloc[1], offset_reloc[2], breg);
ep->X_add_number += off;
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);
&& 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)
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;
{
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 '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;
#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);
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\