[binutils-gdb] RISC-V: check operands for Zqinx

Jan Beulich jbeulich@sourceware.org
Fri Jul 31 09:54:15 GMT 2026


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=0c9151fab17d1c944c8f1cd0fc8afdaea42fb9a2

commit 0c9151fab17d1c944c8f1cd0fc8afdaea42fb9a2
Author: Jan Beulich <jbeulich@suse.com>
Date:   Fri Jul 31 11:52:08 2026 +0200

    RISC-V: check operands for Zqinx
    
    By analogy to Zdinx on RV32, register pair operands are presumably (there
    not being any formal spec afaict) required to be encoded with the low bit
    clear in RV64; in RV32 the low two bits need to be clear. Since match
    functions don't have XLEN available, introduce respective flags, to be
    used explicitly in assembler and disassembler.

Diff:
---
 gas/config/tc-riscv.c                     | 19 ++++++--
 gas/testsuite/gas/riscv/zqinx-rv32-fail.d |  3 ++
 gas/testsuite/gas/riscv/zqinx-rv32-fail.l | 42 ++++++++++++++++++
 gas/testsuite/gas/riscv/zqinx-rv32.d      | 52 ++++++++++++++++++++++
 gas/testsuite/gas/riscv/zqinx-rv32.s      | 54 ++++++++++++++++++++++
 gas/testsuite/gas/riscv/zqinx-rv64-fail.d |  2 +
 gas/testsuite/gas/riscv/zqinx-rv64-fail.l | 62 ++++++++++++++++++++++++++
 gas/testsuite/gas/riscv/zqinx-rv64-fail.s | 70 +++++++++++++++++++++++++++++
 include/opcode/riscv.h                    | 13 ++++++
 opcodes/riscv-dis.c                       | 19 ++++++++
 opcodes/riscv-opc.c                       | 74 +++++++++++++++----------------
 11 files changed, 369 insertions(+), 41 deletions(-)

diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index 1fa33da6ec3..5567c33e88c 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -3010,6 +3010,12 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
    || (rclass) != RCLASS_GPR                     \
    || !((regno) & 1))
 
