aboutsummaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
Diffstat (limited to 'gas')
-rw-r--r--gas/ChangeLog26
-rw-r--r--gas/config/tc-mips.c177
-rw-r--r--gas/doc/as.texinfo7
-rw-r--r--gas/doc/c-mips.texi14
4 files changed, 181 insertions, 43 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 5d9cc80..344ee45 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,29 @@
+2013-10-14 Richard Sandiford <rdsandiford@googlemail.com>
+ Chao-ying Fu <Chao-ying.Fu@imgtec.com>
+
+ * config/tc-mips.c (options): Add OPTION_MSA and OPTION_NO_MSA.
+ (md_longopts): Add mmsa and mno-msa.
+ (mips_ases): Add msa.
+ (RTYPE_MASK): Update.
+ (RTYPE_MSA): New define.
+ (OT_REG_ELEMENT): Replace with...
+ (OT_INTEGER_INDEX, OT_REG_INDEX): ...these new operand types.
+ (mips_operand_token): Replace reg_element with index.
+ (mips_parse_argument_token): Treat vector indices as separate tokens.
+ Handle register indices.
+ (md_begin): Add MSA register names.
+ (operand_reg_mask): Handle cases for OP_IMM_INDEX and OP_REG_INDEX.
+ (convert_reg_type): Handle cases for OP_REG_MSA and OP_REG_MSA_CTRL.
+ (match_mdmx_imm_reg_operand): Update accordingly.
+ (match_imm_index_operand): New function.
+ (match_reg_index_operand): New function.
+ (match_operand): Handle cases for OP_IMM_INDEX and OP_REG_INDEX.
+ (md_convert_frag): Convert bz.b/h/w/d, bnz.b/h/w/d, bz.v bnz.v.
+ (md_show_usage): Print -mmsa and -mno-msa.
+ * doc/as.texinfo: Document -mmsa and -mno-msa.
+ * doc/c-mips.texi: Document -mmsa and -mno-msa.
+ Document .set msa and .set nomsa.
+
2013-10-14 Nick Clifton <nickc@redhat.com>
* read.c (add_include_dir): Use xrealloc.
diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c
index dd61d72..5741d3e 100644
--- a/gas/config/tc-mips.c
+++ b/gas/config/tc-mips.c
@@ -1329,6 +1329,8 @@ enum options
OPTION_NO_MT,
OPTION_VIRT,
OPTION_NO_VIRT,
+ OPTION_MSA,
+ OPTION_NO_MSA,
OPTION_SMARTMIPS,
OPTION_NO_SMARTMIPS,
OPTION_DSPR2,
@@ -1440,6 +1442,8 @@ struct option md_longopts[] =
{"mno-mcu", no_argument, NULL, OPTION_NO_MCU},
{"mvirt", no_argument, NULL, OPTION_VIRT},
{"mno-virt", no_argument, NULL, OPTION_NO_VIRT},
+ {"mmsa", no_argument, NULL, OPTION_MSA},
+ {"mno-msa", no_argument, NULL, OPTION_NO_MSA},
/* Old-style architecture options. Don't add more of these. */
{"m4650", no_argument, NULL, OPTION_M4650},
@@ -1586,6 +1590,10 @@ static const struct mips_ase mips_ases[] = {
{ "virt", ASE_VIRT, ASE_VIRT64,
OPTION_VIRT, OPTION_NO_VIRT,
+ 2, 2, 2, 2 },
+
+ { "msa", ASE_MSA, ASE_MSA64,
+ OPTION_MSA, OPTION_NO_MSA,
2, 2, 2, 2 }
};
@@ -2347,7 +2355,7 @@ struct regname {
};
#define RNUM_MASK 0x00000ff
-#define RTYPE_MASK 0x0efff00
+#define RTYPE_MASK 0x0ffff00
#define RTYPE_NUM 0x0000100
#define RTYPE_FPU 0x0000200
#define RTYPE_FCC 0x0000400
@@ -2363,6 +2371,7 @@ struct regname {
#define RTYPE_R5900_Q 0x0100000
#define RTYPE_R5900_R 0x0200000
#define RTYPE_R5900_ACC 0x0400000
+#define RTYPE_MSA 0x0800000
#define RWARN 0x8000000
#define GENERIC_REGISTER_NUMBERS \
@@ -2747,8 +2756,11 @@ enum mips_operand_token_type {
/* A 4-bit XYZW channel mask. */
OT_CHANNELS,
- /* An element of a vector, e.g. $v0[1]. */
- OT_REG_ELEMENT,
+ /* A constant vector index, e.g. [1]. */
+ OT_INTEGER_INDEX,
+
+ /* A register vector index, e.g. [$2]. */
+ OT_REG_INDEX,
/* A continuous range of registers, e.g. $s0-$s4. */
OT_REG_RANGE,
@@ -2777,17 +2789,14 @@ struct mips_operand_token
enum mips_operand_token_type type;
union
{
- /* The register symbol value for an OT_REG. */
+ /* The register symbol value for an OT_REG or OT_REG_INDEX. */
unsigned int regno;
/* The 4-bit channel mask for an OT_CHANNEL_SUFFIX. */
unsigned int channels;
- /* The register symbol value and index for an OT_REG_ELEMENT. */
- struct {
- unsigned int regno;
- addressT index;
- } reg_element;
+ /* The integer value of an OT_INTEGER_INDEX. */
+ addressT index;
/* The two register symbol values involved in an OT_REG_RANGE. */
struct {
@@ -2948,20 +2957,32 @@ mips_parse_argument_token (char *s, char float_format)
mips_add_token (&token, OT_REG_RANGE);
return s;
}
- else if (*s == '[')
- {
- /* A vector element. */
- expressionS element;
+ /* Add the register itself. */
+ token.u.regno = regno1;
+ mips_add_token (&token, OT_REG);
+
+ /* Check for a vector index. */
+ if (*s == '[')
+ {
++s;
SKIP_SPACE_TABS (s);
- my_getExpression (&element, s);
- if (element.X_op != O_constant)
+ if (mips_parse_register (&s, &token.u.regno, NULL))
+ mips_add_token (&token, OT_REG_INDEX);
+ else
{
- set_insn_error (0, _("vector element must be constant"));
- return 0;
+ expressionS element;
+
+ my_getExpression (&element, s);
+ if (element.X_op != O_constant)
+ {
+ set_insn_error (0, _("vector element must be constant"));
+ return 0;
+ }
+ s = expr_end;
+ token.u.index = element.X_add_number;
+ mips_add_token (&token, OT_INTEGER_INDEX);
}
- s = expr_end;
SKIP_SPACE_TABS (s);
if (*s != ']')
{
@@ -2969,16 +2990,7 @@ mips_parse_argument_token (char *s, char float_format)
return 0;
}
++s;
-
- token.u.reg_element.regno = regno1;
- token.u.reg_element.index = element.X_add_number;
- mips_add_token (&token, OT_REG_ELEMENT);
- return s;
}
-
- /* Looks like just a plain register. */
- token.u.regno = regno1;
- mips_add_token (&token, OT_REG);
return s;
}
@@ -3460,6 +3472,10 @@ md_begin (void)
symbol_table_insert (symbol_new (regname, reg_section,
RTYPE_VI | i, &zero_address_frag));
+ /* MSA register. */
+ snprintf (regname, sizeof (regname) - 1, "$w%d", i);
+ symbol_table_insert (symbol_new (regname, reg_section,
+ RTYPE_MSA | i, &zero_address_frag));
}
obstack_init (&mips_operand_tokens);
@@ -4005,6 +4021,7 @@ operand_reg_mask (const struct mips_cl_insn *insn,
case OP_PC:
case OP_VU0_SUFFIX:
case OP_VU0_MATCH_SUFFIX:
+ case OP_IMM_INDEX:
abort ();
case OP_REG:
@@ -4050,6 +4067,11 @@ operand_reg_mask (const struct mips_cl_insn *insn,
if ((vsel & 0x18) == 0x18)
return 0;
return 1 << (uval & 31);
+
+ case OP_REG_INDEX:
+ if (!(type_mask & (1 << OP_REG_GP)))
+ return 0;
+ return 1 << insn_extract_operand (insn, operand);
}
abort ();
}
@@ -4408,6 +4430,12 @@ convert_reg_type (const struct mips_opcode *opcode,
case OP_REG_R5900_ACC:
return RTYPE_R5900_ACC;
+
+ case OP_REG_MSA:
+ return RTYPE_MSA;
+
+ case OP_REG_MSA_CTRL:
+ return RTYPE_NUM;
}
abort ();
}
@@ -5078,7 +5106,7 @@ match_mdmx_imm_reg_operand (struct mips_arg_info *arg,
uval = mips_extract_operand (operand, opcode->match);
is_qh = (uval != 0);
- if (arg->token->type == OT_REG || arg->token->type == OT_REG_ELEMENT)
+ if (arg->token->type == OT_REG)
{
if ((opcode->membership & INSN_5400)
&& strcmp (opcode->name, "rzu.ob") == 0)
@@ -5088,20 +5116,21 @@ match_mdmx_imm_reg_operand (struct mips_arg_info *arg,
return FALSE;
}
+ if (!match_regno (arg, OP_REG_VEC, arg->token->u.regno, &regno))
+ return FALSE;
+ ++arg->token;
+
/* Check whether this is a vector register or a broadcast of
a single element. */
- if (arg->token->type == OT_REG_ELEMENT)
+ if (arg->token->type == OT_INTEGER_INDEX)
{
- if (!match_regno (arg, OP_REG_VEC, arg->token->u.reg_element.regno,
- &regno))
- return FALSE;
- if (arg->token->u.reg_element.index > (is_qh ? 3 : 7))
+ if (arg->token->u.index > (is_qh ? 3 : 7))
{
set_insn_error (arg->argnum, _("invalid element selector"));
return FALSE;
}
- else
- uval |= arg->token->u.reg_element.index << (is_qh ? 2 : 1) << 5;
+ uval |= arg->token->u.index << (is_qh ? 2 : 1) << 5;
+ ++arg->token;
}
else
{
@@ -5115,15 +5144,12 @@ match_mdmx_imm_reg_operand (struct mips_arg_info *arg,
return FALSE;
}
- if (!match_regno (arg, OP_REG_VEC, arg->token->u.regno, &regno))
- return FALSE;
if (is_qh)
uval |= MDMX_FMTSEL_VEC_QH << 5;
else
uval |= MDMX_FMTSEL_VEC_OB << 5;
}
uval |= regno;
- ++arg->token;
}
else
{
@@ -5146,6 +5172,47 @@ match_mdmx_imm_reg_operand (struct mips_arg_info *arg,
return TRUE;
}
+/* OP_IMM_INDEX matcher. */
+
+static bfd_boolean
+match_imm_index_operand (struct mips_arg_info *arg,
+ const struct mips_operand *operand)
+{
+ unsigned int max_val;
+
+ if (arg->token->type != OT_INTEGER_INDEX)
+ return FALSE;
+
+ max_val = (1 << operand->size) - 1;
+ if (arg->token->u.index > max_val)
+ {
+ match_out_of_range (arg);
+ return FALSE;
+ }
+ insn_insert_operand (arg->insn, operand, arg->token->u.index);
+ ++arg->token;
+ return TRUE;
+}
+
+/* OP_REG_INDEX matcher. */
+
+static bfd_boolean
+match_reg_index_operand (struct mips_arg_info *arg,
+ const struct mips_operand *operand)
+{
+ unsigned int regno;
+
+ if (arg->token->type != OT_REG_INDEX)
+ return FALSE;
+
+ if (!match_regno (arg, OP_REG_GP, arg->token->u.regno, &regno))
+ return FALSE;
+
+ insn_insert_operand (arg->insn, operand, regno);
+ ++arg->token;
+ return TRUE;
+}
+
/* OP_PC matcher. */
static bfd_boolean
@@ -5426,6 +5493,12 @@ match_operand (struct mips_arg_info *arg,
case OP_VU0_MATCH_SUFFIX:
return match_vu0_suffix_operand (arg, operand, TRUE);
+
+ case OP_IMM_INDEX:
+ return match_imm_index_operand (arg, operand);
+
+ case OP_REG_INDEX:
+ return match_reg_index_operand (arg, operand);
}
abort ();
}
@@ -16539,11 +16612,21 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
switch ((insn >> 28) & 0xf)
{
case 4:
- /* bc[0-3][tf]l? instructions can have the condition
- reversed by tweaking a single TF bit, and their
- opcodes all have 0x4???????. */
- gas_assert ((insn & 0xf3e00000) == 0x41000000);
- insn ^= 0x00010000;
+ if ((insn & 0xff000000) == 0x47000000
+ || (insn & 0xff600000) == 0x45600000)
+ {
+ /* BZ.df/BNZ.df, BZ.V/BNZ.V can have the condition
+ reversed by tweaking bit 23. */
+ insn ^= 0x00800000;
+ }
+ else
+ {
+ /* bc[0-3][tf]l? instructions can have the condition
+ reversed by tweaking a single TF bit, and their
+ opcodes all have 0x4???????. */
+ gas_assert ((insn & 0xf3e00000) == 0x41000000);
+ insn ^= 0x00010000;
+ }
break;
case 0:
@@ -16810,6 +16893,11 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
|| (insn & 0xffe30000) == 0x42800000 /* bc2f */
|| (insn & 0xffe30000) == 0x42a00000) /* bc2t */
insn ^= 0x00200000;
+ else if ((insn & 0xff000000) == 0x83000000 /* BZ.df
+ BNZ.df */
+ || (insn & 0xff600000) == 0x81600000) /* BZ.V
+ BNZ.V */
+ insn ^= 0x00800000;
else
abort ();
@@ -18021,6 +18109,9 @@ MIPS options:\n\
-mmcu generate MCU instructions\n\
-mno-mcu do not generate MCU instructions\n"));
fprintf (stream, _("\
+-mmsa generate MSA instructions\n\
+-mno-msa do not generate MSA instructions\n"));
+ fprintf (stream, _("\
-mvirt generate Virtualization instructions\n\
-mno-virt do not generate Virtualization instructions\n"));
fprintf (stream, _("\
diff --git a/gas/doc/as.texinfo b/gas/doc/as.texinfo
index de6b5b0..9843574 100644
--- a/gas/doc/as.texinfo
+++ b/gas/doc/as.texinfo
@@ -412,6 +412,7 @@ gcc(1), ld(1), and the Info entries for @file{binutils} and @file{ld}.
[@b{-mdmx}] [@b{-no-mdmx}]
[@b{-mdsp}] [@b{-mno-dsp}]
[@b{-mdspr2}] [@b{-mno-dspr2}]
+ [@b{-mmsa}] [@b{-mno-msa}]
[@b{-mmt}] [@b{-mno-mt}]
[@b{-mmcu}] [@b{-mno-mcu}]
[@b{-minsn32}] [@b{-mno-insn32}]
@@ -1329,6 +1330,12 @@ This option implies -mdsp.
This tells the assembler to accept DSP Release 2 instructions.
@samp{-mno-dspr2} turns off this option.
+@item -mmsa
+@itemx -mno-msa
+Generate code for the MIPS SIMD Architecture Extension.
+This tells the assembler to accept MSA instructions.
+@samp{-mno-msa} turns off this option.
+
@item -mmt
@itemx -mno-mt
Generate code for the MT Application Specific Extension.
diff --git a/gas/doc/c-mips.texi b/gas/doc/c-mips.texi
index 8a25a76..7927893 100644
--- a/gas/doc/c-mips.texi
+++ b/gas/doc/c-mips.texi
@@ -179,6 +179,12 @@ Generate code for the MCU Application Specific Extension.
This tells the assembler to accept MCU instructions.
@samp{-mno-mcu} turns off this option.
+@item -mmsa
+@itemx -mno-msa
+Generate code for the MIPS SIMD Architecture Extension.
+This tells the assembler to accept MSA instructions.
+@samp{-mno-msa} turns off this option.
+
@item -mvirt
@itemx -mno-virt
Generate code for the Virtualization Application Specific Extension.
@@ -853,6 +859,14 @@ from the MCU Application Specific Extension from that point on
in the assembly. The @code{.set nomcu} directive prevents MCU
instructions from being accepted.
+@cindex MIPS SIMD Architecture instruction generation override
+@kindex @code{.set msa}
+@kindex @code{.set nomsa}
+The directive @code{.set msa} makes the assembler accept instructions
+from the MIPS SIMD Architecture Extension from that point on
+in the assembly. The @code{.set nomsa} directive prevents MSA
+instructions from being accepted.
+
@cindex Virtualization instruction generation override
@kindex @code{.set virt}
@kindex @code{.set novirt}