From 9a5d8d7b904ed7b09eacc29aea07a148391f428d Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Fri, 30 Sep 2022 13:18:15 +0000 Subject: [PATCH] RISC-V: Implement extension variants If there is a instruction with multiple variants with different requirements and the assembler fails to parse all variants, there is a case that needs to refer ALL variants to generate proper diagnostics. If an instruction with INSN_HAS_EXT_VARS fails, the assembler now has a chance to modify the instruction class for proper diagnostics. A typical use of this feature is to select _wider_ instruction class when necessary. gas/ChangeLog: * config/tc-riscv.c (riscv_ip): Add empty INSN_HAS_EXT_VARS handling. include/ChangeLog: * opcode/riscv.h (INSN_HAS_EXT_VARS): New. --- gas/config/tc-riscv.c | 27 +++++++++++++++++++++++++-- include/opcode/riscv.h | 5 +++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c index 5e6fca3de9f..f83b0ff3dad 100644 --- a/gas/config/tc-riscv.c +++ b/gas/config/tc-riscv.c @@ -2376,6 +2376,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr, unsigned int regno; const struct percent_op_match *p; struct riscv_ip_error error; + enum riscv_insn_class insn_class; error.msg = "unrecognized opcode"; error.statement = str; error.missing_ext = NULL; @@ -2402,8 +2403,30 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr, if (!riscv_multi_subset_supports (&riscv_rps_as, insn->insn_class)) { - error.missing_ext = riscv_multi_subset_supports_ext (&riscv_rps_as, - insn->insn_class); + insn_class = insn->insn_class; + if (insn->pinfo != INSN_MACRO && insn->pinfo & INSN_HAS_EXT_VARS) + { + /* If an instruction is not supported for example, there is a + case where some extensions (that is not related to the last + "same name" variants) should be printed for diagnostics. + + For instance, if parsing "fmin.d" fails on both 'D' and + 'Zdinx' variants, we have to require 'D' or 'Zdinx', not just + 'Zdinx', the last "fmin.d" variant in riscv_opcodes. + + For instructions with INSN_HAS_EXT_VARS, we should rewrite the + instruction class (from a specific one to a generic one) + to provide proper error output. + */ + switch (insn_class) + { + default: + break; + } + } + if (!riscv_multi_subset_supports (&riscv_rps_as, insn_class)) + error.missing_ext = riscv_multi_subset_supports_ext (&riscv_rps_as, + insn_class); continue; } diff --git a/include/opcode/riscv.h b/include/opcode/riscv.h index dd2569f6d55..3cfe132babe 100644 --- a/include/opcode/riscv.h +++ b/include/opcode/riscv.h @@ -496,6 +496,11 @@ struct riscv_opcode #define INSN_8_BYTE 0x00000040 #define INSN_16_BYTE 0x00000050 +/* Instruction has different entry that shares the name but differs + in extension requirements (extension variants). Those instructions must be + taken care if we should print an "extension required" error. */ +#define INSN_HAS_EXT_VARS 0x00000080 + /* Instruction is actually a macro. It should be ignored by the disassembler, and requires special treatment by the assembler. */ #define INSN_MACRO 0xffffffff