+#define RV64_EVEN_CHECK(form, rclass, regno)     \
+  (!(ip->insn_mo->pinfo & INSN_RV64_EVEN_##form) \
+   || xlen > 64                                  \
+   || (rclass) != RCLASS_GPR                     \
+   || !((regno) & (xlen == 32 ? 3 : 1)))
+
       for (oparg = insn->args;; ++oparg)
 	{
 	  opargStart = oparg;
@@ -3689,12 +3695,14 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
 		  switch (c)
 		    {
 		    case 'D':
-		      if (!RV32_EVEN_CHECK (D, rclass, regno))
+		      if (!RV32_EVEN_CHECK (D, rclass, regno)
+			  || !RV64_EVEN_CHECK (D, rclass, regno))
 			break;
 		      INSERT_OPERAND (RD, *ip, regno);
 		      continue;
 		    case 'S':
-		      if (!RV32_EVEN_CHECK (S, rclass, regno))
+		      if (!RV32_EVEN_CHECK (S, rclass, regno)
+			  || !RV64_EVEN_CHECK (S, rclass, regno))
 			break;
 		      INSERT_OPERAND (RS1, *ip, regno);
 		      continue;
@@ -3702,12 +3710,14 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
 		      INSERT_OPERAND (RS1, *ip, regno);
 		      /* Fall through.  */
 		    case 'T':
-		      if (!RV32_EVEN_CHECK (T, rclass, regno))
+		      if (!RV32_EVEN_CHECK (T, rclass, regno)
+			  || !RV64_EVEN_CHECK (T, rclass, regno))
 			break;
 		      INSERT_OPERAND (RS2, *ip, regno);
 		      continue;
 		    case 'R':
-		      if (!RV32_EVEN_CHECK (R, rclass, regno))
+		      if (!RV32_EVEN_CHECK (R, rclass, regno)
+			  || !RV64_EVEN_CHECK (R, rclass, regno))
 			break;
 		      INSERT_OPERAND (RS3, *ip, regno);
 		      continue;
@@ -4547,6 +4557,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
     }
 
 #undef RV32_EVEN_CHECK
+#undef RV64_EVEN_CHECK
 
  out:
   /* Restore the character we might have clobbered above.  */
diff --git a/gas/testsuite/gas/riscv/zqinx-rv32-fail.d b/gas/testsuite/gas/riscv/zqinx-rv32-fail.d
new file mode 100644
index 00000000000..0c976f63cf5
--- /dev/null
+++ b/gas/testsuite/gas/riscv/zqinx-rv32-fail.d
@@ -0,0 +1,3 @@
+#as: -march=rv32i_zqinx
+#source: zqinx.s
+#error_output: zqinx-rv32-fail.l
diff --git a/gas/testsuite/gas/riscv/zqinx-rv32-fail.l b/gas/testsuite/gas/riscv/zqinx-rv32-fail.l
new file mode 100644
index 00000000000..66df2fb41f6
--- /dev/null
+++ b/gas/testsuite/gas/riscv/zqinx-rv32-fail.l
@@ -0,0 +1,42 @@
+.*: Assembler messages:
+.*: Error: illegal operands `fadd\.q .*'
+.*: Error: illegal operands `fadd\.q .*'
+.*: Error: illegal operands `fsub\.q .*'
+.*: Error: illegal operands `fsub\.q .*'
+.*: Error: illegal operands `fmul\.q .*'
+.*: Error: illegal operands `fmul\.q .*'
+.*: Error: illegal operands `fdiv\.q .*'
+.*: Error: illegal operands `fdiv\.q .*'
+.*: Error: illegal operands `fsqrt\.q .*'
+.*: Error: illegal operands `fsqrt\.q .*'
+.*: Error: illegal operands `fmin\.q .*'
+.*: Error: illegal operands `fmax\.q .*'
+.*: Error: illegal operands `fmadd\.q .*'
+.*: Error: illegal operands `fmadd\.q .*'
+.*: Error: illegal operands `fnmadd\.q .*'
+.*: Error: illegal operands `fnmadd\.q .*'
+.*: Error: illegal operands `fmsub\.q .*'
+.*: Error: illegal operands `fmsub\.q .*'
+.*: Error: illegal operands `fnmsub\.q .*'
+.*: Error: illegal operands `fnmsub\.q .*'
+.*: Error: unrecognized opcode `fcvt\.l\.q .*'
+.*: Error: unrecognized opcode `fcvt\.l\.q .*'
+.*: Error: unrecognized opcode `fcvt\.lu\.q .*'
+.*: Error: unrecognized opcode `fcvt\.lu\.q .*'
+.*: Error: illegal operands `fcvt\.q\.w .*'
+.*: Error: illegal operands `fcvt\.q\.wu .*'
+.*: Error: unrecognized opcode `fcvt\.q\.l .*'
+.*: Error: unrecognized opcode `fcvt\.q\.lu .*'
+.*: Error: illegal operands `fcvt\.q\.s .*'
+.*: Error: illegal operands `fcvt\.q\.d .*'
+.*: Error: illegal operands `fsgnj\.q .*'
+.*: Error: illegal operands `fsgnjn\.q .*'
+.*: Error: illegal operands `fsgnjx\.q .*'
+.*: Error: illegal operands `feq\.q .*'
+.*: Error: illegal operands `flt\.q .*'
+.*: Error: illegal operands `fle\.q .*'
+.*: Error: illegal operands `fgt\.q .*'
+.*: Error: illegal operands `fge\.q .*'
+.*: Error: illegal operands `fmv\.q .*'
+.*: Error: illegal operands `fneg\.q .*'
+.*: Error: illegal operands `fabs\.q .*'
diff --git a/gas/testsuite/gas/riscv/zqinx-rv32.d b/gas/testsuite/gas/riscv/zqinx-rv32.d
new file mode 100644
index 00000000000..2872b60a803
--- /dev/null
+++ b/gas/testsuite/gas/riscv/zqinx-rv32.d
@@ -0,0 +1,52 @@
+#as: -march=rv32i_zqinx
+#objdump: -dwr
+
+.*:[ 	]+file format .*
+
+Disassembly of section .text:
+
+0+000 <target>:
+[ 	]+[0-9a-f]+:[ 	]+078a7453[ 	]+fadd\.q[ 	]+s0,s4,s8
+[ 	]+[0-9a-f]+:[ 	]+078a0453[ 	]+fadd\.q[ 	]+s0,s4,s8,rne
+[ 	]+[0-9a-f]+:[ 	]+0f8a7453[ 	]+fsub\.q[ 	]+s0,s4,s8
+[ 	]+[0-9a-f]+:[ 	]+0f8a0453[ 	]+fsub\.q[ 	]+s0,s4,s8,rne
+[ 	]+[0-9a-f]+:[ 	]+178a7453[ 	]+fmul\.q[ 	]+s0,s4,s8
+[ 	]+[0-9a-f]+:[ 	]+178a0453[ 	]+fmul\.q[ 	]+s0,s4,s8,rne
+[ 	]+[0-9a-f]+:[ 	]+1f8a7453[ 	]+fdiv\.q[ 	]+s0,s4,s8
+[ 	]+[0-9a-f]+:[ 	]+1f8a0453[ 	]+fdiv\.q[ 	]+s0,s4,s8,rne
+[ 	]+[0-9a-f]+:[ 	]+5e0a7453[ 	]+fsqrt\.q[ 	]+s0,s4
+[ 	]+[0-9a-f]+:[ 	]+5e0a0453[ 	]+fsqrt\.q[ 	]+s0,s4,rne
+[ 	]+[0-9a-f]+:[ 	]+2f8a0453[ 	]+fmin\.q[ 	]+s0,s4,s8
+[ 	]+[0-9a-f]+:[ 	]+2f8a1453[ 	]+fmax\.q[ 	]+s0,s4,s8
+[ 	]+[0-9a-f]+:[ 	]+678a7443[ 	]+fmadd\.q[ 	]+s0,s4,s8,a2
+[ 	]+[0-9a-f]+:[ 	]+678a0443[ 	]+fmadd\.q[ 	]+s0,s4,s8,a2,rne
+[ 	]+[0-9a-f]+:[ 	]+678a744f[ 	]+fnmadd\.q[ 	]+s0,s4,s8,a2
+[ 	]+[0-9a-f]+:[ 	]+678a044f[ 	]+fnmadd\.q[ 	]+s0,s4,s8,a2,rne
+[ 	]+[0-9a-f]+:[ 	]+678a7447[ 	]+fmsub\.q[ 	]+s0,s4,s8,a2
+[ 	]+[0-9a-f]+:[ 	]+678a0447[ 	]+fmsub\.q[ 	]+s0,s4,s8,a2,rne
+[ 	]+[0-9a-f]+:[ 	]+678a744b[ 	]+fnmsub\.q[ 	]+s0,s4,s8,a2
+[ 	]+[0-9a-f]+:[ 	]+678a044b[ 	]+fnmsub\.q[ 	]+s0,s4,s8,a2,rne
+[ 	]+[0-9a-f]+:[ 	]+c60a75d3[ 	]+fcvt\.w\.q[ 	]+a1,s4
+[ 	]+[0-9a-f]+:[ 	]+c60a05d3[ 	]+fcvt\.w\.q[ 	]+a1,s4,rne
+[ 	]+[0-9a-f]+:[ 	]+c61a75d3[ 	]+fcvt\.wu\.q[ 	]+a1,s4
+[ 	]+[0-9a-f]+:[ 	]+c61a05d3[ 	]+fcvt\.wu\.q[ 	]+a1,s4,rne
+[ 	]+[0-9a-f]+:[ 	]+d6058453[ 	]+fcvt\.q\.w[ 	]+s0,a1
+[ 	]+[0-9a-f]+:[ 	]+d6158453[ 	]+fcvt\.q\.wu[ 	]+s0,a1
+[ 	]+[0-9a-f]+:[ 	]+46058453[ 	]+fcvt\.q\.s[ 	]+s0,a1
+[ 	]+[0-9a-f]+:[ 	]+403a75d3[ 	]+fcvt\.s\.q[ 	]+a1,s4
+[ 	]+[0-9a-f]+:[ 	]+403a05d3[ 	]+fcvt\.s\.q[ 	]+a1,s4,rne
+[ 	]+[0-9a-f]+:[ 	]+46150453[ 	]+fcvt\.q\.d[ 	]+s0,a0
+[ 	]+[0-9a-f]+:[ 	]+423a7553[ 	]+fcvt\.d\.q[ 	]+a0,s4
+[ 	]+[0-9a-f]+:[ 	]+423a0553[ 	]+fcvt\.d\.q[ 	]+a0,s4,rne
+[ 	]+[0-9a-f]+:[ 	]+46258453[ 	]+fcvt\.q\.h[ 	]+s0,a1
+[ 	]+[0-9a-f]+:[ 	]+443a75d3[ 	]+fcvt\.h\.q[ 	]+a1,s4
+[ 	]+[0-9a-f]+:[ 	]+443a05d3[ 	]+fcvt\.h\.q[ 	]+a1,s4,rne
+[ 	]+[0-9a-f]+:[ 	]+278a0453[ 	]+fsgnj\.q[ 	]+s0,s4,s8
+[ 	]+[0-9a-f]+:[ 	]+278a1453[ 	]+fsgnjn\.q[ 	]+s0,s4,s8
+[ 	]+[0-9a-f]+:[ 	]+278a2453[ 	]+fsgnjx\.q[ 	]+s0,s4,s8
+[ 	]+[0-9a-f]+:[ 	]+a78a25d3[ 	]+feq\.q[ 	]+a1,s4,s8
+[ 	]+[0-9a-f]+:[ 	]+a78a15d3[ 	]+flt\.q[ 	]+a1,s4,s8
+[ 	]+[0-9a-f]+:[ 	]+a78a05d3[ 	]+fle\.q[ 	]+a1,s4,s8
+[ 	]+[0-9a-f]+:[ 	]+a74c15d3[ 	]+flt\.q[ 	]+a1,s8,s4
+[ 	]+[0-9a-f]+:[ 	]+a74c05d3[ 	]+fle\.q[ 	]+a1,s8,s4
+[ 	]+[0-9a-f]+:[ 	]+274a0453[ 	]+fmv\.q[ 	]+s0,s4
diff --git a/gas/testsuite/gas/riscv/zqinx-rv32.s b/gas/testsuite/gas/riscv/zqinx-rv32.s
new file mode 100644
index 00000000000..f5eb536d298
--- /dev/null
+++ b/gas/testsuite/gas/riscv/zqinx-rv32.s
@@ -0,0 +1,54 @@
+target:
+	fadd.q		s0, s4, s8
+	fadd.q		s0, s4, s8, rne
+	fsub.q		s0, s4, s8
+	fsub.q		s0, s4, s8, rne
+	fmul.q		s0, s4, s8
+	fmul.q		s0, s4, s8, rne
+	fdiv.q		s0, s4, s8
+	fdiv.q		s0, s4, s8, rne
+	fsqrt.q		s0, s4
+	fsqrt.q		s0, s4, rne
+	fmin.q		s0, s4, s8
+	fmax.q		s0, s4, s8
+	fmadd.q		s0, s4, s8, a2
+	fmadd.q		s0, s4, s8, a2, rne
+	fnmadd.q	s0, s4, s8, a2
+	fnmadd.q	s0, s4, s8, a2, rne
+	fmsub.q		s0, s4, s8, a2
+	fmsub.q		s0, s4, s8, a2, rne
+	fnmsub.q	s0, s4, s8, a2
+	fnmsub.q	s0, s4, s8, a2, rne
+
+	fcvt.w.q	a1, s4
+	fcvt.w.q	a1, s4, rne
+	fcvt.wu.q	a1, s4
+	fcvt.wu.q	a1, s4, rne
+	fcvt.q.w	s0, a1
+	fcvt.q.wu	s0, a1
+
+	fcvt.q.s	s0, a1
+	fcvt.s.q	a1, s4
+	fcvt.s.q	a1, s4, rne
+
+	fcvt.q.d	s0, a0
+	fcvt.d.q	a0, s4
+	fcvt.d.q	a0, s4, rne
+
+	.option push
+	.option arch, +zhinxmin
+	fcvt.q.h	s0, a1
+	fcvt.h.q	a1, s4
+	fcvt.h.q	a1, s4, rne
+	.option pop
+
+	fsgnj.q		s0, s4, s8
+	fsgnjn.q	s0, s4, s8
+	fsgnjx.q	s0, s4, s8
+	feq.q		a1, s4, s8
+	flt.q		a1, s4, s8
+	fle.q		a1, s4, s8
+	fgt.q		a1, s4, s8
+	fge.q		a1, s4, s8
+
+	fmv.q		s0, s4
diff --git a/gas/testsuite/gas/riscv/zqinx-rv64-fail.d b/gas/testsuite/gas/riscv/zqinx-rv64-fail.d
new file mode 100644
index 00000000000..236ae08df9c
--- /dev/null
+++ b/gas/testsuite/gas/riscv/zqinx-rv64-fail.d
@@ -0,0 +1,2 @@
+#as: -march=rv64i_zqinx
+#error_output: zqinx-rv64-fail.l
diff --git a/gas/testsuite/gas/riscv/zqinx-rv64-fail.l b/gas/testsuite/gas/riscv/zqinx-rv64-fail.l
new file mode 100644
index 00000000000..1558997eec8
--- /dev/null
+++ b/gas/testsuite/gas/riscv/zqinx-rv64-fail.l
@@ -0,0 +1,62 @@
+.*: Assembler messages:
+.*: Error: illegal operands `fadd\.q .*'
+.*: Error: illegal operands `fadd\.q .*'
+.*: Error: illegal operands `fadd\.q .*'
+.*: Error: illegal operands `fsub\.q .*'
+.*: Error: illegal operands `fsub\.q .*'
+.*: Error: illegal operands `fsub\.q .*'
+.*: Error: illegal operands `fmul\.q .*'
+.*: Error: illegal operands `fmul\.q .*'
+.*: Error: illegal operands `fmul\.q .*'
+.*: Error: illegal operands `fdiv\.q .*'
+.*: Error: illegal operands `fdiv\.q .*'
+.*: Error: illegal operands `fdiv\.q .*'
+.*: Error: illegal operands `fsqrt\.q .*'
+.*: Error: illegal operands `fsqrt\.q .*'
+.*: Error: illegal operands `fmin\.q .*'
+.*: Error: illegal operands `fmin\.q .*'
+.*: Error: illegal operands `fmin\.q .*'
+.*: Error: illegal operands `fmax\.q .*'
+.*: Error: illegal operands `fmax\.q .*'
+.*: Error: illegal operands `fmax\.q .*'
+.*: Error: illegal operands `fmadd\.q .*'
+.*: Error: illegal operands `fmadd\.q .*'
+.*: Error: illegal operands `fmadd\.q .*'
+.*: Error: illegal operands `fmadd\.q .*'
+.*: Error: illegal operands `fnmadd\.q .*'
+.*: Error: illegal operands `fnmadd\.q .*'
+.*: Error: illegal operands `fnmadd\.q .*'
+.*: Error: illegal operands `fnmadd\.q .*'
+.*: Error: illegal operands `fmsub\.q .*'
+.*: Error: illegal operands `fmsub\.q .*'
+.*: Error: illegal operands `fmsub\.q .*'
+.*: Error: illegal operands `fmsub\.q .*'
+.*: Error: illegal operands `fnmsub\.q .*'
+.*: Error: illegal operands `fnmsub\.q .*'
+.*: Error: illegal operands `fnmsub\.q .*'
+.*: Error: illegal operands `fnmsub\.q .*'
+.*: Error: illegal operands `fcvt\.w\.q .*'
+.*: Error: illegal operands `fcvt\.wu\.q .*'
+.*: Error: illegal operands `fcvt\.q\.w .*'
+.*: Error: illegal operands `fcvt\.q\.wu .*'
+.*: Error: illegal operands `fcvt\.q\.s .*'
+.*: Error: illegal operands `fcvt\.s\.q .*'
+.*: Error: illegal operands `fcvt\.q\.d .*'
+.*: Error: illegal operands `fcvt\.d\.q .*'
+.*: Error: illegal operands `fcvt\.q\.h .*'
+.*: Error: illegal operands `fcvt\.h\.q .*'
+.*: Error: illegal operands `fsgnj\.q .*'
+.*: Error: illegal operands `fsgnjn\.q .*'
+.*: Error: illegal operands `fsgnjx\.q .*'
+.*: Error: illegal operands `feq\.q .*'
+.*: Error: illegal operands `flt\.q .*'
+.*: Error: illegal operands `fle\.q .*'
+.*: Error: illegal operands `fgt\.q .*'
+.*: Error: illegal operands `fge\.q .*'
+.*: Error: illegal operands `fmv\.q .*'
+.*: Error: illegal operands `fmv\.q .*'
+.*: Error: illegal operands `fneg\.q .*'
+.*: Error: illegal operands `fneg\.q .*'
+.*: Error: illegal operands `fabs\.q .*'
+.*: Error: illegal operands `fabs\.q .*'
+.*: Error: illegal operands `fclass\.q .*'
diff --git a/gas/testsuite/gas/riscv/zqinx-rv64-fail.s b/gas/testsuite/gas/riscv/zqinx-rv64-fail.s
new file mode 100644
index 00000000000..4a6546dcc6c
--- /dev/null
+++ b/gas/testsuite/gas/riscv/zqinx-rv64-fail.s
@@ -0,0 +1,70 @@
+target:
+	fadd.q		s1, s4, s8
+	fadd.q		s0, s5, s8
+	fadd.q		s0, s4, s9
+	fsub.q		s1, s4, s8
+	fsub.q		s0, s5, s8
+	fsub.q		s0, s4, s9
+	fmul.q		s1, s4, s8
+	fmul.q		s0, s5, s8
+	fmul.q		s0, s4, s9
+	fdiv.q		s1, s4, s8
+	fdiv.q		s0, s5, s8
+	fdiv.q		s0, s4, s9
+	fsqrt.q		s1, s4
+	fsqrt.q		s0, s5
+	fmin.q		s1, s4, s8
+	fmin.q		s0, s5, s8
+	fmin.q		s0, s4, s9
+	fmax.q		s1, s4, s8
+	fmax.q		s0, s5, s8
+	fmax.q		s0, s4, s9
+	fmadd.q		s1, s4, s8, a2
+	fmadd.q		s0, s5, s8, a2
+	fmadd.q		s0, s4, s9, a2
+	fmadd.q		s0, s4, s8, a3
+	fnmadd.q	s1, s4, s8, a2
+	fnmadd.q	s0, s5, s8, a2
+	fnmadd.q	s0, s4, s9, a2
+	fnmadd.q	s0, s4, s8, a3
+	fmsub.q		s1, s4, s8, a2
+	fmsub.q		s0, s5, s8, a2
+	fmsub.q		s0, s4, s9, a2
+	fmsub.q		s0, s4, s8, a3
+	fnmsub.q	s1, s4, s8, a2
+	fnmsub.q	s0, s5, s8, a2
+	fnmsub.q	s0, s4, s9, a2
+	fnmsub.q	s0, s4, s8, a3
+
+	fcvt.w.q	a0, s5
+	fcvt.wu.q	a0, s5
+	fcvt.q.w	s1, a0
+	fcvt.q.wu	s1, a0
+
+	fcvt.q.s	s1, a0
+	fcvt.s.q	a0, s5
+
+	fcvt.q.d	s1, a0
+	fcvt.d.q	a0, s5
+
+	.option push
+	.option arch, +zhinxmin
+	fcvt.q.h	s1, a0
+	fcvt.h.q	a0, s5
+	.option pop
+
+	fsgnj.q		s1, s4, s8
+	fsgnjn.q	s0, s5, s8
+	fsgnjx.q	s0, s4, s9
+	feq.q		a0, s5, s8
+	flt.q		a0, s4, s9
+	fle.q		a0, s5, s8
+	fgt.q		a0, s4, s9
+	fge.q		a0, s5, s8
+	fmv.q		s1, s4
+	fmv.q		s0, s5
+	fneg.q		s1, s4
+	fneg.q		s0, s5
+	fabs.q		s1, s4
+	fabs.q		s0, s5
+	fclass.q	a0, s5
diff --git a/include/opcode/riscv.h b/include/opcode/riscv.h
index d142d3401fa..7c24988ac4b 100644
--- a/include/opcode/riscv.h
+++ b/include/opcode/riscv.h
@@ -721,6 +721,19 @@ struct riscv_opcode
 #define INSN_RV32_EVEN_DU	(INSN_RV32_EVEN_D   | INSN_RV32_EVEN_T)
 #define INSN_RV32_EVEN_ST	(INSN_RV32_EVEN_S   | INSN_RV32_EVEN_T)
 
+/* Operands required to be an even-numbered register (pair) in RV64, and one
+   divisible by 4 on RV32.  */
+#define INSN_RV64_EVEN_D	0x00001000
+#define INSN_RV64_EVEN_S	0x00002000
+#define INSN_RV64_EVEN_T	0x00004000 /* Also covering U.  */
+#define INSN_RV64_EVEN_R	0x00008000
+/* Shorthands for combinations of the above.  */
+#define INSN_RV64_EVEN_DS	(INSN_RV64_EVEN_D   | INSN_RV64_EVEN_S)
+#define INSN_RV64_EVEN_DST	(INSN_RV64_EVEN_DS  | INSN_RV64_EVEN_T)
+#define INSN_RV64_EVEN_DSTR	(INSN_RV64_EVEN_DST | INSN_RV64_EVEN_R)
+#define INSN_RV64_EVEN_DU	(INSN_RV64_EVEN_D   | INSN_RV64_EVEN_T)
+#define INSN_RV64_EVEN_ST	(INSN_RV64_EVEN_S   | INSN_RV64_EVEN_T)
+
 /* Instruction is actually a macro.  It should be ignored by the
    disassembler, and requires special treatment by the assembler.  */
 #define INSN_MACRO		0xffffffff
diff --git a/opcodes/riscv-dis.c b/opcodes/riscv-dis.c
index 696f2d9777f..42b0dd9c9fc 100644
--- a/opcodes/riscv-dis.c
+++ b/opcodes/riscv-dis.c
@@ -1155,6 +1155,25 @@ riscv_disassemble_insn (bfd_vma memaddr,
 		      && (word & (1u << OP_SH_RS3)))
 		    continue;
 		}
+
+	      if (pd->xlen <= 64
+		  && riscv_subset_supports (&pd->riscv_rps_dis, "zqinx"))
+		{
+		  unsigned int mask = pd->xlen == 32 ? 3 : 1;
+
+		  if ((op->pinfo & INSN_RV64_EVEN_D)
+		      && (word & (mask << OP_SH_RD)))
+		    continue;
+		  if ((op->pinfo & INSN_RV64_EVEN_S)
+		      && (word & (mask << OP_SH_RS1)))
+		    continue;
+		  if ((op->pinfo & INSN_RV64_EVEN_T)
+		      && (word & (mask << OP_SH_RS2)))
+		    continue;
+		  if ((op->pinfo & INSN_RV64_EVEN_R)
+		      && (word & (mask << OP_SH_RS3)))
+		    continue;
+		}
 	    }
 
 	  /* It's a match.  */
