diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c index 27d06d2fa3d..d74e7a584eb 100644 --- a/bfd/elfxx-riscv.c +++ b/bfd/elfxx-riscv.c @@ -2402,3 +2402,97 @@ riscv_multi_subset_supports (riscv_parse_subset_t *rps, return false; } } + +/* Each instuction is belonged to an instruction class INSN_CLASS_*. + Call riscv_subset_supports_ext to determine the missing extension. */ + +const char * +riscv_multi_subset_supports_ext (riscv_parse_subset_t *rps, + enum riscv_insn_class insn_class) +{ + switch (insn_class) + { + case INSN_CLASS_I: + return "i"; + case INSN_CLASS_ZICSR: + return "zicsr"; + case INSN_CLASS_ZIFENCEI: + return "zifencei"; + case INSN_CLASS_ZIHINTPAUSE: + return "zihintpause"; + case INSN_CLASS_M: + return "m"; + case INSN_CLASS_A: + return "a"; + case INSN_CLASS_F: + return "f"; + case INSN_CLASS_D: + return "d"; + case INSN_CLASS_Q: + return "q"; + case INSN_CLASS_C: + return "c"; + case INSN_CLASS_F_AND_C: + if (!riscv_subset_supports (rps, "f") + && !riscv_subset_supports (rps, "c")) + return "f' and `c"; + else if (!riscv_subset_supports (rps, "f")) + return "f"; + else + return "c"; + case INSN_CLASS_D_AND_C: + if (!riscv_subset_supports (rps, "d") + && !riscv_subset_supports (rps, "c")) + return "d' and `c"; + else if (!riscv_subset_supports (rps, "d")) + return "d"; + else + return "c"; + case INSN_CLASS_F_OR_ZFINX: + return "f' or `zfinx"; + case INSN_CLASS_D_OR_ZDINX: + return "d' or `zdinx"; + case INSN_CLASS_Q_OR_ZQINX: + return "q' or `zqinx"; + case INSN_CLASS_ZBA: + return "zba"; + case INSN_CLASS_ZBB: + return "zbb"; + case INSN_CLASS_ZBC: + return "zbc"; + case INSN_CLASS_ZBS: + return "zbs"; + case INSN_CLASS_ZBKB: + return "zbkb"; + case INSN_CLASS_ZBKC: + return "zbkc"; + case INSN_CLASS_ZBKX: + return "zbkx"; + case INSN_CLASS_ZBB_OR_ZBKB: + return "zbb' or `zbkb"; + case INSN_CLASS_ZBC_OR_ZBKC: + return "zbc' or `zbkc"; + case INSN_CLASS_ZKND: + return "zknd"; + case INSN_CLASS_ZKNE: + return "zkne"; + case INSN_CLASS_ZKNH: + return "zknh"; + case INSN_CLASS_ZKND_OR_ZKNE: + return "zknd' or `zkne"; + case INSN_CLASS_ZKSED: + return "zksed"; + case INSN_CLASS_ZKSH: + return "zksh"; + case INSN_CLASS_V: + return "v' or `zve64x' or `zve32x"; + case INSN_CLASS_ZVEF: + return "v' or `zve64d' or `zve64f' or `zve32f"; + case INSN_CLASS_SVINVAL: + return "svinval"; + default: + rps->error_handler + (_("internal: unreachable INSN_CLASS_*")); + return NULL; + } +} diff --git a/bfd/elfxx-riscv.h b/bfd/elfxx-riscv.h index 67b7d078232..ea7126bdb4d 100644 --- a/bfd/elfxx-riscv.h +++ b/bfd/elfxx-riscv.h @@ -104,6 +104,9 @@ riscv_subset_supports (riscv_parse_subset_t *, const char *); extern bool riscv_multi_subset_supports (riscv_parse_subset_t *, enum riscv_insn_class); +extern const char * +riscv_multi_subset_supports_ext (riscv_parse_subset_t *, enum riscv_insn_class); + extern void bfd_elf32_riscv_set_data_segment_info (struct bfd_link_info *, int *); extern void diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c index 55799b1f708..322e0f070ba 100644 --- a/gas/config/tc-riscv.c +++ b/gas/config/tc-riscv.c @@ -89,6 +89,20 @@ struct riscv_csr_extra struct riscv_csr_extra *next; }; +/* This structure contains information about errors that occur within the + riscv_ip function */ +struct riscv_ip_error +{ + /* General error message */ + const char* msg; + + /* Statement that caused the error */ + char* statement; + + /* Missing extension that needs to be enabled */ + const char* missing_ext; +}; + #ifndef DEFAULT_ARCH #define DEFAULT_ARCH "riscv64" #endif @@ -2221,7 +2235,7 @@ riscv_is_priv_insn (insn_t insn) side effect, it sets the global variable imm_reloc to the type of relocation to do if one of the operands is an address expression. */ -static const char * +static struct riscv_ip_error riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr, bfd_reloc_code_real_type *imm_reloc, htab_t hash) { @@ -2234,7 +2248,10 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr, unsigned int regno; int argnum; const struct percent_op_match *p; - const char *error = "unrecognized opcode"; + struct riscv_ip_error error; + error.msg = "unrecognized opcode"; + error.statement = str; + error.missing_ext = NULL; /* Indicate we are assembling instruction with CSR. */ bool insn_with_csr = false; @@ -2257,10 +2274,15 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr, continue; if (!riscv_multi_subset_supports (&riscv_rps_as, insn->insn_class)) - continue; + { + error.missing_ext = riscv_multi_subset_supports_ext (&riscv_rps_as, + insn->insn_class); + continue; + } /* Reset error message of the previous round. */ - error = _("illegal operands"); + error.msg = _("illegal operands"); + error.missing_ext = NULL; create_insn (ip, insn); argnum = 1; @@ -2310,14 +2332,14 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr, && riscv_subset_supports (&riscv_rps_as, "zve32x") && !riscv_subset_supports (&riscv_rps_as, "zve64x")) { - error = _("illegal opcode for zve32x"); + error.msg = _("illegal opcode for zve32x"); break; } } if (*asarg != '\0') break; /* Successful assembly. */ - error = NULL; + error.msg = NULL; insn_with_csr = false; goto out; @@ -3253,11 +3275,16 @@ md_assemble (char *str) riscv_mapping_state (MAP_INSN, 0); - const char *error = riscv_ip (str, &insn, &imm_expr, &imm_reloc, op_hash); + const struct riscv_ip_error error = riscv_ip (str, &insn, &imm_expr, + &imm_reloc, op_hash); - if (error) + if (error.msg) { - as_bad ("%s `%s'", error, str); + if (error.missing_ext) + as_bad ("%s `%s', extension `%s' required", error.msg, + error.statement, error.missing_ext); + else + as_bad ("%s `%s'", error.msg, error.statement); return; } @@ -4266,17 +4293,23 @@ s_riscv_insn (int x ATTRIBUTE_UNUSED) riscv_mapping_state (MAP_INSN, 0); - const char *error = riscv_ip (str, &insn, &imm_expr, + struct riscv_ip_error error = riscv_ip (str, &insn, &imm_expr, &imm_reloc, insn_type_hash); - if (error) + if (error.msg) { char *save_in = input_line_pointer; - error = riscv_ip_hardcode (str, &insn, &imm_expr, error); + error.msg = riscv_ip_hardcode (str, &insn, &imm_expr, error.msg); input_line_pointer = save_in; } - if (error) - as_bad ("%s `%s'", error, str); + if (error.msg) + { + if (error.missing_ext) + as_bad ("%s `%s', extension `%s' required", error.msg, error.statement, + error.missing_ext); + else + as_bad ("%s `%s'", error.msg, error.statement); + } else { gas_assert (insn.insn_mo->pinfo != INSN_MACRO); diff --git a/gas/testsuite/gas/riscv/c-fld-fsd-fail.l b/gas/testsuite/gas/riscv/c-fld-fsd-fail.l index 7d99abbaad8..b701fac14c0 100644 --- a/gas/testsuite/gas/riscv/c-fld-fsd-fail.l +++ b/gas/testsuite/gas/riscv/c-fld-fsd-fail.l @@ -1,3 +1,3 @@ .*: Assembler messages: -.*: Error: unrecognized opcode `fld fa0,0\(a0\)' -.*: Error: unrecognized opcode `fsd fa0,0\(a0\)' +.*: Error: unrecognized opcode `fld fa0,0\(a0\)', extension `d' required +.*: Error: unrecognized opcode `fsd fa0,0\(a0\)', extension `d' required diff --git a/gas/testsuite/gas/riscv/march-imply-i2p1-01.l b/gas/testsuite/gas/riscv/march-imply-i2p1-01.l index b54d4ae9acd..7fbee14fe83 100644 --- a/gas/testsuite/gas/riscv/march-imply-i2p1-01.l +++ b/gas/testsuite/gas/riscv/march-imply-i2p1-01.l @@ -1,21 +1,21 @@ .*Assembler messages: -.*Error: unrecognized opcode `csrr t0,ustatus' -.*Error: unrecognized opcode `csrwi ustatus,0x0' -.*Error: unrecognized opcode `csrsi ustatus,0x0' -.*Error: unrecognized opcode `csrci ustatus,0x0' -.*Error: unrecognized opcode `csrw ustatus,t0' -.*Error: unrecognized opcode `csrw ustatus,0x0' -.*Error: unrecognized opcode `csrs ustatus,t0' -.*Error: unrecognized opcode `csrs ustatus,0x0' -.*Error: unrecognized opcode `csrc ustatus,t0' -.*Error: unrecognized opcode `csrc ustatus,0x0' -.*Error: unrecognized opcode `csrrwi t0,ustatus,0x0' -.*Error: unrecognized opcode `csrrsi t0,ustatus,0x0' -.*Error: unrecognized opcode `csrrci t0,ustatus,0x0' -.*Error: unrecognized opcode `csrrw t0,ustatus,t0' -.*Error: unrecognized opcode `csrrw t0,ustatus,0x0' -.*Error: unrecognized opcode `csrrs t0,ustatus,t0' -.*Error: unrecognized opcode `csrrs t0,ustatus,0x0' -.*Error: unrecognized opcode `csrrc t0,ustatus,t0' -.*Error: unrecognized opcode `csrrc t0,ustatus,0x0' -.*Error: unrecognized opcode `fence.i' +.*Error: unrecognized opcode `csrr t0,ustatus', extension `zicsr' required +.*Error: unrecognized opcode `csrwi ustatus,0x0', extension `zicsr' required +.*Error: unrecognized opcode `csrsi ustatus,0x0', extension `zicsr' required +.*Error: unrecognized opcode `csrci ustatus,0x0', extension `zicsr' required +.*Error: unrecognized opcode `csrw ustatus,t0', extension `zicsr' required +.*Error: unrecognized opcode `csrw ustatus,0x0', extension `zicsr' required +.*Error: unrecognized opcode `csrs ustatus,t0', extension `zicsr' required +.*Error: unrecognized opcode `csrs ustatus,0x0', extension `zicsr' required +.*Error: unrecognized opcode `csrc ustatus,t0', extension `zicsr' required +.*Error: unrecognized opcode `csrc ustatus,0x0', extension `zicsr' required +.*Error: unrecognized opcode `csrrwi t0,ustatus,0x0', extension `zicsr' required +.*Error: unrecognized opcode `csrrsi t0,ustatus,0x0', extension `zicsr' required +.*Error: unrecognized opcode `csrrci t0,ustatus,0x0', extension `zicsr' required +.*Error: unrecognized opcode `csrrw t0,ustatus,t0', extension `zicsr' required +.*Error: unrecognized opcode `csrrw t0,ustatus,0x0', extension `zicsr' required +.*Error: unrecognized opcode `csrrs t0,ustatus,t0', extension `zicsr' required +.*Error: unrecognized opcode `csrrs t0,ustatus,0x0', extension `zicsr' required +.*Error: unrecognized opcode `csrrc t0,ustatus,t0', extension `zicsr' required +.*Error: unrecognized opcode `csrrc t0,ustatus,0x0', extension `zicsr' required +.*Error: unrecognized opcode `fence.i', extension `zifencei' required