[3/8] aarch64: rcpc3: Define address operand fields and inserter/extractors

Message ID 20240112165637.2522719-4-victor.donascimento@arm.com
State Unresolved
Headers
Series None |

Checks

Context Check Description
snail/binutils-gdb-check warning Git am fail log

Commit Message

Victor Do Nascimento Jan. 12, 2024, 4:56 p.m. UTC
  Beyond the need to encode any registers involved in data transfer and
the address base register for load/stores, it is necessary to specify
the data register addressing mode and whether the address register is
to be pre/post-indexed, whereby loads may be post-indexed and stores
pre-indexed with write-back.

The use of a single bit to specify both the indexing mode and indexing
value requires a novel function be written to accommodate this for
address operand insertion in assembly and another for extraction in
disassembly, along with the definition of two insn fields for use with
these instructions.

This therefore defines the following functions:

  - aarch64_ins_rcpc3_addr_opt_offset
  - aarch64_ins_rcpc3_addr_offset
  - aarch64_ext_rcpc3_addr_opt_offset
  - aarch64_ext_rcpc3_addr_offset

It extends the `do_special_{encoding|decoding}' functions and defines
two rcpc3 instruction fields:

  - FLD_opc2
  - FLD_rcpc3_size
---
 include/opcode/aarch64.h |  6 ++-
 opcodes/aarch64-asm.c    | 56 +++++++++++++++++++++++++++
 opcodes/aarch64-asm.h    |  2 +
 opcodes/aarch64-dis.c    | 84 ++++++++++++++++++++++++++++++++++++++++
 opcodes/aarch64-dis.h    |  3 ++
 opcodes/aarch64-opc.c    |  2 +
 opcodes/aarch64-opc.h    |  2 +
 7 files changed, 153 insertions(+), 2 deletions(-)
  

Patch

diff --git a/include/opcode/aarch64.h b/include/opcode/aarch64.h
index fe54de7cffe..dc9c98353d4 100644
--- a/include/opcode/aarch64.h
+++ b/include/opcode/aarch64.h
@@ -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
diff --git a/opcodes/aarch64-asm.c b/opcodes/aarch64-asm.c
index 1db290eea7e..4be60964102 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 <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)
diff --git a/opcodes/aarch64-asm.h b/opcodes/aarch64-asm.h
index a3bf7bda013..0b4ae7625db 100644
--- a/opcodes/aarch64-asm.h
+++ b/opcodes/aarch64-asm.h
@@ -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
 
diff --git a/opcodes/aarch64-dis.c b/opcodes/aarch64-dis.c
index 7e088a93c10..0734c448e32 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 <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);
diff --git a/opcodes/aarch64-dis.h b/opcodes/aarch64-dis.h
index 20387db7b39..2d3af5b3ee3 100644
--- a/opcodes/aarch64-dis.h
+++ b/opcodes/aarch64-dis.h
@@ -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
 
diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c
index bf506546fd0..9d994c12f1a 100644
--- a/opcodes/aarch64-opc.c
+++ b/opcodes/aarch64-opc.c
@@ -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
diff --git a/opcodes/aarch64-opc.h b/opcodes/aarch64-opc.h
index f193a90ecc5..b05aaadb5dc 100644
--- a/opcodes/aarch64-opc.h
+++ b/opcodes/aarch64-opc.h
@@ -210,6 +210,8 @@  enum aarch64_field_kind
   FLD_sz,
   FLD_type,
   FLD_vldst_size,
+  FLD_opc2,
+  FLD_rcpc3_size,
 };
 
 /* Field description.  */