diff --git a/opcodes/riscv-opc.c b/opcodes/riscv-opc.c
index 6b01851b757..617b444697e 100644
--- a/opcodes/riscv-opc.c
+++ b/opcodes/riscv-opc.c
@@ -956,10 +956,10 @@ const struct riscv_opcode riscv_opcodes[] =
 {"fcvt.h.wu",  0, INSN_CLASS_ZFH_INX,  "D,sm",      MATCH_FCVT_H_WU, MASK_FCVT_H_WU, match_opcode, 0 },
 {"fcvt.s.h",   0, INSN_CLASS_ZFHMIN_INX, "D,S",     MATCH_FCVT_S_H, MASK_FCVT_S_H|MASK_RM, match_opcode, 0 },
 {"fcvt.d.h",   0, INSN_CLASS_ZFHMIN_AND_D_INX, "D,S", MATCH_FCVT_D_H, MASK_FCVT_D_H|MASK_RM, match_opcode, INSN_RV32_EVEN_D },
-{"fcvt.q.h",   0, INSN_CLASS_ZFHMIN_AND_Q_INX, "D,S", MATCH_FCVT_Q_H, MASK_FCVT_Q_H|MASK_RM, match_opcode, 0 },
+{"fcvt.q.h",   0, INSN_CLASS_ZFHMIN_AND_Q_INX, "D,S", MATCH_FCVT_Q_H, MASK_FCVT_Q_H|MASK_RM, match_opcode, INSN_RV64_EVEN_D },
 {"fcvt.h.s",   0, INSN_CLASS_ZFHMIN_INX, "D,Sm",    MATCH_FCVT_H_S, MASK_FCVT_H_S, match_opcode, 0 },
 {"fcvt.h.d",   0, INSN_CLASS_ZFHMIN_AND_D_INX, "D,Sm", MATCH_FCVT_H_D, MASK_FCVT_H_D, match_opcode, INSN_RV32_EVEN_S },
