[PATCH v2 5/9] Implement dest-register compatibility checks for the MIPS Allegrex VFPU regs.

David Guillen Fandos david@davidgf.net
Tue Jan 20 23:32:13 GMT 2026


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 <david@davidgf.net>
---
 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



More information about the Gcc-patches mailing list