[v4,06/12] RISC-V: check operands for Zdinx in RV32
Checks
| Context |
Check |
Description |
| linaro-tcwg-bot/tcwg_binutils_build--master-arm |
success
|
Build passed
|
| linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 |
success
|
Build passed
|
| linaro-tcwg-bot/tcwg_binutils_check--master-arm |
success
|
Test passed
|
| linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 |
success
|
Test passed
|
Commit Message
Like for Zilsd, register pair operands are required to be encoded with the
low bit clear. Since match functions don't have XLEN available, introduce
respective flags, to be used explicitly in assembler and disassembler.
---
No similar checking is easily possible for scalar vector insns, as element
width there isn't encoded in the insn. (Plus V and Zdinx can't be enabled
together right now anyway.)
We could further use RV32_EVEN_CHECK for Zilsd as well, then allowing to
eliminate one or two match functions. (Hence RV32_EVEN_CHECK()'s scope is
pretty wide.)
Comments
I used to have reservations about these assembler constraint checks
(including those for RVV) because, at the time, there were strong
objections from people whose random test case generators were failing
due to this feature. Essentially, the project involves randomly
generating various assembler instructions (including illegal ones) and
feeding them to the hardware to verify whether the DV (Design
Verification) setup correctly detects the invalid instructions. There
was previously a compromise involving an option to let users toggle
these checks on or off, but I didn't think the option was a good idea
- since it was specific to RVV and addressed only a very small number
of edge cases - so I ultimately removed it. In fact, people can still
assemble these illegal instructions by .insn directives, but it just
wasn't adopted at the time due to the complex certain political
reasons. So now I think it's time to correct the wrong decision and
do the right thing - I think what you are doing is right, allowing
illegal instructions for assembler is wrong and dangerous for general
users, so this patch (and maybe further patches for constraints) looks
good to me.
Thanks
Nelson
On Fri, Jul 24, 2026 at 6:04 PM Jan Beulich <jbeulich@suse.com> wrote:
>
> Like for Zilsd, register pair operands are required to be encoded with the
> low bit clear. Since match functions don't have XLEN available, introduce
> respective flags, to be used explicitly in assembler and disassembler.
> ---
> No similar checking is easily possible for scalar vector insns, as element
> width there isn't encoded in the insn. (Plus V and Zdinx can't be enabled
> together right now anyway.)
>
> We could further use RV32_EVEN_CHECK for Zilsd as well, then allowing to
> eliminate one or two match functions. (Hence RV32_EVEN_CHECK()'s scope is
> pretty wide.)
>
> --- a/gas/config/tc-riscv.c
> +++ b/gas/config/tc-riscv.c
> @@ -3004,6 +3004,12 @@ riscv_ip (char *str, struct riscv_cl_ins
> *imm_reloc = BFD_RELOC_UNUSED;
> p = percent_op_null;
>
> +#define RV32_EVEN_CHECK(form, rclass, regno) \
> + (!(ip->insn_mo->pinfo & INSN_RV32_EVEN_##form) \
> + || xlen != 32 \
> + || (rclass) != RCLASS_GPR \
> + || !((regno) & 1))
> +
> for (oparg = insn->args;; ++oparg)
> {
> opargStart = oparg;
> @@ -3011,6 +3017,8 @@ riscv_ip (char *str, struct riscv_cl_ins
> ++asarg;
> switch (*oparg)
> {
> + enum reg_class rclass;
> +
> case '\0': /* End of args. */
> if (insn->match_func && !insn->match_func (insn, ip->insn_opcode))
> break;
> @@ -3670,32 +3678,40 @@ riscv_ip (char *str, struct riscv_cl_ins
> case 'T': /* Floating point RS2. */
> case 'U': /* Floating point RS1 and RS2. */
> case 'R': /* Floating point RS3. */
> - if (reg_lookup (&asarg,
> - (riscv_subset_supports (&riscv_rps_as, "zfinx")
> - ? RCLASS_GPR : RCLASS_FPR), ®no))
> + rclass = riscv_subset_supports (&riscv_rps_as, "zfinx")
> + ? RCLASS_GPR : RCLASS_FPR;
> + if (reg_lookup (&asarg, rclass, ®no))
> {
> char c = *oparg;
> if (is_whitespace (*asarg))
> ++asarg;
> +
> switch (c)
> {
> case 'D':
> + if (!RV32_EVEN_CHECK (D, rclass, regno))
> + break;
> INSERT_OPERAND (RD, *ip, regno);
> - break;
> + continue;
> case 'S':
> + if (!RV32_EVEN_CHECK (S, rclass, regno))
> + break;
> INSERT_OPERAND (RS1, *ip, regno);
> - break;
> + continue;
> case 'U':
> INSERT_OPERAND (RS1, *ip, regno);
> /* Fall through. */
> case 'T':
> + if (!RV32_EVEN_CHECK (T, rclass, regno))
> + break;
> INSERT_OPERAND (RS2, *ip, regno);
> - break;
> + continue;
> case 'R':
> + if (!RV32_EVEN_CHECK (R, rclass, regno))
> + break;
> INSERT_OPERAND (RS3, *ip, regno);
> - break;
> + continue;
> }
> - continue;
> }
> break;
>
> @@ -4530,6 +4546,8 @@ riscv_ip (char *str, struct riscv_cl_ins
> insn_with_csr = false;
> }
>
> +#undef RV32_EVEN_CHECK
> +
> out:
> /* Restore the character we might have clobbered above. */
> if (save_c)
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/zdinx-rv32.d
> @@ -0,0 +1,52 @@
> +#as: -march=rv32i_zdinx
> +#objdump: -dwr
> +
> +.*:[ ]+file format .*
> +
> +Disassembly of section .text:
> +
> +0+000 <target>:
> +[ ]+[0-9a-f]+:[ ]+02e67553[ ]+fadd\.d[ ]+a0,a2,a4
> +[ ]+[0-9a-f]+:[ ]+02e60553[ ]+fadd\.d[ ]+a0,a2,a4,rne
> +[ ]+[0-9a-f]+:[ ]+0ae67553[ ]+fsub\.d[ ]+a0,a2,a4
> +[ ]+[0-9a-f]+:[ ]+0ae60553[ ]+fsub\.d[ ]+a0,a2,a4,rne
> +[ ]+[0-9a-f]+:[ ]+12e67553[ ]+fmul\.d[ ]+a0,a2,a4
> +[ ]+[0-9a-f]+:[ ]+12e60553[ ]+fmul\.d[ ]+a0,a2,a4,rne
> +[ ]+[0-9a-f]+:[ ]+1ae67553[ ]+fdiv\.d[ ]+a0,a2,a4
> +[ ]+[0-9a-f]+:[ ]+1ae60553[ ]+fdiv\.d[ ]+a0,a2,a4,rne
> +[ ]+[0-9a-f]+:[ ]+5a067553[ ]+fsqrt\.d[ ]+a0,a2
> +[ ]+[0-9a-f]+:[ ]+5a060553[ ]+fsqrt\.d[ ]+a0,a2,rne
> +[ ]+[0-9a-f]+:[ ]+2ae60553[ ]+fmin\.d[ ]+a0,a2,a4
> +[ ]+[0-9a-f]+:[ ]+2ae61553[ ]+fmax\.d[ ]+a0,a2,a4
> +[ ]+[0-9a-f]+:[ ]+82e67543[ ]+fmadd\.d[ ]+a0,a2,a4,a6
> +[ ]+[0-9a-f]+:[ ]+82e60543[ ]+fmadd\.d[ ]+a0,a2,a4,a6,rne
> +[ ]+[0-9a-f]+:[ ]+82e6754f[ ]+fnmadd\.d[ ]+a0,a2,a4,a6
> +[ ]+[0-9a-f]+:[ ]+82e6054f[ ]+fnmadd\.d[ ]+a0,a2,a4,a6,rne
> +[ ]+[0-9a-f]+:[ ]+82e67547[ ]+fmsub\.d[ ]+a0,a2,a4,a6
> +[ ]+[0-9a-f]+:[ ]+82e60547[ ]+fmsub\.d[ ]+a0,a2,a4,a6,rne
> +[ ]+[0-9a-f]+:[ ]+82e6754b[ ]+fnmsub\.d[ ]+a0,a2,a4,a6
> +[ ]+[0-9a-f]+:[ ]+82e6054b[ ]+fnmsub\.d[ ]+a0,a2,a4,a6,rne
> +[ ]+[0-9a-f]+:[ ]+c20675d3[ ]+fcvt\.w\.d[ ]+a1,a2
> +[ ]+[0-9a-f]+:[ ]+c20605d3[ ]+fcvt\.w\.d[ ]+a1,a2,rne
> +[ ]+[0-9a-f]+:[ ]+c21675d3[ ]+fcvt\.wu\.d[ ]+a1,a2
> +[ ]+[0-9a-f]+:[ ]+c21605d3[ ]+fcvt\.wu\.d[ ]+a1,a2,rne
> +[ ]+[0-9a-f]+:[ ]+d2058553[ ]+fcvt\.d\.w[ ]+a0,a1
> +[ ]+[0-9a-f]+:[ ]+d2158553[ ]+fcvt\.d\.wu[ ]+a0,a1
> +[ ]+[0-9a-f]+:[ ]+42058553[ ]+fcvt\.d\.s[ ]+a0,a1
> +[ ]+[0-9a-f]+:[ ]+401675d3[ ]+fcvt\.s\.d[ ]+a1,a2
> +[ ]+[0-9a-f]+:[ ]+401605d3[ ]+fcvt\.s\.d[ ]+a1,a2,rne
> +[ ]+[0-9a-f]+:[ ]+42258553[ ]+fcvt\.d\.h[ ]+a0,a1
> +[ ]+[0-9a-f]+:[ ]+441675d3[ ]+fcvt\.h\.d[ ]+a1,a2
> +[ ]+[0-9a-f]+:[ ]+441605d3[ ]+fcvt\.h\.d[ ]+a1,a2,rne
> +[ ]+[0-9a-f]+:[ ]+22e60553[ ]+fsgnj\.d[ ]+a0,a2,a4
> +[ ]+[0-9a-f]+:[ ]+22e61553[ ]+fsgnjn\.d[ ]+a0,a2,a4
> +[ ]+[0-9a-f]+:[ ]+22e62553[ ]+fsgnjx\.d[ ]+a0,a2,a4
> +[ ]+[0-9a-f]+:[ ]+a2e625d3[ ]+feq\.d[ ]+a1,a2,a4
> +[ ]+[0-9a-f]+:[ ]+a2e615d3[ ]+flt\.d[ ]+a1,a2,a4
> +[ ]+[0-9a-f]+:[ ]+a2e605d3[ ]+fle\.d[ ]+a1,a2,a4
> +[ ]+[0-9a-f]+:[ ]+a2c715d3[ ]+flt\.d[ ]+a1,a4,a2
> +[ ]+[0-9a-f]+:[ ]+a2c705d3[ ]+fle\.d[ ]+a1,a4,a2
> +[ ]+[0-9a-f]+:[ ]+22c60553[ ]+fmv\.d[ ]+a0,a2
> +[ ]+[0-9a-f]+:[ ]+22c61553[ ]+fneg\.d[ ]+a0,a2
> +[ ]+[0-9a-f]+:[ ]+22c62553[ ]+fabs\.d[ ]+a0,a2
> +[ ]+[0-9a-f]+:[ ]+e20615d3[ ]+fclass\.d[ ]+a1,a2
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/zdinx-rv32.s
> @@ -0,0 +1,52 @@
> +target:
> + fadd.d a0, a2, a4
> + fadd.d a0, a2, a4, rne
> + fsub.d a0, a2, a4
> + fsub.d a0, a2, a4, rne
> + fmul.d a0, a2, a4
> + fmul.d a0, a2, a4, rne
> + fdiv.d a0, a2, a4
> + fdiv.d a0, a2, a4, rne
> + fsqrt.d a0, a2
> + fsqrt.d a0, a2, rne
> + fmin.d a0, a2, a4
> + fmax.d a0, a2, a4
> + fmadd.d a0, a2, a4, a6
> + fmadd.d a0, a2, a4, a6, rne
> + fnmadd.d a0, a2, a4, a6
> + fnmadd.d a0, a2, a4, a6, rne
> + fmsub.d a0, a2, a4, a6
> + fmsub.d a0, a2, a4, a6, rne
> + fnmsub.d a0, a2, a4, a6
> + fnmsub.d a0, a2, a4, a6, rne
> +
> + fcvt.w.d a1, a2
> + fcvt.w.d a1, a2, rne
> + fcvt.wu.d a1, a2
> + fcvt.wu.d a1, a2, rne
> + fcvt.d.w a0, a1
> + fcvt.d.wu a0, a1
> +
> + fcvt.d.s a0, a1
> + fcvt.s.d a1, a2
> + fcvt.s.d a1, a2, rne
> +
> + .option push
> + .option arch, +zhinxmin
> + fcvt.d.h a0, a1
> + fcvt.h.d a1, a2
> + fcvt.h.d a1, a2, rne
> + .option pop
> +
> + fsgnj.d a0, a2, a4
> + fsgnjn.d a0, a2, a4
> + fsgnjx.d a0, a2, a4
> + feq.d a1, a2, a4
> + flt.d a1, a2, a4
> + fle.d a1, a2, a4
> + fgt.d a1, a2, a4
> + fge.d a1, a2, a4
> + fmv.d a0, a2
> + fneg.d a0, a2
> + fabs.d a0, a2
> + fclass.d a1, a2
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/zdinx-rv32-fail.d
> @@ -0,0 +1,3 @@
> +#as: -march=rv32i_zdinx
> +#source: zdinx.s
> +#error_output: zdinx-rv32-fail.l
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/zdinx-rv32-fail.l
> @@ -0,0 +1,47 @@
> +.*: Assembler messages:
> +.*: Error: illegal operands `fadd\.d .*'
> +.*: Error: illegal operands `fadd\.d .*'
> +.*: Error: illegal operands `fsub\.d .*'
> +.*: Error: illegal operands `fsub\.d .*'
> +.*: Error: illegal operands `fmul\.d .*'
> +.*: Error: illegal operands `fmul\.d .*'
> +.*: Error: illegal operands `fdiv\.d .*'
> +.*: Error: illegal operands `fdiv\.d .*'
> +.*: Error: illegal operands `fsqrt\.d .*'
> +.*: Error: illegal operands `fsqrt\.d .*'
> +.*: Error: illegal operands `fmin\.d .*'
> +.*: Error: illegal operands `fmax\.d .*'
> +.*: Error: illegal operands `fmadd\.d .*'
> +.*: Error: illegal operands `fmadd\.d .*'
> +.*: Error: illegal operands `fnmadd\.d .*'
> +.*: Error: illegal operands `fnmadd\.d .*'
> +.*: Error: illegal operands `fmsub\.d .*'
> +.*: Error: illegal operands `fmsub\.d .*'
> +.*: Error: illegal operands `fnmsub\.d .*'
> +.*: Error: illegal operands `fnmsub\.d .*'
> +.*: Error: illegal operands `fcvt\.w\.d .*'
> +.*: Error: illegal operands `fcvt\.w\.d .*'
> +.*: Error: illegal operands `fcvt\.wu\.d .*'
> +.*: Error: illegal operands `fcvt\.wu\.d .*'
> +.*: Error: unrecognized opcode `fcvt\.l\.d .*'
> +.*: Error: unrecognized opcode `fcvt\.l\.d .*'
> +.*: Error: unrecognized opcode `fcvt\.lu\.d .*'
> +.*: Error: unrecognized opcode `fcvt\.lu\.d .*'
> +.*: Error: unrecognized opcode `fcvt\.d\.l .*'
> +.*: Error: unrecognized opcode `fcvt\.d\.l .*'
> +.*: Error: unrecognized opcode `fcvt\.d\.lu .*'
> +.*: Error: unrecognized opcode `fcvt\.d\.lu .*'
> +.*: Error: illegal operands `fcvt\.s\.d .*'
> +.*: Error: illegal operands `fcvt\.s\.d .*'
> +.*: Error: illegal operands `fsgnj\.d .*'
> +.*: Error: illegal operands `fsgnjn\.d .*'
> +.*: Error: illegal operands `fsgnjx\.d .*'
> +.*: Error: illegal operands `feq\.d .*'
> +.*: Error: illegal operands `flt\.d .*'
> +.*: Error: illegal operands `fle\.d .*'
> +.*: Error: illegal operands `fgt\.d .*'
> +.*: Error: illegal operands `fge\.d .*'
> +.*: Error: illegal operands `fmv\.d .*'
> +.*: Error: illegal operands `fneg\.d .*'
> +.*: Error: illegal operands `fabs\.d .*'
> +.*: Error: illegal operands `fclass\.d .*'
> --- a/include/opcode/riscv.h
> +++ b/include/opcode/riscv.h
> @@ -709,6 +709,18 @@ struct riscv_opcode
> #define INSN_8_BYTE 0x00000040
> #define INSN_16_BYTE 0x00000050
>
> +/* Operands required to be an even-numbered register (pair) in RV32. */
> +#define INSN_RV32_EVEN_D 0x00000100
> +#define INSN_RV32_EVEN_S 0x00000200
> +#define INSN_RV32_EVEN_T 0x00000400 /* Also covering U. */
> +#define INSN_RV32_EVEN_R 0x00000800
> +/* Shorthands for combinations of the above. */
> +#define INSN_RV32_EVEN_DS (INSN_RV32_EVEN_D | INSN_RV32_EVEN_S)
> +#define INSN_RV32_EVEN_DST (INSN_RV32_EVEN_DS | INSN_RV32_EVEN_T)
> +#define INSN_RV32_EVEN_DSTR (INSN_RV32_EVEN_DST | INSN_RV32_EVEN_R)
> +#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)
> +
> /* Instruction is actually a macro. It should be ignored by the
> disassembler, and requires special treatment by the assembler. */
> #define INSN_MACRO 0xffffffff
> --- a/opcodes/riscv-dis.c
> +++ b/opcodes/riscv-dis.c
> @@ -1138,6 +1138,23 @@ riscv_disassemble_insn (bfd_vma memaddr,
> if (!riscv_multi_subset_supports (&pd->riscv_rps_dis,
> op->insn_class))
> continue;
> +
> + if (pd->xlen == 32
> + && riscv_subset_supports (&pd->riscv_rps_dis, "zdinx"))
> + {
> + if ((op->pinfo & INSN_RV32_EVEN_D)
> + && (word & (1u << OP_SH_RD)))
> + continue;
> + if ((op->pinfo & INSN_RV32_EVEN_S)
> + && (word & (1u << OP_SH_RS1)))
> + continue;
> + if ((op->pinfo & INSN_RV32_EVEN_T)
> + && (word & (1u << OP_SH_RS2)))
> + continue;
> + if ((op->pinfo & INSN_RV32_EVEN_R)
> + && (word & (1u << OP_SH_RS3)))
> + continue;
> + }
> }
>
> /* It's a match. */
> --- a/opcodes/riscv-opc.c
> +++ b/opcodes/riscv-opc.c
> @@ -955,10 +955,10 @@ const struct riscv_opcode riscv_opcodes[
> {"fcvt.h.w", 0, INSN_CLASS_ZFH_INX, "D,sm", MATCH_FCVT_H_W, MASK_FCVT_H_W, match_opcode, 0 },
> {"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, 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, 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.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, 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 },
> {"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 },
> @@ -1045,35 +1045,35 @@ const struct riscv_opcode riscv_opcodes[
> {"fsd", 0, INSN_CLASS_ZCD, "CD,Cl(Cs)", MATCH_C_FSD, MASK_C_FSD, match_opcode, INSN_ALIAS|INSN_DREF|INSN_8_BYTE },
> {"fsd", 0, INSN_CLASS_D, "T,q(s)", MATCH_FSD, MASK_FSD, match_opcode, INSN_DREF|INSN_8_BYTE },
> {"fsd", 0, INSN_CLASS_D, "T,A,s", 0, (int) M_Sx_FSx, match_rs1_nonzero, INSN_MACRO },
> -{"fmv.d", 0, INSN_CLASS_D_INX, "D,U", MATCH_FSGNJ_D, MASK_FSGNJ_D, match_rs1_eq_rs2, INSN_ALIAS },
> -{"fneg.d", 0, INSN_CLASS_D_INX, "D,U", MATCH_FSGNJN_D, MASK_FSGNJN_D, match_rs1_eq_rs2, INSN_ALIAS },
> -{"fabs.d", 0, INSN_CLASS_D_INX, "D,U", MATCH_FSGNJX_D, MASK_FSGNJX_D, match_rs1_eq_rs2, INSN_ALIAS },
> -{"fsgnj.d", 0, INSN_CLASS_D_INX, "D,S,T", MATCH_FSGNJ_D, MASK_FSGNJ_D, match_opcode, 0 },
> -{"fsgnjn.d", 0, INSN_CLASS_D_INX, "D,S,T", MATCH_FSGNJN_D, MASK_FSGNJN_D, match_opcode, 0 },
> -{"fsgnjx.d", 0, INSN_CLASS_D_INX, "D,S,T", MATCH_FSGNJX_D, MASK_FSGNJX_D, match_opcode, 0 },
> -{"fadd.d", 0, INSN_CLASS_D_INX, "D,S,Tm", MATCH_FADD_D, MASK_FADD_D, match_opcode, 0 },
> -{"fsub.d", 0, INSN_CLASS_D_INX, "D,S,Tm", MATCH_FSUB_D, MASK_FSUB_D, match_opcode, 0 },
> -{"fmul.d", 0, INSN_CLASS_D_INX, "D,S,Tm", MATCH_FMUL_D, MASK_FMUL_D, match_opcode, 0 },
> -{"fdiv.d", 0, INSN_CLASS_D_INX, "D,S,Tm", MATCH_FDIV_D, MASK_FDIV_D, match_opcode, 0 },
> -{"fsqrt.d", 0, INSN_CLASS_D_INX, "D,Sm", MATCH_FSQRT_D, MASK_FSQRT_D, match_opcode, 0 },
> -{"fmin.d", 0, INSN_CLASS_D_INX, "D,S,T", MATCH_FMIN_D, MASK_FMIN_D, match_opcode, 0 },
> -{"fmax.d", 0, INSN_CLASS_D_INX, "D,S,T", MATCH_FMAX_D, MASK_FMAX_D, match_opcode, 0 },
> -{"fmadd.d", 0, INSN_CLASS_D_INX, "D,S,T,Rm", MATCH_FMADD_D, MASK_FMADD_D, match_opcode, 0 },
> -{"fnmadd.d", 0, INSN_CLASS_D_INX, "D,S,T,Rm", MATCH_FNMADD_D, MASK_FNMADD_D, match_opcode, 0 },
> -{"fmsub.d", 0, INSN_CLASS_D_INX, "D,S,T,Rm", MATCH_FMSUB_D, MASK_FMSUB_D, match_opcode, 0 },
> -{"fnmsub.d", 0, INSN_CLASS_D_INX, "D,S,T,Rm", MATCH_FNMSUB_D, MASK_FNMSUB_D, match_opcode, 0 },
> -{"fcvt.w.d", 0, INSN_CLASS_D_INX, "d,Sm", MATCH_FCVT_W_D, MASK_FCVT_W_D, match_opcode, 0 },
> -{"fcvt.wu.d", 0, INSN_CLASS_D_INX, "d,Sm", MATCH_FCVT_WU_D, MASK_FCVT_WU_D, match_opcode, 0 },
> -{"fcvt.d.w", 0, INSN_CLASS_D_INX, "D,s", MATCH_FCVT_D_W, MASK_FCVT_D_W|MASK_RM, match_opcode, 0 },
> -{"fcvt.d.wu", 0, INSN_CLASS_D_INX, "D,s", MATCH_FCVT_D_WU, MASK_FCVT_D_WU|MASK_RM, match_opcode, 0 },
> -{"fcvt.d.s", 0, INSN_CLASS_D_INX, "D,S", MATCH_FCVT_D_S, MASK_FCVT_D_S|MASK_RM, match_opcode, 0 },
> -{"fcvt.s.d", 0, INSN_CLASS_D_INX, "D,Sm", MATCH_FCVT_S_D, MASK_FCVT_S_D, match_opcode, 0 },
> -{"fclass.d", 0, INSN_CLASS_D_INX, "d,S", MATCH_FCLASS_D, MASK_FCLASS_D, match_opcode, 0 },
> -{"feq.d", 0, INSN_CLASS_D_INX, "d,S,T", MATCH_FEQ_D, MASK_FEQ_D, match_opcode, 0 },
> -{"flt.d", 0, INSN_CLASS_D_INX, "d,S,T", MATCH_FLT_D, MASK_FLT_D, match_opcode, 0 },
> -{"fle.d", 0, INSN_CLASS_D_INX, "d,S,T", MATCH_FLE_D, MASK_FLE_D, match_opcode, 0 },
> -{"fgt.d", 0, INSN_CLASS_D_INX, "d,T,S", MATCH_FLT_D, MASK_FLT_D, match_opcode, INSN_ALIAS },
> -{"fge.d", 0, INSN_CLASS_D_INX, "d,T,S", MATCH_FLE_D, MASK_FLE_D, match_opcode, INSN_ALIAS },
> +{"fmv.d", 0, INSN_CLASS_D_INX, "D,U", MATCH_FSGNJ_D, MASK_FSGNJ_D, match_rs1_eq_rs2, INSN_ALIAS|INSN_RV32_EVEN_DU },
> +{"fneg.d", 0, INSN_CLASS_D_INX, "D,U", MATCH_FSGNJN_D, MASK_FSGNJN_D, match_rs1_eq_rs2, INSN_ALIAS|INSN_RV32_EVEN_DU },
> +{"fabs.d", 0, INSN_CLASS_D_INX, "D,U", MATCH_FSGNJX_D, MASK_FSGNJX_D, match_rs1_eq_rs2, INSN_ALIAS|INSN_RV32_EVEN_DU },
> +{"fsgnj.d", 0, INSN_CLASS_D_INX, "D,S,T", MATCH_FSGNJ_D, MASK_FSGNJ_D, match_opcode, INSN_RV32_EVEN_DST },
> +{"fsgnjn.d", 0, INSN_CLASS_D_INX, "D,S,T", MATCH_FSGNJN_D, MASK_FSGNJN_D, match_opcode, INSN_RV32_EVEN_DST },
> +{"fsgnjx.d", 0, INSN_CLASS_D_INX, "D,S,T", MATCH_FSGNJX_D, MASK_FSGNJX_D, match_opcode, INSN_RV32_EVEN_DST },
> +{"fadd.d", 0, INSN_CLASS_D_INX, "D,S,Tm", MATCH_FADD_D, MASK_FADD_D, match_opcode, INSN_RV32_EVEN_DST },
> +{"fsub.d", 0, INSN_CLASS_D_INX, "D,S,Tm", MATCH_FSUB_D, MASK_FSUB_D, match_opcode, INSN_RV32_EVEN_DST },
> +{"fmul.d", 0, INSN_CLASS_D_INX, "D,S,Tm", MATCH_FMUL_D, MASK_FMUL_D, match_opcode, INSN_RV32_EVEN_DST },
> +{"fdiv.d", 0, INSN_CLASS_D_INX, "D,S,Tm", MATCH_FDIV_D, MASK_FDIV_D, match_opcode, INSN_RV32_EVEN_DST },
> +{"fsqrt.d", 0, INSN_CLASS_D_INX, "D,Sm", MATCH_FSQRT_D, MASK_FSQRT_D, match_opcode, INSN_RV32_EVEN_DS },
> +{"fmin.d", 0, INSN_CLASS_D_INX, "D,S,T", MATCH_FMIN_D, MASK_FMIN_D, match_opcode, INSN_RV32_EVEN_DST },
> +{"fmax.d", 0, INSN_CLASS_D_INX, "D,S,T", MATCH_FMAX_D, MASK_FMAX_D, match_opcode, INSN_RV32_EVEN_DST },
> +{"fmadd.d", 0, INSN_CLASS_D_INX, "D,S,T,Rm", MATCH_FMADD_D, MASK_FMADD_D, match_opcode, INSN_RV32_EVEN_DSTR },
> +{"fnmadd.d", 0, INSN_CLASS_D_INX, "D,S,T,Rm", MATCH_FNMADD_D, MASK_FNMADD_D, match_opcode, INSN_RV32_EVEN_DSTR },
> +{"fmsub.d", 0, INSN_CLASS_D_INX, "D,S,T,Rm", MATCH_FMSUB_D, MASK_FMSUB_D, match_opcode, INSN_RV32_EVEN_DSTR },
> +{"fnmsub.d", 0, INSN_CLASS_D_INX, "D,S,T,Rm", MATCH_FNMSUB_D, MASK_FNMSUB_D, match_opcode, INSN_RV32_EVEN_DSTR },
> +{"fcvt.w.d", 0, INSN_CLASS_D_INX, "d,Sm", MATCH_FCVT_W_D, MASK_FCVT_W_D, match_opcode, INSN_RV32_EVEN_S },
> +{"fcvt.wu.d", 0, INSN_CLASS_D_INX, "d,Sm", MATCH_FCVT_WU_D, MASK_FCVT_WU_D, match_opcode, INSN_RV32_EVEN_S },
> +{"fcvt.d.w", 0, INSN_CLASS_D_INX, "D,s", MATCH_FCVT_D_W, MASK_FCVT_D_W|MASK_RM, match_opcode, INSN_RV32_EVEN_D },
> +{"fcvt.d.wu", 0, INSN_CLASS_D_INX, "D,s", MATCH_FCVT_D_WU, MASK_FCVT_D_WU|MASK_RM, match_opcode, INSN_RV32_EVEN_D },
> +{"fcvt.d.s", 0, INSN_CLASS_D_INX, "D,S", MATCH_FCVT_D_S, MASK_FCVT_D_S|MASK_RM, match_opcode, INSN_RV32_EVEN_D },
> +{"fcvt.s.d", 0, INSN_CLASS_D_INX, "D,Sm", MATCH_FCVT_S_D, MASK_FCVT_S_D, match_opcode, INSN_RV32_EVEN_S },
> +{"fclass.d", 0, INSN_CLASS_D_INX, "d,S", MATCH_FCLASS_D, MASK_FCLASS_D, match_opcode, INSN_RV32_EVEN_S },
> +{"feq.d", 0, INSN_CLASS_D_INX, "d,S,T", MATCH_FEQ_D, MASK_FEQ_D, match_opcode, INSN_RV32_EVEN_ST },
> +{"flt.d", 0, INSN_CLASS_D_INX, "d,S,T", MATCH_FLT_D, MASK_FLT_D, match_opcode, INSN_RV32_EVEN_ST },
> +{"fle.d", 0, INSN_CLASS_D_INX, "d,S,T", MATCH_FLE_D, MASK_FLE_D, match_opcode, INSN_RV32_EVEN_ST },
> +{"fgt.d", 0, INSN_CLASS_D_INX, "d,T,S", MATCH_FLT_D, MASK_FLT_D, match_opcode, INSN_ALIAS|INSN_RV32_EVEN_ST },
> +{"fge.d", 0, INSN_CLASS_D_INX, "d,T,S", MATCH_FLE_D, MASK_FLE_D, match_opcode, INSN_ALIAS|INSN_RV32_EVEN_ST },
> {"fmv.x.d", 64, INSN_CLASS_D, "d,S", MATCH_FMV_X_D, MASK_FMV_X_D, match_opcode, 0 },
> {"fmv.d.x", 64, INSN_CLASS_D, "D,s", MATCH_FMV_D_X, MASK_FMV_D_X, match_opcode, 0 },
> {"fcvt.l.d", 64, INSN_CLASS_D_INX, "d,Sm", MATCH_FCVT_L_D, MASK_FCVT_L_D, match_opcode, 0 },
>
@@ -3004,6 +3004,12 @@ riscv_ip (char *str, struct riscv_cl_ins
*imm_reloc = BFD_RELOC_UNUSED;
p = percent_op_null;
+#define RV32_EVEN_CHECK(form, rclass, regno) \
+ (!(ip->insn_mo->pinfo & INSN_RV32_EVEN_##form) \
+ || xlen != 32 \
+ || (rclass) != RCLASS_GPR \
+ || !((regno) & 1))
+
for (oparg = insn->args;; ++oparg)
{
opargStart = oparg;
@@ -3011,6 +3017,8 @@ riscv_ip (char *str, struct riscv_cl_ins
++asarg;
switch (*oparg)
{
+ enum reg_class rclass;
+
case '\0': /* End of args. */
if (insn->match_func && !insn->match_func (insn, ip->insn_opcode))
break;
@@ -3670,32 +3678,40 @@ riscv_ip (char *str, struct riscv_cl_ins
case 'T': /* Floating point RS2. */
case 'U': /* Floating point RS1 and RS2. */
case 'R': /* Floating point RS3. */
- if (reg_lookup (&asarg,
- (riscv_subset_supports (&riscv_rps_as, "zfinx")
- ? RCLASS_GPR : RCLASS_FPR), ®no))
+ rclass = riscv_subset_supports (&riscv_rps_as, "zfinx")
+ ? RCLASS_GPR : RCLASS_FPR;
+ if (reg_lookup (&asarg, rclass, ®no))
{
char c = *oparg;
if (is_whitespace (*asarg))
++asarg;
+
switch (c)
{
case 'D':
+ if (!RV32_EVEN_CHECK (D, rclass, regno))
+ break;
INSERT_OPERAND (RD, *ip, regno);
- break;
+ continue;
case 'S':
+ if (!RV32_EVEN_CHECK (S, rclass, regno))
+ break;
INSERT_OPERAND (RS1, *ip, regno);
- break;
+ continue;
case 'U':
INSERT_OPERAND (RS1, *ip, regno);
/* Fall through. */
case 'T':
+ if (!RV32_EVEN_CHECK (T, rclass, regno))
+ break;
INSERT_OPERAND (RS2, *ip, regno);
- break;
+ continue;
case 'R':
+ if (!RV32_EVEN_CHECK (R, rclass, regno))
+ break;
INSERT_OPERAND (RS3, *ip, regno);
- break;
+ continue;
}
- continue;
}
break;
@@ -4530,6 +4546,8 @@ riscv_ip (char *str, struct riscv_cl_ins
insn_with_csr = false;
}
+#undef RV32_EVEN_CHECK
+
out:
/* Restore the character we might have clobbered above. */
if (save_c)
@@ -0,0 +1,52 @@
+#as: -march=rv32i_zdinx
+#objdump: -dwr
+
+.*:[ ]+file format .*
+
+Disassembly of section .text:
+
+0+000 <target>:
+[ ]+[0-9a-f]+:[ ]+02e67553[ ]+fadd\.d[ ]+a0,a2,a4
+[ ]+[0-9a-f]+:[ ]+02e60553[ ]+fadd\.d[ ]+a0,a2,a4,rne
+[ ]+[0-9a-f]+:[ ]+0ae67553[ ]+fsub\.d[ ]+a0,a2,a4
+[ ]+[0-9a-f]+:[ ]+0ae60553[ ]+fsub\.d[ ]+a0,a2,a4,rne
+[ ]+[0-9a-f]+:[ ]+12e67553[ ]+fmul\.d[ ]+a0,a2,a4
+[ ]+[0-9a-f]+:[ ]+12e60553[ ]+fmul\.d[ ]+a0,a2,a4,rne
+[ ]+[0-9a-f]+:[ ]+1ae67553[ ]+fdiv\.d[ ]+a0,a2,a4
+[ ]+[0-9a-f]+:[ ]+1ae60553[ ]+fdiv\.d[ ]+a0,a2,a4,rne
+[ ]+[0-9a-f]+:[ ]+5a067553[ ]+fsqrt\.d[ ]+a0,a2
+[ ]+[0-9a-f]+:[ ]+5a060553[ ]+fsqrt\.d[ ]+a0,a2,rne
+[ ]+[0-9a-f]+:[ ]+2ae60553[ ]+fmin\.d[ ]+a0,a2,a4
+[ ]+[0-9a-f]+:[ ]+2ae61553[ ]+fmax\.d[ ]+a0,a2,a4
+[ ]+[0-9a-f]+:[ ]+82e67543[ ]+fmadd\.d[ ]+a0,a2,a4,a6
+[ ]+[0-9a-f]+:[ ]+82e60543[ ]+fmadd\.d[ ]+a0,a2,a4,a6,rne
+[ ]+[0-9a-f]+:[ ]+82e6754f[ ]+fnmadd\.d[ ]+a0,a2,a4,a6
+[ ]+[0-9a-f]+:[ ]+82e6054f[ ]+fnmadd\.d[ ]+a0,a2,a4,a6,rne
+[ ]+[0-9a-f]+:[ ]+82e67547[ ]+fmsub\.d[ ]+a0,a2,a4,a6
+[ ]+[0-9a-f]+:[ ]+82e60547[ ]+fmsub\.d[ ]+a0,a2,a4,a6,rne
+[ ]+[0-9a-f]+:[ ]+82e6754b[ ]+fnmsub\.d[ ]+a0,a2,a4,a6
+[ ]+[0-9a-f]+:[ ]+82e6054b[ ]+fnmsub\.d[ ]+a0,a2,a4,a6,rne
+[ ]+[0-9a-f]+:[ ]+c20675d3[ ]+fcvt\.w\.d[ ]+a1,a2
+[ ]+[0-9a-f]+:[ ]+c20605d3[ ]+fcvt\.w\.d[ ]+a1,a2,rne
+[ ]+[0-9a-f]+:[ ]+c21675d3[ ]+fcvt\.wu\.d[ ]+a1,a2
+[ ]+[0-9a-f]+:[ ]+c21605d3[ ]+fcvt\.wu\.d[ ]+a1,a2,rne
+[ ]+[0-9a-f]+:[ ]+d2058553[ ]+fcvt\.d\.w[ ]+a0,a1
+[ ]+[0-9a-f]+:[ ]+d2158553[ ]+fcvt\.d\.wu[ ]+a0,a1
+[ ]+[0-9a-f]+:[ ]+42058553[ ]+fcvt\.d\.s[ ]+a0,a1
+[ ]+[0-9a-f]+:[ ]+401675d3[ ]+fcvt\.s\.d[ ]+a1,a2
+[ ]+[0-9a-f]+:[ ]+401605d3[ ]+fcvt\.s\.d[ ]+a1,a2,rne
+[ ]+[0-9a-f]+:[ ]+42258553[ ]+fcvt\.d\.h[ ]+a0,a1
+[ ]+[0-9a-f]+:[ ]+441675d3[ ]+fcvt\.h\.d[ ]+a1,a2
+[ ]+[0-9a-f]+:[ ]+441605d3[ ]+fcvt\.h\.d[ ]+a1,a2,rne
+[ ]+[0-9a-f]+:[ ]+22e60553[ ]+fsgnj\.d[ ]+a0,a2,a4
+[ ]+[0-9a-f]+:[ ]+22e61553[ ]+fsgnjn\.d[ ]+a0,a2,a4
+[ ]+[0-9a-f]+:[ ]+22e62553[ ]+fsgnjx\.d[ ]+a0,a2,a4
+[ ]+[0-9a-f]+:[ ]+a2e625d3[ ]+feq\.d[ ]+a1,a2,a4
+[ ]+[0-9a-f]+:[ ]+a2e615d3[ ]+flt\.d[ ]+a1,a2,a4
+[ ]+[0-9a-f]+:[ ]+a2e605d3[ ]+fle\.d[ ]+a1,a2,a4
+[ ]+[0-9a-f]+:[ ]+a2c715d3[ ]+flt\.d[ ]+a1,a4,a2
+[ ]+[0-9a-f]+:[ ]+a2c705d3[ ]+fle\.d[ ]+a1,a4,a2
+[ ]+[0-9a-f]+:[ ]+22c60553[ ]+fmv\.d[ ]+a0,a2
+[ ]+[0-9a-f]+:[ ]+22c61553[ ]+fneg\.d[ ]+a0,a2
+[ ]+[0-9a-f]+:[ ]+22c62553[ ]+fabs\.d[ ]+a0,a2
+[ ]+[0-9a-f]+:[ ]+e20615d3[ ]+fclass\.d[ ]+a1,a2
@@ -0,0 +1,52 @@
+target:
+ fadd.d a0, a2, a4
+ fadd.d a0, a2, a4, rne
+ fsub.d a0, a2, a4
+ fsub.d a0, a2, a4, rne
+ fmul.d a0, a2, a4
+ fmul.d a0, a2, a4, rne
+ fdiv.d a0, a2, a4
+ fdiv.d a0, a2, a4, rne
+ fsqrt.d a0, a2
+ fsqrt.d a0, a2, rne
+ fmin.d a0, a2, a4
+ fmax.d a0, a2, a4
+ fmadd.d a0, a2, a4, a6
+ fmadd.d a0, a2, a4, a6, rne
+ fnmadd.d a0, a2, a4, a6
+ fnmadd.d a0, a2, a4, a6, rne
+ fmsub.d a0, a2, a4, a6
+ fmsub.d a0, a2, a4, a6, rne
+ fnmsub.d a0, a2, a4, a6
+ fnmsub.d a0, a2, a4, a6, rne
+
+ fcvt.w.d a1, a2
+ fcvt.w.d a1, a2, rne
+ fcvt.wu.d a1, a2
+ fcvt.wu.d a1, a2, rne
+ fcvt.d.w a0, a1
+ fcvt.d.wu a0, a1
+
+ fcvt.d.s a0, a1
+ fcvt.s.d a1, a2
+ fcvt.s.d a1, a2, rne
+
+ .option push
+ .option arch, +zhinxmin
+ fcvt.d.h a0, a1
+ fcvt.h.d a1, a2
+ fcvt.h.d a1, a2, rne
+ .option pop
+
+ fsgnj.d a0, a2, a4
+ fsgnjn.d a0, a2, a4
+ fsgnjx.d a0, a2, a4
+ feq.d a1, a2, a4
+ flt.d a1, a2, a4
+ fle.d a1, a2, a4
+ fgt.d a1, a2, a4
+ fge.d a1, a2, a4
+ fmv.d a0, a2
+ fneg.d a0, a2
+ fabs.d a0, a2
+ fclass.d a1, a2
@@ -0,0 +1,3 @@
+#as: -march=rv32i_zdinx
+#source: zdinx.s
+#error_output: zdinx-rv32-fail.l
@@ -0,0 +1,47 @@
+.*: Assembler messages:
+.*: Error: illegal operands `fadd\.d .*'
+.*: Error: illegal operands `fadd\.d .*'
+.*: Error: illegal operands `fsub\.d .*'
+.*: Error: illegal operands `fsub\.d .*'
+.*: Error: illegal operands `fmul\.d .*'
+.*: Error: illegal operands `fmul\.d .*'
+.*: Error: illegal operands `fdiv\.d .*'
+.*: Error: illegal operands `fdiv\.d .*'
+.*: Error: illegal operands `fsqrt\.d .*'
+.*: Error: illegal operands `fsqrt\.d .*'
+.*: Error: illegal operands `fmin\.d .*'
+.*: Error: illegal operands `fmax\.d .*'
+.*: Error: illegal operands `fmadd\.d .*'
+.*: Error: illegal operands `fmadd\.d .*'
+.*: Error: illegal operands `fnmadd\.d .*'
+.*: Error: illegal operands `fnmadd\.d .*'
+.*: Error: illegal operands `fmsub\.d .*'
+.*: Error: illegal operands `fmsub\.d .*'
+.*: Error: illegal operands `fnmsub\.d .*'
+.*: Error: illegal operands `fnmsub\.d .*'
+.*: Error: illegal operands `fcvt\.w\.d .*'
+.*: Error: illegal operands `fcvt\.w\.d .*'
+.*: Error: illegal operands `fcvt\.wu\.d .*'
+.*: Error: illegal operands `fcvt\.wu\.d .*'
+.*: Error: unrecognized opcode `fcvt\.l\.d .*'
+.*: Error: unrecognized opcode `fcvt\.l\.d .*'
+.*: Error: unrecognized opcode `fcvt\.lu\.d .*'
+.*: Error: unrecognized opcode `fcvt\.lu\.d .*'
+.*: Error: unrecognized opcode `fcvt\.d\.l .*'
+.*: Error: unrecognized opcode `fcvt\.d\.l .*'
+.*: Error: unrecognized opcode `fcvt\.d\.lu .*'
+.*: Error: unrecognized opcode `fcvt\.d\.lu .*'
+.*: Error: illegal operands `fcvt\.s\.d .*'
+.*: Error: illegal operands `fcvt\.s\.d .*'
+.*: Error: illegal operands `fsgnj\.d .*'
+.*: Error: illegal operands `fsgnjn\.d .*'
+.*: Error: illegal operands `fsgnjx\.d .*'
+.*: Error: illegal operands `feq\.d .*'
+.*: Error: illegal operands `flt\.d .*'
+.*: Error: illegal operands `fle\.d .*'
+.*: Error: illegal operands `fgt\.d .*'
+.*: Error: illegal operands `fge\.d .*'
+.*: Error: illegal operands `fmv\.d .*'
+.*: Error: illegal operands `fneg\.d .*'
+.*: Error: illegal operands `fabs\.d .*'
+.*: Error: illegal operands `fclass\.d .*'
@@ -709,6 +709,18 @@ struct riscv_opcode
#define INSN_8_BYTE 0x00000040
#define INSN_16_BYTE 0x00000050
+/* Operands required to be an even-numbered register (pair) in RV32. */
+#define INSN_RV32_EVEN_D 0x00000100
+#define INSN_RV32_EVEN_S 0x00000200
+#define INSN_RV32_EVEN_T 0x00000400 /* Also covering U. */
+#define INSN_RV32_EVEN_R 0x00000800
+/* Shorthands for combinations of the above. */
+#define INSN_RV32_EVEN_DS (INSN_RV32_EVEN_D | INSN_RV32_EVEN_S)
+#define INSN_RV32_EVEN_DST (INSN_RV32_EVEN_DS | INSN_RV32_EVEN_T)
+#define INSN_RV32_EVEN_DSTR (INSN_RV32_EVEN_DST | INSN_RV32_EVEN_R)
+#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)
+
/* Instruction is actually a macro. It should be ignored by the
disassembler, and requires special treatment by the assembler. */
#define INSN_MACRO 0xffffffff
@@ -1138,6 +1138,23 @@ riscv_disassemble_insn (bfd_vma memaddr,
if (!riscv_multi_subset_supports (&pd->riscv_rps_dis,
op->insn_class))
continue;
+
+ if (pd->xlen == 32
+ && riscv_subset_supports (&pd->riscv_rps_dis, "zdinx"))
+ {
+ if ((op->pinfo & INSN_RV32_EVEN_D)
+ && (word & (1u << OP_SH_RD)))
+ continue;
+ if ((op->pinfo & INSN_RV32_EVEN_S)
+ && (word & (1u << OP_SH_RS1)))
+ continue;
+ if ((op->pinfo & INSN_RV32_EVEN_T)
+ && (word & (1u << OP_SH_RS2)))
+ continue;
+ if ((op->pinfo & INSN_RV32_EVEN_R)
+ && (word & (1u << OP_SH_RS3)))
+ continue;
+ }
}
/* It's a match. */
@@ -955,10 +955,10 @@ const struct riscv_opcode riscv_opcodes[
{"fcvt.h.w", 0, INSN_CLASS_ZFH_INX, "D,sm", MATCH_FCVT_H_W, MASK_FCVT_H_W, match_opcode, 0 },
{"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, 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, 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.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, 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 },
{"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 },
@@ -1045,35 +1045,35 @@ const struct riscv_opcode riscv_opcodes[
{"fsd", 0, INSN_CLASS_ZCD, "CD,Cl(Cs)", MATCH_C_FSD, MASK_C_FSD, match_opcode, INSN_ALIAS|INSN_DREF|INSN_8_BYTE },
{"fsd", 0, INSN_CLASS_D, "T,q(s)", MATCH_FSD, MASK_FSD, match_opcode, INSN_DREF|INSN_8_BYTE },
{"fsd", 0, INSN_CLASS_D, "T,A,s", 0, (int) M_Sx_FSx, match_rs1_nonzero, INSN_MACRO },
-{"fmv.d", 0, INSN_CLASS_D_INX, "D,U", MATCH_FSGNJ_D, MASK_FSGNJ_D, match_rs1_eq_rs2, INSN_ALIAS },
-{"fneg.d", 0, INSN_CLASS_D_INX, "D,U", MATCH_FSGNJN_D, MASK_FSGNJN_D, match_rs1_eq_rs2, INSN_ALIAS },
-{"fabs.d", 0, INSN_CLASS_D_INX, "D,U", MATCH_FSGNJX_D, MASK_FSGNJX_D, match_rs1_eq_rs2, INSN_ALIAS },
-{"fsgnj.d", 0, INSN_CLASS_D_INX, "D,S,T", MATCH_FSGNJ_D, MASK_FSGNJ_D, match_opcode, 0 },
-{"fsgnjn.d", 0, INSN_CLASS_D_INX, "D,S,T", MATCH_FSGNJN_D, MASK_FSGNJN_D, match_opcode, 0 },
-{"fsgnjx.d", 0, INSN_CLASS_D_INX, "D,S,T", MATCH_FSGNJX_D, MASK_FSGNJX_D, match_opcode, 0 },
-{"fadd.d", 0, INSN_CLASS_D_INX, "D,S,Tm", MATCH_FADD_D, MASK_FADD_D, match_opcode, 0 },
-{"fsub.d", 0, INSN_CLASS_D_INX, "D,S,Tm", MATCH_FSUB_D, MASK_FSUB_D, match_opcode, 0 },
-{"fmul.d", 0, INSN_CLASS_D_INX, "D,S,Tm", MATCH_FMUL_D, MASK_FMUL_D, match_opcode, 0 },
-{"fdiv.d", 0, INSN_CLASS_D_INX, "D,S,Tm", MATCH_FDIV_D, MASK_FDIV_D, match_opcode, 0 },
-{"fsqrt.d", 0, INSN_CLASS_D_INX, "D,Sm", MATCH_FSQRT_D, MASK_FSQRT_D, match_opcode, 0 },
-{"fmin.d", 0, INSN_CLASS_D_INX, "D,S,T", MATCH_FMIN_D, MASK_FMIN_D, match_opcode, 0 },
-{"fmax.d", 0, INSN_CLASS_D_INX, "D,S,T", MATCH_FMAX_D, MASK_FMAX_D, match_opcode, 0 },
-{"fmadd.d", 0, INSN_CLASS_D_INX, "D,S,T,Rm", MATCH_FMADD_D, MASK_FMADD_D, match_opcode, 0 },
-{"fnmadd.d", 0, INSN_CLASS_D_INX, "D,S,T,Rm", MATCH_FNMADD_D, MASK_FNMADD_D, match_opcode, 0 },
-{"fmsub.d", 0, INSN_CLASS_D_INX, "D,S,T,Rm", MATCH_FMSUB_D, MASK_FMSUB_D, match_opcode, 0 },
-{"fnmsub.d", 0, INSN_CLASS_D_INX, "D,S,T,Rm", MATCH_FNMSUB_D, MASK_FNMSUB_D, match_opcode, 0 },
-{"fcvt.w.d", 0, INSN_CLASS_D_INX, "d,Sm", MATCH_FCVT_W_D, MASK_FCVT_W_D, match_opcode, 0 },
-{"fcvt.wu.d", 0, INSN_CLASS_D_INX, "d,Sm", MATCH_FCVT_WU_D, MASK_FCVT_WU_D, match_opcode, 0 },
-{"fcvt.d.w", 0, INSN_CLASS_D_INX, "D,s", MATCH_FCVT_D_W, MASK_FCVT_D_W|MASK_RM, match_opcode, 0 },
-{"fcvt.d.wu", 0, INSN_CLASS_D_INX, "D,s", MATCH_FCVT_D_WU, MASK_FCVT_D_WU|MASK_RM, match_opcode, 0 },
-{"fcvt.d.s", 0, INSN_CLASS_D_INX, "D,S", MATCH_FCVT_D_S, MASK_FCVT_D_S|MASK_RM, match_opcode, 0 },
-{"fcvt.s.d", 0, INSN_CLASS_D_INX, "D,Sm", MATCH_FCVT_S_D, MASK_FCVT_S_D, match_opcode, 0 },
-{"fclass.d", 0, INSN_CLASS_D_INX, "d,S", MATCH_FCLASS_D, MASK_FCLASS_D, match_opcode, 0 },
-{"feq.d", 0, INSN_CLASS_D_INX, "d,S,T", MATCH_FEQ_D, MASK_FEQ_D, match_opcode, 0 },
-{"flt.d", 0, INSN_CLASS_D_INX, "d,S,T", MATCH_FLT_D, MASK_FLT_D, match_opcode, 0 },
-{"fle.d", 0, INSN_CLASS_D_INX, "d,S,T", MATCH_FLE_D, MASK_FLE_D, match_opcode, 0 },
-{"fgt.d", 0, INSN_CLASS_D_INX, "d,T,S", MATCH_FLT_D, MASK_FLT_D, match_opcode, INSN_ALIAS },
-{"fge.d", 0, INSN_CLASS_D_INX, "d,T,S", MATCH_FLE_D, MASK_FLE_D, match_opcode, INSN_ALIAS },
+{"fmv.d", 0, INSN_CLASS_D_INX, "D,U", MATCH_FSGNJ_D, MASK_FSGNJ_D, match_rs1_eq_rs2, INSN_ALIAS|INSN_RV32_EVEN_DU },
+{"fneg.d", 0, INSN_CLASS_D_INX, "D,U", MATCH_FSGNJN_D, MASK_FSGNJN_D, match_rs1_eq_rs2, INSN_ALIAS|INSN_RV32_EVEN_DU },
+{"fabs.d", 0, INSN_CLASS_D_INX, "D,U", MATCH_FSGNJX_D, MASK_FSGNJX_D, match_rs1_eq_rs2, INSN_ALIAS|INSN_RV32_EVEN_DU },
+{"fsgnj.d", 0, INSN_CLASS_D_INX, "D,S,T", MATCH_FSGNJ_D, MASK_FSGNJ_D, match_opcode, INSN_RV32_EVEN_DST },
+{"fsgnjn.d", 0, INSN_CLASS_D_INX, "D,S,T", MATCH_FSGNJN_D, MASK_FSGNJN_D, match_opcode, INSN_RV32_EVEN_DST },
+{"fsgnjx.d", 0, INSN_CLASS_D_INX, "D,S,T", MATCH_FSGNJX_D, MASK_FSGNJX_D, match_opcode, INSN_RV32_EVEN_DST },
+{"fadd.d", 0, INSN_CLASS_D_INX, "D,S,Tm", MATCH_FADD_D, MASK_FADD_D, match_opcode, INSN_RV32_EVEN_DST },
+{"fsub.d", 0, INSN_CLASS_D_INX, "D,S,Tm", MATCH_FSUB_D, MASK_FSUB_D, match_opcode, INSN_RV32_EVEN_DST },
+{"fmul.d", 0, INSN_CLASS_D_INX, "D,S,Tm", MATCH_FMUL_D, MASK_FMUL_D, match_opcode, INSN_RV32_EVEN_DST },
+{"fdiv.d", 0, INSN_CLASS_D_INX, "D,S,Tm", MATCH_FDIV_D, MASK_FDIV_D, match_opcode, INSN_RV32_EVEN_DST },
+{"fsqrt.d", 0, INSN_CLASS_D_INX, "D,Sm", MATCH_FSQRT_D, MASK_FSQRT_D, match_opcode, INSN_RV32_EVEN_DS },
+{"fmin.d", 0, INSN_CLASS_D_INX, "D,S,T", MATCH_FMIN_D, MASK_FMIN_D, match_opcode, INSN_RV32_EVEN_DST },
+{"fmax.d", 0, INSN_CLASS_D_INX, "D,S,T", MATCH_FMAX_D, MASK_FMAX_D, match_opcode, INSN_RV32_EVEN_DST },
+{"fmadd.d", 0, INSN_CLASS_D_INX, "D,S,T,Rm", MATCH_FMADD_D, MASK_FMADD_D, match_opcode, INSN_RV32_EVEN_DSTR },
+{"fnmadd.d", 0, INSN_CLASS_D_INX, "D,S,T,Rm", MATCH_FNMADD_D, MASK_FNMADD_D, match_opcode, INSN_RV32_EVEN_DSTR },
+{"fmsub.d", 0, INSN_CLASS_D_INX, "D,S,T,Rm", MATCH_FMSUB_D, MASK_FMSUB_D, match_opcode, INSN_RV32_EVEN_DSTR },
+{"fnmsub.d", 0, INSN_CLASS_D_INX, "D,S,T,Rm", MATCH_FNMSUB_D, MASK_FNMSUB_D, match_opcode, INSN_RV32_EVEN_DSTR },
+{"fcvt.w.d", 0, INSN_CLASS_D_INX, "d,Sm", MATCH_FCVT_W_D, MASK_FCVT_W_D, match_opcode, INSN_RV32_EVEN_S },
+{"fcvt.wu.d", 0, INSN_CLASS_D_INX, "d,Sm", MATCH_FCVT_WU_D, MASK_FCVT_WU_D, match_opcode, INSN_RV32_EVEN_S },
+{"fcvt.d.w", 0, INSN_CLASS_D_INX, "D,s", MATCH_FCVT_D_W, MASK_FCVT_D_W|MASK_RM, match_opcode, INSN_RV32_EVEN_D },
+{"fcvt.d.wu", 0, INSN_CLASS_D_INX, "D,s", MATCH_FCVT_D_WU, MASK_FCVT_D_WU|MASK_RM, match_opcode, INSN_RV32_EVEN_D },
+{"fcvt.d.s", 0, INSN_CLASS_D_INX, "D,S", MATCH_FCVT_D_S, MASK_FCVT_D_S|MASK_RM, match_opcode, INSN_RV32_EVEN_D },
+{"fcvt.s.d", 0, INSN_CLASS_D_INX, "D,Sm", MATCH_FCVT_S_D, MASK_FCVT_S_D, match_opcode, INSN_RV32_EVEN_S },
+{"fclass.d", 0, INSN_CLASS_D_INX, "d,S", MATCH_FCLASS_D, MASK_FCLASS_D, match_opcode, INSN_RV32_EVEN_S },
+{"feq.d", 0, INSN_CLASS_D_INX, "d,S,T", MATCH_FEQ_D, MASK_FEQ_D, match_opcode, INSN_RV32_EVEN_ST },
+{"flt.d", 0, INSN_CLASS_D_INX, "d,S,T", MATCH_FLT_D, MASK_FLT_D, match_opcode, INSN_RV32_EVEN_ST },
+{"fle.d", 0, INSN_CLASS_D_INX, "d,S,T", MATCH_FLE_D, MASK_FLE_D, match_opcode, INSN_RV32_EVEN_ST },
+{"fgt.d", 0, INSN_CLASS_D_INX, "d,T,S", MATCH_FLT_D, MASK_FLT_D, match_opcode, INSN_ALIAS|INSN_RV32_EVEN_ST },
+{"fge.d", 0, INSN_CLASS_D_INX, "d,T,S", MATCH_FLE_D, MASK_FLE_D, match_opcode, INSN_ALIAS|INSN_RV32_EVEN_ST },
{"fmv.x.d", 64, INSN_CLASS_D, "d,S", MATCH_FMV_X_D, MASK_FMV_X_D, match_opcode, 0 },
{"fmv.d.x", 64, INSN_CLASS_D, "D,s", MATCH_FMV_D_X, MASK_FMV_D_X, match_opcode, 0 },
{"fcvt.l.d", 64, INSN_CLASS_D_INX, "d,Sm", MATCH_FCVT_L_D, MASK_FCVT_L_D, match_opcode, 0 },