This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: [AArch64][SVE 30/32] Add SVE instruction classes
On 23/08/16 10:25, Richard Sandiford wrote:
> The main purpose of the SVE aarch64_insn_classes is to describe how
> an index into an aarch64_opnd_qualifier_seq_t is represented in the
> instruction encoding. Other instructions usually use flags for this
> information, but (a) we're running out of those and (b) the iclass
> would otherwise be unused for SVE.
>
> OK to install?
>
> Thanks,
> Richard
>
>
> include/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.
>
> opcodes/
> * 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.
>
OK
R.
> diff --git a/include/opcode/aarch64.h b/include/opcode/aarch64.h
> index 8d3fb21..01e6b2c 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/aarch64-asm.c b/opcodes/aarch64-asm.c
> index fd356f4..78fd272 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 385286c..f84f216 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 1ad4ccf..2eb2a81 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 a7654d0..0c3d90e 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,
> };
>