@@ -1261,7 +1261,9 @@ extern const aarch64_opcode aarch64_opcode_table[];
allow. This impacts the constraintts on assembly but yelds no
impact on disassembly. */
#define F_OPD_NARROW (1ULL << 33)
-/* Next bit is 34. */
+/* RCPC3 instruction has the field of 'size'. */
+#define F_RCPC3_SIZE (1ULL << 34)
+/* Next bit is 35. */
/* Instruction constraints. */
/* This instruction has a predication constraint on the instruction at PC+4. */
@@ -1328,7 +1330,7 @@ static inline bool
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)) != 0;
+ | F_GPRSIZE_IN_Q | F_LDS_SIZE | F_MISC | F_N | F_COND | F_RCPC3_SIZE)) != 0;
}
struct aarch64_name_value_pair
@@ -702,6 +702,24 @@ aarch64_ins_addr_offset (const aarch64_operand *self ATTRIBUTE_UNUSED,
return true;
}
+/* Encode the address operand for e.g.
+ stlur <Xt>, [<Xn|SP>{, <amount>}]. */
+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 <Xt>, [<Xn|SP>, #<simm>]!. */
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 <Xt>, <Xt2> [<Xn|SP>, #<simm>]
+ and STILP <Xt>, <Xt2> [<Xn|SP>], #<simm>.*/
+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 <Xt>, [<Xn|SP>{, #<simm>}]. */
bool
aarch64_ins_addr_simm10 (const aarch64_operand *self,
@@ -1858,6 +1898,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)
@@ -112,6 +112,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
@@ -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 <Xs>, <Xt>, [<Xn|SP>{,#-16}]! and
+ LIDAP <Xs>, <Xt>, [<Xn|SP>]{,#-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 <Xt>, [<Xn|SP>{, <amount>}]. */
bool
@@ -2465,6 +2529,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);
@@ -136,6 +136,9 @@ AARCH64_DECL_OPD_EXTRACTOR (ext_imm_rotate2);
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_rcpc3_addr_opt_offset);
+AARCH64_DECL_OPD_EXTRACTOR (ext_rcpc3_addr_offset);
+
#undef AARCH64_DECL_OPD_EXTRACTOR
@@ -400,6 +400,8 @@ const aarch64_field fields[] =
{ 22, 1 }, /* sz: 1-bit element size select. */
{ 22, 2 }, /* type: floating point type field in fp data inst. */
{ 10, 2 }, /* vldst_size: size field in the AdvSIMD load/store inst. */
+ { 12, 4 }, /* opc2: in rcpc3 ld/st pair inst deciding the pre/post-index. */
+ { 30, 2 }, /* rcpc3_size: in rcpc3 ld/st pair, field controls Rt/Rt2 width. */
};
enum aarch64_operand_class
@@ -210,6 +210,8 @@ enum aarch64_field_kind
FLD_sz,
FLD_type,
FLD_vldst_size,
+ FLD_opc2,
+ FLD_rcpc3_size,
};
/* Field description. */