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.
This commit is contained in:
Jiawei
2024-02-27 11:48:11 +08:00
committed by Nelson Chu
parent 2bf280a827
commit 9132c8152b
13 changed files with 641 additions and 0 deletions

View File

@@ -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;
}