Some VFPU instructions do not support certain overlaps between source and
destination registers. Return an error whenever the overlap is not acceptable
for a given instruction and register pair.

Add more VFPU vector instructions with prefix register overlap decorators.

Signed-off-by: David Guillen Fandos <[email protected]>
---
 gas/config/tc-mips.c                          | 80 ++++++++++++++++++-
 gas/testsuite/gas/mips/allegrex-vfpu-errors.l | 38 +++++++++
 gas/testsuite/gas/mips/allegrex-vfpu-errors.s | 39 +++++++++
 gas/testsuite/gas/mips/allegrex-vfpu.d        | 51 ++++++++++++
 gas/testsuite/gas/mips/allegrex-vfpu.s        | 52 ++++++++++++
 include/opcode/mips.h                         | 19 ++++-
 opcodes/mips-formats.h                        | 30 ++++---
 opcodes/mips-opc.c                            | 63 ++++++++++++++-
 8 files changed, 353 insertions(+), 19 deletions(-)

diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c
index 930edceb6ec..79afc9fc9b1 100644
--- a/gas/config/tc-mips.c
+++ b/gas/config/tc-mips.c
@@ -106,7 +106,7 @@ static char *mips_flags_frag;
 
 #define FCSR 31
 
-#define ILLEGAL_REG (32)
+#define ILLEGAL_REG (~0U)
 
 #define AT  mips_opts.at
 
@@ -6819,6 +6819,52 @@ match_vu0_suffix_operand (struct mips_arg_info *arg,
   return true;
 }
 