-{"fcvt.h.q",   0, INSN_CLASS_ZFHMIN_AND_Q_INX, "D,Sm", MATCH_FCVT_H_Q, MASK_FCVT_H_Q, match_opcode, 0 },
+{"fcvt.h.q",   0, INSN_CLASS_ZFHMIN_AND_Q_INX, "D,Sm", MATCH_FCVT_H_Q, MASK_FCVT_H_Q, match_opcode, INSN_RV64_EVEN_S },
 {"fclass.h",   0, INSN_CLASS_ZFH_INX,   "d,S",       MATCH_FCLASS_H, MASK_FCLASS_H, match_opcode, 0 },
 {"feq.h",      0, INSN_CLASS_ZFH_INX,   "d,S,T",     MATCH_FEQ_H, MASK_FEQ_H, match_opcode, 0 },
 {"flt.h",      0, INSN_CLASS_ZFH_INX,   "d,S,T",     MATCH_FLT_H, MASK_FLT_H, match_opcode, 0 },
@@ -1086,41 +1086,41 @@ const struct riscv_opcode riscv_opcodes[] =
 {"flq",        0, INSN_CLASS_Q,   "D,A,s",     0, (int) M_FLx, match_rs1_nonzero, INSN_MACRO },
 {"fsq",        0, INSN_CLASS_Q,   "T,q(s)",    MATCH_FSQ, MASK_FSQ, match_opcode, INSN_DREF|INSN_16_BYTE },
 {"fsq",        0, INSN_CLASS_Q,   "T,A,s",     0, (int) M_Sx_FSx, match_rs1_nonzero, INSN_MACRO },
