summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/ChangeLog7
-rw-r--r--include/opcode/aarch64.h12
-rw-r--r--opcodes/ChangeLog12
-rw-r--r--opcodes/aarch64-asm.c84
-rw-r--r--opcodes/aarch64-dis.c107
-rw-r--r--opcodes/aarch64-opc.c7
-rw-r--r--opcodes/aarch64-opc.h7
7 files changed, 236 insertions, 0 deletions
diff --git a/include/ChangeLog b/include/ChangeLog
index 2bde1625bd7..0db1cbb9dc5 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,5 +1,12 @@
2016-09-21 Richard Sandiford <richard.sandiford@arm.com>
+ * opcode/aarch64.h (sve_cpy, sve_index, sve_limm, sve_misc)
+ (sve_movprfx, sve_pred_zm, sve_shift_pred, sve_shift_unpred)
+ (sve_size_bhs, sve_size_bhsd, sve_size_hsd, sve_size_sd): New
+ aarch64_insn_classes.
+
+2016-09-21 Richard Sandiford <richard.sandiford@arm.com>
+
* opcode/aarch64.h (AARCH64_OPND_SVE_Rm): New aarch64_opnd.
(AARCH64_OPND_SVE_Rn_SP, AARCH64_OPND_SVE_VZn, AARCH64_OPND_SVE_Vd)
(AARCH64_OPND_SVE_Vm, AARCH64_OPND_SVE_Vn): Likewise.
diff --git a/include/opcode/aarch64.h b/include/opcode/aarch64.h
index 8d3fb21fd0e..01e6b2ce790 100644
--- a/include/opcode/aarch64.h
+++ b/include/opcode/aarch64.h
@@ -485,6 +485,18 @@ enum aarch64_insn_class
movewide,
pcreladdr,
ic_system,
+ sve_cpy,
+ sve_index,
+ sve_limm,
+ sve_misc,
+ sve_movprfx,
+ sve_pred_zm,
+ sve_shift_pred,
+ sve_shift_unpred,
+ sve_size_bhs,
+ sve_size_bhsd,
+ sve_size_hsd,
+ sve_size_sd,
testbranch,
};
diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog
index 967de6f3d13..86705872426 100644
--- a/opcodes/ChangeLog
+++ b/opcodes/ChangeLog
@@ -1,5 +1,17 @@
2016-09-21 Richard Sandiford <richard.sandiford@arm.com>
+ * aarch64-opc.h (FLD_SVE_M_4, FLD_SVE_M_14, FLD_SVE_M_16)
+ (FLD_SVE_sz, FLD_SVE_tsz, FLD_SVE_tszl_8, FLD_SVE_tszl_19): New
+ aarch64_field_kinds.
+ * aarch64-opc.c (fields): Add corresponding entries.
+ * aarch64-asm.c (aarch64_get_variant): New function.
+ (aarch64_encode_variant_using_iclass): Likewise.
+ (aarch64_opcode_encode): Call it.
+ * aarch64-dis.c (aarch64_decode_variant_using_iclass): New function.
+ (aarch64_opcode_decode): Call it.
+
+2016-09-21 Richard Sandiford <richard.sandiford@arm.com>
+
* aarch64-tbl.h (AARCH64_OPERANDS): Add entries for the new SVE core
and FP register operands.
* aarch64-opc.h (FLD_SVE_Rm, FLD_SVE_Rn, FLD_SVE_Vd, FLD_SVE_Vm)
diff --git a/opcodes/aarch64-asm.c b/opcodes/aarch64-asm.c
index fd356f44691..78fd27266a6 100644
--- a/opcodes/aarch64-asm.c
+++ b/opcodes/aarch64-asm.c
@@ -1140,6 +1140,27 @@ encode_fcvt (aarch64_inst *inst)
return;
}
+/* Return the index in qualifiers_list that INST is using. Should only
+ be called once the qualifiers are known to be valid. */
+
+static int
+aarch64_get_variant (struct aarch64_inst *inst)
+{
+ int i, nops, variant;
+
+ nops = aarch64_num_of_operands (inst->opcode);
+ for (variant = 0; variant < AARCH64_MAX_QLF_SEQ_NUM; ++variant)
+ {
+ for (i = 0; i < nops; ++i)
+ if (inst->opcode->qualifiers_list[variant][i]
+ != inst->operands[i].qualifier)
+ break;
+ if (i == nops)
+ return variant;
+ }
+ abort ();
+}
+
/* Do miscellaneous encodings that are not common enough to be driven by
flags. */
@@ -1318,6 +1339,65 @@ do_special_encoding (struct aarch64_inst *inst)
DEBUG_TRACE ("exit with coding 0x%x", (uint32_t) inst->value);
}
+/* Some instructions (including all SVE ones) use the instruction class
+ to describe how a qualifiers_list index is represented in the instruction
+ encoding. If INST is such an instruction, encode the chosen qualifier
+ variant. */
+
+static void
+aarch64_encode_variant_using_iclass (struct aarch64_inst *inst)
+{
+ switch (inst->opcode->iclass)
+ {
+ case sve_cpy:
+ insert_fields (&inst->value, aarch64_get_variant (inst),
+ 0, 2, FLD_SVE_M_14, FLD_size);
+ break;
+
+ case sve_index:
+ case sve_shift_pred:
+ case sve_shift_unpred:
+ /* For indices and shift amounts, the variant is encoded as
+ part of the immediate. */
+ break;
+
+ case sve_limm:
+ /* For sve_limm, the .B, .H, and .S forms are just a convenience
+ and depend on the immediate. They don't have a separate
+ encoding. */
+ break;
+
+ case sve_misc:
+ /* sve_misc instructions have only a single variant. */
+ break;
+
+ case sve_movprfx:
+ insert_fields (&inst->value, aarch64_get_variant (inst),
+ 0, 2, FLD_SVE_M_16, FLD_size);
+ break;
+
+ case sve_pred_zm:
+ insert_field (FLD_SVE_M_4, &inst->value, aarch64_get_variant (inst), 0);
+ break;
+
+ case sve_size_bhs:
+ case sve_size_bhsd:
+ insert_field (FLD_size, &inst->value, aarch64_get_variant (inst), 0);
+ break;
+
+ case sve_size_hsd:
+ insert_field (FLD_size, &inst->value, aarch64_get_variant (inst) + 1, 0);
+ break;
+
+ case sve_size_sd:
+ insert_field (FLD_SVE_sz, &inst->value, aarch64_get_variant (inst), 0);
+ break;
+
+ default:
+ break;
+ }
+}
+
/* Converters converting an alias opcode instruction to its real form. */
/* ROR <Wd>, <Ws>, #<shift>
@@ -1686,6 +1766,10 @@ aarch64_opcode_encode (const aarch64_opcode *opcode,
if (opcode_has_special_coder (opcode))
do_special_encoding (inst);
+ /* Possibly use the instruction class to encode the chosen qualifier
+ variant. */
+ aarch64_encode_variant_using_iclass (inst);
+
encoding_exit:
DEBUG_TRACE ("exit with %s", opcode->name);
diff --git a/opcodes/aarch64-dis.c b/opcodes/aarch64-dis.c
index 385286c0c87..f84f216f789 100644
--- a/opcodes/aarch64-dis.c
+++ b/opcodes/aarch64-dis.c
@@ -2444,6 +2444,105 @@ determine_disassembling_preference (struct aarch64_inst *inst)
}
}
+/* Some instructions (including all SVE ones) use the instruction class
+ to describe how a qualifiers_list index is represented in the instruction
+ encoding. If INST is such an instruction, decode the appropriate fields
+ and fill in the operand qualifiers accordingly. Return true if no
+ problems are found. */
+
+static bfd_boolean
+aarch64_decode_variant_using_iclass (aarch64_inst *inst)
+{
+ int i, variant;
+
+ variant = 0;
+ switch (inst->opcode->iclass)
+ {
+ case sve_cpy:
+ variant = extract_fields (inst->value, 0, 2, FLD_size, FLD_SVE_M_14);
+ break;
+
+ case sve_index:
+ i = extract_field (FLD_SVE_tsz, inst->value, 0);
+ if (i == 0)
+ return FALSE;
+ while ((i & 1) == 0)
+ {
+ i >>= 1;
+ variant += 1;
+ }
+ break;
+
+ case sve_limm:
+ /* Pick the smallest applicable element size. */
+ if ((inst->value & 0x20600) == 0x600)
+ variant = 0;
+ else if ((inst->value & 0x20400) == 0x400)
+ variant = 1;
+ else if ((inst->value & 0x20000) == 0)
+ variant = 2;
+ else
+ variant = 3;
+ break;
+
+ case sve_misc:
+ /* sve_misc instructions have only a single variant. */
+ break;
+
+ case sve_movprfx:
+ variant = extract_fields (inst->value, 0, 2, FLD_size, FLD_SVE_M_16);
+ break;
+
+ case sve_pred_zm:
+ variant = extract_field (FLD_SVE_M_4, inst->value, 0);
+ break;
+
+ case sve_shift_pred:
+ i = extract_fields (inst->value, 0, 2, FLD_SVE_tszh, FLD_SVE_tszl_8);
+ sve_shift:
+ if (i == 0)
+ return FALSE;
+ while (i != 1)
+ {
+ i >>= 1;
+ variant += 1;
+ }
+ break;
+
+ case sve_shift_unpred:
+ i = extract_fields (inst->value, 0, 2, FLD_SVE_tszh, FLD_SVE_tszl_19);
+ goto sve_shift;
+
+ case sve_size_bhs:
+ variant = extract_field (FLD_size, inst->value, 0);
+ if (variant >= 3)
+ return FALSE;
+ break;
+
+ case sve_size_bhsd:
+ variant = extract_field (FLD_size, inst->value, 0);
+ break;
+
+ case sve_size_hsd:
+ i = extract_field (FLD_size, inst->value, 0);
+ if (i < 1)
+ return FALSE;
+ variant = i - 1;
+ break;
+
+ case sve_size_sd:
+ variant = extract_field (FLD_SVE_sz, inst->value, 0);
+ break;
+
+ default:
+ /* No mapping between instruction class and qualifiers. */
+ return TRUE;
+ }
+
+ for (i = 0; i < AARCH64_MAX_OPND_NUM; ++i)
+ inst->operands[i].qualifier = inst->opcode->qualifiers_list[variant][i];
+ return TRUE;
+}
/* Decode the CODE according to OPCODE; fill INST. Return 0 if the decoding
fails, which meanes that CODE is not an instruction of OPCODE; otherwise
return 1.
@@ -2491,6 +2590,14 @@ aarch64_opcode_decode (const aarch64_opcode *opcode, const aarch64_insn code,
goto decode_fail;
}
+ /* Possibly use the instruction class to determine the correct
+ qualifier. */
+ if (!aarch64_decode_variant_using_iclass (inst))
+ {
+ DEBUG_TRACE ("iclass-based decoder FAIL");
+ goto decode_fail;
+ }
+
/* Call operand decoders. */
for (i = 0; i < AARCH64_MAX_OPND_NUM; ++i)
{
diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c
index 47c50797fb5..d22e419e421 100644
--- a/opcodes/aarch64-opc.c
+++ b/opcodes/aarch64-opc.c
@@ -264,6 +264,9 @@ const aarch64_field fields[] =
{ 31, 1 }, /* b5: in the test bit and branch instructions. */
{ 19, 5 }, /* b40: in the test bit and branch instructions. */
{ 10, 6 }, /* scale: in the fixed-point scalar to fp converting inst. */
+ { 4, 1 }, /* SVE_M_4: Merge/zero select, bit 4. */
+ { 14, 1 }, /* SVE_M_14: Merge/zero select, bit 14. */
+ { 16, 1 }, /* SVE_M_16: Merge/zero select, bit 16. */
{ 17, 1 }, /* SVE_N: SVE equivalent of N. */
{ 0, 4 }, /* SVE_Pd: p0-p15, bits [3,0]. */
{ 10, 3 }, /* SVE_Pg3: p0-p7, bits [12,10]. */
@@ -299,7 +302,11 @@ const aarch64_field fields[] =
{ 10, 2 }, /* SVE_msz: 2-bit shift amount for ADR. */
{ 5, 5 }, /* SVE_pattern: vector pattern enumeration. */
{ 0, 4 }, /* SVE_prfop: prefetch operation for SVE PRF[BHWD]. */
+ { 22, 1 }, /* SVE_sz: 1-bit element size select. */
+ { 16, 4 }, /* SVE_tsz: triangular size select. */
{ 22, 2 }, /* SVE_tszh: triangular size select high, bits [23,22]. */
+ { 8, 2 }, /* SVE_tszl_8: triangular size select low, bits [9,8]. */
+ { 19, 2 }, /* SVE_tszl_19: triangular size select low, bits [20,19]. */
{ 14, 1 }, /* SVE_xs_14: UXTW/SXTW select (bit 14). */
{ 22, 1 } /* SVE_xs_22: UXTW/SXTW select (bit 22). */
};
diff --git a/opcodes/aarch64-opc.h b/opcodes/aarch64-opc.h
index a7654d004b1..0c3d90e73cf 100644
--- a/opcodes/aarch64-opc.h
+++ b/opcodes/aarch64-opc.h
@@ -91,6 +91,9 @@ enum aarch64_field_kind
FLD_b5,
FLD_b40,
FLD_scale,
+ FLD_SVE_M_4,
+ FLD_SVE_M_14,
+ FLD_SVE_M_16,
FLD_SVE_N,
FLD_SVE_Pd,
FLD_SVE_Pg3,
@@ -126,7 +129,11 @@ enum aarch64_field_kind
FLD_SVE_msz,
FLD_SVE_pattern,
FLD_SVE_prfop,
+ FLD_SVE_sz,
+ FLD_SVE_tsz,
FLD_SVE_tszh,
+ FLD_SVE_tszl_8,
+ FLD_SVE_tszl_19,
FLD_SVE_xs_14,
FLD_SVE_xs_22,
};