diff --git a/include/opcode/aarch64.h b/include/opcode/aarch64.h index 3c1f522b813..85e28d9d287 100644 --- a/include/opcode/aarch64.h +++ b/include/opcode/aarch64.h @@ -1282,7 +1282,9 @@ extern const aarch64_opcode aarch64_opcode_table[]; #define F_OPD_NARROW (1ULL << 33) /* For the instruction with size[22:23] field. */ #define F_OPD_SIZE (1ULL << 34) -/* Next bit is 35. */ +/* RCPC3 instruction has the field of 'size'. */ +#define F_RCPC3_SIZE (1ULL << 35) +/* Next bit is 36. */ /* Instruction constraints. */ /* This instruction has a predication constraint on the instruction at PC+4. */ @@ -1350,7 +1352,7 @@ opcode_has_special_coder (const aarch64_opcode *opcode) { return (opcode->flags & (F_SF | F_LSE_SZ | F_SIZEQ | F_FPTYPE | F_SSIZE | F_T | F_GPRSIZE_IN_Q | F_LDS_SIZE | F_MISC | F_N | F_COND - | F_OPD_SIZE)) != 0; + | F_OPD_SIZE | F_RCPC3_SIZE)) != 0; } struct aarch64_name_value_pair diff --git a/opcodes/aarch64-asm.c b/opcodes/aarch64-asm.c index 4d0b13e4c5a..565c4b10559 100644 --- a/opcodes/aarch64-asm.c +++ b/opcodes/aarch64-asm.c @@ -702,6 +702,24 @@ aarch64_ins_addr_offset (const aarch64_operand *self ATTRIBUTE_UNUSED, return true; } +/* Encode the address operand for e.g. + stlur , [{, }]. */ +bool +aarch64_ins_rcpc3_addr_offset (const aarch64_operand *self ATTRIBUTE_UNUSED, + const aarch64_opnd_info *info, aarch64_insn *code, + const aarch64_inst *inst ATTRIBUTE_UNUSED, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) +{ + /* Rn */ + insert_field (self->fields[0], code, info->addr.base_regno, 0); + + /* simm9 */ + int imm = info->addr.offset.imm; + insert_field (self->fields[1], code, imm, 0); + + return true; +} + /* Encode the address operand for e.g. LDRSW , [, #]!. */ bool aarch64_ins_addr_simm (const aarch64_operand *self, @@ -736,6 +754,28 @@ aarch64_ins_addr_simm (const aarch64_operand *self, return true; } +/* Encode the address operand, potentially offset by the load/store ammount, + e.g. LDIAPP , [, #] + and STILP , [], #.*/ +bool +aarch64_ins_rcpc3_addr_opt_offset (const aarch64_operand *self ATTRIBUTE_UNUSED, + const aarch64_opnd_info *info, + aarch64_insn *code, + const aarch64_inst *inst ATTRIBUTE_UNUSED, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) +{ + int imm; + + /* Rn */ + insert_field (FLD_Rn, code, info->addr.base_regno, 0); + /* simm */ + imm = info->addr.offset.imm; + if (!imm) + insert_field (FLD_opc2, code, 1, 0); + + return true; +} + /* Encode the address operand for e.g. LDRAA , [{, #}]. */ bool aarch64_ins_addr_simm10 (const aarch64_operand *self, @@ -1943,6 +1983,22 @@ do_special_encoding (struct aarch64_inst *inst) ? 1 : 0; insert_field (FLD_lse_sz, &inst->value, value, 0); } + if (inst->opcode->flags & F_RCPC3_SIZE) + { + switch (inst->operands[0].qualifier) + { + case AARCH64_OPND_QLF_W: value = 2; break; + case AARCH64_OPND_QLF_X: value = 3; break; + case AARCH64_OPND_QLF_S_B: value = 0; break; + case AARCH64_OPND_QLF_S_H: value = 1; break; + case AARCH64_OPND_QLF_S_S: value = 2; break; + case AARCH64_OPND_QLF_S_D: value = 3; break; + case AARCH64_OPND_QLF_S_Q: value = 0; break; + default: return; + } + insert_field (FLD_rcpc3_size, &inst->value, value, 0); + } + if (inst->opcode->flags & F_SIZEQ) encode_sizeq (inst); if (inst->opcode->flags & F_FPTYPE) diff --git a/opcodes/aarch64-asm.h b/opcodes/aarch64-asm.h index e48bf0db8a8..c6dde1c4d1b 100644 --- a/opcodes/aarch64-asm.h +++ b/opcodes/aarch64-asm.h @@ -115,6 +115,8 @@ AARCH64_DECL_OPD_INSERTER (ins_imm_rotate2); AARCH64_DECL_OPD_INSERTER (ins_x0_to_x30); AARCH64_DECL_OPD_INSERTER (ins_simple_index); AARCH64_DECL_OPD_INSERTER (ins_plain_shrimm); +AARCH64_DECL_OPD_INSERTER (ins_rcpc3_addr_opt_offset); +AARCH64_DECL_OPD_INSERTER (ins_rcpc3_addr_offset); #undef AARCH64_DECL_OPD_INSERTER diff --git a/opcodes/aarch64-dis.c b/opcodes/aarch64-dis.c index 2896a119f35..f63b74706f6 100644 --- a/opcodes/aarch64-dis.c +++ b/opcodes/aarch64-dis.c @@ -1032,6 +1032,70 @@ aarch64_ext_addr_simple (const aarch64_operand *self ATTRIBUTE_UNUSED, return true; } +/* Decode the address operand for rcpc3 instructions with optional load/store + datasize offset, e.g. STILPP , , [{,#-16}]! and + LIDAP , , []{,#-16}. */ +bool +aarch64_ext_rcpc3_addr_opt_offset (const aarch64_operand *self ATTRIBUTE_UNUSED, + aarch64_opnd_info *info, + aarch64_insn code, + const aarch64_inst *inst ATTRIBUTE_UNUSED, + aarch64_operand_error *err ATTRIBUTE_UNUSED) +{ + info->addr.base_regno = extract_field (FLD_Rn, code, 0); + if (!extract_field (FLD_opc2, code, 0)) + { + info->addr.writeback = 1; + + enum aarch64_opnd type; + for (int i = 0; i < AARCH64_MAX_OPND_NUM; i++) + { + aarch64_opnd_info opnd = info[i]; + type = opnd.type; + if (aarch64_operands[type].op_class == AARCH64_OPND_CLASS_ADDRESS) + break; + } + + assert (aarch64_operands[type].op_class == AARCH64_OPND_CLASS_ADDRESS); + int offset = calc_ldst_datasize (inst->operands); + + switch (type) + { + case AARCH64_OPND_RCPC3_ADDR_OPT_PREIND_WB: + case AARCH64_OPND_RCPC3_ADDR_PREIND_WB: + info->addr.offset.imm = -offset; + info->addr.preind = 1; + break; + case AARCH64_OPND_RCPC3_ADDR_OPT_POSTIND: + case AARCH64_OPND_RCPC3_ADDR_POSTIND: + info->addr.offset.imm = offset; + info->addr.postind = 1; + break; + default: + return false; + } + } + return true; +} + +bool +aarch64_ext_rcpc3_addr_offset (const aarch64_operand *self ATTRIBUTE_UNUSED, + aarch64_opnd_info *info, + aarch64_insn code, + const aarch64_inst *inst ATTRIBUTE_UNUSED, + aarch64_operand_error *errors ATTRIBUTE_UNUSED) +{ + info->qualifier = get_expected_qualifier (inst, info->idx); + + /* Rn */ + info->addr.base_regno = extract_field (self->fields[0], code, 0); + + /* simm9 */ + aarch64_insn imm = extract_fields (code, 0, 1, self->fields[1]); + info->addr.offset.imm = sign_extend (imm, 8); + return true; +} + /* Decode the address operand for e.g. stlur , [{, }]. */ bool @@ -2579,6 +2643,26 @@ do_special_decoding (aarch64_inst *inst) value = extract_field (FLD_lse_sz, inst->value, 0); inst->operands[idx].qualifier = get_greg_qualifier_from_value (value); } + /* rcpc3 'size' field. */ + if (inst->opcode->flags & F_RCPC3_SIZE) + { + value = extract_field (FLD_rcpc3_size, inst->value, 0); + for (int i = 0; + aarch64_operands[inst->operands[i].type].op_class != AARCH64_OPND_CLASS_ADDRESS; + i++) + { + if (aarch64_operands[inst->operands[i].type].op_class + == AARCH64_OPND_CLASS_INT_REG) + inst->operands[i].qualifier = get_greg_qualifier_from_value (value & 1); + else if (aarch64_operands[inst->operands[i].type].op_class + == AARCH64_OPND_CLASS_FP_REG) + { + value += (extract_field (FLD_opc1, inst->value, 0) << 2); + inst->operands[i].qualifier = get_sreg_qualifier_from_value (value); + } + } + } + /* size:Q fields. */ if (inst->opcode->flags & F_SIZEQ) return decode_sizeq (inst); diff --git a/opcodes/aarch64-dis.h b/opcodes/aarch64-dis.h index 48bebfea1e1..6ed6776b679 100644 --- a/opcodes/aarch64-dis.h +++ b/opcodes/aarch64-dis.h @@ -140,6 +140,9 @@ AARCH64_DECL_OPD_EXTRACTOR (ext_x0_to_x30); AARCH64_DECL_OPD_EXTRACTOR (ext_simple_index); AARCH64_DECL_OPD_EXTRACTOR (ext_plain_shrimm); AARCH64_DECL_OPD_EXTRACTOR (ext_sve_reglist_zt); +AARCH64_DECL_OPD_EXTRACTOR (ext_rcpc3_addr_opt_offset); +AARCH64_DECL_OPD_EXTRACTOR (ext_rcpc3_addr_offset); + #undef AARCH64_DECL_OPD_EXTRACTOR diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c index 091df2c54f3..9a72d30268f 100644 --- a/opcodes/aarch64-opc.c +++ b/opcodes/aarch64-opc.c @@ -410,6 +410,8 @@ const aarch64_field fields[] = { 6, 2 }, /* ZAn_2: name of the 2bit encoded ZA tile. */ { 5, 3 }, /* ZAn_3: name of the 3bit encoded ZA tile. */ { 6, 1 }, /* ZAn: name of the bit encoded ZA tile. */ + { 12, 4 }, /* opc2: in rcpc3 ld/st inst deciding the pre/post-index. */ + { 30, 2 }, /* rcpc3_size: in rcpc3 ld/st, field controls Rt/Rt2 width. */ }; enum aarch64_operand_class diff --git a/opcodes/aarch64-opc.h b/opcodes/aarch64-opc.h index 587775152e3..4e781f000cc 100644 --- a/opcodes/aarch64-opc.h +++ b/opcodes/aarch64-opc.h @@ -216,7 +216,9 @@ enum aarch64_field_kind FLD_ol, FLD_ZAn_2, FLD_ZAn_3, - FLD_ZAn + FLD_ZAn, + FLD_opc2, + FLD_rcpc3_size, }; /* Field description. */