-{"fmv.q",      0, INSN_CLASS_Q_INX,   "D,U",       MATCH_FSGNJ_Q, MASK_FSGNJ_Q, match_rs1_eq_rs2, INSN_ALIAS },
-{"fneg.q",     0, INSN_CLASS_Q_INX,   "D,U",       MATCH_FSGNJN_Q, MASK_FSGNJN_Q, match_rs1_eq_rs2, INSN_ALIAS },
-{"fabs.q",     0, INSN_CLASS_Q_INX,   "D,U",       MATCH_FSGNJX_Q, MASK_FSGNJX_Q, match_rs1_eq_rs2, INSN_ALIAS },
-{"fsgnj.q",    0, INSN_CLASS_Q_INX,   "D,S,T",     MATCH_FSGNJ_Q, MASK_FSGNJ_Q, match_opcode, 0 },
-{"fsgnjn.q",   0, INSN_CLASS_Q_INX,   "D,S,T",     MATCH_FSGNJN_Q, MASK_FSGNJN_Q, match_opcode, 0 },
-{"fsgnjx.q",   0, INSN_CLASS_Q_INX,   "D,S,T",     MATCH_FSGNJX_Q, MASK_FSGNJX_Q, match_opcode, 0 },
-{"fadd.q",     0, INSN_CLASS_Q_INX,   "D,S,Tm",    MATCH_FADD_Q, MASK_FADD_Q, match_opcode, 0 },
-{"fsub.q",     0, INSN_CLASS_Q_INX,   "D,S,Tm",    MATCH_FSUB_Q, MASK_FSUB_Q, match_opcode, 0 },
-{"fmul.q",     0, INSN_CLASS_Q_INX,   "D,S,Tm",    MATCH_FMUL_Q, MASK_FMUL_Q, match_opcode, 0 },
-{"fdiv.q",     0, INSN_CLASS_Q_INX,   "D,S,Tm",    MATCH_FDIV_Q, MASK_FDIV_Q, match_opcode, 0 },
-{"fsqrt.q",    0, INSN_CLASS_Q_INX,   "D,Sm",      MATCH_FSQRT_Q, MASK_FSQRT_Q, match_opcode, 0 },
-{"fmin.q",     0, INSN_CLASS_Q_INX,   "D,S,T",     MATCH_FMIN_Q, MASK_FMIN_Q, match_opcode, 0 },
-{"fmax.q",     0, INSN_CLASS_Q_INX,   "D,S,T",     MATCH_FMAX_Q, MASK_FMAX_Q, match_opcode, 0 },
-{"fmadd.q",    0, INSN_CLASS_Q_INX,   "D,S,T,Rm",  MATCH_FMADD_Q, MASK_FMADD_Q, match_opcode, 0 },
-{"fnmadd.q",   0, INSN_CLASS_Q_INX,   "D,S,T,Rm",  MATCH_FNMADD_Q, MASK_FNMADD_Q, match_opcode, 0 },
-{"fmsub.q",    0, INSN_CLASS_Q_INX,   "D,S,T,Rm",  MATCH_FMSUB_Q, MASK_FMSUB_Q, match_opcode, 0 },
-{"fnmsub.q",   0, INSN_CLASS_Q_INX,   "D,S,T,Rm",  MATCH_FNMSUB_Q, MASK_FNMSUB_Q, match_opcode, 0 },
-{"fcvt.w.q",   0, INSN_CLASS_Q_INX,   "d,Sm",      MATCH_FCVT_W_Q, MASK_FCVT_W_Q, match_opcode, 0 },
-{"fcvt.wu.q",  0, INSN_CLASS_Q_INX,   "d,Sm",      MATCH_FCVT_WU_Q, MASK_FCVT_WU_Q, match_opcode, 0 },
-{"fcvt.q.w",   0, INSN_CLASS_Q_INX,   "D,s",       MATCH_FCVT_Q_W, MASK_FCVT_Q_W|MASK_RM, match_opcode, 0 },
-{"fcvt.q.wu",  0, INSN_CLASS_Q_INX,   "D,s",       MATCH_FCVT_Q_WU, MASK_FCVT_Q_WU|MASK_RM, match_opcode, 0 },
-{"fcvt.q.s",   0, INSN_CLASS_Q_INX,   "D,S",       MATCH_FCVT_Q_S, MASK_FCVT_Q_S|MASK_RM, match_opcode, 0 },
-{"fcvt.q.d",   0, INSN_CLASS_Q_INX,   "D,S",       MATCH_FCVT_Q_D, MASK_FCVT_Q_D|MASK_RM, match_opcode, 0 },
-{"fcvt.s.q",   0, INSN_CLASS_Q_INX,   "D,Sm",      MATCH_FCVT_S_Q, MASK_FCVT_S_Q, match_opcode, 0 },
-{"fcvt.d.q",   0, INSN_CLASS_Q_INX,   "D,Sm",      MATCH_FCVT_D_Q, MASK_FCVT_D_Q, match_opcode, 0 },
-{"fclass.q",   0, INSN_CLASS_Q_INX,   "d,S",       MATCH_FCLASS_Q, MASK_FCLASS_Q, match_opcode, 0 },
-{"feq.q",      0, INSN_CLASS_Q_INX,   "d,S,T",     MATCH_FEQ_Q, MASK_FEQ_Q, match_opcode, 0 },
-{"flt.q",      0, INSN_CLASS_Q_INX,   "d,S,T",     MATCH_FLT_Q, MASK_FLT_Q, match_opcode, 0 },
-{"fle.q",      0, INSN_CLASS_Q_INX,   "d,S,T",     MATCH_FLE_Q, MASK_FLE_Q, match_opcode, 0 },
-{"fgt.q",      0, INSN_CLASS_Q_INX,   "d,T,S",     MATCH_FLT_Q, MASK_FLT_Q, match_opcode, INSN_ALIAS },
-{"fge.q",      0, INSN_CLASS_Q_INX,   "d,T,S",     MATCH_FLE_Q, MASK_FLE_Q, match_opcode, INSN_ALIAS },
-{"fcvt.l.q",  64, INSN_CLASS_Q_INX,   "d,Sm",      MATCH_FCVT_L_Q, MASK_FCVT_L_Q, match_opcode, 0 },
-{"fcvt.lu.q", 64, INSN_CLASS_Q_INX,   "d,Sm",      MATCH_FCVT_LU_Q, MASK_FCVT_LU_Q, match_opcode, 0 },
-{"fcvt.q.l",  64, INSN_CLASS_Q_INX,   "D,s",       MATCH_FCVT_Q_L, MASK_FCVT_Q_L|MASK_RM, match_opcode, 0 },
-{"fcvt.q.lu", 64, INSN_CLASS_Q_INX,   "D,s",       MATCH_FCVT_Q_LU, MASK_FCVT_Q_LU|MASK_RM, match_opcode, 0 },
+{"fmv.q",      0, INSN_CLASS_Q_INX,   "D,U",       MATCH_FSGNJ_Q, MASK_FSGNJ_Q, match_rs1_eq_rs2, INSN_ALIAS|INSN_RV64_EVEN_DU },
+{"fneg.q",     0, INSN_CLASS_Q_INX,   "D,U",       MATCH_FSGNJN_Q, MASK_FSGNJN_Q, match_rs1_eq_rs2, INSN_ALIAS|INSN_RV64_EVEN_DU },
+{"fabs.q",     0, INSN_CLASS_Q_INX,   "D,U",       MATCH_FSGNJX_Q, MASK_FSGNJX_Q, match_rs1_eq_rs2, INSN_ALIAS|INSN_RV64_EVEN_DU },
+{"fsgnj.q",    0, INSN_CLASS_Q_INX,   "D,S,T",     MATCH_FSGNJ_Q, MASK_FSGNJ_Q, match_opcode, INSN_RV64_EVEN_DST },
+{"fsgnjn.q",   0, INSN_CLASS_Q_INX,   "D,S,T",     MATCH_FSGNJN_Q, MASK_FSGNJN_Q, match_opcode, INSN_RV64_EVEN_DST },
+{"fsgnjx.q",   0, INSN_CLASS_Q_INX,   "D,S,T",     MATCH_FSGNJX_Q, MASK_FSGNJX_Q, match_opcode, INSN_RV64_EVEN_DST },
+{"fadd.q",     0, INSN_CLASS_Q_INX,   "D,S,Tm",    MATCH_FADD_Q, MASK_FADD_Q, match_opcode, INSN_RV64_EVEN_DST },
+{"fsub.q",     0, INSN_CLASS_Q_INX,   "D,S,Tm",    MATCH_FSUB_Q, MASK_FSUB_Q, match_opcode, INSN_RV64_EVEN_DST },
+{"fmul.q",     0, INSN_CLASS_Q_INX,   "D,S,Tm",    MATCH_FMUL_Q, MASK_FMUL_Q, match_opcode, INSN_RV64_EVEN_DST },
+{"fdiv.q",     0, INSN_CLASS_Q_INX,   "D,S,Tm",    MATCH_FDIV_Q, MASK_FDIV_Q, match_opcode, INSN_RV64_EVEN_DST },
+{"fsqrt.q",    0, INSN_CLASS_Q_INX,   "D,Sm",      MATCH_FSQRT_Q, MASK_FSQRT_Q, match_opcode, INSN_RV64_EVEN_DS },
+{"fmin.q",     0, INSN_CLASS_Q_INX,   "D,S,T",     MATCH_FMIN_Q, MASK_FMIN_Q, match_opcode, INSN_RV64_EVEN_DST },
+{"fmax.q",     0, INSN_CLASS_Q_INX,   "D,S,T",     MATCH_FMAX_Q, MASK_FMAX_Q, match_opcode, INSN_RV64_EVEN_DST },
+{"fmadd.q",    0, INSN_CLASS_Q_INX,   "D,S,T,Rm",  MATCH_FMADD_Q, MASK_FMADD_Q, match_opcode, INSN_RV64_EVEN_DSTR },
+{"fnmadd.q",   0, INSN_CLASS_Q_INX,   "D,S,T,Rm",  MATCH_FNMADD_Q, MASK_FNMADD_Q, match_opcode, INSN_RV64_EVEN_DSTR },
+{"fmsub.q",    0, INSN_CLASS_Q_INX,   "D,S,T,Rm",  MATCH_FMSUB_Q, MASK_FMSUB_Q, match_opcode, INSN_RV64_EVEN_DSTR },
+{"fnmsub.q",   0, INSN_CLASS_Q_INX,   "D,S,T,Rm",  MATCH_FNMSUB_Q, MASK_FNMSUB_Q, match_opcode, INSN_RV64_EVEN_DSTR },
+{"fcvt.w.q",   0, INSN_CLASS_Q_INX,   "d,Sm",      MATCH_FCVT_W_Q, MASK_FCVT_W_Q, match_opcode, INSN_RV64_EVEN_S },
+{"fcvt.wu.q",  0, INSN_CLASS_Q_INX,   "d,Sm",      MATCH_FCVT_WU_Q, MASK_FCVT_WU_Q, match_opcode, INSN_RV64_EVEN_S },
+{"fcvt.q.w",   0, INSN_CLASS_Q_INX,   "D,s",       MATCH_FCVT_Q_W, MASK_FCVT_Q_W|MASK_RM, match_opcode, INSN_RV64_EVEN_D },
+{"fcvt.q.wu",  0, INSN_CLASS_Q_INX,   "D,s",       MATCH_FCVT_Q_WU, MASK_FCVT_Q_WU|MASK_RM, match_opcode, INSN_RV64_EVEN_D },
+{"fcvt.q.s",   0, INSN_CLASS_Q_INX,   "D,S",       MATCH_FCVT_Q_S, MASK_FCVT_Q_S|MASK_RM, match_opcode, INSN_RV64_EVEN_D },
+{"fcvt.q.d",   0, INSN_CLASS_Q_INX,   "D,S",       MATCH_FCVT_Q_D, MASK_FCVT_Q_D|MASK_RM, match_opcode, INSN_RV64_EVEN_D|INSN_RV32_EVEN_S },
+{"fcvt.s.q",   0, INSN_CLASS_Q_INX,   "D,Sm",      MATCH_FCVT_S_Q, MASK_FCVT_S_Q, match_opcode, INSN_RV64_EVEN_S },
+{"fcvt.d.q",   0, INSN_CLASS_Q_INX,   "D,Sm",      MATCH_FCVT_D_Q, MASK_FCVT_D_Q, match_opcode, INSN_RV32_EVEN_D|INSN_RV64_EVEN_S },
+{"fclass.q",   0, INSN_CLASS_Q_INX,   "d,S",       MATCH_FCLASS_Q, MASK_FCLASS_Q, match_opcode, INSN_RV64_EVEN_S },
+{"feq.q",      0, INSN_CLASS_Q_INX,   "d,S,T",     MATCH_FEQ_Q, MASK_FEQ_Q, match_opcode, INSN_RV64_EVEN_ST },
+{"flt.q",      0, INSN_CLASS_Q_INX,   "d,S,T",     MATCH_FLT_Q, MASK_FLT_Q, match_opcode, INSN_RV64_EVEN_ST },
+{"fle.q",      0, INSN_CLASS_Q_INX,   "d,S,T",     MATCH_FLE_Q, MASK_FLE_Q, match_opcode, INSN_RV64_EVEN_ST },
+{"fgt.q",      0, INSN_CLASS_Q_INX,   "d,T,S",     MATCH_FLT_Q, MASK_FLT_Q, match_opcode, INSN_ALIAS|INSN_RV64_EVEN_ST },
+{"fge.q",      0, INSN_CLASS_Q_INX,   "d,T,S",     MATCH_FLE_Q, MASK_FLE_Q, match_opcode, INSN_ALIAS|INSN_RV64_EVEN_ST },
+{"fcvt.l.q",  64, INSN_CLASS_Q_INX,   "d,Sm",      MATCH_FCVT_L_Q, MASK_FCVT_L_Q, match_opcode, INSN_RV64_EVEN_S },
+{"fcvt.lu.q", 64, INSN_CLASS_Q_INX,   "d,Sm",      MATCH_FCVT_LU_Q, MASK_FCVT_LU_Q, match_opcode, INSN_RV64_EVEN_S },
+{"fcvt.q.l",  64, INSN_CLASS_Q_INX,   "D,s",       MATCH_FCVT_Q_L, MASK_FCVT_Q_L|MASK_RM, match_opcode, INSN_RV64_EVEN_D },
+{"fcvt.q.lu", 64, INSN_CLASS_Q_INX,   "D,s",       MATCH_FCVT_Q_LU, MASK_FCVT_Q_LU|MASK_RM, match_opcode, INSN_RV64_EVEN_D },
 
 /* Compressed instructions.  */
 {"c.unimp",    0, INSN_CLASS_ZCA,   "",          0, 0xffffU,  match_opcode, 0 },


More information about the Binutils-cvs mailing list