aboutsummaryrefslogtreecommitdiff
path: root/opcodes/aarch64-opc.h
diff options
context:
space:
mode:
Diffstat (limited to 'opcodes/aarch64-opc.h')
-rw-r--r--opcodes/aarch64-opc.h95
1 files changed, 75 insertions, 20 deletions
diff --git a/opcodes/aarch64-opc.h b/opcodes/aarch64-opc.h
index 9ab9bdf..5d544d5 100644
--- a/opcodes/aarch64-opc.h
+++ b/opcodes/aarch64-opc.h
@@ -30,6 +30,10 @@
enum aarch64_field_kind
{
FLD_NIL,
+ FLD_CONST_0,
+ FLD_CONST_00,
+ FLD_CONST_01,
+ FLD_CONST_1,
FLD_CRm,
FLD_CRm_dsb_nxs,
FLD_CRn,
@@ -66,10 +70,12 @@ enum aarch64_field_kind
FLD_SME_Zdn2,
FLD_SME_Zdn4,
FLD_SME_Zm,
+ FLD_SME_Zm17_3,
FLD_SME_Zm2,
FLD_SME_Zm4,
FLD_SME_Zn2,
FLD_SME_Zn4,
+ FLD_SME_Zn6_3,
FLD_SME_ZtT,
FLD_SME_Zt3,
FLD_SME_Zt2,
@@ -133,6 +139,8 @@ enum aarch64_field_kind
FLD_SVE_size,
FLD_SVE_sz,
FLD_SVE_sz2,
+ FLD_SVE_sz3,
+ FLD_SVE_sz4,
FLD_SVE_tsz,
FLD_SVE_tszh,
FLD_SVE_tszl_8,
@@ -160,6 +168,7 @@ enum aarch64_field_kind
FLD_imm2_0,
FLD_imm2_1,
FLD_imm2_2,
+ FLD_imm2_4,
FLD_imm2_8,
FLD_imm2_10,
FLD_imm2_12,
@@ -185,6 +194,7 @@ enum aarch64_field_kind
FLD_imm7,
FLD_imm8,
FLD_imm9,
+ FLD_imm9_5,
FLD_imm12,
FLD_imm14,
FLD_imm16_0,
@@ -239,16 +249,42 @@ enum aarch64_field_kind
FLD_ZA5_4,
};
-/* Field description. */
+/* Field description.
+
+ If is_const is false, this identifies a bitfield in an instruction encoding
+ that has size WIDTH and has its least significant bit at position NUM.
+
+ If is_const is true, this represents the constant bit string of size WIDTH
+ bits stored in the least significant bits of NUM. In this case, the
+ leading 8-WIDTH bits of VALUE must be zero.
+
+ A sequence of fields can be used to describe how instruction operands are
+ represented in the 32-bit instruction encoding.
+
+ For example, consider an instruction operand Zd that is an even numbered
+ register in z16-z30, with the middle three bits of the register number
+ stored in bits [19:17] of the encoding. The register number can then be
+ constructed by concatenating:
+ - a constant bit '1' (represented here as {1, 1, true}),
+ - bits [19:17] of the encoding (represented here as {3, 17, false}), and
+ - a constant bit '0' (represented here as {1, 0, true}).
+ This sequence of fields fully describes both the constraints on which
+ register numbers are valid, and how valid register numbers are represented
+ in the instruction encoding. */
struct aarch64_field
{
- int lsb;
- int width;
+ unsigned int width:8;
+ unsigned int num:7;
+ bool is_const:1;
};
typedef struct aarch64_field aarch64_field;
-extern const aarch64_field fields[];
+#define AARCH64_FIELD(lsb, width) {width, lsb, false}
+#define AARCH64_FIELD_CONST(val, width) {width, val, true}
+#define AARCH64_FIELD_NIL {0, 0, false}
+
+extern const aarch64_field aarch64_fields[];
/* Operand description. */
@@ -262,9 +298,9 @@ struct aarch64_operand
unsigned int flags;
- /* The associated instruction bit-fields; no operand has more than 4
+ /* The associated instruction bit-fields; no operand has more than 5
bit-fields */
- enum aarch64_field_kind fields[5];
+ enum aarch64_field_kind fields[6];
/* Brief description */
const char *desc;
@@ -304,8 +340,7 @@ verify_constraints (const struct aarch64_inst *, const aarch64_insn, bfd_vma,
#undef F_DEPRECATED
#define F_DEPRECATED (1 << 0) /* Deprecated system register. */
-#undef F_ARCHEXT
-#define F_ARCHEXT (1 << 1) /* Architecture dependent system register. */
+/* (1 << 1) Unused. */
#undef F_HASXT
#define F_HASXT (1 << 2) /* System instruction register <Xt>
@@ -326,7 +361,7 @@ verify_constraints (const struct aarch64_inst *, const aarch64_insn, bfd_vma,
#define F_REG_ALIAS (1 << 6) /* Register name aliases another. */
#undef F_REG_128
-#define F_REG_128 (1 << 7) /* System regsister implementable as 128-bit wide. */
+#define F_REG_128 (1 << 7) /* System register implementable as 128-bit wide. */
/* PSTATE field name for the MSR instruction this is encoded in "op1:op2:CRm".
@@ -424,7 +459,7 @@ static inline unsigned
get_operand_field_width (const aarch64_operand *operand, unsigned n)
{
assert (operand->fields[n] != FLD_NIL);
- return fields[operand->fields[n]].width;
+ return aarch64_fields[operand->fields[n]].width;
}
/* Return the total width of the operand *OPERAND. */
@@ -434,7 +469,7 @@ get_operand_fields_width (const aarch64_operand *operand)
int i = 0;
unsigned width = 0;
while (operand->fields[i] != FLD_NIL)
- width += fields[operand->fields[i++]].width;
+ width += aarch64_fields[operand->fields[i++]].width;
assert (width > 0 && width < 32);
return width;
}
@@ -479,10 +514,10 @@ gen_mask (int width)
static inline int
gen_sub_field (enum aarch64_field_kind kind, int lsb_rel, int width, aarch64_field *ret)
{
- const aarch64_field *field = &fields[kind];
+ const aarch64_field *field = &aarch64_fields[kind];
if (lsb_rel < 0 || width <= 0 || lsb_rel + width > field->width)
return 0;
- ret->lsb = field->lsb + lsb_rel;
+ ret->num = field->num + lsb_rel;
ret->width = width;
return 1;
}
@@ -494,10 +529,16 @@ static inline void
insert_field_2 (const aarch64_field *field, aarch64_insn *code,
aarch64_insn value, aarch64_insn mask)
{
- assert (field->width < 32 && field->width >= 1 && field->lsb >= 0
- && field->lsb + field->width <= 32);
+ assert (field->width < 32 && field->width >= 1
+ && (field->is_const ? (field->num < 1 << field->width)
+ : (field->num + field->width <= 32)));
value &= gen_mask (field->width);
- value <<= field->lsb;
+ if (field->is_const)
+ {
+ assert (value == field->num);
+ return;
+ }
+ value <<= field->num;
/* In some opcodes, field can be part of the base opcode, e.g. the size
field in FADD. The following helps avoid corrupt the base opcode. */
value &= ~mask;
@@ -512,9 +553,13 @@ extract_field_2 (const aarch64_field *field, aarch64_insn code,
aarch64_insn mask)
{
aarch64_insn value;
+ /* Check for constant field. */
+ if (field->is_const)
+ return field->num;
+
/* Clear any bit that is a part of the base opcode. */
code &= ~mask;
- value = (code >> field->lsb) & gen_mask (field->width);
+ value = (code >> field->num) & gen_mask (field->width);
return value;
}
@@ -525,7 +570,7 @@ static inline void
insert_field (enum aarch64_field_kind kind, aarch64_insn *code,
aarch64_insn value, aarch64_insn mask)
{
- insert_field_2 (&fields[kind], code, value, mask);
+ insert_field_2 (&aarch64_fields[kind], code, value, mask);
}
/* Extract field KIND of CODE and return the value. MASK can be zero or the
@@ -535,7 +580,7 @@ static inline aarch64_insn
extract_field (enum aarch64_field_kind kind, aarch64_insn code,
aarch64_insn mask)
{
- return extract_field_2 (&fields[kind], code, mask);
+ return extract_field_2 (&aarch64_fields[kind], code, mask);
}
extern aarch64_insn
@@ -551,6 +596,11 @@ static inline int
select_operand_for_sf_field_coding (const aarch64_opcode *opcode)
{
int idx = -1;
+ if (opcode->iclass == fprcvtfloat2int)
+ return 0;
+ else if (opcode->iclass == fprcvtint2float)
+ return 1;
+
if (aarch64_get_operand_class (opcode->operands[0])
== AARCH64_OPND_CLASS_INT_REG)
/* normal case. */
@@ -572,6 +622,11 @@ static inline int
select_operand_for_fptype_field_coding (const aarch64_opcode *opcode)
{
int idx;
+ if (opcode->iclass == fprcvtfloat2int)
+ return 1;
+ else if (opcode->iclass == fprcvtint2float)
+ return 0;
+
if (aarch64_get_operand_class (opcode->operands[1])
== AARCH64_OPND_CLASS_FP_REG)
/* normal case. */
@@ -602,7 +657,7 @@ select_operand_for_scalar_size_field_coding (const aarch64_opcode *opcode)
src_size = aarch64_get_qualifier_esize (opcode->qualifiers_list[0][1]);
if (src_size == dst_size && src_size == 0)
{ assert (0); abort (); }
- /* When the result is not a sisd register or it is a long operantion. */
+ /* When the result is not a sisd register or it is a long operation. */
if (dst_size == 0 || dst_size == src_size << 1)
return 1;
else