+/* Returns whether a pair of dest/src registers are compatible.  */
+static bfd_boolean
+vfpu_reg_is_compat (unsigned int dst_reg, unsigned int dst_rsize,
+                   unsigned int src_reg, unsigned int src_rsize,
+                   bool accept_partial)
+{
+  static const unsigned short vreg_usage[4][16] = {
+  { 0x0001, 0x0010, 0x0100, 0x1000,
+    0x0002, 0x0020, 0x0200, 0x2000,
+    0x0004, 0x0040, 0x0400, 0x4000,
+    0x0008, 0x0080, 0x0800, 0x8000 },
+  { 0x0003, 0x0030, 0x0300, 0x3000,
+    0x0011, 0x0022, 0x0044, 0x0088,
+    0x000c, 0x00c0, 0x0c00, 0xc000,
+    0x1100, 0x2200, 0x4400, 0x8800 },
+  { 0x0007, 0x0070, 0x0700, 0x7000,
+    0x0111, 0x0222, 0x0444, 0x0888,
+    0x000e, 0x00e0, 0x0e00, 0xe000,
+    0x1110, 0x2220, 0x4440, 0x8880 },
+  { 0x000f, 0x00f0, 0x0f00, 0xf000,
+    0x1111, 0x2222, 0x4444, 0x8888,
+    0x000f, 0x00f0, 0x0f00, 0xf000,
+    0x1111, 0x2222, 0x4444, 0x8888 },
+  };
+
+  unsigned int dmtx = (dst_reg >> 2) & 7;
+  unsigned int smtx = (src_reg >> 2) & 7;
+  if (dmtx == smtx)
+  {
+    unsigned int sidx = src_reg & 3;
+    unsigned int didx = dst_reg & 3;
+    unsigned int sfsl = (src_reg >> 5) & 3;
+    unsigned int dfsl = (dst_reg >> 5) & 3;
+    unsigned int dmap = vreg_usage[dst_rsize][(dfsl << 2) | didx];
+    unsigned int smap = vreg_usage[src_rsize][(sfsl << 2) | sidx];
+
+    if (dmap & smap) {
+      /* There's overlap, if partial is allowed, check for compatibility.  */
+      return (accept_partial && dmap == smap
+             && ((src_reg & 0x32) == (dst_reg & 0x32)));
+    }
+  }
+  return true;
+}
+
+
 /* Generates a VFPU prefix immediate for a given reg type and size.  */
 static bfd_boolean
 calculate_vfpu_prefix_imm (struct mips_arg_info *arg,
@@ -6915,6 +6961,7 @@ match_vfpu_reg_operand (struct mips_arg_info *arg,
 {
   const struct mips_vfpu_reg_operand *regvfpuop;
   enum mips_vfpu_reg_shape rshape;
+  enum mips_vfpu_reg_type rtype;
   unsigned int uval = arg->token->u.reg_vfpu.regno;
 
   /* Validate register type, to ensure we use the right register prefix */
@@ -6931,8 +6978,9 @@ match_vfpu_reg_operand (struct mips_arg_info *arg,
   if (arg->token->type != OT_REG_VFPU || uval >= 128)
     return false;
 
-  rshape = arg->token->u.reg_vfpu.shape;
   regvfpuop = (struct mips_vfpu_reg_operand*)operand;
+  rshape = arg->token->u.reg_vfpu.shape;
+  rtype = regvfpuop->regtype;
 
   if (rshape != val_shap[regvfpuop->rsize].gen &&
       rshape != val_shap[regvfpuop->rsize].spc)
@@ -6943,6 +6991,31 @@ match_vfpu_reg_operand (struct mips_arg_info *arg,
     return false;
   }
 
+  if (rtype == OP_VFPU_REG_D && regvfpuop->regcompat != OP_VFPU_REGCOMPAT_ALL)
+  {
+    arg->dest_regno = uval | (regvfpuop->rsize << 8);
+    if (regvfpuop->regcompat == OP_VFPU_REGCOMPAT_SAME)
+      arg->dest_regno |= 0x8000;
+  }
+
+  if ((rtype == OP_VFPU_REG_S || rtype == OP_VFPU_REG_T)
+      && (arg->dest_regno != ILLEGAL_REG))
+  {
+    /* The destination register could be incompatible with source regs.  */
+    unsigned int dreg = arg->dest_regno & 0x7f;
+    unsigned int drsize = (arg->dest_regno >> 8) & 3;
+    bool canpartial = arg->dest_regno & 0x8000;
+
+    if (!vfpu_reg_is_compat (dreg, drsize, uval, regvfpuop->rsize, canpartial))
+    {
+      set_insn_error_ss(arg->argnum,
+                       "Invalid dest and %s register overlap (%s is allowed)",
+                       rtype == OP_VFPU_REG_S ? "source" : "target",
+                       canpartial ? "identical overlap" : "no overlap");
+      return false;
+    }
+  }
+
   insn_insert_operand (arg->insn, operand, uval);
   ++arg->token;
 
@@ -6954,7 +7027,6 @@ match_vfpu_reg_operand (struct mips_arg_info *arg,
     struct mips_opcode *pop;
     bfd_reloc_code_real_type unused_reloc[3]
       = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
-    enum mips_vfpu_reg_type rtype = regvfpuop->regtype;
 
     const char *pfxmemo = rtype == OP_VFPU_REG_S ? "vpfxs" :
                          rtype == OP_VFPU_REG_T ? "vpfxt" : "vpfxd";
@@ -6977,7 +7049,7 @@ match_vfpu_reg_operand (struct mips_arg_info *arg,
     pop = (struct mips_opcode *) str_hash_find (op_hash, pfxmemo);
     create_insn (&pfxinstr, pop);
 
-    if (!calculate_vfpu_prefix_imm (arg, regvfpuop->regtype, regvfpuop->rsize,
+    if (!calculate_vfpu_prefix_imm (arg, rtype, regvfpuop->rsize,
                                    pfx_lim, &imm24))
       return false;
 
diff --git a/gas/testsuite/gas/mips/allegrex-vfpu-errors.l 
b/gas/testsuite/gas/mips/allegrex-vfpu-errors.l
index 497e7f8aed6..0c113567857 100644
--- a/gas/testsuite/gas/mips/allegrex-vfpu-errors.l
+++ b/gas/testsuite/gas/mips/allegrex-vfpu-errors.l
@@ -20,3 +20,41 @@
 .*:22: Error: invalid source prefix \(only swizzle allowed\) `vabs.q 
R000,R000\[0,x,x,x\]'
 .*:23: Error: invalid source prefix \(only swizzle allowed\) `vneg.q 
R000,R000\[0,x,x,x\]'
 .*:24: Error: invalid source prefix \(only swizzle allowed\) `vt4444.q 
R000,R000\[-x,x,x,x\]'
+.*:25: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vsin.p C000,R000'
+.*:26: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vsin.t R000,R010'
+.*:27: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vsin.q C000,R000'
+.*:28: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vasin.p C100,R100'
+.*:29: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vasin.t R100,R110'
+.*:30: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vasin.q C100,R100'
+.*:31: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vnsin.p C200,R200'
+.*:32: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vnsin.t R200,R210'
+.*:33: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vnsin.q C200,R200'
+.*:34: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vcos.p C700,R700'
+.*:35: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vcos.t R700,R710'
+.*:36: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vcos.q C700,R700'
+.*:37: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vrcp.p C600,R600'
+.*:38: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vrcp.t R600,R610'
+.*:39: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vrcp.q C600,R600'
+.*:40: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vrsq.p C000,R000'
+.*:41: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vrsq.t R000,R010'
+.*:42: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vrsq.q C000,R000'
+.*:43: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vnrcp.p C000,R000'
+.*:44: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vnrcp.t R000,R010'
+.*:45: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vnrcp.q C000,R000'
+.*:46: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vexp2.p C000,R000'
+.*:47: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vexp2.t R000,R010'
+.*:48: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vexp2.q C000,R000'
+.*:49: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vrexp2.p C000,R000'
+.*:50: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vrexp2.t R000,R010'
+.*:51: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vrexp2.q C000,R000'
+.*:52: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vlog2.p C000,R000'
+.*:53: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vlog2.t R000,R010'
+.*:54: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vlog2.q C000,R000'
+.*:55: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vsqrt.p C000,R000'
+.*:56: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vsqrt.t R000,R010'
+.*:57: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vsqrt.q C000,R000'
+.*:58: Error: Invalid dest and target register overlap \(identical overlap is 
allowed\) `vdiv.p C000,C000,R000'
+.*:59: Error: Invalid dest and target register overlap \(identical overlap is 
allowed\) `vdiv.t C000,C000,R000'
+.*:60: Error: Invalid dest and target register overlap \(identical overlap is 
allowed\) `vdiv.q C000,C000,R000'
+.*:61: Error: Invalid dest and source register overlap \(no overlap is 
allowed\) `vcrsp.t R000,R000,R100'
+.*:62: Error: Invalid dest and source register overlap \(no overlap is 
allowed\) `vqmul.q R000,R000,R100'
diff --git a/gas/testsuite/gas/mips/allegrex-vfpu-errors.s 
b/gas/testsuite/gas/mips/allegrex-vfpu-errors.s
index 67024c61348..25193f0ac4a 100644
--- a/gas/testsuite/gas/mips/allegrex-vfpu-errors.s
+++ b/gas/testsuite/gas/mips/allegrex-vfpu-errors.s
@@ -22,6 +22,45 @@
        vabs.q R000, R000[0,x,x,x]
        vneg.q R000, R000[0,x,x,x]
        vt4444.q R000, R000[-x,x,x,x]
+       vsin.p C000, R000
+       vsin.t R000, R010
+       vsin.q C000, R000
+       vasin.p C100, R100
+       vasin.t R100, R110
+       vasin.q C100, R100
+       vnsin.p C200, R200
+       vnsin.t R200, R210
+       vnsin.q C200, R200
+       vcos.p C700, R700
+       vcos.t R700, R710
+       vcos.q C700, R700
+       vrcp.p C600, R600
+       vrcp.t R600, R610
+       vrcp.q C600, R600
+       vrsq.p C000, R000
+       vrsq.t R000, R010
+       vrsq.q C000, R000
+       vnrcp.p C000, R000
+       vnrcp.t R000, R010
+       vnrcp.q C000, R000
+       vexp2.p C000, R000
+       vexp2.t R000, R010
+       vexp2.q C000, R000
+       vrexp2.p C000, R000
+       vrexp2.t R000, R010
+       vrexp2.q C000, R000
+       vlog2.p C000, R000
+       vlog2.t R000, R010
+       vlog2.q C000, R000
+       vsqrt.p C000, R000
+       vsqrt.t R000, R010
+       vsqrt.q C000, R000
+       vdiv.p C000, C000, R000
+       vdiv.t C000, C000, R000
+       vdiv.q C000, C000, R000
+       vcrsp.t R000, R000, R100
+       vqmul.q R000, R000, R100
+
 
 # Force some (non-delay-slot) zero bytes, to make 'objdump' print ...
        .align  4, 0
diff --git a/gas/testsuite/gas/mips/allegrex-vfpu.d 
b/gas/testsuite/gas/mips/allegrex-vfpu.d
index ce91768e006..277b65707f7 100644
--- a/gas/testsuite/gas/mips/allegrex-vfpu.d
+++ b/gas/testsuite/gas/mips/allegrex-vfpu.d
@@ -128,4 +128,55 @@ Disassembly of section .text:
 0x000001dc de000100    vpfxd   m,,,
 0x000001e0 dc000050    vpfxs   x,x,y,y
 0x000001e4 d03ea0a0    vi2us.q R000.p,R000.q
+0x000001e8 d0171717    vasin.s S530.s,S530.s
+0x000001ec d01764e4    vasin.p R120.p,R120.p
+0x000001f0 d017e464    vasin.t R110.t,R110.t
+0x000001f4 d017a4a4    vasin.q R100.q,R100.q
+0x000001f8 d0131717    vcos.s  S530.s,S530.s
+0x000001fc d01364e4    vcos.p  R120.p,R120.p
+0x00000200 d013e464    vcos.t  R110.t,R110.t
+0x00000204 d013a4a4    vcos.q  R100.q,R100.q
+0x00000208 f2e6e564    vcrsp.t R110.t,R111.t,R112.t
+0x0000020c 6684a404    vcrs.t  C100.t,R100.t,C100.t
+0x00000210 63971717    vdiv.s  S530.s,S530.s,S530.s
+0x00000214 63e464e4    vdiv.p  R120.p,R120.p,R120.p
+0x00000218 63e4e464    vdiv.t  R110.t,R110.t,R110.t
+0x0000021c 63a4a4a4    vdiv.q  R100.q,R100.q,R100.q
+0x00000220 d0141717    vexp2.s S530.s,S530.s
+0x00000224 d01464e4    vexp2.p R120.p,R120.p
+0x00000228 d014e464    vexp2.t R110.t,R110.t
+0x0000022c d014a4a4    vexp2.q R100.q,R100.q
+0x00000230 d0151717    vlog2.s S530.s,S530.s
+0x00000234 d01564e4    vlog2.p R120.p,R120.p
+0x00000238 d015e464    vlog2.t R110.t,R110.t
+0x0000023c d015a4a4    vlog2.q R100.q,R100.q
+0x00000240 d0181717    vnrcp.s S530.s,S530.s
+0x00000244 d01864e4    vnrcp.p R120.p,R120.p
+0x00000248 d018e464    vnrcp.t R110.t,R110.t
+0x0000024c d018a4a4    vnrcp.q R100.q,R100.q
+0x00000250 d01a1717    vnsin.s S530.s,S530.s
+0x00000254 d01a64e4    vnsin.p R120.p,R120.p
+0x00000258 d01ae464    vnsin.t R110.t,R110.t
+0x0000025c d01aa4a4    vnsin.q R100.q,R100.q
+0x00000260 f2a8a0a4    vqmul.q R100.q,R000.q,R200.q
+0x00000264 d0101717    vrcp.s  S530.s,S530.s
+0x00000268 d01064e4    vrcp.p  R120.p,R120.p
+0x0000026c d010e464    vrcp.t  R110.t,R110.t
+0x00000270 d010a4a4    vrcp.q  R100.q,R100.q
+0x00000274 d01c1717    vrexp2.s        S530.s,S530.s
+0x00000278 d01c64e4    vrexp2.p        R120.p,R120.p
+0x0000027c d01ce464    vrexp2.t        R110.t,R110.t
+0x00000280 d01ca4a4    vrexp2.q        R100.q,R100.q
+0x00000284 d0111717    vrsq.s  S530.s,S530.s
+0x00000288 d01164e4    vrsq.p  R120.p,R120.p
+0x0000028c d011e464    vrsq.t  R110.t,R110.t
+0x00000290 d011a4a4    vrsq.q  R100.q,R100.q
+0x00000294 d0121717    vsin.s  S530.s,S530.s
+0x00000298 d01264e4    vsin.p  R120.p,R120.p
+0x0000029c d012e464    vsin.t  R110.t,R110.t
+0x000002a0 d012a4a4    vsin.q  R100.q,R100.q
+0x000002a4 d0161717    vsqrt.s S530.s,S530.s
+0x000002a8 d01664e4    vsqrt.p R120.p,R120.p
+0x000002ac d016e464    vsqrt.t R110.t,R110.t
+0x000002b0 d016a4a4    vsqrt.q R100.q,R100.q
        \.\.\.
diff --git a/gas/testsuite/gas/mips/allegrex-vfpu.s 
b/gas/testsuite/gas/mips/allegrex-vfpu.s
index c40acb84ca9..1bba03ca974 100644
--- a/gas/testsuite/gas/mips/allegrex-vfpu.s
+++ b/gas/testsuite/gas/mips/allegrex-vfpu.s
@@ -114,6 +114,58 @@
        vt5650.q R000, R000[w,z,y,x]
        vi2us.q R000[m,], R000[x,x,y,y]
 
+       vasin.s S530, S530
+       vasin.p R120, R120
+       vasin.t R110, R110
+       vasin.q R100, R100
+       vcos.s S530, S530
+       vcos.p R120, R120
+       vcos.t R110, R110
+       vcos.q R100, R100
+       vcrsp.t R110, R111, R112
+       vcrs.t C100, R100, C100
+       vdiv.s S530, S530, S530
+       vdiv.p R120, R120, R120
+       vdiv.t R110, R110, R110
+       vdiv.q R100, R100, R100
+       vexp2.s S530, S530
+       vexp2.p R120, R120
+       vexp2.t R110, R110
+       vexp2.q R100, R100
+       vlog2.s S530, S530
+       vlog2.p R120, R120
+       vlog2.t R110, R110
+       vlog2.q R100, R100
+       vnrcp.s S530, S530
+       vnrcp.p R120, R120
+       vnrcp.t R110, R110
+       vnrcp.q R100, R100
+       vnsin.s S530, S530
+       vnsin.p R120, R120
+       vnsin.t R110, R110
+       vnsin.q R100, R100
+       vqmul.q R100, R000, R200
+       vrcp.s S530, S530
+       vrcp.p R120, R120
+       vrcp.t R110, R110
+       vrcp.q R100, R100
+       vrexp2.s S530, S530
+       vrexp2.p R120, R120
+       vrexp2.t R110, R110
+       vrexp2.q R100, R100
+       vrsq.s S530, S530
+       vrsq.p R120, R120
+       vrsq.t R110, R110
+       vrsq.q R100, R100
+       vsin.s S530, S530
+       vsin.p R120, R120
+       vsin.t R110, R110
+       vsin.q R100, R100
+       vsqrt.s S530, S530
+       vsqrt.p R120, R120
+       vsqrt.t R110, R110
+       vsqrt.q R100, R100
+
 # Force some (non-delay-slot) zero bytes, to make 'objdump' print ...
        .align  4, 0
        .space  16
diff --git a/include/opcode/mips.h b/include/opcode/mips.h
index 0a8f1fd0f1c..b90f8ea33f7 100644
--- a/include/opcode/mips.h
+++ b/include/opcode/mips.h
@@ -264,6 +264,18 @@ enum mips_vfpu_regpfx_compat {
   OP_VFPU_PFXCOMPAT_LIMITED
 };
 
+/* Enumerates the types of VFPU register-register compatibility.  */
+enum mips_vfpu_regdst_compat {
+  /* All registers are allowed.  */
+  OP_VFPU_REGCOMPAT_ALL,
+
+  /* Identical overlap is allowed.  */
+  OP_VFPU_REGCOMPAT_SAME,
+
+  /* No overlap whatsover is allowed.  */
+  OP_VFPU_REGCOMPAT_NONE
+};
+
 
 /* Base class for all operands.  */
 struct mips_operand
@@ -408,11 +420,14 @@ struct mips_vfpu_reg_operand
   /* Register (sub)type.  */
   enum mips_vfpu_reg_type regtype;
 
+  /* Register access size.  */
+  unsigned int rsize;
+
   /* Register-prefix compatibility.  */
   enum mips_vfpu_regpfx_compat pfxcompat;
 
-  /* Register access size.  */
-  unsigned int rsize;
+  /* Register-register compatibility.  */
+  enum mips_vfpu_regdst_compat regcompat;
 };
 
 /* Return true if the assembly syntax allows OPERAND to be omitted.  */
diff --git a/opcodes/mips-formats.h b/opcodes/mips-formats.h
index 00e11de1fad..9d91d83b730 100644
--- a/opcodes/mips-formats.h
+++ b/opcodes/mips-formats.h
@@ -112,34 +112,44 @@
     return &op.root; \
   }
 
-#define VFPU_REGEXP(OP, SIZE, LSB, RTYPE, RSIZE, PFXCOMPAT) \
+#define VFPU_REGEXP(OP, SIZE, LSB, RTYPE, RSIZE, PFX_COMPAT, REG_COMPAT) \
   { \
     static const struct mips_vfpu_reg_operand op[] = { \
-      { { OP_VFPU_##OP, SIZE, LSB }, OP_VFPU_REG_##RTYPE, PFXCOMPAT, 0 }, \
-      { { OP_VFPU_##OP, SIZE, LSB }, OP_VFPU_REG_##RTYPE, PFXCOMPAT, 1 }, \
-      { { OP_VFPU_##OP, SIZE, LSB }, OP_VFPU_REG_##RTYPE, PFXCOMPAT, 2 }, \
-      { { OP_VFPU_##OP, SIZE, LSB }, OP_VFPU_REG_##RTYPE, PFXCOMPAT, 3 }, \
+      { { OP_VFPU_##OP, SIZE, LSB }, OP_VFPU_REG_##RTYPE, 0, \
+       OP_VFPU_PFXCOMPAT_##PFX_COMPAT, OP_VFPU_REGCOMPAT_##REG_COMPAT}, \
+      { { OP_VFPU_##OP, SIZE, LSB }, OP_VFPU_REG_##RTYPE, 1, \
+       OP_VFPU_PFXCOMPAT_##PFX_COMPAT, OP_VFPU_REGCOMPAT_##REG_COMPAT}, \
+      { { OP_VFPU_##OP, SIZE, LSB }, OP_VFPU_REG_##RTYPE, 2, \
+       OP_VFPU_PFXCOMPAT_##PFX_COMPAT, OP_VFPU_REGCOMPAT_##REG_COMPAT}, \
+      { { OP_VFPU_##OP, SIZE, LSB }, OP_VFPU_REG_##RTYPE, 3, \
+       OP_VFPU_PFXCOMPAT_##PFX_COMPAT, OP_VFPU_REGCOMPAT_##REG_COMPAT}, \
     }; \
     return &op[RSIZE].root; \
   }
 
-#define VFPU_REG(SIZE, LSB, RTYPE, RSIZE, PFX_COMPAT) \
+#define VFPU_REG(SIZE, LSB, RTYPE, RSIZE, PFX_COMPAT, REG_COMPAT) \
   { \
     switch (PFX_COMPAT) \
     { \
       case 'a': \
-       VFPU_REGEXP(REG, SIZE, LSB, RTYPE, RSIZE, OP_VFPU_PFXCOMPAT_ALL) \
+       VFPU_REGEXP(REG, SIZE, LSB, RTYPE, RSIZE, ALL, REG_COMPAT) \
       case 'n': \
-       VFPU_REGEXP(REG, SIZE, LSB, RTYPE, RSIZE, OP_VFPU_PFXCOMPAT_NONE) \
+       VFPU_REGEXP(REG, SIZE, LSB, RTYPE, RSIZE, NONE, REG_COMPAT) \
       case 'l': \
-       VFPU_REGEXP(REG, SIZE, LSB, RTYPE, RSIZE, OP_VFPU_PFXCOMPAT_LIMITED) \
+       VFPU_REGEXP(REG, SIZE, LSB, RTYPE, RSIZE, LIMITED, REG_COMPAT) \
       default: \
        abort(); \
     } \
   }
 
+#define VFPU_SREG(SIZE, LSB, RTYPE, RSIZE, PFX_COMPAT) \
+  VFPU_REG(SIZE, LSB, RTYPE, RSIZE, PFX_COMPAT, ALL)
+
+#define VFPU_DREG(SIZE, LSB, RTYPE, RSIZE, PFX_COMPAT, REG_COMPAT) \
+  VFPU_REG(SIZE, LSB, RTYPE, RSIZE, PFX_COMPAT, REG_COMPAT)
+
 #define VFPU_PFX(SIZE, LSB, RTYPE, RSIZE) \
-  VFPU_REGEXP(PFX, SIZE, LSB, RTYPE, RSIZE, OP_VFPU_PFXCOMPAT_ALL)
+  VFPU_REGEXP(PFX, SIZE, LSB, RTYPE, RSIZE, ALL, ALL)
 
 #define PCREL(SIZE, LSB, IS_SIGNED, SHIFT, ALIGN_LOG2, INCLUDE_ISA_BIT, \
               FLIP_ISA_BIT) \
diff --git a/opcodes/mips-opc.c b/opcodes/mips-opc.c
index b5dd46f9cf4..847ad0f30e5 100644
--- a/opcodes/mips-opc.c
+++ b/opcodes/mips-opc.c
@@ -145,16 +145,22 @@ decode_mips_operand (const char *p)
     case '?':
       switch (p[1])
        {
-       case 'd': VFPU_REG(7,  0, D, p[2] - '0', p[3]);
-       case 's': VFPU_REG(7,  8, S, p[2] - '0', p[3]);
-       case 't': VFPU_REG(7, 16, T, p[2] - '0', p[3]);
+       case 's': VFPU_SREG(7,  8, S, p[2] - '0', p[3]);
+       case 't': VFPU_SREG(7, 16, T, p[2] - '0', p[3]);
+       case 'd': VFPU_DREG(7,  0, D, p[2] - '0', p[3], ALL);
+       case 'D': VFPU_DREG(7,  0, D, p[2] - '0', p[3], SAME);
+       case 'i': VFPU_DREG(7,  0, D, p[2] - '0', p[3], NONE);
        case 'p':
          switch (p[2])
          {
            case 'd': VFPU_PFX(24, 0, D, 3);
            case 's': VFPU_PFX(24, 0, S, 3);
            case 't': VFPU_PFX(24, 0, T, 3);
+           default:
+             abort();
          }
+       default:
+         abort();
        }
       break;
 
@@ -695,12 +701,30 @@ const struct mips_opcode mips_builtin_opcodes[] =
 {"vadd.q",             "?d3a,?s3a,?t3a", 0x60008080, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vadd.s",             "?d0a,?s0a,?t0a", 0x60000000, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vadd.t",             "?d2a,?s2a,?t2a", 0x60008000, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vasin.p",            "?D1n,?s1n",      0xd0170080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vasin.q",            "?D3n,?s3n",      0xd0178080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vasin.s",            "?D0n,?s0n",      0xd0170000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vasin.t",            "?D2n,?s2n",      0xd0178000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vavg.p",             "?d0a,?s1a",      0xd0470080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vavg.q",             "?d0a,?s3a",      0xd0478080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vavg.t",             "?d0a,?s2a",      0xd0478000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vcos.p",             "?D1n,?s1n",      0xd0130080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vcos.q",             "?D3n,?s3n",      0xd0138080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vcos.s",             "?D0n,?s0n",      0xd0130000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vcos.t",             "?D2n,?s2n",      0xd0138000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vcrsp.t",            "?i2n,?s2n,?t2n", 0xf2808000, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vcrs.t",             "?d2a,?s2n,?t2n", 0x66808000, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vdiv.p",             "?D1n,?s1n,?t1n", 0x63800080, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vdiv.q",             "?D3n,?s3n,?t3n", 0x63808080, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vdiv.s",             "?D0n,?s0n,?t0n", 0x63800000, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vdiv.t",             "?D2n,?s2n,?t2n", 0x63808000, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vdot.p",             "?d0a,?s1a,?t1a", 0x64800080, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vdot.q",             "?d0a,?s3a,?t3a", 0x64808080, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vdot.t",             "?d0a,?s2a,?t2a", 0x64808000, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vexp2.p",            "?D1n,?s1n",      0xd0140080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vexp2.q",            "?D3n,?s3n",      0xd0148080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vexp2.s",            "?D0n,?s0n",      0xd0140000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vexp2.t",            "?D2n,?s2n",      0xd0148000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vfad.p",             "?d0a,?s1a",      0xd0460080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vfad.q",             "?d0a,?s3a",      0xd0468080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vfad.t",             "?d0a,?s2a",      0xd0468000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
@@ -709,6 +733,10 @@ const struct mips_opcode mips_builtin_opcodes[] =
 {"vi2us.q",            "?d1l,?s3l",      0xd03e8080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vidt.p",             "?d1a",           0xd0030080, 0xffffff80,       WR_C2,  
        0,              ALX,            0,      0 },
 {"vidt.q",             "?d3a",           0xd0038080, 0xffffff80,       WR_C2,  
        0,              ALX,            0,      0 },
+{"vlog2.p",            "?D1n,?s1n",      0xd0150080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vlog2.q",            "?D3n,?s3n",      0xd0158080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vlog2.s",            "?D0n,?s0n",      0xd0150000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vlog2.t",            "?D2n,?s2n",      0xd0158000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vmax.p",             "?d1a,?s1a,?t1a", 0x6d800080, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vmax.q",             "?d3a,?s3a,?t3a", 0x6d808080, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vmax.s",             "?d0a,?s0a,?t0a", 0x6d800000, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
@@ -729,6 +757,14 @@ const struct mips_opcode mips_builtin_opcodes[] =
 {"vneg.q",             "?d3a,?s3l",      0xd0028080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vneg.s",             "?d0a,?s0l",      0xd0020000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vneg.t",             "?d2a,?s2l",      0xd0028000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vnrcp.p",            "?D1n,?s1n",      0xd0180080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vnrcp.q",            "?D3n,?s3n",      0xd0188080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vnrcp.s",            "?D0n,?s0n",      0xd0180000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vnrcp.t",            "?D2n,?s2n",      0xd0188000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vnsin.p",            "?D1n,?s1n",      0xd01a0080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vnsin.q",            "?D3n,?s3n",      0xd01a8080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vnsin.s",            "?D0n,?s0n",      0xd01a0000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vnsin.t",            "?D2n,?s2n",      0xd01a8000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vocp.p",             "?d1a,?s1n",      0xd0440080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vocp.q",             "?d3a,?s3n",      0xd0448080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vocp.s",             "?d0a,?s0n",      0xd0440000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
@@ -740,6 +776,19 @@ const struct mips_opcode mips_builtin_opcodes[] =
 {"vpfxd",              "?pd.",           0xde000000, 0xff000000,       CP,     
        ALXPFX,         ALX,            0,      0 },
 {"vpfxs",              "?ps.",           0xdc000000, 0xff000000,       CP,     
        ALXPFX,         ALX,            0,      0 },
 {"vpfxt",              "?pt.",           0xdd000000, 0xff000000,       CP,     
        ALXPFX,         ALX,            0,      0 },
+{"vqmul.q",            "?i3n,?s3n,?t3n", 0xf2808080, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vrcp.p",             "?D1n,?s1n",      0xd0100080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vrcp.q",             "?D3n,?s3n",      0xd0108080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vrcp.s",             "?D0n,?s0n",      0xd0100000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vrcp.t",             "?D2n,?s2n",      0xd0108000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vrexp2.p",           "?D1n,?s1n",      0xd01c0080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vrexp2.q",           "?D3n,?s3n",      0xd01c8080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vrexp2.s",           "?D0n,?s0n",      0xd01c0000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vrexp2.t",           "?D2n,?s2n",      0xd01c8000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vrsq.p",             "?D1n,?s1n",      0xd0110080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vrsq.q",             "?D3n,?s3n",      0xd0118080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vrsq.s",             "?D0n,?s0n",      0xd0110000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vrsq.t",             "?D2n,?s2n",      0xd0118000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vsat0.p",            "?d1n,?s1a",      0xd0040080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vsat0.q",            "?d3n,?s3a",      0xd0048080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vsat0.s",            "?d0n,?s0a",      0xd0040000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
@@ -763,10 +812,18 @@ const struct mips_opcode mips_builtin_opcodes[] =
 {"vsgn.q",             "?d3a,?s3a",      0xd04a8080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vsgn.s",             "?d0a,?s0a",      0xd04a0000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vsgn.t",             "?d2a,?s2a",      0xd04a8000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vsin.p",             "?D1n,?s1n",      0xd0120080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vsin.q",             "?D3n,?s3n",      0xd0128080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vsin.s",             "?D0n,?s0n",      0xd0120000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vsin.t",             "?D2n,?s2n",      0xd0128000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vslt.p",             "?d1a,?s1a,?t1a", 0x6f800080, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vslt.q",             "?d3a,?s3a,?t3a", 0x6f808080, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vslt.s",             "?d0a,?s0a,?t0a", 0x6f800000, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vslt.t",             "?d2a,?s2a,?t2a", 0x6f808000, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vsqrt.p",            "?D1n,?s1n",      0xd0160080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vsqrt.q",            "?D3n,?s3n",      0xd0168080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vsqrt.s",            "?D0n,?s0n",      0xd0160000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vsqrt.t",            "?D2n,?s2n",      0xd0168000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vsub.p",             "?d1a,?s1a,?t1a", 0x60800080, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vsub.q",             "?d3a,?s3a,?t3a", 0x60808080, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vsub.s",             "?d0a,?s0a,?t0a", 0x60800000, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
-- 
2.51.1

Reply via email to