diff options
Diffstat (limited to 'opcodes')
-rw-r--r-- | opcodes/aarch64-dis.c | 5 | ||||
-rw-r--r-- | opcodes/aarch64-opc.c | 74 |
2 files changed, 56 insertions, 23 deletions
diff --git a/opcodes/aarch64-dis.c b/opcodes/aarch64-dis.c index 05e285fac99..e722514053e 100644 --- a/opcodes/aarch64-dis.c +++ b/opcodes/aarch64-dis.c @@ -439,6 +439,7 @@ aarch64_ext_reglist (const aarch64_operand *self, aarch64_opnd_info *info, info->reglist.first_regno = extract_field (self->fields[0], code, 0); /* len */ info->reglist.num_regs = extract_field (FLD_len, code, 0) + 1; + info->reglist.stride = 1; return true; } @@ -482,6 +483,7 @@ aarch64_ext_ldst_reglist (const aarch64_operand *self ATTRIBUTE_UNUSED, if (expected_num != data[value].num_elements || data[value].is_reserved) return false; info->reglist.num_regs = data[value].num_regs; + info->reglist.stride = 1; return true; } @@ -510,6 +512,7 @@ aarch64_ext_ldst_reglist_r (const aarch64_operand *self ATTRIBUTE_UNUSED, if (info->reglist.num_regs == 1 && value == (aarch64_insn) 1) info->reglist.num_regs = 2; + info->reglist.stride = 1; return true; } @@ -573,6 +576,7 @@ aarch64_ext_ldst_elemlist (const aarch64_operand *self ATTRIBUTE_UNUSED, info->reglist.has_index = 1; info->reglist.num_regs = 0; + info->reglist.stride = 1; /* Number of registers is equal to the number of elements in each structure to be loaded/stored. */ info->reglist.num_regs = get_opcode_dependent_value (inst->opcode); @@ -1982,6 +1986,7 @@ aarch64_ext_sve_reglist (const aarch64_operand *self, { info->reglist.first_regno = extract_field (self->fields[0], code, 0); info->reglist.num_regs = get_opcode_dependent_value (inst->opcode); + info->reglist.stride = 1; return true; } diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c index 8a9e51faebd..4e950cf70f8 100644 --- a/opcodes/aarch64-opc.c +++ b/opcodes/aarch64-opc.c @@ -1439,12 +1439,22 @@ set_unaligned_error (aarch64_operand_error *mismatch_detail, int idx, } static inline void -set_reg_list_error (aarch64_operand_error *mismatch_detail, int idx, - int expected_num) +set_reg_list_length_error (aarch64_operand_error *mismatch_detail, int idx, + int expected_num) { if (mismatch_detail == NULL) return; - set_error (mismatch_detail, AARCH64_OPDE_REG_LIST, idx, NULL); + set_error (mismatch_detail, AARCH64_OPDE_REG_LIST_LENGTH, idx, NULL); + mismatch_detail->data[0].i = 1 << expected_num; +} + +static inline void +set_reg_list_stride_error (aarch64_operand_error *mismatch_detail, int idx, + int expected_num) +{ + if (mismatch_detail == NULL) + return; + set_error (mismatch_detail, AARCH64_OPDE_REG_LIST_STRIDE, idx, NULL); mismatch_detail->data[0].i = 1 << expected_num; } @@ -1482,6 +1492,27 @@ check_reglane (const aarch64_opnd_info *opnd, return true; } +/* Check that register list operand OPND has NUM_REGS registers and a + register stride of STRIDE. */ + +static bool +check_reglist (const aarch64_opnd_info *opnd, + aarch64_operand_error *mismatch_detail, int idx, + int num_regs, int stride) +{ + if (opnd->reglist.num_regs != num_regs) + { + set_reg_list_length_error (mismatch_detail, idx, num_regs); + return false; + } + if (opnd->reglist.stride != stride) + { + set_reg_list_stride_error (mismatch_detail, idx, stride); + return false; + } + return true; +} + /* Check that indexed ZA operand OPND has: - a selection register in the range [MIN_WREG, MIN_WREG + 3] @@ -1637,11 +1668,8 @@ operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx, case AARCH64_OPND_CLASS_SVE_REGLIST: num = get_opcode_dependent_value (opcode); - if (opnd->reglist.num_regs != num) - { - set_reg_list_error (mismatch_detail, idx, num); - return 0; - } + if (!check_reglist (opnd, mismatch_detail, idx, num, 1)) + return 0; break; case AARCH64_OPND_CLASS_ZA_ACCESS: @@ -2123,26 +2151,25 @@ operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx, assert (num >= 1 && num <= 4); /* Unless LD1/ST1, the number of registers should be equal to that of the structure elements. */ - if (num != 1 && opnd->reglist.num_regs != num) - { - set_reg_list_error (mismatch_detail, idx, num); - return 0; - } + if (num != 1 && !check_reglist (opnd, mismatch_detail, idx, num, 1)) + return 0; break; case AARCH64_OPND_LVt_AL: case AARCH64_OPND_LEt: assert (num >= 1 && num <= 4); /* The number of registers should be equal to that of the structure elements. */ - if (opnd->reglist.num_regs != num) - { - set_reg_list_error (mismatch_detail, idx, num); - return 0; - } + if (!check_reglist (opnd, mismatch_detail, idx, num, 1)) + return 0; break; default: break; } + if (opnd->reglist.stride != 1) + { + set_reg_list_stride_error (mismatch_detail, idx, 1); + return 0; + } break; case AARCH64_OPND_CLASS_IMMEDIATE: @@ -3199,8 +3226,9 @@ print_register_list (char *buf, size_t size, const aarch64_opnd_info *opnd, const char *prefix, struct aarch64_styler *styler) { const int num_regs = opnd->reglist.num_regs; + const int stride = opnd->reglist.stride; const int first_reg = opnd->reglist.first_regno; - const int last_reg = (first_reg + num_regs - 1) & 0x1f; + const int last_reg = (first_reg + (num_regs - 1) * stride) & 0x1f; const char *qlf_name = aarch64_get_qualifier_name (opnd->qualifier); char tb[16]; /* Temporary buffer. */ @@ -3218,16 +3246,16 @@ print_register_list (char *buf, size_t size, const aarch64_opnd_info *opnd, /* The hyphenated form is preferred for disassembly if there are more than two registers in the list, and the register numbers are monotonically increasing in increments of one. */ - if (num_regs > 2 && last_reg > first_reg) + if (stride == 1 && num_regs > 2 && last_reg > first_reg) snprintf (buf, size, "{%s-%s}%s", style_reg (styler, "%s%d.%s", prefix, first_reg, qlf_name), style_reg (styler, "%s%d.%s", prefix, last_reg, qlf_name), tb); else { const int reg0 = first_reg; - const int reg1 = (first_reg + 1) & 0x1f; - const int reg2 = (first_reg + 2) & 0x1f; - const int reg3 = (first_reg + 3) & 0x1f; + const int reg1 = (first_reg + stride) & 0x1f; + const int reg2 = (first_reg + stride * 2) & 0x1f; + const int reg3 = (first_reg + stride * 3) & 0x1f; switch (num_regs) { |