forked from Imagelibrary/binutils-gdb
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:
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user