From e950b3453948830c5ce9c2f70d114d0b38a4b4ac Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Wed, 21 Sep 2016 16:56:57 +0100 Subject: [AArch64][SVE 27/32] Add SVE integer immediate operands This patch adds the new SVE integer immediate operands. There are three kinds: - simple signed and unsigned ranges, but with new widths and positions. - 13-bit logical immediates. These have the same form as in base AArch64, but at a different bit position. In the case of the "MOV Zn., #" alias of DUPM, the logical immediate is not allowed to be a valid DUP immediate, since DUP is preferred over DUPM for constants that both instructions can handle. - a new 9-bit arithmetic immediate, of the form "{, LSL #8}". In some contexts the operand is signed and in others it's unsigned. As an extension, we allow shifted immediates to be written as a single integer, e.g. "#256" is equivalent to "#1, LSL #8". We also use the shiftless form as the preferred disassembly, except for the special case of "#0, LSL #8" (a redundant encoding of 0). include/ * opcode/aarch64.h (AARCH64_OPND_SIMM5): New aarch64_opnd. (AARCH64_OPND_SVE_AIMM, AARCH64_OPND_SVE_ASIMM) (AARCH64_OPND_SVE_INV_LIMM, AARCH64_OPND_SVE_LIMM) (AARCH64_OPND_SVE_LIMM_MOV, AARCH64_OPND_SVE_SHLIMM_PRED) (AARCH64_OPND_SVE_SHLIMM_UNPRED, AARCH64_OPND_SVE_SHRIMM_PRED) (AARCH64_OPND_SVE_SHRIMM_UNPRED, AARCH64_OPND_SVE_SIMM5) (AARCH64_OPND_SVE_SIMM5B, AARCH64_OPND_SVE_SIMM6) (AARCH64_OPND_SVE_SIMM8, AARCH64_OPND_SVE_UIMM3) (AARCH64_OPND_SVE_UIMM7, AARCH64_OPND_SVE_UIMM8) (AARCH64_OPND_SVE_UIMM8_53): Likewise. (aarch64_sve_dupm_mov_immediate_p): Declare. opcodes/ * aarch64-tbl.h (AARCH64_OPERANDS): Add entries for the new SVE integer immediate operands. * aarch64-opc.h (FLD_SVE_immN, FLD_SVE_imm3, FLD_SVE_imm5) (FLD_SVE_imm5b, FLD_SVE_imm7, FLD_SVE_imm8, FLD_SVE_imm9) (FLD_SVE_immr, FLD_SVE_imms, FLD_SVE_tszh): New aarch64_field_kinds. * aarch64-opc.c (fields): Add corresponding entries. (operand_general_constraint_met_p): Handle the new SVE integer immediate operands. (aarch64_print_operand): Likewise. (aarch64_sve_dupm_mov_immediate_p): New function. * aarch64-opc-2.c: Regenerate. * aarch64-asm.h (ins_inv_limm, ins_sve_aimm, ins_sve_asimm) (ins_sve_limm_mov, ins_sve_shlimm, ins_sve_shrimm): New inserters. * aarch64-asm.c (aarch64_ins_limm_1): New function, split out from... (aarch64_ins_limm): ...here. (aarch64_ins_inv_limm): New function. (aarch64_ins_sve_aimm): Likewise. (aarch64_ins_sve_asimm): Likewise. (aarch64_ins_sve_limm_mov): Likewise. (aarch64_ins_sve_shlimm): Likewise. (aarch64_ins_sve_shrimm): Likewise. * aarch64-asm-2.c: Regenerate. * aarch64-dis.h (ext_inv_limm, ext_sve_aimm, ext_sve_asimm) (ext_sve_limm_mov, ext_sve_shlimm, ext_sve_shrimm): New extractors. * aarch64-dis.c (decode_limm): New function, split out from... (aarch64_ext_limm): ...here. (aarch64_ext_inv_limm): New function. (decode_sve_aimm): Likewise. (aarch64_ext_sve_aimm): Likewise. (aarch64_ext_sve_asimm): Likewise. (aarch64_ext_sve_limm_mov): Likewise. (aarch64_top_bit): Likewise. (aarch64_ext_sve_shlimm): Likewise. (aarch64_ext_sve_shrimm): Likewise. * aarch64-dis-2.c: Regenerate. gas/ * config/tc-aarch64.c (parse_operands): Handle the new SVE integer immediate operands. --- opcodes/aarch64-dis.c | 144 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 127 insertions(+), 17 deletions(-) (limited to 'opcodes/aarch64-dis.c') diff --git a/opcodes/aarch64-dis.c b/opcodes/aarch64-dis.c index ba6befd..ed050cd 100644 --- a/opcodes/aarch64-dis.c +++ b/opcodes/aarch64-dis.c @@ -734,32 +734,21 @@ aarch64_ext_aimm (const aarch64_operand *self ATTRIBUTE_UNUSED, return 1; } -/* Decode logical immediate for e.g. ORR , , #. */ - -int -aarch64_ext_limm (const aarch64_operand *self ATTRIBUTE_UNUSED, - aarch64_opnd_info *info, const aarch64_insn code, - const aarch64_inst *inst ATTRIBUTE_UNUSED) +/* Return true if VALUE is a valid logical immediate encoding, storing the + decoded value in *RESULT if so. ESIZE is the number of bytes in the + decoded immediate. */ +static int +decode_limm (uint32_t esize, aarch64_insn value, int64_t *result) { uint64_t imm, mask; - uint32_t sf; uint32_t N, R, S; unsigned simd_size; - aarch64_insn value; - - value = extract_fields (code, 0, 3, FLD_N, FLD_immr, FLD_imms); - assert (inst->operands[0].qualifier == AARCH64_OPND_QLF_W - || inst->operands[0].qualifier == AARCH64_OPND_QLF_X); - sf = aarch64_get_qualifier_esize (inst->operands[0].qualifier) != 4; /* value is N:immr:imms. */ S = value & 0x3f; R = (value >> 6) & 0x3f; N = (value >> 12) & 0x1; - if (sf == 0 && N == 1) - return 0; - /* The immediate value is S+1 bits to 1, left rotated by SIMDsize - R (in other words, right rotated by R), then replicated. */ if (N != 0) @@ -782,6 +771,10 @@ aarch64_ext_limm (const aarch64_operand *self ATTRIBUTE_UNUSED, /* Top bits are IGNORED. */ R &= simd_size - 1; } + + if (simd_size > esize * 8) + return 0; + /* NOTE: if S = simd_size - 1 we get 0xf..f which is rejected. */ if (S == simd_size - 1) return 0; @@ -803,8 +796,35 @@ aarch64_ext_limm (const aarch64_operand *self ATTRIBUTE_UNUSED, default: assert (0); return 0; } - info->imm.value = sf ? imm : imm & 0xffffffff; + *result = imm & ~((uint64_t) -1 << (esize * 4) << (esize * 4)); + + return 1; +} + +/* Decode a logical immediate for e.g. ORR , , #. */ +int +aarch64_ext_limm (const aarch64_operand *self, + aarch64_opnd_info *info, const aarch64_insn code, + const aarch64_inst *inst) +{ + uint32_t esize; + aarch64_insn value; + + value = extract_fields (code, 0, 3, self->fields[0], self->fields[1], + self->fields[2]); + esize = aarch64_get_qualifier_esize (inst->operands[0].qualifier); + return decode_limm (esize, value, &info->imm.value); +} +/* Decode a logical immediate for the BIC alias of AND (etc.). */ +int +aarch64_ext_inv_limm (const aarch64_operand *self, + aarch64_opnd_info *info, const aarch64_insn code, + const aarch64_inst *inst) +{ + if (!aarch64_ext_limm (self, info, code, inst)) + return 0; + info->imm.value = ~info->imm.value; return 1; } @@ -1404,6 +1424,47 @@ aarch64_ext_sve_addr_zz_uxtw (const aarch64_operand *self, return aarch64_ext_sve_addr_zz (self, info, code, AARCH64_MOD_UXTW); } +/* Finish decoding an SVE arithmetic immediate, given that INFO already + has the raw field value and that the low 8 bits decode to VALUE. */ +static int +decode_sve_aimm (aarch64_opnd_info *info, int64_t value) +{ + info->shifter.kind = AARCH64_MOD_LSL; + info->shifter.amount = 0; + if (info->imm.value & 0x100) + { + if (value == 0) + /* Decode 0x100 as #0, LSL #8. */ + info->shifter.amount = 8; + else + value *= 256; + } + info->shifter.operator_present = (info->shifter.amount != 0); + info->shifter.amount_present = (info->shifter.amount != 0); + info->imm.value = value; + return 1; +} + +/* Decode an SVE ADD/SUB immediate. */ +int +aarch64_ext_sve_aimm (const aarch64_operand *self, + aarch64_opnd_info *info, const aarch64_insn code, + const aarch64_inst *inst) +{ + return (aarch64_ext_imm (self, info, code, inst) + && decode_sve_aimm (info, (uint8_t) info->imm.value)); +} + +/* Decode an SVE CPY/DUP immediate. */ +int +aarch64_ext_sve_asimm (const aarch64_operand *self, + aarch64_opnd_info *info, const aarch64_insn code, + const aarch64_inst *inst) +{ + return (aarch64_ext_imm (self, info, code, inst) + && decode_sve_aimm (info, (int8_t) info->imm.value)); +} + /* Decode Zn[MM], where MM has a 7-bit triangular encoding. The fields array specifies which field to use for Zn. MM is encoded in the concatenation of imm5 and SVE_tszh, with imm5 being the less @@ -1425,6 +1486,17 @@ aarch64_ext_sve_index (const aarch64_operand *self, return 1; } +/* Decode a logical immediate for the MOV alias of SVE DUPM. */ +int +aarch64_ext_sve_limm_mov (const aarch64_operand *self, + aarch64_opnd_info *info, const aarch64_insn code, + const aarch64_inst *inst) +{ + int esize = aarch64_get_qualifier_esize (inst->operands[0].qualifier); + return (aarch64_ext_limm (self, info, code, inst) + && aarch64_sve_dupm_mov_immediate_p (info->imm.value, esize)); +} + /* Decode {Zn. - Zm.}. The fields array specifies which field to use for Zn. The opcode-dependent value specifies the number of registers in the list. */ @@ -1457,6 +1529,44 @@ aarch64_ext_sve_scale (const aarch64_operand *self, info->shifter.amount_present = (val != 0); return 1; } + +/* Return the top set bit in VALUE, which is expected to be relatively + small. */ +static uint64_t +get_top_bit (uint64_t value) +{ + while ((value & -value) != value) + value -= value & -value; + return value; +} + +/* Decode an SVE shift-left immediate. */ +int +aarch64_ext_sve_shlimm (const aarch64_operand *self, + aarch64_opnd_info *info, const aarch64_insn code, + const aarch64_inst *inst) +{ + if (!aarch64_ext_imm (self, info, code, inst) + || info->imm.value == 0) + return 0; + + info->imm.value -= get_top_bit (info->imm.value); + return 1; +} + +/* Decode an SVE shift-right immediate. */ +int +aarch64_ext_sve_shrimm (const aarch64_operand *self, + aarch64_opnd_info *info, const aarch64_insn code, + const aarch64_inst *inst) +{ + if (!aarch64_ext_imm (self, info, code, inst) + || info->imm.value == 0) + return 0; + + info->imm.value = get_top_bit (info->imm.value) * 2 - info->imm.value; + return 1; +} /* Bitfields that are commonly used to encode certain operands' information may be partially used as part of the base opcode in some instructions. -- cgit v1.1