aboutsummaryrefslogtreecommitdiff
path: root/opcodes
diff options
context:
space:
mode:
authorJiawei <jiawei@iscas.ac.cn>2024-02-27 11:48:11 +0800
committerNelson Chu <nelson@rivosinc.com>2024-04-09 15:56:12 +0800
commit9132c8152b899a1683bc886f8ba76bedadb48aa1 (patch)
treeaa2ea7d660f18ce24eddcc70b8da58bf0508fabf /opcodes
parent2bf280a827577eaf26d657af9f5e29dbf77e6ee2 (diff)
downloadgdb-9132c8152b899a1683bc886f8ba76bedadb48aa1.zip
gdb-9132c8152b899a1683bc886f8ba76bedadb48aa1.tar.gz
gdb-9132c8152b899a1683bc886f8ba76bedadb48aa1.tar.bz2
RISC-V: Support Zcmp push/pop instructions.
Support zcmp extension push/pop/popret and popret zero instructions. The `reg_list' is a list containing 1 to 13 registers, we can use: "{ra}, {ra, s0}, {ra, s0-s1}, {ra, s0-s2} ... {ra, s0-sN}" to present this feature. Passed gcc/binutils regressions of riscv-gnu-toolchain. Most of work was finished by Sinan Lin. Co-Authored by: Charlie Keaney <charlie.keaney@embecosm.com> Co-Authored by: Mary Bennett <mary.bennett@embecosm.com> Co-Authored by: Nandni Jamnadas <nandni.jamnadas@embecosm.com> Co-Authored by: Sinan Lin <sinan.lin@linux.alibaba.com> Co-Authored by: Simon Cook <simon.cook@embecosm.com> Co-Authored by: Shihua Liao <shihua@iscas.ac.cn> Co-Authored by: Yulong Shi <yulong@iscas.ac.cn> bfd/ChangeLog: * elfxx-riscv.c (riscv_implicit_subset): Imply zca for zcmp. (riscv_supported_std_z_ext): Added zcmp with version 1.0. (riscv_parse_check_conflicts): Zcmp conflicts with d/zcd. (riscv_multi_subset_supports): Handle zcmp. (riscv_multi_subset_supports_ext): Ditto. gas/ChangeLog: * NEWS: Updated. * config/tc-riscv.c (regno_to_reg_list): New function, used to map register to reg_list number. (reglist_lookup): Called reglist_lookup_internal. Return false if reg_list number is zero, which is an invalid value. (reglist_lookup_internal): Parse register list, and return the last register by regno_to_reg_list. (validate_riscv_insn): New operators. (riscv_ip): Ditto. * testsuite/gas/riscv/march-help.l: Updated. * testsuite/gas/riscv/zcmp-push-pop-fail.d: New test. * testsuite/gas/riscv/zcmp-push-pop-fail.l: New test. * testsuite/gas/riscv/zcmp-push-pop-fail.s: New test. * testsuite/gas/riscv/zcmp-push-pop.d: New test. * testsuite/gas/riscv/zcmp-push-pop.s: New test. include/ChangeLog: * opcode/riscv-opc.h (MATCH/MASK_CM_PUSH): New macros for zcmp. (MATCH/MASK_CM_POP): Ditto. (MATCH/MASK_CM_POPRET): Ditto. (MATCH/MASK_CM_POPRETZ): Ditto. (DECLARE_INSN): New declarations for zcmp. * opcode/riscv.h (EXTRACT/ENCODE/VALID_ZCMP_SPIMM): Handle spimm operand for zcmp. (OP_MASK_REG_LIST): Handle operand for zcmp register list. (OP_SH_REG_LIST): Ditto. (ZCMP_SP_ALIGNMENT): New argument, used in riscv_get_sp_base. (X_S0, X_S1, X_S2, X_S10, X_S11): New register numbers. (enum riscv_insn_class): Added INSN_CLASS_ZCMP. (extern riscv_get_sp_base): Added. opcodes/ChangeLog: * riscv-dis.c (print_reg_list): New function, used to get zcmp reg_list field. (riscv_get_spimm): New function, used to get zcmp sp adjustment immediate. (print_insn_args): Handle new operands for zcmp. * riscv-opc.c (riscv_get_sp_base): New function, used by gas and objdump. Get sp base adjustment. (riscv_opcodes): Added zcmp instructions.
Diffstat (limited to 'opcodes')
-rw-r--r--opcodes/riscv-dis.c51
-rw-r--r--opcodes/riscv-opc.c20
2 files changed, 71 insertions, 0 deletions
diff --git a/opcodes/riscv-dis.c b/opcodes/riscv-dis.c
index 3019b9a..684098d3 100644
--- a/opcodes/riscv-dis.c
+++ b/opcodes/riscv-dis.c
@@ -215,6 +215,48 @@ maybe_print_address (struct riscv_private_data *pd, int base_reg, int offset,
pd->print_addr = (bfd_vma)(uint32_t)pd->print_addr;
}
+/* Get Zcmp reg_list field. */
+
+static void
+print_reg_list (disassemble_info *info, insn_t l)
+{
+ bool numeric = riscv_gpr_names == riscv_gpr_names_numeric;
+ unsigned reg_list = (int)EXTRACT_OPERAND (REG_LIST, l);
+ unsigned r_start = numeric ? X_S2 : X_S0;
+ info->fprintf_func (info->stream, "%s", riscv_gpr_names[X_RA]);
+
+ if (reg_list == 5)
+ info->fprintf_func (info->stream, ",%s",
+ riscv_gpr_names[X_S0]);
+ else if (reg_list == 6 || (numeric && reg_list > 6))
+ info->fprintf_func (info->stream, ",%s-%s",
+ riscv_gpr_names[X_S0],
+ riscv_gpr_names[X_S1]);
+ if (reg_list == 15)
+ info->fprintf_func (info->stream, ",%s-%s",
+ riscv_gpr_names[r_start],
+ riscv_gpr_names[X_S11]);
+ else if (reg_list == 7 && numeric)
+ info->fprintf_func (info->stream, ",%s",
+ riscv_gpr_names[X_S2]);
+ else if (reg_list > 6)
+ info->fprintf_func (info->stream, ",%s-%s",
+ riscv_gpr_names[r_start],
+ riscv_gpr_names[reg_list + 11]);
+}
+
+/* Get Zcmp sp adjustment immediate. */
+
+static int
+riscv_get_spimm (insn_t l)
+{
+ int spimm = riscv_get_sp_base(l, *riscv_rps_dis.xlen);
+ spimm += EXTRACT_ZCMP_SPIMM (l);
+ if (((l ^ MATCH_CM_PUSH) & MASK_CM_PUSH) == 0)
+ spimm *= -1;
+ return spimm;
+}
+
/* Print insn arguments for 32/64-bit code. */
static void
@@ -420,6 +462,8 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info
case ')':
case '[':
case ']':
+ case '{':
+ case '}':
print (info->stream, dis_style_text, "%c", *oparg);
break;
@@ -634,6 +678,13 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info
print (info->stream, dis_style_immediate, "%d",
(int)EXTRACT_ZCB_HALFWORD_UIMM (l));
break;
+ case 'r':
+ print_reg_list (info, l);
+ break;
+ case 'p':
+ print (info->stream, dis_style_immediate, "%d",
+ riscv_get_spimm (l));
+ break;
default:
goto undefined_modifier;
}
diff --git a/opcodes/riscv-opc.c b/opcodes/riscv-opc.c
index daa888d..38a4624 100644
--- a/opcodes/riscv-opc.c
+++ b/opcodes/riscv-opc.c
@@ -143,6 +143,20 @@ const float riscv_fli_numval[32] =
0x1p+3, 0x1p+4, 0x1p+7, 0x1p+8, 0x1p+15, 0x1p+16, 0x0p+0, 0x0p+0
};
+/* Get sp base adjustment. */
+
+unsigned int
+riscv_get_sp_base (insn_t opcode, unsigned int xlen)
+{
+ unsigned reg_size = xlen / 8;
+ unsigned reg_list = EXTRACT_BITS (opcode, OP_MASK_REG_LIST, OP_SH_REG_LIST);
+ unsigned min_sp_adj = (reg_list - 3) * reg_size
+ + (reg_list == 15 ? reg_size : 0);
+ return (((min_sp_adj / ZCMP_SP_ALIGNMENT)
+ + (min_sp_adj % ZCMP_SP_ALIGNMENT != 0))
+ * ZCMP_SP_ALIGNMENT);
+}
+
#define MASK_RS1 (OP_MASK_RS1 << OP_SH_RS1)
#define MASK_RS2 (OP_MASK_RS2 << OP_SH_RS2)
#define MASK_RD (OP_MASK_RD << OP_SH_RD)
@@ -2068,6 +2082,12 @@ const struct riscv_opcode riscv_opcodes[] =
{"c.zext.b", 0, INSN_CLASS_ZCB, "Cs", MATCH_C_ZEXT_B, MASK_C_ZEXT_B, match_opcode, 0 },
{"c.sext.w", 64, INSN_CLASS_ZCB, "d", MATCH_C_ADDIW, MASK_C_ADDIW|MASK_RVC_IMM, match_rd_nonzero, INSN_ALIAS },
+/* Zcmp instructions. */
+{"cm.push", 0, INSN_CLASS_ZCMP, "{Wcr},Wcp", MATCH_CM_PUSH, MASK_CM_PUSH, match_opcode, 0 },
+{"cm.pop", 0, INSN_CLASS_ZCMP, "{Wcr},Wcp", MATCH_CM_POP, MASK_CM_POP, match_opcode, 0 },
+{"cm.popret", 0, INSN_CLASS_ZCMP, "{Wcr},Wcp", MATCH_CM_POPRET, MASK_CM_POPRET, match_opcode, 0 },
+{"cm.popretz", 0, INSN_CLASS_ZCMP, "{Wcr},Wcp", MATCH_CM_POPRETZ, MASK_CM_POPRETZ, match_opcode, 0 },
+
/* Supervisor instructions. */
{"csrr", 0, INSN_CLASS_ZICSR, "d,E", MATCH_CSRRS, MASK_CSRRS|MASK_RS1, match_opcode, INSN_ALIAS },
{"csrwi", 0, INSN_CLASS_ZICSR, "E,Z", MATCH_CSRRWI, MASK_CSRRWI|MASK_RD, match_opcode, INSN_ALIAS },