diff options
author | Richard Sandiford <richard.sandiford@arm.com> | 2016-09-21 16:56:57 +0100 |
---|---|---|
committer | Richard Sandiford <richard.sandiford@arm.com> | 2016-09-21 16:56:57 +0100 |
commit | e950b3453948830c5ce9c2f70d114d0b38a4b4ac (patch) | |
tree | 86d0ac10f2bf7783666d4059419b606d3fbb5a38 /opcodes/aarch64-dis.c | |
parent | 98907a704908c5877d929c57b2ddb2e5f899d9a9 (diff) | |
download | gdb-e950b3453948830c5ce9c2f70d114d0b38a4b4ac.zip gdb-e950b3453948830c5ce9c2f70d114d0b38a4b4ac.tar.gz gdb-e950b3453948830c5ce9c2f70d114d0b38a4b4ac.tar.bz2 |
[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.<T>, #<limm>" alias of DUPM, the logical
immediate <limm> 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 "<imm8>{, 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.
Diffstat (limited to 'opcodes/aarch64-dis.c')
-rw-r--r-- | opcodes/aarch64-dis.c | 144 |
1 files changed, 127 insertions, 17 deletions
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 <Wd|WSP>, <Wn>, #<imm>. */ - -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 <Wd|WSP>, <Wn>, #<imm>. */ +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.<T> - Zm.<T>}. 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. |