2012-08-13 16:52:54 +02:00
|
|
|
|
/* aarch64-dis.c -- AArch64 disassembler.
|
2018-01-03 06:17:27 +01:00
|
|
|
|
Copyright (C) 2009-2018 Free Software Foundation, Inc.
|
2012-08-13 16:52:54 +02:00
|
|
|
|
Contributed by ARM Ltd.
|
|
|
|
|
|
|
|
|
|
This file is part of the GNU opcodes library.
|
|
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify
|
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
|
the Free Software Foundation; either version 3, or (at your option)
|
|
|
|
|
any later version.
|
|
|
|
|
|
|
|
|
|
It is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
|
|
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
|
|
|
License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program; see the file COPYING3. If not,
|
|
|
|
|
see <http://www.gnu.org/licenses/>. */
|
|
|
|
|
|
|
|
|
|
#include "sysdep.h"
|
|
|
|
|
#include "bfd_stdint.h"
|
Don't use print_insn_XXX in GDB
This is a follow-up to
[PATCH 0/6] Unify the disassembler selection in gdb and objdump
https://sourceware.org/ml/binutils/2017-05/msg00192.html
that is, opcodes is able to select the right disassembler, so gdb
doesn't have to select them. Instead, gdb can just use
default_print_insn. As a result, these print_insn_XXX are not used
out of opcodes, so this patch also moves their declarations from
include/dis-asm.h to opcodes/disassemble.h. With this change,
GDB doesn't use any print_insn_XXX directly any more.
gdb:
2017-06-14 Yao Qi <yao.qi@linaro.org>
* aarch64-tdep.c (aarch64_gdb_print_insn): Call
default_print_insn instead of print_insn_aarch64.
* arm-tdep.c (gdb_print_insn_arm): Call
default_print_insn instead of print_insn_big_arm
and print_insn_little_arm.
* i386-tdep.c (i386_print_insn): Call default_print_insn
instead of print_insn_i386.
* ia64-tdep.c (ia64_print_insn): Call
default_print_insn instead of print_insn_ia64.
* mips-tdep.c (gdb_print_insn_mips): Call
default_print_insn instead of print_insn_big_mips
and print_insn_little_mips.
* spu-tdep.c (gdb_print_insn_spu): Call default_print_insn
instead of print_insn_spu.
include:
2017-06-14 Yao Qi <yao.qi@linaro.org>
* dis-asm.h (print_insn_aarch64): Move it to opcodes/disassemble.h.
(print_insn_big_arm, print_insn_big_mips): Likewise.
(print_insn_i386, print_insn_ia64): Likewise.
(print_insn_little_arm, print_insn_little_mips): Likewise.
(print_insn_spu): Likewise.
opcodes:
2017-06-14 Yao Qi <yao.qi@linaro.org>
* aarch64-dis.c: Include disassemble.h instead of dis-asm.h.
* arm-dis.c: Likewise.
* ia64-dis.c: Likewise.
* mips-dis.c: Likewise.
* spu-dis.c: Likewise.
* disassemble.h (print_insn_aarch64): New declaration, moved from
include/dis-asm.h.
(print_insn_big_arm, print_insn_big_mips): Likewise.
(print_insn_i386, print_insn_ia64): Likewise.
(print_insn_little_arm, print_insn_little_mips): Likewise.
2017-06-14 17:28:30 +02:00
|
|
|
|
#include "disassemble.h"
|
2012-08-13 16:52:54 +02:00
|
|
|
|
#include "libiberty.h"
|
|
|
|
|
#include "opintl.h"
|
|
|
|
|
#include "aarch64-dis.h"
|
|
|
|
|
#include "elf-bfd.h"
|
|
|
|
|
|
|
|
|
|
#define ERR_OK 0
|
|
|
|
|
#define ERR_UND -1
|
|
|
|
|
#define ERR_UNP -3
|
|
|
|
|
#define ERR_NYI -5
|
|
|
|
|
|
|
|
|
|
#define INSNLEN 4
|
|
|
|
|
|
|
|
|
|
/* Cached mapping symbol state. */
|
|
|
|
|
enum map_type
|
|
|
|
|
{
|
|
|
|
|
MAP_INSN,
|
|
|
|
|
MAP_DATA
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static enum map_type last_type;
|
|
|
|
|
static int last_mapping_sym = -1;
|
|
|
|
|
static bfd_vma last_mapping_addr = 0;
|
|
|
|
|
|
|
|
|
|
/* Other options */
|
|
|
|
|
static int no_aliases = 0; /* If set disassemble as most general inst. */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
set_default_aarch64_dis_options (struct disassemble_info *info ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
parse_aarch64_dis_option (const char *option, unsigned int len ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
/* Try to match options that are simple flags */
|
|
|
|
|
if (CONST_STRNEQ (option, "no-aliases"))
|
|
|
|
|
{
|
|
|
|
|
no_aliases = 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (CONST_STRNEQ (option, "aliases"))
|
|
|
|
|
{
|
|
|
|
|
no_aliases = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG_AARCH64
|
|
|
|
|
if (CONST_STRNEQ (option, "debug_dump"))
|
|
|
|
|
{
|
|
|
|
|
debug_dump = 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
#endif /* DEBUG_AARCH64 */
|
|
|
|
|
|
|
|
|
|
/* Invalid option. */
|
|
|
|
|
fprintf (stderr, _("Unrecognised disassembler option: %s\n"), option);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
parse_aarch64_dis_options (const char *options)
|
|
|
|
|
{
|
|
|
|
|
const char *option_end;
|
|
|
|
|
|
|
|
|
|
if (options == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
while (*options != '\0')
|
|
|
|
|
{
|
|
|
|
|
/* Skip empty options. */
|
|
|
|
|
if (*options == ',')
|
|
|
|
|
{
|
|
|
|
|
options++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* We know that *options is neither NUL or a comma. */
|
|
|
|
|
option_end = options + 1;
|
|
|
|
|
while (*option_end != ',' && *option_end != '\0')
|
|
|
|
|
option_end++;
|
|
|
|
|
|
|
|
|
|
parse_aarch64_dis_option (options, option_end - options);
|
|
|
|
|
|
|
|
|
|
/* Go on to the next one. If option_end points to a comma, it
|
|
|
|
|
will be skipped above. */
|
|
|
|
|
options = option_end;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Functions doing the instruction disassembling. */
|
|
|
|
|
|
|
|
|
|
/* The unnamed arguments consist of the number of fields and information about
|
|
|
|
|
these fields where the VALUE will be extracted from CODE and returned.
|
|
|
|
|
MASK can be zero or the base mask of the opcode.
|
|
|
|
|
|
|
|
|
|
N.B. the fields are required to be in such an order than the most signficant
|
|
|
|
|
field for VALUE comes the first, e.g. the <index> in
|
|
|
|
|
SQDMLAL <Va><d>, <Vb><n>, <Vm>.<Ts>[<index>]
|
2013-08-23 09:54:19 +02:00
|
|
|
|
is encoded in H:L:M in some cases, the fields H:L:M should be passed in
|
2012-08-13 16:52:54 +02:00
|
|
|
|
the order of H, L, M. */
|
|
|
|
|
|
[AArch64][SVE 31/32] Add SVE instructions
This patch adds the SVE instruction definitions and associated OP_*
enum values.
include/
* opcode/aarch64.h (AARCH64_FEATURE_SVE): New macro.
(OP_MOV_P_P, OP_MOV_Z_P_Z, OP_MOV_Z_V, OP_MOV_Z_Z, OP_MOV_Z_Zi)
(OP_MOVM_P_P_P, OP_MOVS_P_P, OP_MOVZS_P_P_P, OP_MOVZ_P_P_P)
(OP_NOTS_P_P_P_Z, OP_NOT_P_P_P_Z): New aarch64_ops.
opcodes/
* aarch64-tbl.h (OP_SVE_B, OP_SVE_BB, OP_SVE_BBBU, OP_SVE_BMB)
(OP_SVE_BPB, OP_SVE_BUB, OP_SVE_BUBB, OP_SVE_BUU, OP_SVE_BZ)
(OP_SVE_BZB, OP_SVE_BZBB, OP_SVE_BZU, OP_SVE_DD, OP_SVE_DDD)
(OP_SVE_DMD, OP_SVE_DMH, OP_SVE_DMS, OP_SVE_DU, OP_SVE_DUD, OP_SVE_DUU)
(OP_SVE_DUV_BHS, OP_SVE_DUV_BHSD, OP_SVE_DZD, OP_SVE_DZU, OP_SVE_HB)
(OP_SVE_HMD, OP_SVE_HMS, OP_SVE_HU, OP_SVE_HUU, OP_SVE_HZU, OP_SVE_RR)
(OP_SVE_RURV_BHSD, OP_SVE_RUV_BHSD, OP_SVE_SMD, OP_SVE_SMH, OP_SVE_SMS)
(OP_SVE_SU, OP_SVE_SUS, OP_SVE_SUU, OP_SVE_SZS, OP_SVE_SZU, OP_SVE_UB)
(OP_SVE_UUD, OP_SVE_UUS, OP_SVE_VMR_BHSD, OP_SVE_VMU_SD)
(OP_SVE_VMVD_BHS, OP_SVE_VMVU_BHSD, OP_SVE_VMVU_SD, OP_SVE_VMVV_BHSD)
(OP_SVE_VMVV_SD, OP_SVE_VMV_BHSD, OP_SVE_VMV_HSD, OP_SVE_VMV_SD)
(OP_SVE_VM_SD, OP_SVE_VPU_BHSD, OP_SVE_VPV_BHSD, OP_SVE_VRR_BHSD)
(OP_SVE_VRU_BHSD, OP_SVE_VR_BHSD, OP_SVE_VUR_BHSD, OP_SVE_VUU_BHSD)
(OP_SVE_VUVV_BHSD, OP_SVE_VUVV_SD, OP_SVE_VUV_BHSD, OP_SVE_VUV_SD)
(OP_SVE_VU_BHSD, OP_SVE_VU_HSD, OP_SVE_VU_SD, OP_SVE_VVD_BHS)
(OP_SVE_VVU_BHSD, OP_SVE_VVVU_SD, OP_SVE_VVV_BHSD, OP_SVE_VVV_SD)
(OP_SVE_VV_BHSD, OP_SVE_VV_HSD_BHS, OP_SVE_VV_SD, OP_SVE_VWW_BHSD)
(OP_SVE_VXX_BHSD, OP_SVE_VZVD_BHS, OP_SVE_VZVU_BHSD, OP_SVE_VZVV_BHSD)
(OP_SVE_VZVV_SD, OP_SVE_VZV_SD, OP_SVE_V_SD, OP_SVE_WU, OP_SVE_WV_BHSD)
(OP_SVE_XU, OP_SVE_XUV_BHSD, OP_SVE_XVW_BHSD, OP_SVE_XV_BHSD)
(OP_SVE_XWU, OP_SVE_XXU): New macros.
(aarch64_feature_sve): New variable.
(SVE): New macro.
(_SVE_INSN): Likewise.
(aarch64_opcode_table): Add SVE instructions.
* aarch64-opc.h (extract_fields): Declare.
* aarch64-opc-2.c: Regenerate.
* aarch64-asm.c (do_misc_encoding): Handle the new SVE aarch64_ops.
* aarch64-asm-2.c: Regenerate.
* aarch64-dis.c (extract_fields): Make global.
(do_misc_decoding): Handle the new SVE aarch64_ops.
* aarch64-dis-2.c: Regenerate.
gas/
* doc/c-aarch64.texi: Document the "sve" feature.
* config/tc-aarch64.c (REG_TYPE_R_Z_BHSDQ_VZP): New register type.
(get_reg_expected_msg): Handle it.
(parse_operands): When parsing operands of an SVE instruction,
disallow immediates that match REG_TYPE_R_Z_BHSDQ_VZP.
(aarch64_features): Add an entry for SVE.
2016-09-21 17:58:48 +02:00
|
|
|
|
aarch64_insn
|
2012-08-13 16:52:54 +02:00
|
|
|
|
extract_fields (aarch64_insn code, aarch64_insn mask, ...)
|
|
|
|
|
{
|
|
|
|
|
uint32_t num;
|
|
|
|
|
const aarch64_field *field;
|
|
|
|
|
enum aarch64_field_kind kind;
|
|
|
|
|
va_list va;
|
|
|
|
|
|
|
|
|
|
va_start (va, mask);
|
|
|
|
|
num = va_arg (va, uint32_t);
|
|
|
|
|
assert (num <= 5);
|
|
|
|
|
aarch64_insn value = 0x0;
|
|
|
|
|
while (num--)
|
|
|
|
|
{
|
|
|
|
|
kind = va_arg (va, enum aarch64_field_kind);
|
|
|
|
|
field = &fields[kind];
|
|
|
|
|
value <<= field->width;
|
|
|
|
|
value |= extract_field (kind, code, mask);
|
|
|
|
|
}
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-21 17:51:16 +02:00
|
|
|
|
/* Extract the value of all fields in SELF->fields from instruction CODE.
|
|
|
|
|
The least significant bit comes from the final field. */
|
|
|
|
|
|
|
|
|
|
static aarch64_insn
|
|
|
|
|
extract_all_fields (const aarch64_operand *self, aarch64_insn code)
|
|
|
|
|
{
|
|
|
|
|
aarch64_insn value;
|
|
|
|
|
unsigned int i;
|
|
|
|
|
enum aarch64_field_kind kind;
|
|
|
|
|
|
|
|
|
|
value = 0;
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE (self->fields) && self->fields[i] != FLD_NIL; ++i)
|
|
|
|
|
{
|
|
|
|
|
kind = self->fields[i];
|
|
|
|
|
value <<= fields[kind].width;
|
|
|
|
|
value |= extract_field (kind, code, 0);
|
|
|
|
|
}
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-13 16:52:54 +02:00
|
|
|
|
/* Sign-extend bit I of VALUE. */
|
|
|
|
|
static inline int32_t
|
|
|
|
|
sign_extend (aarch64_insn value, unsigned i)
|
|
|
|
|
{
|
|
|
|
|
uint32_t ret = value;
|
|
|
|
|
|
|
|
|
|
assert (i < 32);
|
|
|
|
|
if ((value >> i) & 0x1)
|
|
|
|
|
{
|
|
|
|
|
uint32_t val = (uint32_t)(-1) << i;
|
|
|
|
|
ret = ret | val;
|
|
|
|
|
}
|
|
|
|
|
return (int32_t) ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* N.B. the following inline helpfer functions create a dependency on the
|
|
|
|
|
order of operand qualifier enumerators. */
|
|
|
|
|
|
|
|
|
|
/* Given VALUE, return qualifier for a general purpose register. */
|
|
|
|
|
static inline enum aarch64_opnd_qualifier
|
|
|
|
|
get_greg_qualifier_from_value (aarch64_insn value)
|
|
|
|
|
{
|
|
|
|
|
enum aarch64_opnd_qualifier qualifier = AARCH64_OPND_QLF_W + value;
|
|
|
|
|
assert (value <= 0x1
|
|
|
|
|
&& aarch64_get_qualifier_standard_value (qualifier) == value);
|
|
|
|
|
return qualifier;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-14 18:27:52 +01:00
|
|
|
|
/* Given VALUE, return qualifier for a vector register. This does not support
|
|
|
|
|
decoding instructions that accept the 2H vector type. */
|
|
|
|
|
|
2012-08-13 16:52:54 +02:00
|
|
|
|
static inline enum aarch64_opnd_qualifier
|
|
|
|
|
get_vreg_qualifier_from_value (aarch64_insn value)
|
|
|
|
|
{
|
|
|
|
|
enum aarch64_opnd_qualifier qualifier = AARCH64_OPND_QLF_V_8B + value;
|
|
|
|
|
|
2015-12-14 18:27:52 +01:00
|
|
|
|
/* Instructions using vector type 2H should not call this function. Skip over
|
|
|
|
|
the 2H qualifier. */
|
|
|
|
|
if (qualifier >= AARCH64_OPND_QLF_V_2H)
|
|
|
|
|
qualifier += 1;
|
|
|
|
|
|
2012-08-13 16:52:54 +02:00
|
|
|
|
assert (value <= 0x8
|
|
|
|
|
&& aarch64_get_qualifier_standard_value (qualifier) == value);
|
|
|
|
|
return qualifier;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Given VALUE, return qualifier for an FP or AdvSIMD scalar register. */
|
|
|
|
|
static inline enum aarch64_opnd_qualifier
|
|
|
|
|
get_sreg_qualifier_from_value (aarch64_insn value)
|
|
|
|
|
{
|
|
|
|
|
enum aarch64_opnd_qualifier qualifier = AARCH64_OPND_QLF_S_B + value;
|
|
|
|
|
|
|
|
|
|
assert (value <= 0x4
|
|
|
|
|
&& aarch64_get_qualifier_standard_value (qualifier) == value);
|
|
|
|
|
return qualifier;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Given the instruction in *INST which is probably half way through the
|
|
|
|
|
decoding and our caller wants to know the expected qualifier for operand
|
|
|
|
|
I. Return such a qualifier if we can establish it; otherwise return
|
|
|
|
|
AARCH64_OPND_QLF_NIL. */
|
|
|
|
|
|
|
|
|
|
static aarch64_opnd_qualifier_t
|
|
|
|
|
get_expected_qualifier (const aarch64_inst *inst, int i)
|
|
|
|
|
{
|
|
|
|
|
aarch64_opnd_qualifier_seq_t qualifiers;
|
|
|
|
|
/* Should not be called if the qualifier is known. */
|
|
|
|
|
assert (inst->operands[i].qualifier == AARCH64_OPND_QLF_NIL);
|
|
|
|
|
if (aarch64_find_best_match (inst, inst->opcode->qualifiers_list,
|
|
|
|
|
i, qualifiers))
|
|
|
|
|
return qualifiers[i];
|
|
|
|
|
else
|
|
|
|
|
return AARCH64_OPND_QLF_NIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Operand extractors. */
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_regno (const aarch64_operand *self, aarch64_opnd_info *info,
|
|
|
|
|
const aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
info->reg.regno = extract_field (self->fields[0], code, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-03 15:40:41 +02:00
|
|
|
|
int
|
|
|
|
|
aarch64_ext_regno_pair (const aarch64_operand *self ATTRIBUTE_UNUSED, aarch64_opnd_info *info,
|
|
|
|
|
const aarch64_insn code ATTRIBUTE_UNUSED,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
assert (info->idx == 1
|
|
|
|
|
|| info->idx ==3);
|
|
|
|
|
info->reg.regno = inst->operands[info->idx - 1].reg.regno + 1;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-13 16:52:54 +02:00
|
|
|
|
/* e.g. IC <ic_op>{, <Xt>}. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_regrt_sysins (const aarch64_operand *self, aarch64_opnd_info *info,
|
|
|
|
|
const aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
info->reg.regno = extract_field (self->fields[0], code, 0);
|
|
|
|
|
assert (info->idx == 1
|
|
|
|
|
&& (aarch64_get_operand_class (inst->operands[0].type)
|
|
|
|
|
== AARCH64_OPND_CLASS_SYSTEM));
|
|
|
|
|
/* This will make the constraint checking happy and more importantly will
|
|
|
|
|
help the disassembler determine whether this operand is optional or
|
|
|
|
|
not. */
|
2015-12-10 17:31:35 +01:00
|
|
|
|
info->present = aarch64_sys_ins_reg_has_xt (inst->operands[0].sysins_op);
|
2012-08-13 16:52:54 +02:00
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* e.g. SQDMLAL <Va><d>, <Vb><n>, <Vm>.<Ts>[<index>]. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_reglane (const aarch64_operand *self, aarch64_opnd_info *info,
|
|
|
|
|
const aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
/* regno */
|
|
|
|
|
info->reglane.regno = extract_field (self->fields[0], code,
|
|
|
|
|
inst->opcode->mask);
|
|
|
|
|
|
|
|
|
|
/* Index and/or type. */
|
|
|
|
|
if (inst->opcode->iclass == asisdone
|
|
|
|
|
|| inst->opcode->iclass == asimdins)
|
|
|
|
|
{
|
|
|
|
|
if (info->type == AARCH64_OPND_En
|
|
|
|
|
&& inst->opcode->operands[0] == AARCH64_OPND_Ed)
|
|
|
|
|
{
|
|
|
|
|
unsigned shift;
|
|
|
|
|
/* index2 for e.g. INS <Vd>.<Ts>[<index1>], <Vn>.<Ts>[<index2>]. */
|
|
|
|
|
assert (info->idx == 1); /* Vn */
|
|
|
|
|
aarch64_insn value = extract_field (FLD_imm4, code, 0);
|
|
|
|
|
/* Depend on AARCH64_OPND_Ed to determine the qualifier. */
|
|
|
|
|
info->qualifier = get_expected_qualifier (inst, info->idx);
|
|
|
|
|
shift = get_logsz (aarch64_get_qualifier_esize (info->qualifier));
|
|
|
|
|
info->reglane.index = value >> shift;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* index and type for e.g. DUP <V><d>, <Vn>.<T>[<index>].
|
|
|
|
|
imm5<3:0> <V>
|
|
|
|
|
0000 RESERVED
|
|
|
|
|
xxx1 B
|
|
|
|
|
xx10 H
|
|
|
|
|
x100 S
|
|
|
|
|
1000 D */
|
|
|
|
|
int pos = -1;
|
|
|
|
|
aarch64_insn value = extract_field (FLD_imm5, code, 0);
|
|
|
|
|
while (++pos <= 3 && (value & 0x1) == 0)
|
|
|
|
|
value >>= 1;
|
|
|
|
|
if (pos > 3)
|
|
|
|
|
return 0;
|
|
|
|
|
info->qualifier = get_sreg_qualifier_from_value (pos);
|
|
|
|
|
info->reglane.index = (unsigned) (value >> 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-06-28 12:09:01 +02:00
|
|
|
|
else if (inst->opcode->iclass == dotproduct)
|
|
|
|
|
{
|
|
|
|
|
/* Need information in other operand(s) to help decoding. */
|
|
|
|
|
info->qualifier = get_expected_qualifier (inst, info->idx);
|
|
|
|
|
switch (info->qualifier)
|
|
|
|
|
{
|
2017-12-19 13:05:20 +01:00
|
|
|
|
case AARCH64_OPND_QLF_S_4B:
|
2017-06-28 12:09:01 +02:00
|
|
|
|
/* L:H */
|
|
|
|
|
info->reglane.index = extract_fields (code, 0, 2, FLD_H, FLD_L);
|
|
|
|
|
info->reglane.regno &= 0x1f;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
Adds the new Fields and Operand types for the new instructions in Armv8.4-a.
gas/
* config/tc-aarch64.c (process_omitted_operand):
Add AARCH64_OPND_Va, AARCH64_OPND_SM3_IMM2
and AARCH64_OPND_IMM_2.
(parse_operands): Add AARCH64_OPND_Va, AARCH64_OPND_SM3_IMM2,
AARCH64_OPND_IMM_2, AARCH64_OPND_MASK
and AARCH64_OPND_ADDR_OFFSET.
include/
* opcode/aarch64.h:
(aarch64_opnd): Add AARCH64_OPND_Va, AARCH64_OPND_MASK,
AARCH64_OPND_IMM_2, AARCH64_OPND_ADDR_OFFSET
and AARCH64_OPND_SM3_IMM2.
(aarch64_insn_class): Add cryptosm3 and cryptosm4.
(arch64_feature_set): Make uint64_t.
opcodes/
* aarch64-asm.h (ins_addr_offset): New.
* aarch64-asm.c (aarch64_ins_reglane): Add cryptosm3.
(aarch64_ins_addr_offset): New.
* aarch64-asm-2.c: Regenerate.
* aarch64-dis.h (ext_addr_offset): New.
* aarch64-dis.c (aarch64_ext_reglane): Add cryptosm3.
(aarch64_ext_addr_offset): New.
* aarch64-dis-2.c: Regenerate.
* aarch64-opc.h (aarch64_field_kind): Add FLD_imm6_2,
FLD_imm4_2 and FLD_SM3_imm2.
* aarch64-opc.c (fields): Add FLD_imm6_2,
FLD_imm4_2 and FLD_SM3_imm2.
(operand_general_constraint_met_p): Add AARCH64_OPND_ADDR_OFFSET.
(aarch64_print_operand): Add AARCH64_OPND_Va, AARCH64_OPND_SM3_IMM2,
AARCH64_OPND_MASK, AARCH64_OPND_IMM_2 and AARCH64_OPND_ADDR_OFFSET.
* aarch64-opc-2.c (Va, MASK, IMM_2, ADDR_OFFSET, SM3_IMM2): New.
* aarch64-tbl.h
(aarch64_opcode_table): Add Va, MASK, IMM_2, ADDR_OFFSET, SM3_IMM2.
2017-11-09 16:22:30 +01:00
|
|
|
|
else if (inst->opcode->iclass == cryptosm3)
|
|
|
|
|
{
|
|
|
|
|
/* index for e.g. SM3TT2A <Vd>.4S, <Vn>.4S, <Vm>S[<imm2>]. */
|
|
|
|
|
info->reglane.index = extract_field (FLD_SM3_imm2, code, 0);
|
|
|
|
|
}
|
2012-08-13 16:52:54 +02:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Index only for e.g. SQDMLAL <Va><d>, <Vb><n>, <Vm>.<Ts>[<index>]
|
|
|
|
|
or SQDMLAL <Va><d>, <Vb><n>, <Vm>.<Ts>[<index>]. */
|
|
|
|
|
|
|
|
|
|
/* Need information in other operand(s) to help decoding. */
|
|
|
|
|
info->qualifier = get_expected_qualifier (inst, info->idx);
|
|
|
|
|
switch (info->qualifier)
|
|
|
|
|
{
|
|
|
|
|
case AARCH64_OPND_QLF_S_H:
|
|
|
|
|
/* h:l:m */
|
|
|
|
|
info->reglane.index = extract_fields (code, 0, 3, FLD_H, FLD_L,
|
|
|
|
|
FLD_M);
|
|
|
|
|
info->reglane.regno &= 0xf;
|
|
|
|
|
break;
|
|
|
|
|
case AARCH64_OPND_QLF_S_S:
|
|
|
|
|
/* h:l */
|
|
|
|
|
info->reglane.index = extract_fields (code, 0, 2, FLD_H, FLD_L);
|
|
|
|
|
break;
|
|
|
|
|
case AARCH64_OPND_QLF_S_D:
|
|
|
|
|
/* H */
|
|
|
|
|
info->reglane.index = extract_field (FLD_H, code, 0);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
[AArch64] Add ARMv8.3 FCMLA and FCADD instructions
Add support for FCMLA and FCADD complex arithmetic SIMD instructions.
FCMLA has an indexed element variant where the index range has to be
treated specially because a complex number takes two elements and the
indexed vector size depends on the other operands.
These complex number SIMD instructions are part of ARMv8.3
https://community.arm.com/groups/processors/blog/2016/10/27/armv8-a-architecture-2016-additions
include/
2016-11-18 Szabolcs Nagy <szabolcs.nagy@arm.com>
* opcode/aarch64.h (enum aarch64_opnd): Add AARCH64_OPND_IMM_ROT1,
AARCH64_OPND_IMM_ROT2, AARCH64_OPND_IMM_ROT3.
(enum aarch64_op): Add OP_FCMLA_ELEM.
opcodes/
2016-11-18 Szabolcs Nagy <szabolcs.nagy@arm.com>
* aarch64-tbl.h (QL_V3SAMEHSD_ROT, QL_ELEMENT_ROT): Define.
(aarch64_feature_simd_v8_3, SIMD_V8_3): Define.
(aarch64_opcode_table): Add fcmla and fcadd.
(AARCH64_OPERANDS): Add IMM_ROT{1,2,3}.
* aarch64-asm.h (aarch64_ins_imm_rotate): Declare.
* aarch64-asm.c (aarch64_ins_imm_rotate): Define.
* aarch64-dis.h (aarch64_ext_imm_rotate): Declare.
* aarch64-dis.c (aarch64_ext_imm_rotate): Define.
* aarch64-opc.h (enum aarch64_field_kind): Add FLD_rotate{1,2,3}.
* aarch64-opc.c (fields): Add FLD_rotate{1,2,3}.
(operand_general_constraint_met_p): Rotate and index range check.
(aarch64_print_operand): Handle rotate operand.
* aarch64-asm-2.c: Regenerate.
* aarch64-dis-2.c: Likewise.
* aarch64-opc-2.c: Likewise.
gas/
2016-11-18 Szabolcs Nagy <szabolcs.nagy@arm.com>
* config/tc-aarch64.c (parse_operands): Handle AARCH64_OPND_IMM_ROT*.
* testsuite/gas/aarch64/advsimd-armv8_3.d: New.
* testsuite/gas/aarch64/advsimd-armv8_3.s: New.
* testsuite/gas/aarch64/illegal-fcmla.s: New.
* testsuite/gas/aarch64/illegal-fcmla.l: New.
* testsuite/gas/aarch64/illegal-fcmla.d: New.
2016-11-18 11:02:16 +01:00
|
|
|
|
|
|
|
|
|
if (inst->opcode->op == OP_FCMLA_ELEM)
|
|
|
|
|
{
|
|
|
|
|
/* Complex operand takes two elements. */
|
|
|
|
|
if (info->reglane.index & 1)
|
|
|
|
|
return 0;
|
|
|
|
|
info->reglane.index /= 2;
|
|
|
|
|
}
|
2012-08-13 16:52:54 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_reglist (const aarch64_operand *self, aarch64_opnd_info *info,
|
|
|
|
|
const aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
/* R */
|
|
|
|
|
info->reglist.first_regno = extract_field (self->fields[0], code, 0);
|
|
|
|
|
/* len */
|
|
|
|
|
info->reglist.num_regs = extract_field (FLD_len, code, 0) + 1;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode Rt and opcode fields of Vt in AdvSIMD load/store instructions. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_ldst_reglist (const aarch64_operand *self ATTRIBUTE_UNUSED,
|
|
|
|
|
aarch64_opnd_info *info, const aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst)
|
|
|
|
|
{
|
|
|
|
|
aarch64_insn value;
|
|
|
|
|
/* Number of elements in each structure to be loaded/stored. */
|
|
|
|
|
unsigned expected_num = get_opcode_dependent_value (inst->opcode);
|
|
|
|
|
|
|
|
|
|
struct
|
|
|
|
|
{
|
|
|
|
|
unsigned is_reserved;
|
|
|
|
|
unsigned num_regs;
|
|
|
|
|
unsigned num_elements;
|
|
|
|
|
} data [] =
|
|
|
|
|
{ {0, 4, 4},
|
|
|
|
|
{1, 4, 4},
|
|
|
|
|
{0, 4, 1},
|
|
|
|
|
{0, 4, 2},
|
|
|
|
|
{0, 3, 3},
|
|
|
|
|
{1, 3, 3},
|
|
|
|
|
{0, 3, 1},
|
|
|
|
|
{0, 1, 1},
|
|
|
|
|
{0, 2, 2},
|
|
|
|
|
{1, 2, 2},
|
|
|
|
|
{0, 2, 1},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Rt */
|
|
|
|
|
info->reglist.first_regno = extract_field (FLD_Rt, code, 0);
|
|
|
|
|
/* opcode */
|
|
|
|
|
value = extract_field (FLD_opcode, code, 0);
|
2017-06-15 14:26:54 +02:00
|
|
|
|
/* PR 21595: Check for a bogus value. */
|
|
|
|
|
if (value >= ARRAY_SIZE (data))
|
|
|
|
|
return 0;
|
2012-08-13 16:52:54 +02:00
|
|
|
|
if (expected_num != data[value].num_elements || data[value].is_reserved)
|
|
|
|
|
return 0;
|
|
|
|
|
info->reglist.num_regs = data[value].num_regs;
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode Rt and S fields of Vt in AdvSIMD load single structure to all
|
|
|
|
|
lanes instructions. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_ldst_reglist_r (const aarch64_operand *self ATTRIBUTE_UNUSED,
|
|
|
|
|
aarch64_opnd_info *info, const aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst)
|
|
|
|
|
{
|
|
|
|
|
aarch64_insn value;
|
|
|
|
|
|
|
|
|
|
/* Rt */
|
|
|
|
|
info->reglist.first_regno = extract_field (FLD_Rt, code, 0);
|
|
|
|
|
/* S */
|
|
|
|
|
value = extract_field (FLD_S, code, 0);
|
|
|
|
|
|
|
|
|
|
/* Number of registers is equal to the number of elements in
|
|
|
|
|
each structure to be loaded/stored. */
|
|
|
|
|
info->reglist.num_regs = get_opcode_dependent_value (inst->opcode);
|
|
|
|
|
assert (info->reglist.num_regs >= 1 && info->reglist.num_regs <= 4);
|
|
|
|
|
|
|
|
|
|
/* Except when it is LD1R. */
|
|
|
|
|
if (info->reglist.num_regs == 1 && value == (aarch64_insn) 1)
|
|
|
|
|
info->reglist.num_regs = 2;
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode Q, opcode<2:1>, S, size and Rt fields of Vt in AdvSIMD
|
|
|
|
|
load/store single element instructions. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_ldst_elemlist (const aarch64_operand *self ATTRIBUTE_UNUSED,
|
|
|
|
|
aarch64_opnd_info *info, const aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
aarch64_field field = {0, 0};
|
|
|
|
|
aarch64_insn QSsize; /* fields Q:S:size. */
|
|
|
|
|
aarch64_insn opcodeh2; /* opcode<2:1> */
|
|
|
|
|
|
|
|
|
|
/* Rt */
|
|
|
|
|
info->reglist.first_regno = extract_field (FLD_Rt, code, 0);
|
|
|
|
|
|
|
|
|
|
/* Decode the index, opcode<2:1> and size. */
|
|
|
|
|
gen_sub_field (FLD_asisdlso_opcode, 1, 2, &field);
|
|
|
|
|
opcodeh2 = extract_field_2 (&field, code, 0);
|
|
|
|
|
QSsize = extract_fields (code, 0, 3, FLD_Q, FLD_S, FLD_vldst_size);
|
|
|
|
|
switch (opcodeh2)
|
|
|
|
|
{
|
|
|
|
|
case 0x0:
|
|
|
|
|
info->qualifier = AARCH64_OPND_QLF_S_B;
|
|
|
|
|
/* Index encoded in "Q:S:size". */
|
|
|
|
|
info->reglist.index = QSsize;
|
|
|
|
|
break;
|
|
|
|
|
case 0x1:
|
2014-03-26 19:44:27 +01:00
|
|
|
|
if (QSsize & 0x1)
|
|
|
|
|
/* UND. */
|
|
|
|
|
return 0;
|
2012-08-13 16:52:54 +02:00
|
|
|
|
info->qualifier = AARCH64_OPND_QLF_S_H;
|
|
|
|
|
/* Index encoded in "Q:S:size<1>". */
|
|
|
|
|
info->reglist.index = QSsize >> 1;
|
|
|
|
|
break;
|
|
|
|
|
case 0x2:
|
2014-03-26 19:44:27 +01:00
|
|
|
|
if ((QSsize >> 1) & 0x1)
|
|
|
|
|
/* UND. */
|
|
|
|
|
return 0;
|
2012-08-13 16:52:54 +02:00
|
|
|
|
if ((QSsize & 0x1) == 0)
|
|
|
|
|
{
|
|
|
|
|
info->qualifier = AARCH64_OPND_QLF_S_S;
|
|
|
|
|
/* Index encoded in "Q:S". */
|
|
|
|
|
info->reglist.index = QSsize >> 2;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (extract_field (FLD_S, code, 0))
|
|
|
|
|
/* UND */
|
|
|
|
|
return 0;
|
2014-03-26 19:44:27 +01:00
|
|
|
|
info->qualifier = AARCH64_OPND_QLF_S_D;
|
|
|
|
|
/* Index encoded in "Q". */
|
|
|
|
|
info->reglist.index = QSsize >> 3;
|
2012-08-13 16:52:54 +02:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
info->reglist.has_index = 1;
|
|
|
|
|
info->reglist.num_regs = 0;
|
|
|
|
|
/* Number of registers is equal to the number of elements in
|
|
|
|
|
each structure to be loaded/stored. */
|
|
|
|
|
info->reglist.num_regs = get_opcode_dependent_value (inst->opcode);
|
|
|
|
|
assert (info->reglist.num_regs >= 1 && info->reglist.num_regs <= 4);
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode fields immh:immb and/or Q for e.g.
|
|
|
|
|
SSHR <Vd>.<T>, <Vn>.<T>, #<shift>
|
|
|
|
|
or SSHR <V><d>, <V><n>, #<shift>. */
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_advsimd_imm_shift (const aarch64_operand *self ATTRIBUTE_UNUSED,
|
|
|
|
|
aarch64_opnd_info *info, const aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst)
|
|
|
|
|
{
|
|
|
|
|
int pos;
|
|
|
|
|
aarch64_insn Q, imm, immh;
|
|
|
|
|
enum aarch64_insn_class iclass = inst->opcode->iclass;
|
|
|
|
|
|
|
|
|
|
immh = extract_field (FLD_immh, code, 0);
|
|
|
|
|
if (immh == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
imm = extract_fields (code, 0, 2, FLD_immh, FLD_immb);
|
|
|
|
|
pos = 4;
|
|
|
|
|
/* Get highest set bit in immh. */
|
|
|
|
|
while (--pos >= 0 && (immh & 0x8) == 0)
|
|
|
|
|
immh <<= 1;
|
|
|
|
|
|
|
|
|
|
assert ((iclass == asimdshf || iclass == asisdshf)
|
|
|
|
|
&& (info->type == AARCH64_OPND_IMM_VLSR
|
|
|
|
|
|| info->type == AARCH64_OPND_IMM_VLSL));
|
|
|
|
|
|
|
|
|
|
if (iclass == asimdshf)
|
|
|
|
|
{
|
|
|
|
|
Q = extract_field (FLD_Q, code, 0);
|
|
|
|
|
/* immh Q <T>
|
|
|
|
|
0000 x SEE AdvSIMD modified immediate
|
|
|
|
|
0001 0 8B
|
|
|
|
|
0001 1 16B
|
|
|
|
|
001x 0 4H
|
|
|
|
|
001x 1 8H
|
|
|
|
|
01xx 0 2S
|
|
|
|
|
01xx 1 4S
|
|
|
|
|
1xxx 0 RESERVED
|
|
|
|
|
1xxx 1 2D */
|
|
|
|
|
info->qualifier =
|
|
|
|
|
get_vreg_qualifier_from_value ((pos << 1) | (int) Q);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
info->qualifier = get_sreg_qualifier_from_value (pos);
|
|
|
|
|
|
|
|
|
|
if (info->type == AARCH64_OPND_IMM_VLSR)
|
|
|
|
|
/* immh <shift>
|
|
|
|
|
0000 SEE AdvSIMD modified immediate
|
|
|
|
|
0001 (16-UInt(immh:immb))
|
|
|
|
|
001x (32-UInt(immh:immb))
|
|
|
|
|
01xx (64-UInt(immh:immb))
|
|
|
|
|
1xxx (128-UInt(immh:immb)) */
|
|
|
|
|
info->imm.value = (16 << pos) - imm;
|
|
|
|
|
else
|
|
|
|
|
/* immh:immb
|
|
|
|
|
immh <shift>
|
|
|
|
|
0000 SEE AdvSIMD modified immediate
|
|
|
|
|
0001 (UInt(immh:immb)-8)
|
|
|
|
|
001x (UInt(immh:immb)-16)
|
|
|
|
|
01xx (UInt(immh:immb)-32)
|
|
|
|
|
1xxx (UInt(immh:immb)-64) */
|
|
|
|
|
info->imm.value = imm - (8 << pos);
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode shift immediate for e.g. sshr (imm). */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_shll_imm (const aarch64_operand *self ATTRIBUTE_UNUSED,
|
|
|
|
|
aarch64_opnd_info *info, const aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
int64_t imm;
|
|
|
|
|
aarch64_insn val;
|
|
|
|
|
val = extract_field (FLD_size, code, 0);
|
|
|
|
|
switch (val)
|
|
|
|
|
{
|
|
|
|
|
case 0: imm = 8; break;
|
|
|
|
|
case 1: imm = 16; break;
|
|
|
|
|
case 2: imm = 32; break;
|
|
|
|
|
default: return 0;
|
|
|
|
|
}
|
|
|
|
|
info->imm.value = imm;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode imm for e.g. BFM <Wd>, <Wn>, #<immr>, #<imms>.
|
|
|
|
|
value in the field(s) will be extracted as unsigned immediate value. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_imm (const aarch64_operand *self, aarch64_opnd_info *info,
|
|
|
|
|
const aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
int64_t imm;
|
|
|
|
|
|
2016-09-21 17:51:16 +02:00
|
|
|
|
imm = extract_all_fields (self, code);
|
2012-08-13 16:52:54 +02:00
|
|
|
|
|
|
|
|
|
if (operand_need_sign_extension (self))
|
|
|
|
|
imm = sign_extend (imm, get_operand_fields_width (self) - 1);
|
|
|
|
|
|
|
|
|
|
if (operand_need_shift_by_two (self))
|
|
|
|
|
imm <<= 2;
|
|
|
|
|
|
|
|
|
|
if (info->type == AARCH64_OPND_ADDR_ADRP)
|
|
|
|
|
imm <<= 12;
|
|
|
|
|
|
|
|
|
|
info->imm.value = imm;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode imm and its shifter for e.g. MOVZ <Wd>, #<imm16>{, LSL #<shift>}. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_imm_half (const aarch64_operand *self, aarch64_opnd_info *info,
|
|
|
|
|
const aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
aarch64_ext_imm (self, info, code, inst);
|
|
|
|
|
info->shifter.kind = AARCH64_MOD_LSL;
|
|
|
|
|
info->shifter.amount = extract_field (FLD_hw, code, 0) << 4;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode cmode and "a:b:c:d:e:f:g:h" for e.g.
|
|
|
|
|
MOVI <Vd>.<T>, #<imm8> {, LSL #<amount>}. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_advsimd_imm_modified (const aarch64_operand *self ATTRIBUTE_UNUSED,
|
|
|
|
|
aarch64_opnd_info *info,
|
|
|
|
|
const aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
uint64_t imm;
|
|
|
|
|
enum aarch64_opnd_qualifier opnd0_qualifier = inst->operands[0].qualifier;
|
|
|
|
|
aarch64_field field = {0, 0};
|
|
|
|
|
|
|
|
|
|
assert (info->idx == 1);
|
|
|
|
|
|
|
|
|
|
if (info->type == AARCH64_OPND_SIMD_FPIMM)
|
|
|
|
|
info->imm.is_fp = 1;
|
|
|
|
|
|
|
|
|
|
/* a:b:c:d:e:f:g:h */
|
|
|
|
|
imm = extract_fields (code, 0, 2, FLD_abc, FLD_defgh);
|
|
|
|
|
if (!info->imm.is_fp && aarch64_get_qualifier_esize (opnd0_qualifier) == 8)
|
|
|
|
|
{
|
|
|
|
|
/* Either MOVI <Dd>, #<imm>
|
|
|
|
|
or MOVI <Vd>.2D, #<imm>.
|
|
|
|
|
<imm> is a 64-bit immediate
|
|
|
|
|
'aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffgggggggghhhhhhhh',
|
|
|
|
|
encoded in "a:b:c:d:e:f:g:h". */
|
|
|
|
|
int i;
|
|
|
|
|
unsigned abcdefgh = imm;
|
|
|
|
|
for (imm = 0ull, i = 0; i < 8; i++)
|
|
|
|
|
if (((abcdefgh >> i) & 0x1) != 0)
|
|
|
|
|
imm |= 0xffull << (8 * i);
|
|
|
|
|
}
|
|
|
|
|
info->imm.value = imm;
|
|
|
|
|
|
|
|
|
|
/* cmode */
|
|
|
|
|
info->qualifier = get_expected_qualifier (inst, info->idx);
|
|
|
|
|
switch (info->qualifier)
|
|
|
|
|
{
|
|
|
|
|
case AARCH64_OPND_QLF_NIL:
|
|
|
|
|
/* no shift */
|
|
|
|
|
info->shifter.kind = AARCH64_MOD_NONE;
|
|
|
|
|
return 1;
|
|
|
|
|
case AARCH64_OPND_QLF_LSL:
|
|
|
|
|
/* shift zeros */
|
|
|
|
|
info->shifter.kind = AARCH64_MOD_LSL;
|
|
|
|
|
switch (aarch64_get_qualifier_esize (opnd0_qualifier))
|
|
|
|
|
{
|
|
|
|
|
case 4: gen_sub_field (FLD_cmode, 1, 2, &field); break; /* per word */
|
|
|
|
|
case 2: gen_sub_field (FLD_cmode, 1, 1, &field); break; /* per half */
|
2013-01-17 17:09:44 +01:00
|
|
|
|
case 1: gen_sub_field (FLD_cmode, 1, 0, &field); break; /* per byte */
|
2012-08-13 16:52:54 +02:00
|
|
|
|
default: assert (0); return 0;
|
|
|
|
|
}
|
|
|
|
|
/* 00: 0; 01: 8; 10:16; 11:24. */
|
|
|
|
|
info->shifter.amount = extract_field_2 (&field, code, 0) << 3;
|
|
|
|
|
break;
|
|
|
|
|
case AARCH64_OPND_QLF_MSL:
|
|
|
|
|
/* shift ones */
|
|
|
|
|
info->shifter.kind = AARCH64_MOD_MSL;
|
|
|
|
|
gen_sub_field (FLD_cmode, 0, 1, &field); /* per word */
|
|
|
|
|
info->shifter.amount = extract_field_2 (&field, code, 0) ? 16 : 8;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert (0);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-21 17:51:24 +02:00
|
|
|
|
/* Decode an 8-bit floating-point immediate. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_fpimm (const aarch64_operand *self, aarch64_opnd_info *info,
|
|
|
|
|
const aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
info->imm.value = extract_all_fields (self, code);
|
|
|
|
|
info->imm.is_fp = 1;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
[AArch64] Additional SVE instructions
This patch supports some additions to the SVE architecture prior to
its public release.
include/
* opcode/aarch64.h (AARCH64_OPND_SVE_ADDR_RI_S4x16)
(AARCH64_OPND_SVE_IMM_ROT1, AARCH64_OPND_SVE_IMM_ROT2)
(AARCH64_OPND_SVE_Zm3_INDEX, AARCH64_OPND_SVE_Zm3_22_INDEX)
(AARCH64_OPND_SVE_Zm4_INDEX): New aarch64_opnds.
opcodes/
* aarch64-tbl.h (OP_SVE_HMH, OP_SVE_VMU_HSD, OP_SVE_VMVU_HSD)
(OP_SVE_VMVV_HSD, OP_SVE_VMVVU_HSD, OP_SVE_VM_HSD, OP_SVE_VUVV_HSD)
(OP_SVE_VUV_HSD, OP_SVE_VU_HSD, OP_SVE_VVVU_H, OP_SVE_VVVU_S)
(OP_SVE_VVVU_HSD, OP_SVE_VVV_D, OP_SVE_VVV_D_H, OP_SVE_VVV_H)
(OP_SVE_VVV_HSD, OP_SVE_VVV_S, OP_SVE_VVV_S_B, OP_SVE_VVV_SD_BH)
(OP_SVE_VV_BHSDQ, OP_SVE_VV_HSD, OP_SVE_VZVV_HSD, OP_SVE_VZV_HSD)
(OP_SVE_V_HSD): New macros.
(OP_SVE_VMU_SD, OP_SVE_VMVU_SD, OP_SVE_VM_SD, OP_SVE_VUVV_SD)
(OP_SVE_VU_SD, OP_SVE_VVVU_SD, OP_SVE_VVV_SD, OP_SVE_VZVV_SD)
(OP_SVE_VZV_SD, OP_SVE_V_SD): Delete.
(aarch64_opcode_table): Add new SVE instructions.
(aarch64_opcode_table): Use imm_rotate{1,2} instead of imm_rotate
for rotation operands. Add new SVE operands.
* aarch64-asm.h (ins_sve_addr_ri_s4): New inserter.
(ins_sve_quad_index): Likewise.
(ins_imm_rotate): Split into...
(ins_imm_rotate1, ins_imm_rotate2): ...these two inserters.
* aarch64-asm.c (aarch64_ins_imm_rotate): Split into...
(aarch64_ins_imm_rotate1, aarch64_ins_imm_rotate2): ...these two
functions.
(aarch64_ins_sve_addr_ri_s4): New function.
(aarch64_ins_sve_quad_index): Likewise.
(do_misc_encoding): Handle "MOV Zn.Q, Qm".
* aarch64-asm-2.c: Regenerate.
* aarch64-dis.h (ext_sve_addr_ri_s4): New extractor.
(ext_sve_quad_index): Likewise.
(ext_imm_rotate): Split into...
(ext_imm_rotate1, ext_imm_rotate2): ...these two extractors.
* aarch64-dis.c (aarch64_ext_imm_rotate): Split into...
(aarch64_ext_imm_rotate1, aarch64_ext_imm_rotate2): ...these two
functions.
(aarch64_ext_sve_addr_ri_s4): New function.
(aarch64_ext_sve_quad_index): Likewise.
(aarch64_ext_sve_index): Allow quad indices.
(do_misc_decoding): Likewise.
* aarch64-dis-2.c: Regenerate.
* aarch64-opc.h (FLD_SVE_i3h, FLD_SVE_rot1, FLD_SVE_rot2): New
aarch64_field_kinds.
(OPD_F_OD_MASK): Widen by one bit.
(OPD_F_NO_ZR): Bump accordingly.
(get_operand_field_width): New function.
* aarch64-opc.c (fields): Add new SVE fields.
(operand_general_constraint_met_p): Handle new SVE operands.
(aarch64_print_operand): Likewise.
* aarch64-opc-2.c: Regenerate.
gas/
* doc/c-aarch64.texi: Document that sve implies fp16, simd and compnum.
* config/tc-aarch64.c (parse_vector_type_for_operand): Allow .q
to be used with SVE registers.
(parse_operands): Handle new SVE operands.
(aarch64_features): Make "sve" require F16 rather than FP. Also
require COMPNUM.
* testsuite/gas/aarch64/sve.s: Add tests for new instructions.
Include compnum tests.
* testsuite/gas/aarch64/sve.d: Update accordingly.
* testsuite/gas/aarch64/sve-invalid.s: Add tests for new instructions.
* testsuite/gas/aarch64/sve-invalid.l: Update accordingly. Also
update expected output for new FMOV and MOV alternatives.
2017-02-24 19:29:00 +01:00
|
|
|
|
/* Decode a 1-bit rotate immediate (#90 or #270). */
|
[AArch64] Add ARMv8.3 FCMLA and FCADD instructions
Add support for FCMLA and FCADD complex arithmetic SIMD instructions.
FCMLA has an indexed element variant where the index range has to be
treated specially because a complex number takes two elements and the
indexed vector size depends on the other operands.
These complex number SIMD instructions are part of ARMv8.3
https://community.arm.com/groups/processors/blog/2016/10/27/armv8-a-architecture-2016-additions
include/
2016-11-18 Szabolcs Nagy <szabolcs.nagy@arm.com>
* opcode/aarch64.h (enum aarch64_opnd): Add AARCH64_OPND_IMM_ROT1,
AARCH64_OPND_IMM_ROT2, AARCH64_OPND_IMM_ROT3.
(enum aarch64_op): Add OP_FCMLA_ELEM.
opcodes/
2016-11-18 Szabolcs Nagy <szabolcs.nagy@arm.com>
* aarch64-tbl.h (QL_V3SAMEHSD_ROT, QL_ELEMENT_ROT): Define.
(aarch64_feature_simd_v8_3, SIMD_V8_3): Define.
(aarch64_opcode_table): Add fcmla and fcadd.
(AARCH64_OPERANDS): Add IMM_ROT{1,2,3}.
* aarch64-asm.h (aarch64_ins_imm_rotate): Declare.
* aarch64-asm.c (aarch64_ins_imm_rotate): Define.
* aarch64-dis.h (aarch64_ext_imm_rotate): Declare.
* aarch64-dis.c (aarch64_ext_imm_rotate): Define.
* aarch64-opc.h (enum aarch64_field_kind): Add FLD_rotate{1,2,3}.
* aarch64-opc.c (fields): Add FLD_rotate{1,2,3}.
(operand_general_constraint_met_p): Rotate and index range check.
(aarch64_print_operand): Handle rotate operand.
* aarch64-asm-2.c: Regenerate.
* aarch64-dis-2.c: Likewise.
* aarch64-opc-2.c: Likewise.
gas/
2016-11-18 Szabolcs Nagy <szabolcs.nagy@arm.com>
* config/tc-aarch64.c (parse_operands): Handle AARCH64_OPND_IMM_ROT*.
* testsuite/gas/aarch64/advsimd-armv8_3.d: New.
* testsuite/gas/aarch64/advsimd-armv8_3.s: New.
* testsuite/gas/aarch64/illegal-fcmla.s: New.
* testsuite/gas/aarch64/illegal-fcmla.l: New.
* testsuite/gas/aarch64/illegal-fcmla.d: New.
2016-11-18 11:02:16 +01:00
|
|
|
|
int
|
[AArch64] Additional SVE instructions
This patch supports some additions to the SVE architecture prior to
its public release.
include/
* opcode/aarch64.h (AARCH64_OPND_SVE_ADDR_RI_S4x16)
(AARCH64_OPND_SVE_IMM_ROT1, AARCH64_OPND_SVE_IMM_ROT2)
(AARCH64_OPND_SVE_Zm3_INDEX, AARCH64_OPND_SVE_Zm3_22_INDEX)
(AARCH64_OPND_SVE_Zm4_INDEX): New aarch64_opnds.
opcodes/
* aarch64-tbl.h (OP_SVE_HMH, OP_SVE_VMU_HSD, OP_SVE_VMVU_HSD)
(OP_SVE_VMVV_HSD, OP_SVE_VMVVU_HSD, OP_SVE_VM_HSD, OP_SVE_VUVV_HSD)
(OP_SVE_VUV_HSD, OP_SVE_VU_HSD, OP_SVE_VVVU_H, OP_SVE_VVVU_S)
(OP_SVE_VVVU_HSD, OP_SVE_VVV_D, OP_SVE_VVV_D_H, OP_SVE_VVV_H)
(OP_SVE_VVV_HSD, OP_SVE_VVV_S, OP_SVE_VVV_S_B, OP_SVE_VVV_SD_BH)
(OP_SVE_VV_BHSDQ, OP_SVE_VV_HSD, OP_SVE_VZVV_HSD, OP_SVE_VZV_HSD)
(OP_SVE_V_HSD): New macros.
(OP_SVE_VMU_SD, OP_SVE_VMVU_SD, OP_SVE_VM_SD, OP_SVE_VUVV_SD)
(OP_SVE_VU_SD, OP_SVE_VVVU_SD, OP_SVE_VVV_SD, OP_SVE_VZVV_SD)
(OP_SVE_VZV_SD, OP_SVE_V_SD): Delete.
(aarch64_opcode_table): Add new SVE instructions.
(aarch64_opcode_table): Use imm_rotate{1,2} instead of imm_rotate
for rotation operands. Add new SVE operands.
* aarch64-asm.h (ins_sve_addr_ri_s4): New inserter.
(ins_sve_quad_index): Likewise.
(ins_imm_rotate): Split into...
(ins_imm_rotate1, ins_imm_rotate2): ...these two inserters.
* aarch64-asm.c (aarch64_ins_imm_rotate): Split into...
(aarch64_ins_imm_rotate1, aarch64_ins_imm_rotate2): ...these two
functions.
(aarch64_ins_sve_addr_ri_s4): New function.
(aarch64_ins_sve_quad_index): Likewise.
(do_misc_encoding): Handle "MOV Zn.Q, Qm".
* aarch64-asm-2.c: Regenerate.
* aarch64-dis.h (ext_sve_addr_ri_s4): New extractor.
(ext_sve_quad_index): Likewise.
(ext_imm_rotate): Split into...
(ext_imm_rotate1, ext_imm_rotate2): ...these two extractors.
* aarch64-dis.c (aarch64_ext_imm_rotate): Split into...
(aarch64_ext_imm_rotate1, aarch64_ext_imm_rotate2): ...these two
functions.
(aarch64_ext_sve_addr_ri_s4): New function.
(aarch64_ext_sve_quad_index): Likewise.
(aarch64_ext_sve_index): Allow quad indices.
(do_misc_decoding): Likewise.
* aarch64-dis-2.c: Regenerate.
* aarch64-opc.h (FLD_SVE_i3h, FLD_SVE_rot1, FLD_SVE_rot2): New
aarch64_field_kinds.
(OPD_F_OD_MASK): Widen by one bit.
(OPD_F_NO_ZR): Bump accordingly.
(get_operand_field_width): New function.
* aarch64-opc.c (fields): Add new SVE fields.
(operand_general_constraint_met_p): Handle new SVE operands.
(aarch64_print_operand): Likewise.
* aarch64-opc-2.c: Regenerate.
gas/
* doc/c-aarch64.texi: Document that sve implies fp16, simd and compnum.
* config/tc-aarch64.c (parse_vector_type_for_operand): Allow .q
to be used with SVE registers.
(parse_operands): Handle new SVE operands.
(aarch64_features): Make "sve" require F16 rather than FP. Also
require COMPNUM.
* testsuite/gas/aarch64/sve.s: Add tests for new instructions.
Include compnum tests.
* testsuite/gas/aarch64/sve.d: Update accordingly.
* testsuite/gas/aarch64/sve-invalid.s: Add tests for new instructions.
* testsuite/gas/aarch64/sve-invalid.l: Update accordingly. Also
update expected output for new FMOV and MOV alternatives.
2017-02-24 19:29:00 +01:00
|
|
|
|
aarch64_ext_imm_rotate1 (const aarch64_operand *self, aarch64_opnd_info *info,
|
|
|
|
|
const aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
[AArch64] Add ARMv8.3 FCMLA and FCADD instructions
Add support for FCMLA and FCADD complex arithmetic SIMD instructions.
FCMLA has an indexed element variant where the index range has to be
treated specially because a complex number takes two elements and the
indexed vector size depends on the other operands.
These complex number SIMD instructions are part of ARMv8.3
https://community.arm.com/groups/processors/blog/2016/10/27/armv8-a-architecture-2016-additions
include/
2016-11-18 Szabolcs Nagy <szabolcs.nagy@arm.com>
* opcode/aarch64.h (enum aarch64_opnd): Add AARCH64_OPND_IMM_ROT1,
AARCH64_OPND_IMM_ROT2, AARCH64_OPND_IMM_ROT3.
(enum aarch64_op): Add OP_FCMLA_ELEM.
opcodes/
2016-11-18 Szabolcs Nagy <szabolcs.nagy@arm.com>
* aarch64-tbl.h (QL_V3SAMEHSD_ROT, QL_ELEMENT_ROT): Define.
(aarch64_feature_simd_v8_3, SIMD_V8_3): Define.
(aarch64_opcode_table): Add fcmla and fcadd.
(AARCH64_OPERANDS): Add IMM_ROT{1,2,3}.
* aarch64-asm.h (aarch64_ins_imm_rotate): Declare.
* aarch64-asm.c (aarch64_ins_imm_rotate): Define.
* aarch64-dis.h (aarch64_ext_imm_rotate): Declare.
* aarch64-dis.c (aarch64_ext_imm_rotate): Define.
* aarch64-opc.h (enum aarch64_field_kind): Add FLD_rotate{1,2,3}.
* aarch64-opc.c (fields): Add FLD_rotate{1,2,3}.
(operand_general_constraint_met_p): Rotate and index range check.
(aarch64_print_operand): Handle rotate operand.
* aarch64-asm-2.c: Regenerate.
* aarch64-dis-2.c: Likewise.
* aarch64-opc-2.c: Likewise.
gas/
2016-11-18 Szabolcs Nagy <szabolcs.nagy@arm.com>
* config/tc-aarch64.c (parse_operands): Handle AARCH64_OPND_IMM_ROT*.
* testsuite/gas/aarch64/advsimd-armv8_3.d: New.
* testsuite/gas/aarch64/advsimd-armv8_3.s: New.
* testsuite/gas/aarch64/illegal-fcmla.s: New.
* testsuite/gas/aarch64/illegal-fcmla.l: New.
* testsuite/gas/aarch64/illegal-fcmla.d: New.
2016-11-18 11:02:16 +01:00
|
|
|
|
{
|
|
|
|
|
uint64_t rot = extract_field (self->fields[0], code, 0);
|
[AArch64] Additional SVE instructions
This patch supports some additions to the SVE architecture prior to
its public release.
include/
* opcode/aarch64.h (AARCH64_OPND_SVE_ADDR_RI_S4x16)
(AARCH64_OPND_SVE_IMM_ROT1, AARCH64_OPND_SVE_IMM_ROT2)
(AARCH64_OPND_SVE_Zm3_INDEX, AARCH64_OPND_SVE_Zm3_22_INDEX)
(AARCH64_OPND_SVE_Zm4_INDEX): New aarch64_opnds.
opcodes/
* aarch64-tbl.h (OP_SVE_HMH, OP_SVE_VMU_HSD, OP_SVE_VMVU_HSD)
(OP_SVE_VMVV_HSD, OP_SVE_VMVVU_HSD, OP_SVE_VM_HSD, OP_SVE_VUVV_HSD)
(OP_SVE_VUV_HSD, OP_SVE_VU_HSD, OP_SVE_VVVU_H, OP_SVE_VVVU_S)
(OP_SVE_VVVU_HSD, OP_SVE_VVV_D, OP_SVE_VVV_D_H, OP_SVE_VVV_H)
(OP_SVE_VVV_HSD, OP_SVE_VVV_S, OP_SVE_VVV_S_B, OP_SVE_VVV_SD_BH)
(OP_SVE_VV_BHSDQ, OP_SVE_VV_HSD, OP_SVE_VZVV_HSD, OP_SVE_VZV_HSD)
(OP_SVE_V_HSD): New macros.
(OP_SVE_VMU_SD, OP_SVE_VMVU_SD, OP_SVE_VM_SD, OP_SVE_VUVV_SD)
(OP_SVE_VU_SD, OP_SVE_VVVU_SD, OP_SVE_VVV_SD, OP_SVE_VZVV_SD)
(OP_SVE_VZV_SD, OP_SVE_V_SD): Delete.
(aarch64_opcode_table): Add new SVE instructions.
(aarch64_opcode_table): Use imm_rotate{1,2} instead of imm_rotate
for rotation operands. Add new SVE operands.
* aarch64-asm.h (ins_sve_addr_ri_s4): New inserter.
(ins_sve_quad_index): Likewise.
(ins_imm_rotate): Split into...
(ins_imm_rotate1, ins_imm_rotate2): ...these two inserters.
* aarch64-asm.c (aarch64_ins_imm_rotate): Split into...
(aarch64_ins_imm_rotate1, aarch64_ins_imm_rotate2): ...these two
functions.
(aarch64_ins_sve_addr_ri_s4): New function.
(aarch64_ins_sve_quad_index): Likewise.
(do_misc_encoding): Handle "MOV Zn.Q, Qm".
* aarch64-asm-2.c: Regenerate.
* aarch64-dis.h (ext_sve_addr_ri_s4): New extractor.
(ext_sve_quad_index): Likewise.
(ext_imm_rotate): Split into...
(ext_imm_rotate1, ext_imm_rotate2): ...these two extractors.
* aarch64-dis.c (aarch64_ext_imm_rotate): Split into...
(aarch64_ext_imm_rotate1, aarch64_ext_imm_rotate2): ...these two
functions.
(aarch64_ext_sve_addr_ri_s4): New function.
(aarch64_ext_sve_quad_index): Likewise.
(aarch64_ext_sve_index): Allow quad indices.
(do_misc_decoding): Likewise.
* aarch64-dis-2.c: Regenerate.
* aarch64-opc.h (FLD_SVE_i3h, FLD_SVE_rot1, FLD_SVE_rot2): New
aarch64_field_kinds.
(OPD_F_OD_MASK): Widen by one bit.
(OPD_F_NO_ZR): Bump accordingly.
(get_operand_field_width): New function.
* aarch64-opc.c (fields): Add new SVE fields.
(operand_general_constraint_met_p): Handle new SVE operands.
(aarch64_print_operand): Likewise.
* aarch64-opc-2.c: Regenerate.
gas/
* doc/c-aarch64.texi: Document that sve implies fp16, simd and compnum.
* config/tc-aarch64.c (parse_vector_type_for_operand): Allow .q
to be used with SVE registers.
(parse_operands): Handle new SVE operands.
(aarch64_features): Make "sve" require F16 rather than FP. Also
require COMPNUM.
* testsuite/gas/aarch64/sve.s: Add tests for new instructions.
Include compnum tests.
* testsuite/gas/aarch64/sve.d: Update accordingly.
* testsuite/gas/aarch64/sve-invalid.s: Add tests for new instructions.
* testsuite/gas/aarch64/sve-invalid.l: Update accordingly. Also
update expected output for new FMOV and MOV alternatives.
2017-02-24 19:29:00 +01:00
|
|
|
|
assert (rot < 2U);
|
|
|
|
|
info->imm.value = rot * 180 + 90;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
[AArch64] Add ARMv8.3 FCMLA and FCADD instructions
Add support for FCMLA and FCADD complex arithmetic SIMD instructions.
FCMLA has an indexed element variant where the index range has to be
treated specially because a complex number takes two elements and the
indexed vector size depends on the other operands.
These complex number SIMD instructions are part of ARMv8.3
https://community.arm.com/groups/processors/blog/2016/10/27/armv8-a-architecture-2016-additions
include/
2016-11-18 Szabolcs Nagy <szabolcs.nagy@arm.com>
* opcode/aarch64.h (enum aarch64_opnd): Add AARCH64_OPND_IMM_ROT1,
AARCH64_OPND_IMM_ROT2, AARCH64_OPND_IMM_ROT3.
(enum aarch64_op): Add OP_FCMLA_ELEM.
opcodes/
2016-11-18 Szabolcs Nagy <szabolcs.nagy@arm.com>
* aarch64-tbl.h (QL_V3SAMEHSD_ROT, QL_ELEMENT_ROT): Define.
(aarch64_feature_simd_v8_3, SIMD_V8_3): Define.
(aarch64_opcode_table): Add fcmla and fcadd.
(AARCH64_OPERANDS): Add IMM_ROT{1,2,3}.
* aarch64-asm.h (aarch64_ins_imm_rotate): Declare.
* aarch64-asm.c (aarch64_ins_imm_rotate): Define.
* aarch64-dis.h (aarch64_ext_imm_rotate): Declare.
* aarch64-dis.c (aarch64_ext_imm_rotate): Define.
* aarch64-opc.h (enum aarch64_field_kind): Add FLD_rotate{1,2,3}.
* aarch64-opc.c (fields): Add FLD_rotate{1,2,3}.
(operand_general_constraint_met_p): Rotate and index range check.
(aarch64_print_operand): Handle rotate operand.
* aarch64-asm-2.c: Regenerate.
* aarch64-dis-2.c: Likewise.
* aarch64-opc-2.c: Likewise.
gas/
2016-11-18 Szabolcs Nagy <szabolcs.nagy@arm.com>
* config/tc-aarch64.c (parse_operands): Handle AARCH64_OPND_IMM_ROT*.
* testsuite/gas/aarch64/advsimd-armv8_3.d: New.
* testsuite/gas/aarch64/advsimd-armv8_3.s: New.
* testsuite/gas/aarch64/illegal-fcmla.s: New.
* testsuite/gas/aarch64/illegal-fcmla.l: New.
* testsuite/gas/aarch64/illegal-fcmla.d: New.
2016-11-18 11:02:16 +01:00
|
|
|
|
|
[AArch64] Additional SVE instructions
This patch supports some additions to the SVE architecture prior to
its public release.
include/
* opcode/aarch64.h (AARCH64_OPND_SVE_ADDR_RI_S4x16)
(AARCH64_OPND_SVE_IMM_ROT1, AARCH64_OPND_SVE_IMM_ROT2)
(AARCH64_OPND_SVE_Zm3_INDEX, AARCH64_OPND_SVE_Zm3_22_INDEX)
(AARCH64_OPND_SVE_Zm4_INDEX): New aarch64_opnds.
opcodes/
* aarch64-tbl.h (OP_SVE_HMH, OP_SVE_VMU_HSD, OP_SVE_VMVU_HSD)
(OP_SVE_VMVV_HSD, OP_SVE_VMVVU_HSD, OP_SVE_VM_HSD, OP_SVE_VUVV_HSD)
(OP_SVE_VUV_HSD, OP_SVE_VU_HSD, OP_SVE_VVVU_H, OP_SVE_VVVU_S)
(OP_SVE_VVVU_HSD, OP_SVE_VVV_D, OP_SVE_VVV_D_H, OP_SVE_VVV_H)
(OP_SVE_VVV_HSD, OP_SVE_VVV_S, OP_SVE_VVV_S_B, OP_SVE_VVV_SD_BH)
(OP_SVE_VV_BHSDQ, OP_SVE_VV_HSD, OP_SVE_VZVV_HSD, OP_SVE_VZV_HSD)
(OP_SVE_V_HSD): New macros.
(OP_SVE_VMU_SD, OP_SVE_VMVU_SD, OP_SVE_VM_SD, OP_SVE_VUVV_SD)
(OP_SVE_VU_SD, OP_SVE_VVVU_SD, OP_SVE_VVV_SD, OP_SVE_VZVV_SD)
(OP_SVE_VZV_SD, OP_SVE_V_SD): Delete.
(aarch64_opcode_table): Add new SVE instructions.
(aarch64_opcode_table): Use imm_rotate{1,2} instead of imm_rotate
for rotation operands. Add new SVE operands.
* aarch64-asm.h (ins_sve_addr_ri_s4): New inserter.
(ins_sve_quad_index): Likewise.
(ins_imm_rotate): Split into...
(ins_imm_rotate1, ins_imm_rotate2): ...these two inserters.
* aarch64-asm.c (aarch64_ins_imm_rotate): Split into...
(aarch64_ins_imm_rotate1, aarch64_ins_imm_rotate2): ...these two
functions.
(aarch64_ins_sve_addr_ri_s4): New function.
(aarch64_ins_sve_quad_index): Likewise.
(do_misc_encoding): Handle "MOV Zn.Q, Qm".
* aarch64-asm-2.c: Regenerate.
* aarch64-dis.h (ext_sve_addr_ri_s4): New extractor.
(ext_sve_quad_index): Likewise.
(ext_imm_rotate): Split into...
(ext_imm_rotate1, ext_imm_rotate2): ...these two extractors.
* aarch64-dis.c (aarch64_ext_imm_rotate): Split into...
(aarch64_ext_imm_rotate1, aarch64_ext_imm_rotate2): ...these two
functions.
(aarch64_ext_sve_addr_ri_s4): New function.
(aarch64_ext_sve_quad_index): Likewise.
(aarch64_ext_sve_index): Allow quad indices.
(do_misc_decoding): Likewise.
* aarch64-dis-2.c: Regenerate.
* aarch64-opc.h (FLD_SVE_i3h, FLD_SVE_rot1, FLD_SVE_rot2): New
aarch64_field_kinds.
(OPD_F_OD_MASK): Widen by one bit.
(OPD_F_NO_ZR): Bump accordingly.
(get_operand_field_width): New function.
* aarch64-opc.c (fields): Add new SVE fields.
(operand_general_constraint_met_p): Handle new SVE operands.
(aarch64_print_operand): Likewise.
* aarch64-opc-2.c: Regenerate.
gas/
* doc/c-aarch64.texi: Document that sve implies fp16, simd and compnum.
* config/tc-aarch64.c (parse_vector_type_for_operand): Allow .q
to be used with SVE registers.
(parse_operands): Handle new SVE operands.
(aarch64_features): Make "sve" require F16 rather than FP. Also
require COMPNUM.
* testsuite/gas/aarch64/sve.s: Add tests for new instructions.
Include compnum tests.
* testsuite/gas/aarch64/sve.d: Update accordingly.
* testsuite/gas/aarch64/sve-invalid.s: Add tests for new instructions.
* testsuite/gas/aarch64/sve-invalid.l: Update accordingly. Also
update expected output for new FMOV and MOV alternatives.
2017-02-24 19:29:00 +01:00
|
|
|
|
/* Decode a 2-bit rotate immediate (#0, #90, #180 or #270). */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_imm_rotate2 (const aarch64_operand *self, aarch64_opnd_info *info,
|
|
|
|
|
const aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
uint64_t rot = extract_field (self->fields[0], code, 0);
|
|
|
|
|
assert (rot < 4U);
|
[AArch64] Add ARMv8.3 FCMLA and FCADD instructions
Add support for FCMLA and FCADD complex arithmetic SIMD instructions.
FCMLA has an indexed element variant where the index range has to be
treated specially because a complex number takes two elements and the
indexed vector size depends on the other operands.
These complex number SIMD instructions are part of ARMv8.3
https://community.arm.com/groups/processors/blog/2016/10/27/armv8-a-architecture-2016-additions
include/
2016-11-18 Szabolcs Nagy <szabolcs.nagy@arm.com>
* opcode/aarch64.h (enum aarch64_opnd): Add AARCH64_OPND_IMM_ROT1,
AARCH64_OPND_IMM_ROT2, AARCH64_OPND_IMM_ROT3.
(enum aarch64_op): Add OP_FCMLA_ELEM.
opcodes/
2016-11-18 Szabolcs Nagy <szabolcs.nagy@arm.com>
* aarch64-tbl.h (QL_V3SAMEHSD_ROT, QL_ELEMENT_ROT): Define.
(aarch64_feature_simd_v8_3, SIMD_V8_3): Define.
(aarch64_opcode_table): Add fcmla and fcadd.
(AARCH64_OPERANDS): Add IMM_ROT{1,2,3}.
* aarch64-asm.h (aarch64_ins_imm_rotate): Declare.
* aarch64-asm.c (aarch64_ins_imm_rotate): Define.
* aarch64-dis.h (aarch64_ext_imm_rotate): Declare.
* aarch64-dis.c (aarch64_ext_imm_rotate): Define.
* aarch64-opc.h (enum aarch64_field_kind): Add FLD_rotate{1,2,3}.
* aarch64-opc.c (fields): Add FLD_rotate{1,2,3}.
(operand_general_constraint_met_p): Rotate and index range check.
(aarch64_print_operand): Handle rotate operand.
* aarch64-asm-2.c: Regenerate.
* aarch64-dis-2.c: Likewise.
* aarch64-opc-2.c: Likewise.
gas/
2016-11-18 Szabolcs Nagy <szabolcs.nagy@arm.com>
* config/tc-aarch64.c (parse_operands): Handle AARCH64_OPND_IMM_ROT*.
* testsuite/gas/aarch64/advsimd-armv8_3.d: New.
* testsuite/gas/aarch64/advsimd-armv8_3.s: New.
* testsuite/gas/aarch64/illegal-fcmla.s: New.
* testsuite/gas/aarch64/illegal-fcmla.l: New.
* testsuite/gas/aarch64/illegal-fcmla.d: New.
2016-11-18 11:02:16 +01:00
|
|
|
|
info->imm.value = rot * 90;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-13 16:52:54 +02:00
|
|
|
|
/* Decode scale for e.g. SCVTF <Dd>, <Wn>, #<fbits>. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_fbits (const aarch64_operand *self ATTRIBUTE_UNUSED,
|
|
|
|
|
aarch64_opnd_info *info, const aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
info->imm.value = 64- extract_field (FLD_scale, code, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode arithmetic immediate for e.g.
|
|
|
|
|
SUBS <Wd>, <Wn|WSP>, #<imm> {, <shift>}. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_aimm (const aarch64_operand *self ATTRIBUTE_UNUSED,
|
|
|
|
|
aarch64_opnd_info *info, const aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
aarch64_insn value;
|
|
|
|
|
|
|
|
|
|
info->shifter.kind = AARCH64_MOD_LSL;
|
|
|
|
|
/* shift */
|
|
|
|
|
value = extract_field (FLD_shift, code, 0);
|
|
|
|
|
if (value >= 2)
|
|
|
|
|
return 0;
|
|
|
|
|
info->shifter.amount = value ? 12 : 0;
|
|
|
|
|
/* imm12 (unsigned) */
|
|
|
|
|
info->imm.value = extract_field (FLD_imm12, code, 0);
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
[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.
2016-09-21 17:56:57 +02:00
|
|
|
|
/* 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)
|
2012-08-13 16:52:54 +02:00
|
|
|
|
{
|
|
|
|
|
uint64_t imm, mask;
|
|
|
|
|
uint32_t N, R, S;
|
|
|
|
|
unsigned simd_size;
|
|
|
|
|
|
|
|
|
|
/* value is N:immr:imms. */
|
|
|
|
|
S = value & 0x3f;
|
|
|
|
|
R = (value >> 6) & 0x3f;
|
|
|
|
|
N = (value >> 12) & 0x1;
|
|
|
|
|
|
|
|
|
|
/* 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)
|
|
|
|
|
{
|
|
|
|
|
simd_size = 64;
|
|
|
|
|
mask = 0xffffffffffffffffull;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
switch (S)
|
|
|
|
|
{
|
|
|
|
|
case 0x00 ... 0x1f: /* 0xxxxx */ simd_size = 32; break;
|
|
|
|
|
case 0x20 ... 0x2f: /* 10xxxx */ simd_size = 16; S &= 0xf; break;
|
|
|
|
|
case 0x30 ... 0x37: /* 110xxx */ simd_size = 8; S &= 0x7; break;
|
|
|
|
|
case 0x38 ... 0x3b: /* 1110xx */ simd_size = 4; S &= 0x3; break;
|
|
|
|
|
case 0x3c ... 0x3d: /* 11110x */ simd_size = 2; S &= 0x1; break;
|
|
|
|
|
default: return 0;
|
|
|
|
|
}
|
|
|
|
|
mask = (1ull << simd_size) - 1;
|
|
|
|
|
/* Top bits are IGNORED. */
|
|
|
|
|
R &= simd_size - 1;
|
|
|
|
|
}
|
[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.
2016-09-21 17:56:57 +02:00
|
|
|
|
|
|
|
|
|
if (simd_size > esize * 8)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2012-08-13 16:52:54 +02:00
|
|
|
|
/* NOTE: if S = simd_size - 1 we get 0xf..f which is rejected. */
|
|
|
|
|
if (S == simd_size - 1)
|
|
|
|
|
return 0;
|
|
|
|
|
/* S+1 consecutive bits to 1. */
|
|
|
|
|
/* NOTE: S can't be 63 due to detection above. */
|
|
|
|
|
imm = (1ull << (S + 1)) - 1;
|
|
|
|
|
/* Rotate to the left by simd_size - R. */
|
|
|
|
|
if (R != 0)
|
|
|
|
|
imm = ((imm << (simd_size - R)) & mask) | (imm >> R);
|
|
|
|
|
/* Replicate the value according to SIMD size. */
|
|
|
|
|
switch (simd_size)
|
|
|
|
|
{
|
|
|
|
|
case 2: imm = (imm << 2) | imm;
|
2016-10-05 09:47:02 +02:00
|
|
|
|
/* Fall through. */
|
2012-08-13 16:52:54 +02:00
|
|
|
|
case 4: imm = (imm << 4) | imm;
|
2016-10-05 09:47:02 +02:00
|
|
|
|
/* Fall through. */
|
2012-08-13 16:52:54 +02:00
|
|
|
|
case 8: imm = (imm << 8) | imm;
|
2016-10-05 09:47:02 +02:00
|
|
|
|
/* Fall through. */
|
2012-08-13 16:52:54 +02:00
|
|
|
|
case 16: imm = (imm << 16) | imm;
|
2016-10-05 09:47:02 +02:00
|
|
|
|
/* Fall through. */
|
2012-08-13 16:52:54 +02:00
|
|
|
|
case 32: imm = (imm << 32) | imm;
|
2016-10-05 09:47:02 +02:00
|
|
|
|
/* Fall through. */
|
2012-08-13 16:52:54 +02:00
|
|
|
|
case 64: break;
|
|
|
|
|
default: assert (0); return 0;
|
|
|
|
|
}
|
|
|
|
|
|
[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.
2016-09-21 17:56:57 +02:00
|
|
|
|
*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);
|
|
|
|
|
}
|
2012-08-13 16:52:54 +02:00
|
|
|
|
|
[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.
2016-09-21 17:56:57 +02:00
|
|
|
|
/* 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;
|
2012-08-13 16:52:54 +02:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode Ft for e.g. STR <Qt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]
|
|
|
|
|
or LDP <Qt1>, <Qt2>, [<Xn|SP>], #<imm>. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_ft (const aarch64_operand *self ATTRIBUTE_UNUSED,
|
|
|
|
|
aarch64_opnd_info *info,
|
|
|
|
|
const aarch64_insn code, const aarch64_inst *inst)
|
|
|
|
|
{
|
|
|
|
|
aarch64_insn value;
|
|
|
|
|
|
|
|
|
|
/* Rt */
|
|
|
|
|
info->reg.regno = extract_field (FLD_Rt, code, 0);
|
|
|
|
|
|
|
|
|
|
/* size */
|
|
|
|
|
value = extract_field (FLD_ldst_size, code, 0);
|
|
|
|
|
if (inst->opcode->iclass == ldstpair_indexed
|
|
|
|
|
|| inst->opcode->iclass == ldstnapair_offs
|
|
|
|
|
|| inst->opcode->iclass == ldstpair_off
|
|
|
|
|
|| inst->opcode->iclass == loadlit)
|
|
|
|
|
{
|
|
|
|
|
enum aarch64_opnd_qualifier qualifier;
|
|
|
|
|
switch (value)
|
|
|
|
|
{
|
|
|
|
|
case 0: qualifier = AARCH64_OPND_QLF_S_S; break;
|
|
|
|
|
case 1: qualifier = AARCH64_OPND_QLF_S_D; break;
|
|
|
|
|
case 2: qualifier = AARCH64_OPND_QLF_S_Q; break;
|
|
|
|
|
default: return 0;
|
|
|
|
|
}
|
|
|
|
|
info->qualifier = qualifier;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* opc1:size */
|
|
|
|
|
value = extract_fields (code, 0, 2, FLD_opc1, FLD_ldst_size);
|
|
|
|
|
if (value > 0x4)
|
|
|
|
|
return 0;
|
|
|
|
|
info->qualifier = get_sreg_qualifier_from_value (value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode the address operand for e.g. STXRB <Ws>, <Wt>, [<Xn|SP>{,#0}]. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_addr_simple (const aarch64_operand *self ATTRIBUTE_UNUSED,
|
|
|
|
|
aarch64_opnd_info *info,
|
|
|
|
|
aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
/* Rn */
|
|
|
|
|
info->addr.base_regno = extract_field (FLD_Rn, code, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
Adds the new Fields and Operand types for the new instructions in Armv8.4-a.
gas/
* config/tc-aarch64.c (process_omitted_operand):
Add AARCH64_OPND_Va, AARCH64_OPND_SM3_IMM2
and AARCH64_OPND_IMM_2.
(parse_operands): Add AARCH64_OPND_Va, AARCH64_OPND_SM3_IMM2,
AARCH64_OPND_IMM_2, AARCH64_OPND_MASK
and AARCH64_OPND_ADDR_OFFSET.
include/
* opcode/aarch64.h:
(aarch64_opnd): Add AARCH64_OPND_Va, AARCH64_OPND_MASK,
AARCH64_OPND_IMM_2, AARCH64_OPND_ADDR_OFFSET
and AARCH64_OPND_SM3_IMM2.
(aarch64_insn_class): Add cryptosm3 and cryptosm4.
(arch64_feature_set): Make uint64_t.
opcodes/
* aarch64-asm.h (ins_addr_offset): New.
* aarch64-asm.c (aarch64_ins_reglane): Add cryptosm3.
(aarch64_ins_addr_offset): New.
* aarch64-asm-2.c: Regenerate.
* aarch64-dis.h (ext_addr_offset): New.
* aarch64-dis.c (aarch64_ext_reglane): Add cryptosm3.
(aarch64_ext_addr_offset): New.
* aarch64-dis-2.c: Regenerate.
* aarch64-opc.h (aarch64_field_kind): Add FLD_imm6_2,
FLD_imm4_2 and FLD_SM3_imm2.
* aarch64-opc.c (fields): Add FLD_imm6_2,
FLD_imm4_2 and FLD_SM3_imm2.
(operand_general_constraint_met_p): Add AARCH64_OPND_ADDR_OFFSET.
(aarch64_print_operand): Add AARCH64_OPND_Va, AARCH64_OPND_SM3_IMM2,
AARCH64_OPND_MASK, AARCH64_OPND_IMM_2 and AARCH64_OPND_ADDR_OFFSET.
* aarch64-opc-2.c (Va, MASK, IMM_2, ADDR_OFFSET, SM3_IMM2): New.
* aarch64-tbl.h
(aarch64_opcode_table): Add Va, MASK, IMM_2, ADDR_OFFSET, SM3_IMM2.
2017-11-09 16:22:30 +01:00
|
|
|
|
/* Decode the address operand for e.g.
|
|
|
|
|
stlur <Xt>, [<Xn|SP>{, <amount>}]. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_addr_offset (const aarch64_operand *self ATTRIBUTE_UNUSED,
|
|
|
|
|
aarch64_opnd_info *info,
|
|
|
|
|
aarch64_insn code, const aarch64_inst *inst)
|
|
|
|
|
{
|
|
|
|
|
info->qualifier = get_expected_qualifier (inst, info->idx);
|
|
|
|
|
|
|
|
|
|
/* Rn */
|
|
|
|
|
info->addr.base_regno = extract_field (self->fields[0], code, 0);
|
|
|
|
|
|
|
|
|
|
/* simm9 */
|
|
|
|
|
aarch64_insn imm = extract_fields (code, 0, 1, self->fields[1]);
|
|
|
|
|
info->addr.offset.imm = sign_extend (imm, 8);
|
|
|
|
|
if (extract_field (self->fields[2], code, 0) == 1) {
|
|
|
|
|
info->addr.writeback = 1;
|
|
|
|
|
info->addr.preind = 1;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-13 16:52:54 +02:00
|
|
|
|
/* Decode the address operand for e.g.
|
|
|
|
|
STR <Qt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_addr_regoff (const aarch64_operand *self ATTRIBUTE_UNUSED,
|
|
|
|
|
aarch64_opnd_info *info,
|
|
|
|
|
aarch64_insn code, const aarch64_inst *inst)
|
|
|
|
|
{
|
|
|
|
|
aarch64_insn S, value;
|
|
|
|
|
|
|
|
|
|
/* Rn */
|
|
|
|
|
info->addr.base_regno = extract_field (FLD_Rn, code, 0);
|
|
|
|
|
/* Rm */
|
|
|
|
|
info->addr.offset.regno = extract_field (FLD_Rm, code, 0);
|
|
|
|
|
/* option */
|
|
|
|
|
value = extract_field (FLD_option, code, 0);
|
|
|
|
|
info->shifter.kind =
|
|
|
|
|
aarch64_get_operand_modifier_from_value (value, TRUE /* extend_p */);
|
|
|
|
|
/* Fix-up the shifter kind; although the table-driven approach is
|
|
|
|
|
efficient, it is slightly inflexible, thus needing this fix-up. */
|
|
|
|
|
if (info->shifter.kind == AARCH64_MOD_UXTX)
|
|
|
|
|
info->shifter.kind = AARCH64_MOD_LSL;
|
|
|
|
|
/* S */
|
|
|
|
|
S = extract_field (FLD_S, code, 0);
|
|
|
|
|
if (S == 0)
|
|
|
|
|
{
|
|
|
|
|
info->shifter.amount = 0;
|
|
|
|
|
info->shifter.amount_present = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int size;
|
|
|
|
|
/* Need information in other operand(s) to help achieve the decoding
|
|
|
|
|
from 'S' field. */
|
|
|
|
|
info->qualifier = get_expected_qualifier (inst, info->idx);
|
|
|
|
|
/* Get the size of the data element that is accessed, which may be
|
|
|
|
|
different from that of the source register size, e.g. in strb/ldrb. */
|
|
|
|
|
size = aarch64_get_qualifier_esize (info->qualifier);
|
|
|
|
|
info->shifter.amount = get_logsz (size);
|
|
|
|
|
info->shifter.amount_present = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode the address operand for e.g. LDRSW <Xt>, [<Xn|SP>], #<simm>. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_addr_simm (const aarch64_operand *self, aarch64_opnd_info *info,
|
|
|
|
|
aarch64_insn code, const aarch64_inst *inst)
|
|
|
|
|
{
|
|
|
|
|
aarch64_insn imm;
|
|
|
|
|
info->qualifier = get_expected_qualifier (inst, info->idx);
|
|
|
|
|
|
|
|
|
|
/* Rn */
|
|
|
|
|
info->addr.base_regno = extract_field (FLD_Rn, code, 0);
|
|
|
|
|
/* simm (imm9 or imm7) */
|
|
|
|
|
imm = extract_field (self->fields[0], code, 0);
|
|
|
|
|
info->addr.offset.imm = sign_extend (imm, fields[self->fields[0]].width - 1);
|
|
|
|
|
if (self->fields[0] == FLD_imm7)
|
|
|
|
|
/* scaled immediate in ld/st pair instructions. */
|
|
|
|
|
info->addr.offset.imm *= aarch64_get_qualifier_esize (info->qualifier);
|
|
|
|
|
/* qualifier */
|
|
|
|
|
if (inst->opcode->iclass == ldst_unscaled
|
|
|
|
|
|| inst->opcode->iclass == ldstnapair_offs
|
|
|
|
|
|| inst->opcode->iclass == ldstpair_off
|
|
|
|
|
|| inst->opcode->iclass == ldst_unpriv)
|
|
|
|
|
info->addr.writeback = 0;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* pre/post- index */
|
|
|
|
|
info->addr.writeback = 1;
|
|
|
|
|
if (extract_field (self->fields[1], code, 0) == 1)
|
|
|
|
|
info->addr.preind = 1;
|
|
|
|
|
else
|
|
|
|
|
info->addr.postind = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode the address operand for e.g. LDRSW <Xt>, [<Xn|SP>{, #<simm>}]. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_addr_uimm12 (const aarch64_operand *self, aarch64_opnd_info *info,
|
|
|
|
|
aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
int shift;
|
|
|
|
|
info->qualifier = get_expected_qualifier (inst, info->idx);
|
|
|
|
|
shift = get_logsz (aarch64_get_qualifier_esize (info->qualifier));
|
|
|
|
|
/* Rn */
|
|
|
|
|
info->addr.base_regno = extract_field (self->fields[0], code, 0);
|
|
|
|
|
/* uimm12 */
|
|
|
|
|
info->addr.offset.imm = extract_field (self->fields[1], code, 0) << shift;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-18 10:49:06 +01:00
|
|
|
|
/* Decode the address operand for e.g. LDRAA <Xt>, [<Xn|SP>{, #<simm>}]. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_addr_simm10 (const aarch64_operand *self, aarch64_opnd_info *info,
|
|
|
|
|
aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
aarch64_insn imm;
|
|
|
|
|
|
|
|
|
|
info->qualifier = get_expected_qualifier (inst, info->idx);
|
|
|
|
|
/* Rn */
|
|
|
|
|
info->addr.base_regno = extract_field (self->fields[0], code, 0);
|
|
|
|
|
/* simm10 */
|
|
|
|
|
imm = extract_fields (code, 0, 2, self->fields[1], self->fields[2]);
|
|
|
|
|
info->addr.offset.imm = sign_extend (imm, 9) << 3;
|
|
|
|
|
if (extract_field (self->fields[3], code, 0) == 1) {
|
|
|
|
|
info->addr.writeback = 1;
|
|
|
|
|
info->addr.preind = 1;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-13 16:52:54 +02:00
|
|
|
|
/* Decode the address operand for e.g.
|
|
|
|
|
LD1 {<Vt>.<T>, <Vt2>.<T>, <Vt3>.<T>}, [<Xn|SP>], <Xm|#<amount>>. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_simd_addr_post (const aarch64_operand *self ATTRIBUTE_UNUSED,
|
|
|
|
|
aarch64_opnd_info *info,
|
|
|
|
|
aarch64_insn code, const aarch64_inst *inst)
|
|
|
|
|
{
|
|
|
|
|
/* The opcode dependent area stores the number of elements in
|
|
|
|
|
each structure to be loaded/stored. */
|
|
|
|
|
int is_ld1r = get_opcode_dependent_value (inst->opcode) == 1;
|
|
|
|
|
|
|
|
|
|
/* Rn */
|
|
|
|
|
info->addr.base_regno = extract_field (FLD_Rn, code, 0);
|
|
|
|
|
/* Rm | #<amount> */
|
|
|
|
|
info->addr.offset.regno = extract_field (FLD_Rm, code, 0);
|
|
|
|
|
if (info->addr.offset.regno == 31)
|
|
|
|
|
{
|
|
|
|
|
if (inst->opcode->operands[0] == AARCH64_OPND_LVt_AL)
|
|
|
|
|
/* Special handling of loading single structure to all lane. */
|
|
|
|
|
info->addr.offset.imm = (is_ld1r ? 1
|
|
|
|
|
: inst->operands[0].reglist.num_regs)
|
|
|
|
|
* aarch64_get_qualifier_esize (inst->operands[0].qualifier);
|
|
|
|
|
else
|
|
|
|
|
info->addr.offset.imm = inst->operands[0].reglist.num_regs
|
|
|
|
|
* aarch64_get_qualifier_esize (inst->operands[0].qualifier)
|
|
|
|
|
* aarch64_get_qualifier_nelem (inst->operands[0].qualifier);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
info->addr.offset.is_reg = 1;
|
|
|
|
|
info->addr.writeback = 1;
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode the condition operand for e.g. CSEL <Xd>, <Xn>, <Xm>, <cond>. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_cond (const aarch64_operand *self ATTRIBUTE_UNUSED,
|
|
|
|
|
aarch64_opnd_info *info,
|
|
|
|
|
aarch64_insn code, const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
aarch64_insn value;
|
|
|
|
|
/* cond */
|
|
|
|
|
value = extract_field (FLD_cond, code, 0);
|
|
|
|
|
info->cond = get_cond_from_value (value);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode the system register operand for e.g. MRS <Xt>, <systemreg>. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_sysreg (const aarch64_operand *self ATTRIBUTE_UNUSED,
|
|
|
|
|
aarch64_opnd_info *info,
|
|
|
|
|
aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
/* op0:op1:CRn:CRm:op2 */
|
|
|
|
|
info->sysreg = extract_fields (code, 0, 5, FLD_op0, FLD_op1, FLD_CRn,
|
|
|
|
|
FLD_CRm, FLD_op2);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode the PSTATE field operand for e.g. MSR <pstatefield>, #<imm>. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_pstatefield (const aarch64_operand *self ATTRIBUTE_UNUSED,
|
|
|
|
|
aarch64_opnd_info *info, aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
/* op1:op2 */
|
|
|
|
|
info->pstatefield = extract_fields (code, 0, 2, FLD_op1, FLD_op2);
|
|
|
|
|
for (i = 0; aarch64_pstatefields[i].name != NULL; ++i)
|
|
|
|
|
if (aarch64_pstatefields[i].value == (aarch64_insn)info->pstatefield)
|
|
|
|
|
return 1;
|
|
|
|
|
/* Reserved value in <pstatefield>. */
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode the system instruction op operand for e.g. AT <at_op>, <Xt>. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_sysins_op (const aarch64_operand *self ATTRIBUTE_UNUSED,
|
|
|
|
|
aarch64_opnd_info *info,
|
|
|
|
|
aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
aarch64_insn value;
|
|
|
|
|
const aarch64_sys_ins_reg *sysins_ops;
|
|
|
|
|
/* op0:op1:CRn:CRm:op2 */
|
|
|
|
|
value = extract_fields (code, 0, 5,
|
|
|
|
|
FLD_op0, FLD_op1, FLD_CRn,
|
|
|
|
|
FLD_CRm, FLD_op2);
|
|
|
|
|
|
|
|
|
|
switch (info->type)
|
|
|
|
|
{
|
|
|
|
|
case AARCH64_OPND_SYSREG_AT: sysins_ops = aarch64_sys_regs_at; break;
|
|
|
|
|
case AARCH64_OPND_SYSREG_DC: sysins_ops = aarch64_sys_regs_dc; break;
|
|
|
|
|
case AARCH64_OPND_SYSREG_IC: sysins_ops = aarch64_sys_regs_ic; break;
|
|
|
|
|
case AARCH64_OPND_SYSREG_TLBI: sysins_ops = aarch64_sys_regs_tlbi; break;
|
|
|
|
|
default: assert (0); return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-07 13:23:15 +02:00
|
|
|
|
for (i = 0; sysins_ops[i].name != NULL; ++i)
|
2012-08-13 16:52:54 +02:00
|
|
|
|
if (sysins_ops[i].value == value)
|
|
|
|
|
{
|
|
|
|
|
info->sysins_op = sysins_ops + i;
|
|
|
|
|
DEBUG_TRACE ("%s found value: %x, has_xt: %d, i: %d.",
|
2015-10-07 13:23:15 +02:00
|
|
|
|
info->sysins_op->name,
|
2012-08-13 16:52:54 +02:00
|
|
|
|
(unsigned)info->sysins_op->value,
|
2015-12-10 17:31:35 +01:00
|
|
|
|
aarch64_sys_ins_reg_has_xt (info->sysins_op), i);
|
2012-08-13 16:52:54 +02:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode the memory barrier option operand for e.g. DMB <option>|#<imm>. */
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_barrier (const aarch64_operand *self ATTRIBUTE_UNUSED,
|
|
|
|
|
aarch64_opnd_info *info,
|
|
|
|
|
aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
/* CRm */
|
|
|
|
|
info->barrier = aarch64_barrier_options + extract_field (FLD_CRm, code, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode the prefetch operation option operand for e.g.
|
|
|
|
|
PRFM <prfop>, [<Xn|SP>{, #<pimm>}]. */
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_prfop (const aarch64_operand *self ATTRIBUTE_UNUSED,
|
|
|
|
|
aarch64_opnd_info *info,
|
|
|
|
|
aarch64_insn code, const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
/* prfop in Rt */
|
|
|
|
|
info->prfop = aarch64_prfops + extract_field (FLD_Rt, code, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-11 11:11:27 +01:00
|
|
|
|
/* Decode the hint number for an alias taking an operand. Set info->hint_option
|
|
|
|
|
to the matching name/value pair in aarch64_hint_options. */
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_hint (const aarch64_operand *self ATTRIBUTE_UNUSED,
|
|
|
|
|
aarch64_opnd_info *info,
|
|
|
|
|
aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
/* CRm:op2. */
|
|
|
|
|
unsigned hint_number;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
hint_number = extract_fields (code, 0, 2, FLD_CRm, FLD_op2);
|
|
|
|
|
|
|
|
|
|
for (i = 0; aarch64_hint_options[i].name != NULL; i++)
|
|
|
|
|
{
|
|
|
|
|
if (hint_number == aarch64_hint_options[i].value)
|
|
|
|
|
{
|
|
|
|
|
info->hint_option = &(aarch64_hint_options[i]);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-13 16:52:54 +02:00
|
|
|
|
/* Decode the extended register operand for e.g.
|
|
|
|
|
STR <Qt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_reg_extended (const aarch64_operand *self ATTRIBUTE_UNUSED,
|
|
|
|
|
aarch64_opnd_info *info,
|
|
|
|
|
aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
aarch64_insn value;
|
|
|
|
|
|
|
|
|
|
/* Rm */
|
|
|
|
|
info->reg.regno = extract_field (FLD_Rm, code, 0);
|
|
|
|
|
/* option */
|
|
|
|
|
value = extract_field (FLD_option, code, 0);
|
|
|
|
|
info->shifter.kind =
|
|
|
|
|
aarch64_get_operand_modifier_from_value (value, TRUE /* extend_p */);
|
|
|
|
|
/* imm3 */
|
|
|
|
|
info->shifter.amount = extract_field (FLD_imm3, code, 0);
|
|
|
|
|
|
|
|
|
|
/* This makes the constraint checking happy. */
|
|
|
|
|
info->shifter.operator_present = 1;
|
|
|
|
|
|
|
|
|
|
/* Assume inst->operands[0].qualifier has been resolved. */
|
|
|
|
|
assert (inst->operands[0].qualifier != AARCH64_OPND_QLF_NIL);
|
|
|
|
|
info->qualifier = AARCH64_OPND_QLF_W;
|
|
|
|
|
if (inst->operands[0].qualifier == AARCH64_OPND_QLF_X
|
|
|
|
|
&& (info->shifter.kind == AARCH64_MOD_UXTX
|
|
|
|
|
|| info->shifter.kind == AARCH64_MOD_SXTX))
|
|
|
|
|
info->qualifier = AARCH64_OPND_QLF_X;
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode the shifted register operand for e.g.
|
|
|
|
|
SUBS <Xd>, <Xn>, <Xm> {, <shift> #<amount>}. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_reg_shifted (const aarch64_operand *self ATTRIBUTE_UNUSED,
|
|
|
|
|
aarch64_opnd_info *info,
|
|
|
|
|
aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
aarch64_insn value;
|
|
|
|
|
|
|
|
|
|
/* Rm */
|
|
|
|
|
info->reg.regno = extract_field (FLD_Rm, code, 0);
|
|
|
|
|
/* shift */
|
|
|
|
|
value = extract_field (FLD_shift, code, 0);
|
|
|
|
|
info->shifter.kind =
|
|
|
|
|
aarch64_get_operand_modifier_from_value (value, FALSE /* extend_p */);
|
|
|
|
|
if (info->shifter.kind == AARCH64_MOD_ROR
|
|
|
|
|
&& inst->opcode->iclass != log_shift)
|
|
|
|
|
/* ROR is not available for the shifted register operand in arithmetic
|
|
|
|
|
instructions. */
|
|
|
|
|
return 0;
|
|
|
|
|
/* imm6 */
|
|
|
|
|
info->shifter.amount = extract_field (FLD_imm6, code, 0);
|
|
|
|
|
|
|
|
|
|
/* This makes the constraint checking happy. */
|
|
|
|
|
info->shifter.operator_present = 1;
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
[AArch64][SVE 21/32] Add Zn and Pn registers
This patch adds the Zn and Pn registers, and associated fields and
operands.
include/
* opcode/aarch64.h (AARCH64_OPND_CLASS_SVE_REG): New
aarch64_operand_class.
(AARCH64_OPND_CLASS_PRED_REG): Likewise.
(AARCH64_OPND_SVE_Pd, AARCH64_OPND_SVE_Pg3, AARCH64_OPND_SVE_Pg4_5)
(AARCH64_OPND_SVE_Pg4_10, AARCH64_OPND_SVE_Pg4_16)
(AARCH64_OPND_SVE_Pm, AARCH64_OPND_SVE_Pn, AARCH64_OPND_SVE_Pt)
(AARCH64_OPND_SVE_Za_5, AARCH64_OPND_SVE_Za_16, AARCH64_OPND_SVE_Zd)
(AARCH64_OPND_SVE_Zm_5, AARCH64_OPND_SVE_Zm_16, AARCH64_OPND_SVE_Zn)
(AARCH64_OPND_SVE_Zn_INDEX, AARCH64_OPND_SVE_ZnxN)
(AARCH64_OPND_SVE_Zt, AARCH64_OPND_SVE_ZtxN): New aarch64_opnds.
opcodes/
* aarch64-tbl.h (AARCH64_OPERANDS): Add entries for new SVE operands.
* aarch64-opc.h (FLD_SVE_Pd, FLD_SVE_Pg3, FLD_SVE_Pg4_5)
(FLD_SVE_Pg4_10, FLD_SVE_Pg4_16, FLD_SVE_Pm, FLD_SVE_Pn, FLD_SVE_Pt)
(FLD_SVE_Za_5, FLD_SVE_Za_16, FLD_SVE_Zd, FLD_SVE_Zm_5, FLD_SVE_Zm_16)
(FLD_SVE_Zn, FLD_SVE_Zt, FLD_SVE_tzsh): New aarch64_field_kinds.
* aarch64-opc.c (fields): Add corresponding entries here.
(operand_general_constraint_met_p): Check that SVE register lists
have the correct length. Check the ranges of SVE index registers.
Check for cases where p8-p15 are used in 3-bit predicate fields.
(aarch64_print_operand): Handle the new SVE operands.
* aarch64-opc-2.c: Regenerate.
* aarch64-asm.h (ins_sve_index, ins_sve_reglist): New inserters.
* aarch64-asm.c (aarch64_ins_sve_index): New function.
(aarch64_ins_sve_reglist): Likewise.
* aarch64-asm-2.c: Regenerate.
* aarch64-dis.h (ext_sve_index, ext_sve_reglist): New extractors.
* aarch64-dis.c (aarch64_ext_sve_index): New function.
(aarch64_ext_sve_reglist): Likewise.
* aarch64-dis-2.c: Regenerate.
gas/
* config/tc-aarch64.c (NTA_HASVARWIDTH): New macro.
(AARCH64_REG_TYPES): Add ZN and PN.
(get_reg_expected_msg): Handle them.
(parse_vector_type_for_operand): Add a reg_type parameter.
Skip the width for Zn and Pn registers.
(parse_typed_reg): Extend vector handling to Zn and Pn. Update the
call to parse_vector_type_for_operand. Set HASVARTYPE for Zn and Pn,
expecting the width to be 0.
(parse_vector_reg_list): Restrict error about [BHSD]nn operands to
REG_TYPE_VN.
(vectype_to_qualifier): Use S_[BHSD] qualifiers for NTA_HASVARWIDTH.
(parse_operands): Handle the new Zn and Pn operands.
(REGSET16): New macro, split out from...
(REGSET31): ...here.
(reg_names): Add Zn and Pn entries.
2016-09-21 17:53:54 +02:00
|
|
|
|
|
[AArch64][SVE 26/32] Add SVE MUL VL addressing modes
This patch adds support for addresses of the form:
[<base>, #<offset>, MUL VL]
This involves adding a new AARCH64_MOD_MUL_VL modifier, which is
why I split it out from the other addressing modes.
For LD2, LD3 and LD4, the offset must be a multiple of the structure
size, so for LD3 the possible values are 0, 3, 6, .... The patch
therefore extends value_aligned_p to handle non-power-of-2 alignments.
include/
* opcode/aarch64.h (AARCH64_OPND_SVE_ADDR_RI_S4xVL): New aarch64_opnd.
(AARCH64_OPND_SVE_ADDR_RI_S4x2xVL, AARCH64_OPND_SVE_ADDR_RI_S4x3xVL)
(AARCH64_OPND_SVE_ADDR_RI_S4x4xVL, AARCH64_OPND_SVE_ADDR_RI_S6xVL)
(AARCH64_OPND_SVE_ADDR_RI_S9xVL): Likewise.
(AARCH64_MOD_MUL_VL): New aarch64_modifier_kind.
opcodes/
* aarch64-tbl.h (AARCH64_OPERANDS): Add entries for new MUL VL
operands.
* aarch64-opc.c (aarch64_operand_modifiers): Initialize
the AARCH64_MOD_MUL_VL entry.
(value_aligned_p): Cope with non-power-of-two alignments.
(operand_general_constraint_met_p): Handle the new MUL VL addresses.
(print_immediate_offset_address): Likewise.
(aarch64_print_operand): Likewise.
* aarch64-opc-2.c: Regenerate.
* aarch64-asm.h (ins_sve_addr_ri_s4xvl, ins_sve_addr_ri_s6xvl)
(ins_sve_addr_ri_s9xvl): New inserters.
* aarch64-asm.c (aarch64_ins_sve_addr_ri_s4xvl): New function.
(aarch64_ins_sve_addr_ri_s6xvl): Likewise.
(aarch64_ins_sve_addr_ri_s9xvl): Likewise.
* aarch64-asm-2.c: Regenerate.
* aarch64-dis.h (ext_sve_addr_ri_s4xvl, ext_sve_addr_ri_s6xvl)
(ext_sve_addr_ri_s9xvl): New extractors.
* aarch64-dis.c (aarch64_ext_sve_addr_reg_mul_vl): New function.
(aarch64_ext_sve_addr_ri_s4xvl): Likewise.
(aarch64_ext_sve_addr_ri_s6xvl): Likewise.
(aarch64_ext_sve_addr_ri_s9xvl): Likewise.
* aarch64-dis-2.c: Regenerate.
gas/
* config/tc-aarch64.c (SHIFTED_NONE, SHIFTED_MUL_VL): New
parse_shift_modes.
(parse_shift): Handle SHIFTED_MUL_VL.
(parse_address_main): Add an imm_shift_mode parameter.
(parse_address, parse_sve_address): Update accordingly.
(parse_operands): Handle MUL VL addressing modes.
2016-09-21 17:56:15 +02:00
|
|
|
|
/* Decode an SVE address [<base>, #<offset>*<factor>, MUL VL],
|
|
|
|
|
where <offset> is given by the OFFSET parameter and where <factor> is
|
|
|
|
|
1 plus SELF's operand-dependent value. fields[0] specifies the field
|
|
|
|
|
that holds <base>. */
|
|
|
|
|
static int
|
|
|
|
|
aarch64_ext_sve_addr_reg_mul_vl (const aarch64_operand *self,
|
|
|
|
|
aarch64_opnd_info *info, aarch64_insn code,
|
|
|
|
|
int64_t offset)
|
|
|
|
|
{
|
|
|
|
|
info->addr.base_regno = extract_field (self->fields[0], code, 0);
|
|
|
|
|
info->addr.offset.imm = offset * (1 + get_operand_specific_data (self));
|
|
|
|
|
info->addr.offset.is_reg = FALSE;
|
|
|
|
|
info->addr.writeback = FALSE;
|
|
|
|
|
info->addr.preind = TRUE;
|
|
|
|
|
if (offset != 0)
|
|
|
|
|
info->shifter.kind = AARCH64_MOD_MUL_VL;
|
|
|
|
|
info->shifter.amount = 1;
|
|
|
|
|
info->shifter.operator_present = (info->addr.offset.imm != 0);
|
|
|
|
|
info->shifter.amount_present = FALSE;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode an SVE address [<base>, #<simm4>*<factor>, MUL VL],
|
|
|
|
|
where <simm4> is a 4-bit signed value and where <factor> is 1 plus
|
|
|
|
|
SELF's operand-dependent value. fields[0] specifies the field that
|
|
|
|
|
holds <base>. <simm4> is encoded in the SVE_imm4 field. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_sve_addr_ri_s4xvl (const aarch64_operand *self,
|
|
|
|
|
aarch64_opnd_info *info, aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
int offset;
|
|
|
|
|
|
|
|
|
|
offset = extract_field (FLD_SVE_imm4, code, 0);
|
|
|
|
|
offset = ((offset + 8) & 15) - 8;
|
|
|
|
|
return aarch64_ext_sve_addr_reg_mul_vl (self, info, code, offset);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode an SVE address [<base>, #<simm6>*<factor>, MUL VL],
|
|
|
|
|
where <simm6> is a 6-bit signed value and where <factor> is 1 plus
|
|
|
|
|
SELF's operand-dependent value. fields[0] specifies the field that
|
|
|
|
|
holds <base>. <simm6> is encoded in the SVE_imm6 field. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_sve_addr_ri_s6xvl (const aarch64_operand *self,
|
|
|
|
|
aarch64_opnd_info *info, aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
int offset;
|
|
|
|
|
|
|
|
|
|
offset = extract_field (FLD_SVE_imm6, code, 0);
|
|
|
|
|
offset = (((offset + 32) & 63) - 32);
|
|
|
|
|
return aarch64_ext_sve_addr_reg_mul_vl (self, info, code, offset);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode an SVE address [<base>, #<simm9>*<factor>, MUL VL],
|
|
|
|
|
where <simm9> is a 9-bit signed value and where <factor> is 1 plus
|
|
|
|
|
SELF's operand-dependent value. fields[0] specifies the field that
|
|
|
|
|
holds <base>. <simm9> is encoded in the concatenation of the SVE_imm6
|
|
|
|
|
and imm3 fields, with imm3 being the less-significant part. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_sve_addr_ri_s9xvl (const aarch64_operand *self,
|
|
|
|
|
aarch64_opnd_info *info,
|
|
|
|
|
aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
int offset;
|
|
|
|
|
|
|
|
|
|
offset = extract_fields (code, 0, 2, FLD_SVE_imm6, FLD_imm3);
|
|
|
|
|
offset = (((offset + 256) & 511) - 256);
|
|
|
|
|
return aarch64_ext_sve_addr_reg_mul_vl (self, info, code, offset);
|
|
|
|
|
}
|
|
|
|
|
|
[AArch64][SVE 25/32] Add support for SVE addressing modes
This patch adds most of the new SVE addressing modes and associated
operands. A follow-on patch adds MUL VL, since handling it separately
makes the changes easier to read.
The patch also introduces a new "operand-dependent data" field to the
operand flags, based closely on the existing one for opcode flags.
For SVE this new field needs only 2 bits, but it could be widened
in future if necessary.
include/
* opcode/aarch64.h (AARCH64_OPND_SVE_ADDR_RI_U6): New aarch64_opnd.
(AARCH64_OPND_SVE_ADDR_RI_U6x2, AARCH64_OPND_SVE_ADDR_RI_U6x4)
(AARCH64_OPND_SVE_ADDR_RI_U6x8, AARCH64_OPND_SVE_ADDR_RR)
(AARCH64_OPND_SVE_ADDR_RR_LSL1, AARCH64_OPND_SVE_ADDR_RR_LSL2)
(AARCH64_OPND_SVE_ADDR_RR_LSL3, AARCH64_OPND_SVE_ADDR_RX)
(AARCH64_OPND_SVE_ADDR_RX_LSL1, AARCH64_OPND_SVE_ADDR_RX_LSL2)
(AARCH64_OPND_SVE_ADDR_RX_LSL3, AARCH64_OPND_SVE_ADDR_RZ)
(AARCH64_OPND_SVE_ADDR_RZ_LSL1, AARCH64_OPND_SVE_ADDR_RZ_LSL2)
(AARCH64_OPND_SVE_ADDR_RZ_LSL3, AARCH64_OPND_SVE_ADDR_RZ_XTW_14)
(AARCH64_OPND_SVE_ADDR_RZ_XTW_22, AARCH64_OPND_SVE_ADDR_RZ_XTW1_14)
(AARCH64_OPND_SVE_ADDR_RZ_XTW1_22, AARCH64_OPND_SVE_ADDR_RZ_XTW2_14)
(AARCH64_OPND_SVE_ADDR_RZ_XTW2_22, AARCH64_OPND_SVE_ADDR_RZ_XTW3_14)
(AARCH64_OPND_SVE_ADDR_RZ_XTW3_22, AARCH64_OPND_SVE_ADDR_ZI_U5)
(AARCH64_OPND_SVE_ADDR_ZI_U5x2, AARCH64_OPND_SVE_ADDR_ZI_U5x4)
(AARCH64_OPND_SVE_ADDR_ZI_U5x8, AARCH64_OPND_SVE_ADDR_ZZ_LSL)
(AARCH64_OPND_SVE_ADDR_ZZ_SXTW, AARCH64_OPND_SVE_ADDR_ZZ_UXTW):
Likewise.
opcodes/
* aarch64-tbl.h (AARCH64_OPERANDS): Add entries for the new SVE
address operands.
* aarch64-opc.h (FLD_SVE_imm6, FLD_SVE_msz, FLD_SVE_xs_14)
(FLD_SVE_xs_22): New aarch64_field_kinds.
(OPD_F_OD_MASK, OPD_F_OD_LSB, OPD_F_NO_ZR): New flags.
(get_operand_specific_data): New function.
* aarch64-opc.c (fields): Add entries for FLD_SVE_imm6, FLD_SVE_msz,
FLD_SVE_xs_14 and FLD_SVE_xs_22.
(operand_general_constraint_met_p): Handle the new SVE address
operands.
(sve_reg): New array.
(get_addr_sve_reg_name): New function.
(aarch64_print_operand): Handle the new SVE address operands.
* aarch64-opc-2.c: Regenerate.
* aarch64-asm.h (ins_sve_addr_ri_u6, ins_sve_addr_rr_lsl)
(ins_sve_addr_rz_xtw, ins_sve_addr_zi_u5, ins_sve_addr_zz_lsl)
(ins_sve_addr_zz_sxtw, ins_sve_addr_zz_uxtw): New inserters.
* aarch64-asm.c (aarch64_ins_sve_addr_ri_u6): New function.
(aarch64_ins_sve_addr_rr_lsl): Likewise.
(aarch64_ins_sve_addr_rz_xtw): Likewise.
(aarch64_ins_sve_addr_zi_u5): Likewise.
(aarch64_ins_sve_addr_zz): Likewise.
(aarch64_ins_sve_addr_zz_lsl): Likewise.
(aarch64_ins_sve_addr_zz_sxtw): Likewise.
(aarch64_ins_sve_addr_zz_uxtw): Likewise.
* aarch64-asm-2.c: Regenerate.
* aarch64-dis.h (ext_sve_addr_ri_u6, ext_sve_addr_rr_lsl)
(ext_sve_addr_rz_xtw, ext_sve_addr_zi_u5, ext_sve_addr_zz_lsl)
(ext_sve_addr_zz_sxtw, ext_sve_addr_zz_uxtw): New extractors.
* aarch64-dis.c (aarch64_ext_sve_add_reg_imm): New function.
(aarch64_ext_sve_addr_ri_u6): Likewise.
(aarch64_ext_sve_addr_rr_lsl): Likewise.
(aarch64_ext_sve_addr_rz_xtw): Likewise.
(aarch64_ext_sve_addr_zi_u5): Likewise.
(aarch64_ext_sve_addr_zz): Likewise.
(aarch64_ext_sve_addr_zz_lsl): Likewise.
(aarch64_ext_sve_addr_zz_sxtw): Likewise.
(aarch64_ext_sve_addr_zz_uxtw): Likewise.
* aarch64-dis-2.c: Regenerate.
gas/
* config/tc-aarch64.c (REG_TYPE_SVE_BASE, REG_TYPE_SVE_OFFSET): New
register types.
(get_reg_expected_msg): Handle them.
(aarch64_addr_reg_parse): New function, split out from
aarch64_reg_parse_32_64. Handle Z registers too.
(aarch64_reg_parse_32_64): Call it.
(parse_address_main): Add base_qualifier, offset_qualifier,
base_type and offset_type parameters. Handle SVE base and offset
registers.
(parse_address): Update call to parse_address_main.
(parse_sve_address): New function.
(parse_operands): Parse the new SVE address operands.
2016-09-21 17:55:49 +02:00
|
|
|
|
/* Decode an SVE address [<base>, #<offset> << <shift>], where <offset>
|
|
|
|
|
is given by the OFFSET parameter and where <shift> is SELF's operand-
|
|
|
|
|
dependent value. fields[0] specifies the base register field <base>. */
|
|
|
|
|
static int
|
|
|
|
|
aarch64_ext_sve_addr_reg_imm (const aarch64_operand *self,
|
|
|
|
|
aarch64_opnd_info *info, aarch64_insn code,
|
|
|
|
|
int64_t offset)
|
|
|
|
|
{
|
|
|
|
|
info->addr.base_regno = extract_field (self->fields[0], code, 0);
|
|
|
|
|
info->addr.offset.imm = offset * (1 << get_operand_specific_data (self));
|
|
|
|
|
info->addr.offset.is_reg = FALSE;
|
|
|
|
|
info->addr.writeback = FALSE;
|
|
|
|
|
info->addr.preind = TRUE;
|
|
|
|
|
info->shifter.operator_present = FALSE;
|
|
|
|
|
info->shifter.amount_present = FALSE;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
[AArch64] Additional SVE instructions
This patch supports some additions to the SVE architecture prior to
its public release.
include/
* opcode/aarch64.h (AARCH64_OPND_SVE_ADDR_RI_S4x16)
(AARCH64_OPND_SVE_IMM_ROT1, AARCH64_OPND_SVE_IMM_ROT2)
(AARCH64_OPND_SVE_Zm3_INDEX, AARCH64_OPND_SVE_Zm3_22_INDEX)
(AARCH64_OPND_SVE_Zm4_INDEX): New aarch64_opnds.
opcodes/
* aarch64-tbl.h (OP_SVE_HMH, OP_SVE_VMU_HSD, OP_SVE_VMVU_HSD)
(OP_SVE_VMVV_HSD, OP_SVE_VMVVU_HSD, OP_SVE_VM_HSD, OP_SVE_VUVV_HSD)
(OP_SVE_VUV_HSD, OP_SVE_VU_HSD, OP_SVE_VVVU_H, OP_SVE_VVVU_S)
(OP_SVE_VVVU_HSD, OP_SVE_VVV_D, OP_SVE_VVV_D_H, OP_SVE_VVV_H)
(OP_SVE_VVV_HSD, OP_SVE_VVV_S, OP_SVE_VVV_S_B, OP_SVE_VVV_SD_BH)
(OP_SVE_VV_BHSDQ, OP_SVE_VV_HSD, OP_SVE_VZVV_HSD, OP_SVE_VZV_HSD)
(OP_SVE_V_HSD): New macros.
(OP_SVE_VMU_SD, OP_SVE_VMVU_SD, OP_SVE_VM_SD, OP_SVE_VUVV_SD)
(OP_SVE_VU_SD, OP_SVE_VVVU_SD, OP_SVE_VVV_SD, OP_SVE_VZVV_SD)
(OP_SVE_VZV_SD, OP_SVE_V_SD): Delete.
(aarch64_opcode_table): Add new SVE instructions.
(aarch64_opcode_table): Use imm_rotate{1,2} instead of imm_rotate
for rotation operands. Add new SVE operands.
* aarch64-asm.h (ins_sve_addr_ri_s4): New inserter.
(ins_sve_quad_index): Likewise.
(ins_imm_rotate): Split into...
(ins_imm_rotate1, ins_imm_rotate2): ...these two inserters.
* aarch64-asm.c (aarch64_ins_imm_rotate): Split into...
(aarch64_ins_imm_rotate1, aarch64_ins_imm_rotate2): ...these two
functions.
(aarch64_ins_sve_addr_ri_s4): New function.
(aarch64_ins_sve_quad_index): Likewise.
(do_misc_encoding): Handle "MOV Zn.Q, Qm".
* aarch64-asm-2.c: Regenerate.
* aarch64-dis.h (ext_sve_addr_ri_s4): New extractor.
(ext_sve_quad_index): Likewise.
(ext_imm_rotate): Split into...
(ext_imm_rotate1, ext_imm_rotate2): ...these two extractors.
* aarch64-dis.c (aarch64_ext_imm_rotate): Split into...
(aarch64_ext_imm_rotate1, aarch64_ext_imm_rotate2): ...these two
functions.
(aarch64_ext_sve_addr_ri_s4): New function.
(aarch64_ext_sve_quad_index): Likewise.
(aarch64_ext_sve_index): Allow quad indices.
(do_misc_decoding): Likewise.
* aarch64-dis-2.c: Regenerate.
* aarch64-opc.h (FLD_SVE_i3h, FLD_SVE_rot1, FLD_SVE_rot2): New
aarch64_field_kinds.
(OPD_F_OD_MASK): Widen by one bit.
(OPD_F_NO_ZR): Bump accordingly.
(get_operand_field_width): New function.
* aarch64-opc.c (fields): Add new SVE fields.
(operand_general_constraint_met_p): Handle new SVE operands.
(aarch64_print_operand): Likewise.
* aarch64-opc-2.c: Regenerate.
gas/
* doc/c-aarch64.texi: Document that sve implies fp16, simd and compnum.
* config/tc-aarch64.c (parse_vector_type_for_operand): Allow .q
to be used with SVE registers.
(parse_operands): Handle new SVE operands.
(aarch64_features): Make "sve" require F16 rather than FP. Also
require COMPNUM.
* testsuite/gas/aarch64/sve.s: Add tests for new instructions.
Include compnum tests.
* testsuite/gas/aarch64/sve.d: Update accordingly.
* testsuite/gas/aarch64/sve-invalid.s: Add tests for new instructions.
* testsuite/gas/aarch64/sve-invalid.l: Update accordingly. Also
update expected output for new FMOV and MOV alternatives.
2017-02-24 19:29:00 +01:00
|
|
|
|
/* Decode an SVE address [X<n>, #<SVE_imm4> << <shift>], where <SVE_imm4>
|
|
|
|
|
is a 4-bit signed number and where <shift> is SELF's operand-dependent
|
|
|
|
|
value. fields[0] specifies the base register field. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_sve_addr_ri_s4 (const aarch64_operand *self,
|
|
|
|
|
aarch64_opnd_info *info, aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
int offset = sign_extend (extract_field (FLD_SVE_imm4, code, 0), 3);
|
|
|
|
|
return aarch64_ext_sve_addr_reg_imm (self, info, code, offset);
|
|
|
|
|
}
|
|
|
|
|
|
[AArch64][SVE 25/32] Add support for SVE addressing modes
This patch adds most of the new SVE addressing modes and associated
operands. A follow-on patch adds MUL VL, since handling it separately
makes the changes easier to read.
The patch also introduces a new "operand-dependent data" field to the
operand flags, based closely on the existing one for opcode flags.
For SVE this new field needs only 2 bits, but it could be widened
in future if necessary.
include/
* opcode/aarch64.h (AARCH64_OPND_SVE_ADDR_RI_U6): New aarch64_opnd.
(AARCH64_OPND_SVE_ADDR_RI_U6x2, AARCH64_OPND_SVE_ADDR_RI_U6x4)
(AARCH64_OPND_SVE_ADDR_RI_U6x8, AARCH64_OPND_SVE_ADDR_RR)
(AARCH64_OPND_SVE_ADDR_RR_LSL1, AARCH64_OPND_SVE_ADDR_RR_LSL2)
(AARCH64_OPND_SVE_ADDR_RR_LSL3, AARCH64_OPND_SVE_ADDR_RX)
(AARCH64_OPND_SVE_ADDR_RX_LSL1, AARCH64_OPND_SVE_ADDR_RX_LSL2)
(AARCH64_OPND_SVE_ADDR_RX_LSL3, AARCH64_OPND_SVE_ADDR_RZ)
(AARCH64_OPND_SVE_ADDR_RZ_LSL1, AARCH64_OPND_SVE_ADDR_RZ_LSL2)
(AARCH64_OPND_SVE_ADDR_RZ_LSL3, AARCH64_OPND_SVE_ADDR_RZ_XTW_14)
(AARCH64_OPND_SVE_ADDR_RZ_XTW_22, AARCH64_OPND_SVE_ADDR_RZ_XTW1_14)
(AARCH64_OPND_SVE_ADDR_RZ_XTW1_22, AARCH64_OPND_SVE_ADDR_RZ_XTW2_14)
(AARCH64_OPND_SVE_ADDR_RZ_XTW2_22, AARCH64_OPND_SVE_ADDR_RZ_XTW3_14)
(AARCH64_OPND_SVE_ADDR_RZ_XTW3_22, AARCH64_OPND_SVE_ADDR_ZI_U5)
(AARCH64_OPND_SVE_ADDR_ZI_U5x2, AARCH64_OPND_SVE_ADDR_ZI_U5x4)
(AARCH64_OPND_SVE_ADDR_ZI_U5x8, AARCH64_OPND_SVE_ADDR_ZZ_LSL)
(AARCH64_OPND_SVE_ADDR_ZZ_SXTW, AARCH64_OPND_SVE_ADDR_ZZ_UXTW):
Likewise.
opcodes/
* aarch64-tbl.h (AARCH64_OPERANDS): Add entries for the new SVE
address operands.
* aarch64-opc.h (FLD_SVE_imm6, FLD_SVE_msz, FLD_SVE_xs_14)
(FLD_SVE_xs_22): New aarch64_field_kinds.
(OPD_F_OD_MASK, OPD_F_OD_LSB, OPD_F_NO_ZR): New flags.
(get_operand_specific_data): New function.
* aarch64-opc.c (fields): Add entries for FLD_SVE_imm6, FLD_SVE_msz,
FLD_SVE_xs_14 and FLD_SVE_xs_22.
(operand_general_constraint_met_p): Handle the new SVE address
operands.
(sve_reg): New array.
(get_addr_sve_reg_name): New function.
(aarch64_print_operand): Handle the new SVE address operands.
* aarch64-opc-2.c: Regenerate.
* aarch64-asm.h (ins_sve_addr_ri_u6, ins_sve_addr_rr_lsl)
(ins_sve_addr_rz_xtw, ins_sve_addr_zi_u5, ins_sve_addr_zz_lsl)
(ins_sve_addr_zz_sxtw, ins_sve_addr_zz_uxtw): New inserters.
* aarch64-asm.c (aarch64_ins_sve_addr_ri_u6): New function.
(aarch64_ins_sve_addr_rr_lsl): Likewise.
(aarch64_ins_sve_addr_rz_xtw): Likewise.
(aarch64_ins_sve_addr_zi_u5): Likewise.
(aarch64_ins_sve_addr_zz): Likewise.
(aarch64_ins_sve_addr_zz_lsl): Likewise.
(aarch64_ins_sve_addr_zz_sxtw): Likewise.
(aarch64_ins_sve_addr_zz_uxtw): Likewise.
* aarch64-asm-2.c: Regenerate.
* aarch64-dis.h (ext_sve_addr_ri_u6, ext_sve_addr_rr_lsl)
(ext_sve_addr_rz_xtw, ext_sve_addr_zi_u5, ext_sve_addr_zz_lsl)
(ext_sve_addr_zz_sxtw, ext_sve_addr_zz_uxtw): New extractors.
* aarch64-dis.c (aarch64_ext_sve_add_reg_imm): New function.
(aarch64_ext_sve_addr_ri_u6): Likewise.
(aarch64_ext_sve_addr_rr_lsl): Likewise.
(aarch64_ext_sve_addr_rz_xtw): Likewise.
(aarch64_ext_sve_addr_zi_u5): Likewise.
(aarch64_ext_sve_addr_zz): Likewise.
(aarch64_ext_sve_addr_zz_lsl): Likewise.
(aarch64_ext_sve_addr_zz_sxtw): Likewise.
(aarch64_ext_sve_addr_zz_uxtw): Likewise.
* aarch64-dis-2.c: Regenerate.
gas/
* config/tc-aarch64.c (REG_TYPE_SVE_BASE, REG_TYPE_SVE_OFFSET): New
register types.
(get_reg_expected_msg): Handle them.
(aarch64_addr_reg_parse): New function, split out from
aarch64_reg_parse_32_64. Handle Z registers too.
(aarch64_reg_parse_32_64): Call it.
(parse_address_main): Add base_qualifier, offset_qualifier,
base_type and offset_type parameters. Handle SVE base and offset
registers.
(parse_address): Update call to parse_address_main.
(parse_sve_address): New function.
(parse_operands): Parse the new SVE address operands.
2016-09-21 17:55:49 +02:00
|
|
|
|
/* Decode an SVE address [X<n>, #<SVE_imm6> << <shift>], where <SVE_imm6>
|
|
|
|
|
is a 6-bit unsigned number and where <shift> is SELF's operand-dependent
|
|
|
|
|
value. fields[0] specifies the base register field. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_sve_addr_ri_u6 (const aarch64_operand *self,
|
|
|
|
|
aarch64_opnd_info *info, aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
int offset = extract_field (FLD_SVE_imm6, code, 0);
|
|
|
|
|
return aarch64_ext_sve_addr_reg_imm (self, info, code, offset);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode an SVE address [X<n>, X<m>{, LSL #<shift>}], where <shift>
|
|
|
|
|
is SELF's operand-dependent value. fields[0] specifies the base
|
|
|
|
|
register field and fields[1] specifies the offset register field. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_sve_addr_rr_lsl (const aarch64_operand *self,
|
|
|
|
|
aarch64_opnd_info *info, aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
2016-10-18 05:36:01 +02:00
|
|
|
|
int index_regno;
|
[AArch64][SVE 25/32] Add support for SVE addressing modes
This patch adds most of the new SVE addressing modes and associated
operands. A follow-on patch adds MUL VL, since handling it separately
makes the changes easier to read.
The patch also introduces a new "operand-dependent data" field to the
operand flags, based closely on the existing one for opcode flags.
For SVE this new field needs only 2 bits, but it could be widened
in future if necessary.
include/
* opcode/aarch64.h (AARCH64_OPND_SVE_ADDR_RI_U6): New aarch64_opnd.
(AARCH64_OPND_SVE_ADDR_RI_U6x2, AARCH64_OPND_SVE_ADDR_RI_U6x4)
(AARCH64_OPND_SVE_ADDR_RI_U6x8, AARCH64_OPND_SVE_ADDR_RR)
(AARCH64_OPND_SVE_ADDR_RR_LSL1, AARCH64_OPND_SVE_ADDR_RR_LSL2)
(AARCH64_OPND_SVE_ADDR_RR_LSL3, AARCH64_OPND_SVE_ADDR_RX)
(AARCH64_OPND_SVE_ADDR_RX_LSL1, AARCH64_OPND_SVE_ADDR_RX_LSL2)
(AARCH64_OPND_SVE_ADDR_RX_LSL3, AARCH64_OPND_SVE_ADDR_RZ)
(AARCH64_OPND_SVE_ADDR_RZ_LSL1, AARCH64_OPND_SVE_ADDR_RZ_LSL2)
(AARCH64_OPND_SVE_ADDR_RZ_LSL3, AARCH64_OPND_SVE_ADDR_RZ_XTW_14)
(AARCH64_OPND_SVE_ADDR_RZ_XTW_22, AARCH64_OPND_SVE_ADDR_RZ_XTW1_14)
(AARCH64_OPND_SVE_ADDR_RZ_XTW1_22, AARCH64_OPND_SVE_ADDR_RZ_XTW2_14)
(AARCH64_OPND_SVE_ADDR_RZ_XTW2_22, AARCH64_OPND_SVE_ADDR_RZ_XTW3_14)
(AARCH64_OPND_SVE_ADDR_RZ_XTW3_22, AARCH64_OPND_SVE_ADDR_ZI_U5)
(AARCH64_OPND_SVE_ADDR_ZI_U5x2, AARCH64_OPND_SVE_ADDR_ZI_U5x4)
(AARCH64_OPND_SVE_ADDR_ZI_U5x8, AARCH64_OPND_SVE_ADDR_ZZ_LSL)
(AARCH64_OPND_SVE_ADDR_ZZ_SXTW, AARCH64_OPND_SVE_ADDR_ZZ_UXTW):
Likewise.
opcodes/
* aarch64-tbl.h (AARCH64_OPERANDS): Add entries for the new SVE
address operands.
* aarch64-opc.h (FLD_SVE_imm6, FLD_SVE_msz, FLD_SVE_xs_14)
(FLD_SVE_xs_22): New aarch64_field_kinds.
(OPD_F_OD_MASK, OPD_F_OD_LSB, OPD_F_NO_ZR): New flags.
(get_operand_specific_data): New function.
* aarch64-opc.c (fields): Add entries for FLD_SVE_imm6, FLD_SVE_msz,
FLD_SVE_xs_14 and FLD_SVE_xs_22.
(operand_general_constraint_met_p): Handle the new SVE address
operands.
(sve_reg): New array.
(get_addr_sve_reg_name): New function.
(aarch64_print_operand): Handle the new SVE address operands.
* aarch64-opc-2.c: Regenerate.
* aarch64-asm.h (ins_sve_addr_ri_u6, ins_sve_addr_rr_lsl)
(ins_sve_addr_rz_xtw, ins_sve_addr_zi_u5, ins_sve_addr_zz_lsl)
(ins_sve_addr_zz_sxtw, ins_sve_addr_zz_uxtw): New inserters.
* aarch64-asm.c (aarch64_ins_sve_addr_ri_u6): New function.
(aarch64_ins_sve_addr_rr_lsl): Likewise.
(aarch64_ins_sve_addr_rz_xtw): Likewise.
(aarch64_ins_sve_addr_zi_u5): Likewise.
(aarch64_ins_sve_addr_zz): Likewise.
(aarch64_ins_sve_addr_zz_lsl): Likewise.
(aarch64_ins_sve_addr_zz_sxtw): Likewise.
(aarch64_ins_sve_addr_zz_uxtw): Likewise.
* aarch64-asm-2.c: Regenerate.
* aarch64-dis.h (ext_sve_addr_ri_u6, ext_sve_addr_rr_lsl)
(ext_sve_addr_rz_xtw, ext_sve_addr_zi_u5, ext_sve_addr_zz_lsl)
(ext_sve_addr_zz_sxtw, ext_sve_addr_zz_uxtw): New extractors.
* aarch64-dis.c (aarch64_ext_sve_add_reg_imm): New function.
(aarch64_ext_sve_addr_ri_u6): Likewise.
(aarch64_ext_sve_addr_rr_lsl): Likewise.
(aarch64_ext_sve_addr_rz_xtw): Likewise.
(aarch64_ext_sve_addr_zi_u5): Likewise.
(aarch64_ext_sve_addr_zz): Likewise.
(aarch64_ext_sve_addr_zz_lsl): Likewise.
(aarch64_ext_sve_addr_zz_sxtw): Likewise.
(aarch64_ext_sve_addr_zz_uxtw): Likewise.
* aarch64-dis-2.c: Regenerate.
gas/
* config/tc-aarch64.c (REG_TYPE_SVE_BASE, REG_TYPE_SVE_OFFSET): New
register types.
(get_reg_expected_msg): Handle them.
(aarch64_addr_reg_parse): New function, split out from
aarch64_reg_parse_32_64. Handle Z registers too.
(aarch64_reg_parse_32_64): Call it.
(parse_address_main): Add base_qualifier, offset_qualifier,
base_type and offset_type parameters. Handle SVE base and offset
registers.
(parse_address): Update call to parse_address_main.
(parse_sve_address): New function.
(parse_operands): Parse the new SVE address operands.
2016-09-21 17:55:49 +02:00
|
|
|
|
|
2016-10-18 05:36:01 +02:00
|
|
|
|
index_regno = extract_field (self->fields[1], code, 0);
|
|
|
|
|
if (index_regno == 31 && (self->flags & OPD_F_NO_ZR) != 0)
|
[AArch64][SVE 25/32] Add support for SVE addressing modes
This patch adds most of the new SVE addressing modes and associated
operands. A follow-on patch adds MUL VL, since handling it separately
makes the changes easier to read.
The patch also introduces a new "operand-dependent data" field to the
operand flags, based closely on the existing one for opcode flags.
For SVE this new field needs only 2 bits, but it could be widened
in future if necessary.
include/
* opcode/aarch64.h (AARCH64_OPND_SVE_ADDR_RI_U6): New aarch64_opnd.
(AARCH64_OPND_SVE_ADDR_RI_U6x2, AARCH64_OPND_SVE_ADDR_RI_U6x4)
(AARCH64_OPND_SVE_ADDR_RI_U6x8, AARCH64_OPND_SVE_ADDR_RR)
(AARCH64_OPND_SVE_ADDR_RR_LSL1, AARCH64_OPND_SVE_ADDR_RR_LSL2)
(AARCH64_OPND_SVE_ADDR_RR_LSL3, AARCH64_OPND_SVE_ADDR_RX)
(AARCH64_OPND_SVE_ADDR_RX_LSL1, AARCH64_OPND_SVE_ADDR_RX_LSL2)
(AARCH64_OPND_SVE_ADDR_RX_LSL3, AARCH64_OPND_SVE_ADDR_RZ)
(AARCH64_OPND_SVE_ADDR_RZ_LSL1, AARCH64_OPND_SVE_ADDR_RZ_LSL2)
(AARCH64_OPND_SVE_ADDR_RZ_LSL3, AARCH64_OPND_SVE_ADDR_RZ_XTW_14)
(AARCH64_OPND_SVE_ADDR_RZ_XTW_22, AARCH64_OPND_SVE_ADDR_RZ_XTW1_14)
(AARCH64_OPND_SVE_ADDR_RZ_XTW1_22, AARCH64_OPND_SVE_ADDR_RZ_XTW2_14)
(AARCH64_OPND_SVE_ADDR_RZ_XTW2_22, AARCH64_OPND_SVE_ADDR_RZ_XTW3_14)
(AARCH64_OPND_SVE_ADDR_RZ_XTW3_22, AARCH64_OPND_SVE_ADDR_ZI_U5)
(AARCH64_OPND_SVE_ADDR_ZI_U5x2, AARCH64_OPND_SVE_ADDR_ZI_U5x4)
(AARCH64_OPND_SVE_ADDR_ZI_U5x8, AARCH64_OPND_SVE_ADDR_ZZ_LSL)
(AARCH64_OPND_SVE_ADDR_ZZ_SXTW, AARCH64_OPND_SVE_ADDR_ZZ_UXTW):
Likewise.
opcodes/
* aarch64-tbl.h (AARCH64_OPERANDS): Add entries for the new SVE
address operands.
* aarch64-opc.h (FLD_SVE_imm6, FLD_SVE_msz, FLD_SVE_xs_14)
(FLD_SVE_xs_22): New aarch64_field_kinds.
(OPD_F_OD_MASK, OPD_F_OD_LSB, OPD_F_NO_ZR): New flags.
(get_operand_specific_data): New function.
* aarch64-opc.c (fields): Add entries for FLD_SVE_imm6, FLD_SVE_msz,
FLD_SVE_xs_14 and FLD_SVE_xs_22.
(operand_general_constraint_met_p): Handle the new SVE address
operands.
(sve_reg): New array.
(get_addr_sve_reg_name): New function.
(aarch64_print_operand): Handle the new SVE address operands.
* aarch64-opc-2.c: Regenerate.
* aarch64-asm.h (ins_sve_addr_ri_u6, ins_sve_addr_rr_lsl)
(ins_sve_addr_rz_xtw, ins_sve_addr_zi_u5, ins_sve_addr_zz_lsl)
(ins_sve_addr_zz_sxtw, ins_sve_addr_zz_uxtw): New inserters.
* aarch64-asm.c (aarch64_ins_sve_addr_ri_u6): New function.
(aarch64_ins_sve_addr_rr_lsl): Likewise.
(aarch64_ins_sve_addr_rz_xtw): Likewise.
(aarch64_ins_sve_addr_zi_u5): Likewise.
(aarch64_ins_sve_addr_zz): Likewise.
(aarch64_ins_sve_addr_zz_lsl): Likewise.
(aarch64_ins_sve_addr_zz_sxtw): Likewise.
(aarch64_ins_sve_addr_zz_uxtw): Likewise.
* aarch64-asm-2.c: Regenerate.
* aarch64-dis.h (ext_sve_addr_ri_u6, ext_sve_addr_rr_lsl)
(ext_sve_addr_rz_xtw, ext_sve_addr_zi_u5, ext_sve_addr_zz_lsl)
(ext_sve_addr_zz_sxtw, ext_sve_addr_zz_uxtw): New extractors.
* aarch64-dis.c (aarch64_ext_sve_add_reg_imm): New function.
(aarch64_ext_sve_addr_ri_u6): Likewise.
(aarch64_ext_sve_addr_rr_lsl): Likewise.
(aarch64_ext_sve_addr_rz_xtw): Likewise.
(aarch64_ext_sve_addr_zi_u5): Likewise.
(aarch64_ext_sve_addr_zz): Likewise.
(aarch64_ext_sve_addr_zz_lsl): Likewise.
(aarch64_ext_sve_addr_zz_sxtw): Likewise.
(aarch64_ext_sve_addr_zz_uxtw): Likewise.
* aarch64-dis-2.c: Regenerate.
gas/
* config/tc-aarch64.c (REG_TYPE_SVE_BASE, REG_TYPE_SVE_OFFSET): New
register types.
(get_reg_expected_msg): Handle them.
(aarch64_addr_reg_parse): New function, split out from
aarch64_reg_parse_32_64. Handle Z registers too.
(aarch64_reg_parse_32_64): Call it.
(parse_address_main): Add base_qualifier, offset_qualifier,
base_type and offset_type parameters. Handle SVE base and offset
registers.
(parse_address): Update call to parse_address_main.
(parse_sve_address): New function.
(parse_operands): Parse the new SVE address operands.
2016-09-21 17:55:49 +02:00
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
info->addr.base_regno = extract_field (self->fields[0], code, 0);
|
2016-10-18 05:36:01 +02:00
|
|
|
|
info->addr.offset.regno = index_regno;
|
[AArch64][SVE 25/32] Add support for SVE addressing modes
This patch adds most of the new SVE addressing modes and associated
operands. A follow-on patch adds MUL VL, since handling it separately
makes the changes easier to read.
The patch also introduces a new "operand-dependent data" field to the
operand flags, based closely on the existing one for opcode flags.
For SVE this new field needs only 2 bits, but it could be widened
in future if necessary.
include/
* opcode/aarch64.h (AARCH64_OPND_SVE_ADDR_RI_U6): New aarch64_opnd.
(AARCH64_OPND_SVE_ADDR_RI_U6x2, AARCH64_OPND_SVE_ADDR_RI_U6x4)
(AARCH64_OPND_SVE_ADDR_RI_U6x8, AARCH64_OPND_SVE_ADDR_RR)
(AARCH64_OPND_SVE_ADDR_RR_LSL1, AARCH64_OPND_SVE_ADDR_RR_LSL2)
(AARCH64_OPND_SVE_ADDR_RR_LSL3, AARCH64_OPND_SVE_ADDR_RX)
(AARCH64_OPND_SVE_ADDR_RX_LSL1, AARCH64_OPND_SVE_ADDR_RX_LSL2)
(AARCH64_OPND_SVE_ADDR_RX_LSL3, AARCH64_OPND_SVE_ADDR_RZ)
(AARCH64_OPND_SVE_ADDR_RZ_LSL1, AARCH64_OPND_SVE_ADDR_RZ_LSL2)
(AARCH64_OPND_SVE_ADDR_RZ_LSL3, AARCH64_OPND_SVE_ADDR_RZ_XTW_14)
(AARCH64_OPND_SVE_ADDR_RZ_XTW_22, AARCH64_OPND_SVE_ADDR_RZ_XTW1_14)
(AARCH64_OPND_SVE_ADDR_RZ_XTW1_22, AARCH64_OPND_SVE_ADDR_RZ_XTW2_14)
(AARCH64_OPND_SVE_ADDR_RZ_XTW2_22, AARCH64_OPND_SVE_ADDR_RZ_XTW3_14)
(AARCH64_OPND_SVE_ADDR_RZ_XTW3_22, AARCH64_OPND_SVE_ADDR_ZI_U5)
(AARCH64_OPND_SVE_ADDR_ZI_U5x2, AARCH64_OPND_SVE_ADDR_ZI_U5x4)
(AARCH64_OPND_SVE_ADDR_ZI_U5x8, AARCH64_OPND_SVE_ADDR_ZZ_LSL)
(AARCH64_OPND_SVE_ADDR_ZZ_SXTW, AARCH64_OPND_SVE_ADDR_ZZ_UXTW):
Likewise.
opcodes/
* aarch64-tbl.h (AARCH64_OPERANDS): Add entries for the new SVE
address operands.
* aarch64-opc.h (FLD_SVE_imm6, FLD_SVE_msz, FLD_SVE_xs_14)
(FLD_SVE_xs_22): New aarch64_field_kinds.
(OPD_F_OD_MASK, OPD_F_OD_LSB, OPD_F_NO_ZR): New flags.
(get_operand_specific_data): New function.
* aarch64-opc.c (fields): Add entries for FLD_SVE_imm6, FLD_SVE_msz,
FLD_SVE_xs_14 and FLD_SVE_xs_22.
(operand_general_constraint_met_p): Handle the new SVE address
operands.
(sve_reg): New array.
(get_addr_sve_reg_name): New function.
(aarch64_print_operand): Handle the new SVE address operands.
* aarch64-opc-2.c: Regenerate.
* aarch64-asm.h (ins_sve_addr_ri_u6, ins_sve_addr_rr_lsl)
(ins_sve_addr_rz_xtw, ins_sve_addr_zi_u5, ins_sve_addr_zz_lsl)
(ins_sve_addr_zz_sxtw, ins_sve_addr_zz_uxtw): New inserters.
* aarch64-asm.c (aarch64_ins_sve_addr_ri_u6): New function.
(aarch64_ins_sve_addr_rr_lsl): Likewise.
(aarch64_ins_sve_addr_rz_xtw): Likewise.
(aarch64_ins_sve_addr_zi_u5): Likewise.
(aarch64_ins_sve_addr_zz): Likewise.
(aarch64_ins_sve_addr_zz_lsl): Likewise.
(aarch64_ins_sve_addr_zz_sxtw): Likewise.
(aarch64_ins_sve_addr_zz_uxtw): Likewise.
* aarch64-asm-2.c: Regenerate.
* aarch64-dis.h (ext_sve_addr_ri_u6, ext_sve_addr_rr_lsl)
(ext_sve_addr_rz_xtw, ext_sve_addr_zi_u5, ext_sve_addr_zz_lsl)
(ext_sve_addr_zz_sxtw, ext_sve_addr_zz_uxtw): New extractors.
* aarch64-dis.c (aarch64_ext_sve_add_reg_imm): New function.
(aarch64_ext_sve_addr_ri_u6): Likewise.
(aarch64_ext_sve_addr_rr_lsl): Likewise.
(aarch64_ext_sve_addr_rz_xtw): Likewise.
(aarch64_ext_sve_addr_zi_u5): Likewise.
(aarch64_ext_sve_addr_zz): Likewise.
(aarch64_ext_sve_addr_zz_lsl): Likewise.
(aarch64_ext_sve_addr_zz_sxtw): Likewise.
(aarch64_ext_sve_addr_zz_uxtw): Likewise.
* aarch64-dis-2.c: Regenerate.
gas/
* config/tc-aarch64.c (REG_TYPE_SVE_BASE, REG_TYPE_SVE_OFFSET): New
register types.
(get_reg_expected_msg): Handle them.
(aarch64_addr_reg_parse): New function, split out from
aarch64_reg_parse_32_64. Handle Z registers too.
(aarch64_reg_parse_32_64): Call it.
(parse_address_main): Add base_qualifier, offset_qualifier,
base_type and offset_type parameters. Handle SVE base and offset
registers.
(parse_address): Update call to parse_address_main.
(parse_sve_address): New function.
(parse_operands): Parse the new SVE address operands.
2016-09-21 17:55:49 +02:00
|
|
|
|
info->addr.offset.is_reg = TRUE;
|
|
|
|
|
info->addr.writeback = FALSE;
|
|
|
|
|
info->addr.preind = TRUE;
|
|
|
|
|
info->shifter.kind = AARCH64_MOD_LSL;
|
|
|
|
|
info->shifter.amount = get_operand_specific_data (self);
|
|
|
|
|
info->shifter.operator_present = (info->shifter.amount != 0);
|
|
|
|
|
info->shifter.amount_present = (info->shifter.amount != 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode an SVE address [X<n>, Z<m>.<T>, (S|U)XTW {#<shift>}], where
|
|
|
|
|
<shift> is SELF's operand-dependent value. fields[0] specifies the
|
|
|
|
|
base register field, fields[1] specifies the offset register field and
|
|
|
|
|
fields[2] is a single-bit field that selects SXTW over UXTW. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_sve_addr_rz_xtw (const aarch64_operand *self,
|
|
|
|
|
aarch64_opnd_info *info, aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
info->addr.base_regno = extract_field (self->fields[0], code, 0);
|
|
|
|
|
info->addr.offset.regno = extract_field (self->fields[1], code, 0);
|
|
|
|
|
info->addr.offset.is_reg = TRUE;
|
|
|
|
|
info->addr.writeback = FALSE;
|
|
|
|
|
info->addr.preind = TRUE;
|
|
|
|
|
if (extract_field (self->fields[2], code, 0))
|
|
|
|
|
info->shifter.kind = AARCH64_MOD_SXTW;
|
|
|
|
|
else
|
|
|
|
|
info->shifter.kind = AARCH64_MOD_UXTW;
|
|
|
|
|
info->shifter.amount = get_operand_specific_data (self);
|
|
|
|
|
info->shifter.operator_present = TRUE;
|
|
|
|
|
info->shifter.amount_present = (info->shifter.amount != 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode an SVE address [Z<n>.<T>, #<imm5> << <shift>], where <imm5> is a
|
|
|
|
|
5-bit unsigned number and where <shift> is SELF's operand-dependent value.
|
|
|
|
|
fields[0] specifies the base register field. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_sve_addr_zi_u5 (const aarch64_operand *self,
|
|
|
|
|
aarch64_opnd_info *info, aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
int offset = extract_field (FLD_imm5, code, 0);
|
|
|
|
|
return aarch64_ext_sve_addr_reg_imm (self, info, code, offset);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode an SVE address [Z<n>.<T>, Z<m>.<T>{, <modifier> {#<msz>}}],
|
|
|
|
|
where <modifier> is given by KIND and where <msz> is a 2-bit unsigned
|
|
|
|
|
number. fields[0] specifies the base register field and fields[1]
|
|
|
|
|
specifies the offset register field. */
|
|
|
|
|
static int
|
|
|
|
|
aarch64_ext_sve_addr_zz (const aarch64_operand *self, aarch64_opnd_info *info,
|
|
|
|
|
aarch64_insn code, enum aarch64_modifier_kind kind)
|
|
|
|
|
{
|
|
|
|
|
info->addr.base_regno = extract_field (self->fields[0], code, 0);
|
|
|
|
|
info->addr.offset.regno = extract_field (self->fields[1], code, 0);
|
|
|
|
|
info->addr.offset.is_reg = TRUE;
|
|
|
|
|
info->addr.writeback = FALSE;
|
|
|
|
|
info->addr.preind = TRUE;
|
|
|
|
|
info->shifter.kind = kind;
|
|
|
|
|
info->shifter.amount = extract_field (FLD_SVE_msz, code, 0);
|
|
|
|
|
info->shifter.operator_present = (kind != AARCH64_MOD_LSL
|
|
|
|
|
|| info->shifter.amount != 0);
|
|
|
|
|
info->shifter.amount_present = (info->shifter.amount != 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode an SVE address [Z<n>.<T>, Z<m>.<T>{, LSL #<msz>}], where
|
|
|
|
|
<msz> is a 2-bit unsigned number. fields[0] specifies the base register
|
|
|
|
|
field and fields[1] specifies the offset register field. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_sve_addr_zz_lsl (const aarch64_operand *self,
|
|
|
|
|
aarch64_opnd_info *info, aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
return aarch64_ext_sve_addr_zz (self, info, code, AARCH64_MOD_LSL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode an SVE address [Z<n>.<T>, Z<m>.<T>, SXTW {#<msz>}], where
|
|
|
|
|
<msz> is a 2-bit unsigned number. fields[0] specifies the base register
|
|
|
|
|
field and fields[1] specifies the offset register field. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_sve_addr_zz_sxtw (const aarch64_operand *self,
|
|
|
|
|
aarch64_opnd_info *info, aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
return aarch64_ext_sve_addr_zz (self, info, code, AARCH64_MOD_SXTW);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode an SVE address [Z<n>.<T>, Z<m>.<T>, UXTW {#<msz>}], where
|
|
|
|
|
<msz> is a 2-bit unsigned number. fields[0] specifies the base register
|
|
|
|
|
field and fields[1] specifies the offset register field. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_sve_addr_zz_uxtw (const aarch64_operand *self,
|
|
|
|
|
aarch64_opnd_info *info, aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
return aarch64_ext_sve_addr_zz (self, info, code, AARCH64_MOD_UXTW);
|
|
|
|
|
}
|
|
|
|
|
|
[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.
2016-09-21 17:56:57 +02:00
|
|
|
|
/* 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));
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-21 17:57:22 +02:00
|
|
|
|
/* Decode a single-bit immediate that selects between #0.5 and #1.0.
|
|
|
|
|
The fields array specifies which field to use. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_sve_float_half_one (const aarch64_operand *self,
|
|
|
|
|
aarch64_opnd_info *info, aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
if (extract_field (self->fields[0], code, 0))
|
|
|
|
|
info->imm.value = 0x3f800000;
|
|
|
|
|
else
|
|
|
|
|
info->imm.value = 0x3f000000;
|
|
|
|
|
info->imm.is_fp = TRUE;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode a single-bit immediate that selects between #0.5 and #2.0.
|
|
|
|
|
The fields array specifies which field to use. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_sve_float_half_two (const aarch64_operand *self,
|
|
|
|
|
aarch64_opnd_info *info, aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
if (extract_field (self->fields[0], code, 0))
|
|
|
|
|
info->imm.value = 0x40000000;
|
|
|
|
|
else
|
|
|
|
|
info->imm.value = 0x3f000000;
|
|
|
|
|
info->imm.is_fp = TRUE;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode a single-bit immediate that selects between #0.0 and #1.0.
|
|
|
|
|
The fields array specifies which field to use. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_sve_float_zero_one (const aarch64_operand *self,
|
|
|
|
|
aarch64_opnd_info *info, aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
if (extract_field (self->fields[0], code, 0))
|
|
|
|
|
info->imm.value = 0x3f800000;
|
|
|
|
|
else
|
|
|
|
|
info->imm.value = 0x0;
|
|
|
|
|
info->imm.is_fp = TRUE;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
[AArch64][SVE 21/32] Add Zn and Pn registers
This patch adds the Zn and Pn registers, and associated fields and
operands.
include/
* opcode/aarch64.h (AARCH64_OPND_CLASS_SVE_REG): New
aarch64_operand_class.
(AARCH64_OPND_CLASS_PRED_REG): Likewise.
(AARCH64_OPND_SVE_Pd, AARCH64_OPND_SVE_Pg3, AARCH64_OPND_SVE_Pg4_5)
(AARCH64_OPND_SVE_Pg4_10, AARCH64_OPND_SVE_Pg4_16)
(AARCH64_OPND_SVE_Pm, AARCH64_OPND_SVE_Pn, AARCH64_OPND_SVE_Pt)
(AARCH64_OPND_SVE_Za_5, AARCH64_OPND_SVE_Za_16, AARCH64_OPND_SVE_Zd)
(AARCH64_OPND_SVE_Zm_5, AARCH64_OPND_SVE_Zm_16, AARCH64_OPND_SVE_Zn)
(AARCH64_OPND_SVE_Zn_INDEX, AARCH64_OPND_SVE_ZnxN)
(AARCH64_OPND_SVE_Zt, AARCH64_OPND_SVE_ZtxN): New aarch64_opnds.
opcodes/
* aarch64-tbl.h (AARCH64_OPERANDS): Add entries for new SVE operands.
* aarch64-opc.h (FLD_SVE_Pd, FLD_SVE_Pg3, FLD_SVE_Pg4_5)
(FLD_SVE_Pg4_10, FLD_SVE_Pg4_16, FLD_SVE_Pm, FLD_SVE_Pn, FLD_SVE_Pt)
(FLD_SVE_Za_5, FLD_SVE_Za_16, FLD_SVE_Zd, FLD_SVE_Zm_5, FLD_SVE_Zm_16)
(FLD_SVE_Zn, FLD_SVE_Zt, FLD_SVE_tzsh): New aarch64_field_kinds.
* aarch64-opc.c (fields): Add corresponding entries here.
(operand_general_constraint_met_p): Check that SVE register lists
have the correct length. Check the ranges of SVE index registers.
Check for cases where p8-p15 are used in 3-bit predicate fields.
(aarch64_print_operand): Handle the new SVE operands.
* aarch64-opc-2.c: Regenerate.
* aarch64-asm.h (ins_sve_index, ins_sve_reglist): New inserters.
* aarch64-asm.c (aarch64_ins_sve_index): New function.
(aarch64_ins_sve_reglist): Likewise.
* aarch64-asm-2.c: Regenerate.
* aarch64-dis.h (ext_sve_index, ext_sve_reglist): New extractors.
* aarch64-dis.c (aarch64_ext_sve_index): New function.
(aarch64_ext_sve_reglist): Likewise.
* aarch64-dis-2.c: Regenerate.
gas/
* config/tc-aarch64.c (NTA_HASVARWIDTH): New macro.
(AARCH64_REG_TYPES): Add ZN and PN.
(get_reg_expected_msg): Handle them.
(parse_vector_type_for_operand): Add a reg_type parameter.
Skip the width for Zn and Pn registers.
(parse_typed_reg): Extend vector handling to Zn and Pn. Update the
call to parse_vector_type_for_operand. Set HASVARTYPE for Zn and Pn,
expecting the width to be 0.
(parse_vector_reg_list): Restrict error about [BHSD]nn operands to
REG_TYPE_VN.
(vectype_to_qualifier): Use S_[BHSD] qualifiers for NTA_HASVARWIDTH.
(parse_operands): Handle the new Zn and Pn operands.
(REGSET16): New macro, split out from...
(REGSET31): ...here.
(reg_names): Add Zn and Pn entries.
2016-09-21 17:53:54 +02:00
|
|
|
|
/* 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
|
|
|
|
|
significant part. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_sve_index (const aarch64_operand *self,
|
|
|
|
|
aarch64_opnd_info *info, aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
int val;
|
|
|
|
|
|
|
|
|
|
info->reglane.regno = extract_field (self->fields[0], code, 0);
|
|
|
|
|
val = extract_fields (code, 0, 2, FLD_SVE_tszh, FLD_imm5);
|
[AArch64] Additional SVE instructions
This patch supports some additions to the SVE architecture prior to
its public release.
include/
* opcode/aarch64.h (AARCH64_OPND_SVE_ADDR_RI_S4x16)
(AARCH64_OPND_SVE_IMM_ROT1, AARCH64_OPND_SVE_IMM_ROT2)
(AARCH64_OPND_SVE_Zm3_INDEX, AARCH64_OPND_SVE_Zm3_22_INDEX)
(AARCH64_OPND_SVE_Zm4_INDEX): New aarch64_opnds.
opcodes/
* aarch64-tbl.h (OP_SVE_HMH, OP_SVE_VMU_HSD, OP_SVE_VMVU_HSD)
(OP_SVE_VMVV_HSD, OP_SVE_VMVVU_HSD, OP_SVE_VM_HSD, OP_SVE_VUVV_HSD)
(OP_SVE_VUV_HSD, OP_SVE_VU_HSD, OP_SVE_VVVU_H, OP_SVE_VVVU_S)
(OP_SVE_VVVU_HSD, OP_SVE_VVV_D, OP_SVE_VVV_D_H, OP_SVE_VVV_H)
(OP_SVE_VVV_HSD, OP_SVE_VVV_S, OP_SVE_VVV_S_B, OP_SVE_VVV_SD_BH)
(OP_SVE_VV_BHSDQ, OP_SVE_VV_HSD, OP_SVE_VZVV_HSD, OP_SVE_VZV_HSD)
(OP_SVE_V_HSD): New macros.
(OP_SVE_VMU_SD, OP_SVE_VMVU_SD, OP_SVE_VM_SD, OP_SVE_VUVV_SD)
(OP_SVE_VU_SD, OP_SVE_VVVU_SD, OP_SVE_VVV_SD, OP_SVE_VZVV_SD)
(OP_SVE_VZV_SD, OP_SVE_V_SD): Delete.
(aarch64_opcode_table): Add new SVE instructions.
(aarch64_opcode_table): Use imm_rotate{1,2} instead of imm_rotate
for rotation operands. Add new SVE operands.
* aarch64-asm.h (ins_sve_addr_ri_s4): New inserter.
(ins_sve_quad_index): Likewise.
(ins_imm_rotate): Split into...
(ins_imm_rotate1, ins_imm_rotate2): ...these two inserters.
* aarch64-asm.c (aarch64_ins_imm_rotate): Split into...
(aarch64_ins_imm_rotate1, aarch64_ins_imm_rotate2): ...these two
functions.
(aarch64_ins_sve_addr_ri_s4): New function.
(aarch64_ins_sve_quad_index): Likewise.
(do_misc_encoding): Handle "MOV Zn.Q, Qm".
* aarch64-asm-2.c: Regenerate.
* aarch64-dis.h (ext_sve_addr_ri_s4): New extractor.
(ext_sve_quad_index): Likewise.
(ext_imm_rotate): Split into...
(ext_imm_rotate1, ext_imm_rotate2): ...these two extractors.
* aarch64-dis.c (aarch64_ext_imm_rotate): Split into...
(aarch64_ext_imm_rotate1, aarch64_ext_imm_rotate2): ...these two
functions.
(aarch64_ext_sve_addr_ri_s4): New function.
(aarch64_ext_sve_quad_index): Likewise.
(aarch64_ext_sve_index): Allow quad indices.
(do_misc_decoding): Likewise.
* aarch64-dis-2.c: Regenerate.
* aarch64-opc.h (FLD_SVE_i3h, FLD_SVE_rot1, FLD_SVE_rot2): New
aarch64_field_kinds.
(OPD_F_OD_MASK): Widen by one bit.
(OPD_F_NO_ZR): Bump accordingly.
(get_operand_field_width): New function.
* aarch64-opc.c (fields): Add new SVE fields.
(operand_general_constraint_met_p): Handle new SVE operands.
(aarch64_print_operand): Likewise.
* aarch64-opc-2.c: Regenerate.
gas/
* doc/c-aarch64.texi: Document that sve implies fp16, simd and compnum.
* config/tc-aarch64.c (parse_vector_type_for_operand): Allow .q
to be used with SVE registers.
(parse_operands): Handle new SVE operands.
(aarch64_features): Make "sve" require F16 rather than FP. Also
require COMPNUM.
* testsuite/gas/aarch64/sve.s: Add tests for new instructions.
Include compnum tests.
* testsuite/gas/aarch64/sve.d: Update accordingly.
* testsuite/gas/aarch64/sve-invalid.s: Add tests for new instructions.
* testsuite/gas/aarch64/sve-invalid.l: Update accordingly. Also
update expected output for new FMOV and MOV alternatives.
2017-02-24 19:29:00 +01:00
|
|
|
|
if ((val & 31) == 0)
|
[AArch64][SVE 21/32] Add Zn and Pn registers
This patch adds the Zn and Pn registers, and associated fields and
operands.
include/
* opcode/aarch64.h (AARCH64_OPND_CLASS_SVE_REG): New
aarch64_operand_class.
(AARCH64_OPND_CLASS_PRED_REG): Likewise.
(AARCH64_OPND_SVE_Pd, AARCH64_OPND_SVE_Pg3, AARCH64_OPND_SVE_Pg4_5)
(AARCH64_OPND_SVE_Pg4_10, AARCH64_OPND_SVE_Pg4_16)
(AARCH64_OPND_SVE_Pm, AARCH64_OPND_SVE_Pn, AARCH64_OPND_SVE_Pt)
(AARCH64_OPND_SVE_Za_5, AARCH64_OPND_SVE_Za_16, AARCH64_OPND_SVE_Zd)
(AARCH64_OPND_SVE_Zm_5, AARCH64_OPND_SVE_Zm_16, AARCH64_OPND_SVE_Zn)
(AARCH64_OPND_SVE_Zn_INDEX, AARCH64_OPND_SVE_ZnxN)
(AARCH64_OPND_SVE_Zt, AARCH64_OPND_SVE_ZtxN): New aarch64_opnds.
opcodes/
* aarch64-tbl.h (AARCH64_OPERANDS): Add entries for new SVE operands.
* aarch64-opc.h (FLD_SVE_Pd, FLD_SVE_Pg3, FLD_SVE_Pg4_5)
(FLD_SVE_Pg4_10, FLD_SVE_Pg4_16, FLD_SVE_Pm, FLD_SVE_Pn, FLD_SVE_Pt)
(FLD_SVE_Za_5, FLD_SVE_Za_16, FLD_SVE_Zd, FLD_SVE_Zm_5, FLD_SVE_Zm_16)
(FLD_SVE_Zn, FLD_SVE_Zt, FLD_SVE_tzsh): New aarch64_field_kinds.
* aarch64-opc.c (fields): Add corresponding entries here.
(operand_general_constraint_met_p): Check that SVE register lists
have the correct length. Check the ranges of SVE index registers.
Check for cases where p8-p15 are used in 3-bit predicate fields.
(aarch64_print_operand): Handle the new SVE operands.
* aarch64-opc-2.c: Regenerate.
* aarch64-asm.h (ins_sve_index, ins_sve_reglist): New inserters.
* aarch64-asm.c (aarch64_ins_sve_index): New function.
(aarch64_ins_sve_reglist): Likewise.
* aarch64-asm-2.c: Regenerate.
* aarch64-dis.h (ext_sve_index, ext_sve_reglist): New extractors.
* aarch64-dis.c (aarch64_ext_sve_index): New function.
(aarch64_ext_sve_reglist): Likewise.
* aarch64-dis-2.c: Regenerate.
gas/
* config/tc-aarch64.c (NTA_HASVARWIDTH): New macro.
(AARCH64_REG_TYPES): Add ZN and PN.
(get_reg_expected_msg): Handle them.
(parse_vector_type_for_operand): Add a reg_type parameter.
Skip the width for Zn and Pn registers.
(parse_typed_reg): Extend vector handling to Zn and Pn. Update the
call to parse_vector_type_for_operand. Set HASVARTYPE for Zn and Pn,
expecting the width to be 0.
(parse_vector_reg_list): Restrict error about [BHSD]nn operands to
REG_TYPE_VN.
(vectype_to_qualifier): Use S_[BHSD] qualifiers for NTA_HASVARWIDTH.
(parse_operands): Handle the new Zn and Pn operands.
(REGSET16): New macro, split out from...
(REGSET31): ...here.
(reg_names): Add Zn and Pn entries.
2016-09-21 17:53:54 +02:00
|
|
|
|
return 0;
|
|
|
|
|
while ((val & 1) == 0)
|
|
|
|
|
val /= 2;
|
|
|
|
|
info->reglane.index = val / 2;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
[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.
2016-09-21 17:56:57 +02:00
|
|
|
|
/* 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));
|
|
|
|
|
}
|
|
|
|
|
|
[AArch64] Additional SVE instructions
This patch supports some additions to the SVE architecture prior to
its public release.
include/
* opcode/aarch64.h (AARCH64_OPND_SVE_ADDR_RI_S4x16)
(AARCH64_OPND_SVE_IMM_ROT1, AARCH64_OPND_SVE_IMM_ROT2)
(AARCH64_OPND_SVE_Zm3_INDEX, AARCH64_OPND_SVE_Zm3_22_INDEX)
(AARCH64_OPND_SVE_Zm4_INDEX): New aarch64_opnds.
opcodes/
* aarch64-tbl.h (OP_SVE_HMH, OP_SVE_VMU_HSD, OP_SVE_VMVU_HSD)
(OP_SVE_VMVV_HSD, OP_SVE_VMVVU_HSD, OP_SVE_VM_HSD, OP_SVE_VUVV_HSD)
(OP_SVE_VUV_HSD, OP_SVE_VU_HSD, OP_SVE_VVVU_H, OP_SVE_VVVU_S)
(OP_SVE_VVVU_HSD, OP_SVE_VVV_D, OP_SVE_VVV_D_H, OP_SVE_VVV_H)
(OP_SVE_VVV_HSD, OP_SVE_VVV_S, OP_SVE_VVV_S_B, OP_SVE_VVV_SD_BH)
(OP_SVE_VV_BHSDQ, OP_SVE_VV_HSD, OP_SVE_VZVV_HSD, OP_SVE_VZV_HSD)
(OP_SVE_V_HSD): New macros.
(OP_SVE_VMU_SD, OP_SVE_VMVU_SD, OP_SVE_VM_SD, OP_SVE_VUVV_SD)
(OP_SVE_VU_SD, OP_SVE_VVVU_SD, OP_SVE_VVV_SD, OP_SVE_VZVV_SD)
(OP_SVE_VZV_SD, OP_SVE_V_SD): Delete.
(aarch64_opcode_table): Add new SVE instructions.
(aarch64_opcode_table): Use imm_rotate{1,2} instead of imm_rotate
for rotation operands. Add new SVE operands.
* aarch64-asm.h (ins_sve_addr_ri_s4): New inserter.
(ins_sve_quad_index): Likewise.
(ins_imm_rotate): Split into...
(ins_imm_rotate1, ins_imm_rotate2): ...these two inserters.
* aarch64-asm.c (aarch64_ins_imm_rotate): Split into...
(aarch64_ins_imm_rotate1, aarch64_ins_imm_rotate2): ...these two
functions.
(aarch64_ins_sve_addr_ri_s4): New function.
(aarch64_ins_sve_quad_index): Likewise.
(do_misc_encoding): Handle "MOV Zn.Q, Qm".
* aarch64-asm-2.c: Regenerate.
* aarch64-dis.h (ext_sve_addr_ri_s4): New extractor.
(ext_sve_quad_index): Likewise.
(ext_imm_rotate): Split into...
(ext_imm_rotate1, ext_imm_rotate2): ...these two extractors.
* aarch64-dis.c (aarch64_ext_imm_rotate): Split into...
(aarch64_ext_imm_rotate1, aarch64_ext_imm_rotate2): ...these two
functions.
(aarch64_ext_sve_addr_ri_s4): New function.
(aarch64_ext_sve_quad_index): Likewise.
(aarch64_ext_sve_index): Allow quad indices.
(do_misc_decoding): Likewise.
* aarch64-dis-2.c: Regenerate.
* aarch64-opc.h (FLD_SVE_i3h, FLD_SVE_rot1, FLD_SVE_rot2): New
aarch64_field_kinds.
(OPD_F_OD_MASK): Widen by one bit.
(OPD_F_NO_ZR): Bump accordingly.
(get_operand_field_width): New function.
* aarch64-opc.c (fields): Add new SVE fields.
(operand_general_constraint_met_p): Handle new SVE operands.
(aarch64_print_operand): Likewise.
* aarch64-opc-2.c: Regenerate.
gas/
* doc/c-aarch64.texi: Document that sve implies fp16, simd and compnum.
* config/tc-aarch64.c (parse_vector_type_for_operand): Allow .q
to be used with SVE registers.
(parse_operands): Handle new SVE operands.
(aarch64_features): Make "sve" require F16 rather than FP. Also
require COMPNUM.
* testsuite/gas/aarch64/sve.s: Add tests for new instructions.
Include compnum tests.
* testsuite/gas/aarch64/sve.d: Update accordingly.
* testsuite/gas/aarch64/sve-invalid.s: Add tests for new instructions.
* testsuite/gas/aarch64/sve-invalid.l: Update accordingly. Also
update expected output for new FMOV and MOV alternatives.
2017-02-24 19:29:00 +01:00
|
|
|
|
/* Decode Zn[MM], where Zn occupies the least-significant part of the field
|
|
|
|
|
and where MM occupies the most-significant part. The operand-dependent
|
|
|
|
|
value specifies the number of bits in Zn. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_sve_quad_index (const aarch64_operand *self,
|
|
|
|
|
aarch64_opnd_info *info, aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
unsigned int reg_bits = get_operand_specific_data (self);
|
|
|
|
|
unsigned int val = extract_all_fields (self, code);
|
|
|
|
|
info->reglane.regno = val & ((1 << reg_bits) - 1);
|
|
|
|
|
info->reglane.index = val >> reg_bits;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
[AArch64][SVE 21/32] Add Zn and Pn registers
This patch adds the Zn and Pn registers, and associated fields and
operands.
include/
* opcode/aarch64.h (AARCH64_OPND_CLASS_SVE_REG): New
aarch64_operand_class.
(AARCH64_OPND_CLASS_PRED_REG): Likewise.
(AARCH64_OPND_SVE_Pd, AARCH64_OPND_SVE_Pg3, AARCH64_OPND_SVE_Pg4_5)
(AARCH64_OPND_SVE_Pg4_10, AARCH64_OPND_SVE_Pg4_16)
(AARCH64_OPND_SVE_Pm, AARCH64_OPND_SVE_Pn, AARCH64_OPND_SVE_Pt)
(AARCH64_OPND_SVE_Za_5, AARCH64_OPND_SVE_Za_16, AARCH64_OPND_SVE_Zd)
(AARCH64_OPND_SVE_Zm_5, AARCH64_OPND_SVE_Zm_16, AARCH64_OPND_SVE_Zn)
(AARCH64_OPND_SVE_Zn_INDEX, AARCH64_OPND_SVE_ZnxN)
(AARCH64_OPND_SVE_Zt, AARCH64_OPND_SVE_ZtxN): New aarch64_opnds.
opcodes/
* aarch64-tbl.h (AARCH64_OPERANDS): Add entries for new SVE operands.
* aarch64-opc.h (FLD_SVE_Pd, FLD_SVE_Pg3, FLD_SVE_Pg4_5)
(FLD_SVE_Pg4_10, FLD_SVE_Pg4_16, FLD_SVE_Pm, FLD_SVE_Pn, FLD_SVE_Pt)
(FLD_SVE_Za_5, FLD_SVE_Za_16, FLD_SVE_Zd, FLD_SVE_Zm_5, FLD_SVE_Zm_16)
(FLD_SVE_Zn, FLD_SVE_Zt, FLD_SVE_tzsh): New aarch64_field_kinds.
* aarch64-opc.c (fields): Add corresponding entries here.
(operand_general_constraint_met_p): Check that SVE register lists
have the correct length. Check the ranges of SVE index registers.
Check for cases where p8-p15 are used in 3-bit predicate fields.
(aarch64_print_operand): Handle the new SVE operands.
* aarch64-opc-2.c: Regenerate.
* aarch64-asm.h (ins_sve_index, ins_sve_reglist): New inserters.
* aarch64-asm.c (aarch64_ins_sve_index): New function.
(aarch64_ins_sve_reglist): Likewise.
* aarch64-asm-2.c: Regenerate.
* aarch64-dis.h (ext_sve_index, ext_sve_reglist): New extractors.
* aarch64-dis.c (aarch64_ext_sve_index): New function.
(aarch64_ext_sve_reglist): Likewise.
* aarch64-dis-2.c: Regenerate.
gas/
* config/tc-aarch64.c (NTA_HASVARWIDTH): New macro.
(AARCH64_REG_TYPES): Add ZN and PN.
(get_reg_expected_msg): Handle them.
(parse_vector_type_for_operand): Add a reg_type parameter.
Skip the width for Zn and Pn registers.
(parse_typed_reg): Extend vector handling to Zn and Pn. Update the
call to parse_vector_type_for_operand. Set HASVARTYPE for Zn and Pn,
expecting the width to be 0.
(parse_vector_reg_list): Restrict error about [BHSD]nn operands to
REG_TYPE_VN.
(vectype_to_qualifier): Use S_[BHSD] qualifiers for NTA_HASVARWIDTH.
(parse_operands): Handle the new Zn and Pn operands.
(REGSET16): New macro, split out from...
(REGSET31): ...here.
(reg_names): Add Zn and Pn entries.
2016-09-21 17:53:54 +02:00
|
|
|
|
/* 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. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_sve_reglist (const aarch64_operand *self,
|
|
|
|
|
aarch64_opnd_info *info, aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
info->reglist.first_regno = extract_field (self->fields[0], code, 0);
|
|
|
|
|
info->reglist.num_regs = get_opcode_dependent_value (inst->opcode);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
[AArch64][SVE 24/32] Add AARCH64_OPND_SVE_PATTERN_SCALED
Some SVE instructions count the number of elements in a given vector
pattern and allow a scale factor of [1, 16] to be applied to the result.
This scale factor is written ", MUL #n", where "MUL" is a new operator.
E.g.:
UQINCD X0, POW2, MUL #2
This patch adds support for this kind of operand.
All existing operators were shifts of some kind, so there was a natural
range of [0, 63] regardless of context. This was then narrowered further
by later checks (e.g. to [0, 31] when used for 32-bit values).
In contrast, MUL doesn't really have a natural context-independent range.
Rather than pick one arbitrarily, it seemed better to make the "shift"
amount a full 64-bit value and leave the range test to the usual
operand-checking code. I've rearranged the fields of aarch64_opnd_info
so that this doesn't increase the size of the structure (although I don't
think its size is critical anyway).
include/
* opcode/aarch64.h (AARCH64_OPND_SVE_PATTERN_SCALED): New
aarch64_opnd.
(AARCH64_MOD_MUL): New aarch64_modifier_kind.
(aarch64_opnd_info): Make shifter.amount an int64_t and
rearrange the fields.
opcodes/
* aarch64-tbl.h (AARCH64_OPERANDS): Add an entry for
AARCH64_OPND_SVE_PATTERN_SCALED.
* aarch64-opc.h (FLD_SVE_imm4): New aarch64_field_kind.
* aarch64-opc.c (fields): Add a corresponding entry.
(set_multiplier_out_of_range_error): New function.
(aarch64_operand_modifiers): Add entry for AARCH64_MOD_MUL.
(operand_general_constraint_met_p): Handle
AARCH64_OPND_SVE_PATTERN_SCALED.
(print_register_offset_address): Use PRIi64 to print the
shift amount.
(aarch64_print_operand): Likewise. Handle
AARCH64_OPND_SVE_PATTERN_SCALED.
* aarch64-opc-2.c: Regenerate.
* aarch64-asm.h (ins_sve_scale): New inserter.
* aarch64-asm.c (aarch64_ins_sve_scale): New function.
* aarch64-asm-2.c: Regenerate.
* aarch64-dis.h (ext_sve_scale): New inserter.
* aarch64-dis.c (aarch64_ext_sve_scale): New function.
* aarch64-dis-2.c: Regenerate.
gas/
* config/tc-aarch64.c (SHIFTED_MUL): New parse_shift_mode.
(parse_shift): Handle it. Reject AARCH64_MOD_MUL for all other
shift modes. Skip range tests for AARCH64_MOD_MUL.
(process_omitted_operand): Handle AARCH64_OPND_SVE_PATTERN_SCALED.
(parse_operands): Likewise.
2016-09-21 17:55:22 +02:00
|
|
|
|
|
|
|
|
|
/* Decode <pattern>{, MUL #<amount>}. The fields array specifies which
|
|
|
|
|
fields to use for <pattern>. <amount> - 1 is encoded in the SVE_imm4
|
|
|
|
|
field. */
|
|
|
|
|
int
|
|
|
|
|
aarch64_ext_sve_scale (const aarch64_operand *self,
|
|
|
|
|
aarch64_opnd_info *info, aarch64_insn code,
|
|
|
|
|
const aarch64_inst *inst)
|
|
|
|
|
{
|
|
|
|
|
int val;
|
|
|
|
|
|
|
|
|
|
if (!aarch64_ext_imm (self, info, code, inst))
|
|
|
|
|
return 0;
|
|
|
|
|
val = extract_field (FLD_SVE_imm4, code, 0);
|
|
|
|
|
info->shifter.kind = AARCH64_MOD_MUL;
|
|
|
|
|
info->shifter.amount = val + 1;
|
|
|
|
|
info->shifter.operator_present = (val != 0);
|
|
|
|
|
info->shifter.amount_present = (val != 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
[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.
2016-09-21 17:56:57 +02:00
|
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
}
|
2012-08-13 16:52:54 +02:00
|
|
|
|
|
|
|
|
|
/* Bitfields that are commonly used to encode certain operands' information
|
|
|
|
|
may be partially used as part of the base opcode in some instructions.
|
|
|
|
|
For example, the bit 1 of the field 'size' in
|
|
|
|
|
FCVTXN <Vb><d>, <Va><n>
|
|
|
|
|
is actually part of the base opcode, while only size<0> is available
|
|
|
|
|
for encoding the register type. Another example is the AdvSIMD
|
|
|
|
|
instruction ORR (register), in which the field 'size' is also used for
|
|
|
|
|
the base opcode, leaving only the field 'Q' available to encode the
|
|
|
|
|
vector register arrangement specifier '8B' or '16B'.
|
|
|
|
|
|
|
|
|
|
This function tries to deduce the qualifier from the value of partially
|
|
|
|
|
constrained field(s). Given the VALUE of such a field or fields, the
|
|
|
|
|
qualifiers CANDIDATES and the MASK (indicating which bits are valid for
|
|
|
|
|
operand encoding), the function returns the matching qualifier or
|
|
|
|
|
AARCH64_OPND_QLF_NIL if nothing matches.
|
|
|
|
|
|
|
|
|
|
N.B. CANDIDATES is a group of possible qualifiers that are valid for
|
|
|
|
|
one operand; it has a maximum of AARCH64_MAX_QLF_SEQ_NUM qualifiers and
|
|
|
|
|
may end with AARCH64_OPND_QLF_NIL. */
|
|
|
|
|
|
|
|
|
|
static enum aarch64_opnd_qualifier
|
|
|
|
|
get_qualifier_from_partial_encoding (aarch64_insn value,
|
|
|
|
|
const enum aarch64_opnd_qualifier* \
|
|
|
|
|
candidates,
|
|
|
|
|
aarch64_insn mask)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
DEBUG_TRACE ("enter with value: %d, mask: %d", (int)value, (int)mask);
|
|
|
|
|
for (i = 0; i < AARCH64_MAX_QLF_SEQ_NUM; ++i)
|
|
|
|
|
{
|
|
|
|
|
aarch64_insn standard_value;
|
|
|
|
|
if (candidates[i] == AARCH64_OPND_QLF_NIL)
|
|
|
|
|
break;
|
|
|
|
|
standard_value = aarch64_get_qualifier_standard_value (candidates[i]);
|
|
|
|
|
if ((standard_value & mask) == (value & mask))
|
|
|
|
|
return candidates[i];
|
|
|
|
|
}
|
|
|
|
|
return AARCH64_OPND_QLF_NIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Given a list of qualifier sequences, return all possible valid qualifiers
|
|
|
|
|
for operand IDX in QUALIFIERS.
|
|
|
|
|
Assume QUALIFIERS is an array whose length is large enough. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
get_operand_possible_qualifiers (int idx,
|
|
|
|
|
const aarch64_opnd_qualifier_seq_t *list,
|
|
|
|
|
enum aarch64_opnd_qualifier *qualifiers)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
for (i = 0; i < AARCH64_MAX_QLF_SEQ_NUM; ++i)
|
|
|
|
|
if ((qualifiers[i] = list[i][idx]) == AARCH64_OPND_QLF_NIL)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode the size Q field for e.g. SHADD.
|
|
|
|
|
We tag one operand with the qualifer according to the code;
|
|
|
|
|
whether the qualifier is valid for this opcode or not, it is the
|
|
|
|
|
duty of the semantic checking. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
decode_sizeq (aarch64_inst *inst)
|
|
|
|
|
{
|
|
|
|
|
int idx;
|
|
|
|
|
enum aarch64_opnd_qualifier qualifier;
|
|
|
|
|
aarch64_insn code;
|
|
|
|
|
aarch64_insn value, mask;
|
|
|
|
|
enum aarch64_field_kind fld_sz;
|
|
|
|
|
enum aarch64_opnd_qualifier candidates[AARCH64_MAX_QLF_SEQ_NUM];
|
|
|
|
|
|
|
|
|
|
if (inst->opcode->iclass == asisdlse
|
|
|
|
|
|| inst->opcode->iclass == asisdlsep
|
|
|
|
|
|| inst->opcode->iclass == asisdlso
|
|
|
|
|
|| inst->opcode->iclass == asisdlsop)
|
|
|
|
|
fld_sz = FLD_vldst_size;
|
|
|
|
|
else
|
|
|
|
|
fld_sz = FLD_size;
|
|
|
|
|
|
|
|
|
|
code = inst->value;
|
|
|
|
|
value = extract_fields (code, inst->opcode->mask, 2, fld_sz, FLD_Q);
|
|
|
|
|
/* Obtain the info that which bits of fields Q and size are actually
|
|
|
|
|
available for operand encoding. Opcodes like FMAXNM and FMLA have
|
|
|
|
|
size[1] unavailable. */
|
|
|
|
|
mask = extract_fields (~inst->opcode->mask, 0, 2, fld_sz, FLD_Q);
|
|
|
|
|
|
|
|
|
|
/* The index of the operand we are going to tag a qualifier and the qualifer
|
|
|
|
|
itself are reasoned from the value of the size and Q fields and the
|
|
|
|
|
possible valid qualifier lists. */
|
|
|
|
|
idx = aarch64_select_operand_for_sizeq_field_coding (inst->opcode);
|
|
|
|
|
DEBUG_TRACE ("key idx: %d", idx);
|
|
|
|
|
|
|
|
|
|
/* For most related instruciton, size:Q are fully available for operand
|
|
|
|
|
encoding. */
|
|
|
|
|
if (mask == 0x7)
|
|
|
|
|
{
|
|
|
|
|
inst->operands[idx].qualifier = get_vreg_qualifier_from_value (value);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
get_operand_possible_qualifiers (idx, inst->opcode->qualifiers_list,
|
|
|
|
|
candidates);
|
|
|
|
|
#ifdef DEBUG_AARCH64
|
|
|
|
|
if (debug_dump)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
for (i = 0; candidates[i] != AARCH64_OPND_QLF_NIL
|
|
|
|
|
&& i < AARCH64_MAX_QLF_SEQ_NUM; ++i)
|
|
|
|
|
DEBUG_TRACE ("qualifier %d: %s", i,
|
|
|
|
|
aarch64_get_qualifier_name(candidates[i]));
|
|
|
|
|
DEBUG_TRACE ("%d, %d", (int)value, (int)mask);
|
|
|
|
|
}
|
|
|
|
|
#endif /* DEBUG_AARCH64 */
|
|
|
|
|
|
|
|
|
|
qualifier = get_qualifier_from_partial_encoding (value, candidates, mask);
|
|
|
|
|
|
|
|
|
|
if (qualifier == AARCH64_OPND_QLF_NIL)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
inst->operands[idx].qualifier = qualifier;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode size[0]:Q, i.e. bit 22 and bit 30, for
|
|
|
|
|
e.g. FCVTN<Q> <Vd>.<Tb>, <Vn>.<Ta>. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
decode_asimd_fcvt (aarch64_inst *inst)
|
|
|
|
|
{
|
|
|
|
|
aarch64_field field = {0, 0};
|
|
|
|
|
aarch64_insn value;
|
|
|
|
|
enum aarch64_opnd_qualifier qualifier;
|
|
|
|
|
|
|
|
|
|
gen_sub_field (FLD_size, 0, 1, &field);
|
|
|
|
|
value = extract_field_2 (&field, inst->value, 0);
|
|
|
|
|
qualifier = value == 0 ? AARCH64_OPND_QLF_V_4S
|
|
|
|
|
: AARCH64_OPND_QLF_V_2D;
|
|
|
|
|
switch (inst->opcode->op)
|
|
|
|
|
{
|
|
|
|
|
case OP_FCVTN:
|
|
|
|
|
case OP_FCVTN2:
|
|
|
|
|
/* FCVTN<Q> <Vd>.<Tb>, <Vn>.<Ta>. */
|
|
|
|
|
inst->operands[1].qualifier = qualifier;
|
|
|
|
|
break;
|
|
|
|
|
case OP_FCVTL:
|
|
|
|
|
case OP_FCVTL2:
|
|
|
|
|
/* FCVTL<Q> <Vd>.<Ta>, <Vn>.<Tb>. */
|
|
|
|
|
inst->operands[0].qualifier = qualifier;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert (0);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode size[0], i.e. bit 22, for
|
|
|
|
|
e.g. FCVTXN <Vb><d>, <Va><n>. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
decode_asisd_fcvtxn (aarch64_inst *inst)
|
|
|
|
|
{
|
|
|
|
|
aarch64_field field = {0, 0};
|
|
|
|
|
gen_sub_field (FLD_size, 0, 1, &field);
|
|
|
|
|
if (!extract_field_2 (&field, inst->value, 0))
|
|
|
|
|
return 0;
|
|
|
|
|
inst->operands[0].qualifier = AARCH64_OPND_QLF_S_S;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decode the 'opc' field for e.g. FCVT <Dd>, <Sn>. */
|
|
|
|
|
static int
|
|
|
|
|
decode_fcvt (aarch64_inst *inst)
|
|
|
|
|
{
|
|
|
|
|
enum aarch64_opnd_qualifier qualifier;
|
|
|
|
|
aarch64_insn value;
|
|
|
|
|
const aarch64_field field = {15, 2};
|
|
|
|
|
|
|
|
|
|
/* opc dstsize */
|
|
|
|
|
value = extract_field_2 (&field, inst->value, 0);
|
|
|
|
|
switch (value)
|
|
|
|
|
{
|
|
|
|
|
case 0: qualifier = AARCH64_OPND_QLF_S_S; break;
|
|
|
|
|
case 1: qualifier = AARCH64_OPND_QLF_S_D; break;
|
|
|
|
|
case 3: qualifier = AARCH64_OPND_QLF_S_H; break;
|
|
|
|
|
default: return 0;
|
|
|
|
|
}
|
|
|
|
|
inst->operands[0].qualifier = qualifier;
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Do miscellaneous decodings that are not common enough to be driven by
|
|
|
|
|
flags. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
do_misc_decoding (aarch64_inst *inst)
|
|
|
|
|
{
|
[AArch64][SVE 31/32] Add SVE instructions
This patch adds the SVE instruction definitions and associated OP_*
enum values.
include/
* opcode/aarch64.h (AARCH64_FEATURE_SVE): New macro.
(OP_MOV_P_P, OP_MOV_Z_P_Z, OP_MOV_Z_V, OP_MOV_Z_Z, OP_MOV_Z_Zi)
(OP_MOVM_P_P_P, OP_MOVS_P_P, OP_MOVZS_P_P_P, OP_MOVZ_P_P_P)
(OP_NOTS_P_P_P_Z, OP_NOT_P_P_P_Z): New aarch64_ops.
opcodes/
* aarch64-tbl.h (OP_SVE_B, OP_SVE_BB, OP_SVE_BBBU, OP_SVE_BMB)
(OP_SVE_BPB, OP_SVE_BUB, OP_SVE_BUBB, OP_SVE_BUU, OP_SVE_BZ)
(OP_SVE_BZB, OP_SVE_BZBB, OP_SVE_BZU, OP_SVE_DD, OP_SVE_DDD)
(OP_SVE_DMD, OP_SVE_DMH, OP_SVE_DMS, OP_SVE_DU, OP_SVE_DUD, OP_SVE_DUU)
(OP_SVE_DUV_BHS, OP_SVE_DUV_BHSD, OP_SVE_DZD, OP_SVE_DZU, OP_SVE_HB)
(OP_SVE_HMD, OP_SVE_HMS, OP_SVE_HU, OP_SVE_HUU, OP_SVE_HZU, OP_SVE_RR)
(OP_SVE_RURV_BHSD, OP_SVE_RUV_BHSD, OP_SVE_SMD, OP_SVE_SMH, OP_SVE_SMS)
(OP_SVE_SU, OP_SVE_SUS, OP_SVE_SUU, OP_SVE_SZS, OP_SVE_SZU, OP_SVE_UB)
(OP_SVE_UUD, OP_SVE_UUS, OP_SVE_VMR_BHSD, OP_SVE_VMU_SD)
(OP_SVE_VMVD_BHS, OP_SVE_VMVU_BHSD, OP_SVE_VMVU_SD, OP_SVE_VMVV_BHSD)
(OP_SVE_VMVV_SD, OP_SVE_VMV_BHSD, OP_SVE_VMV_HSD, OP_SVE_VMV_SD)
(OP_SVE_VM_SD, OP_SVE_VPU_BHSD, OP_SVE_VPV_BHSD, OP_SVE_VRR_BHSD)
(OP_SVE_VRU_BHSD, OP_SVE_VR_BHSD, OP_SVE_VUR_BHSD, OP_SVE_VUU_BHSD)
(OP_SVE_VUVV_BHSD, OP_SVE_VUVV_SD, OP_SVE_VUV_BHSD, OP_SVE_VUV_SD)
(OP_SVE_VU_BHSD, OP_SVE_VU_HSD, OP_SVE_VU_SD, OP_SVE_VVD_BHS)
(OP_SVE_VVU_BHSD, OP_SVE_VVVU_SD, OP_SVE_VVV_BHSD, OP_SVE_VVV_SD)
(OP_SVE_VV_BHSD, OP_SVE_VV_HSD_BHS, OP_SVE_VV_SD, OP_SVE_VWW_BHSD)
(OP_SVE_VXX_BHSD, OP_SVE_VZVD_BHS, OP_SVE_VZVU_BHSD, OP_SVE_VZVV_BHSD)
(OP_SVE_VZVV_SD, OP_SVE_VZV_SD, OP_SVE_V_SD, OP_SVE_WU, OP_SVE_WV_BHSD)
(OP_SVE_XU, OP_SVE_XUV_BHSD, OP_SVE_XVW_BHSD, OP_SVE_XV_BHSD)
(OP_SVE_XWU, OP_SVE_XXU): New macros.
(aarch64_feature_sve): New variable.
(SVE): New macro.
(_SVE_INSN): Likewise.
(aarch64_opcode_table): Add SVE instructions.
* aarch64-opc.h (extract_fields): Declare.
* aarch64-opc-2.c: Regenerate.
* aarch64-asm.c (do_misc_encoding): Handle the new SVE aarch64_ops.
* aarch64-asm-2.c: Regenerate.
* aarch64-dis.c (extract_fields): Make global.
(do_misc_decoding): Handle the new SVE aarch64_ops.
* aarch64-dis-2.c: Regenerate.
gas/
* doc/c-aarch64.texi: Document the "sve" feature.
* config/tc-aarch64.c (REG_TYPE_R_Z_BHSDQ_VZP): New register type.
(get_reg_expected_msg): Handle it.
(parse_operands): When parsing operands of an SVE instruction,
disallow immediates that match REG_TYPE_R_Z_BHSDQ_VZP.
(aarch64_features): Add an entry for SVE.
2016-09-21 17:58:48 +02:00
|
|
|
|
unsigned int value;
|
2012-08-13 16:52:54 +02:00
|
|
|
|
switch (inst->opcode->op)
|
|
|
|
|
{
|
|
|
|
|
case OP_FCVT:
|
|
|
|
|
return decode_fcvt (inst);
|
[AArch64][SVE 31/32] Add SVE instructions
This patch adds the SVE instruction definitions and associated OP_*
enum values.
include/
* opcode/aarch64.h (AARCH64_FEATURE_SVE): New macro.
(OP_MOV_P_P, OP_MOV_Z_P_Z, OP_MOV_Z_V, OP_MOV_Z_Z, OP_MOV_Z_Zi)
(OP_MOVM_P_P_P, OP_MOVS_P_P, OP_MOVZS_P_P_P, OP_MOVZ_P_P_P)
(OP_NOTS_P_P_P_Z, OP_NOT_P_P_P_Z): New aarch64_ops.
opcodes/
* aarch64-tbl.h (OP_SVE_B, OP_SVE_BB, OP_SVE_BBBU, OP_SVE_BMB)
(OP_SVE_BPB, OP_SVE_BUB, OP_SVE_BUBB, OP_SVE_BUU, OP_SVE_BZ)
(OP_SVE_BZB, OP_SVE_BZBB, OP_SVE_BZU, OP_SVE_DD, OP_SVE_DDD)
(OP_SVE_DMD, OP_SVE_DMH, OP_SVE_DMS, OP_SVE_DU, OP_SVE_DUD, OP_SVE_DUU)
(OP_SVE_DUV_BHS, OP_SVE_DUV_BHSD, OP_SVE_DZD, OP_SVE_DZU, OP_SVE_HB)
(OP_SVE_HMD, OP_SVE_HMS, OP_SVE_HU, OP_SVE_HUU, OP_SVE_HZU, OP_SVE_RR)
(OP_SVE_RURV_BHSD, OP_SVE_RUV_BHSD, OP_SVE_SMD, OP_SVE_SMH, OP_SVE_SMS)
(OP_SVE_SU, OP_SVE_SUS, OP_SVE_SUU, OP_SVE_SZS, OP_SVE_SZU, OP_SVE_UB)
(OP_SVE_UUD, OP_SVE_UUS, OP_SVE_VMR_BHSD, OP_SVE_VMU_SD)
(OP_SVE_VMVD_BHS, OP_SVE_VMVU_BHSD, OP_SVE_VMVU_SD, OP_SVE_VMVV_BHSD)
(OP_SVE_VMVV_SD, OP_SVE_VMV_BHSD, OP_SVE_VMV_HSD, OP_SVE_VMV_SD)
(OP_SVE_VM_SD, OP_SVE_VPU_BHSD, OP_SVE_VPV_BHSD, OP_SVE_VRR_BHSD)
(OP_SVE_VRU_BHSD, OP_SVE_VR_BHSD, OP_SVE_VUR_BHSD, OP_SVE_VUU_BHSD)
(OP_SVE_VUVV_BHSD, OP_SVE_VUVV_SD, OP_SVE_VUV_BHSD, OP_SVE_VUV_SD)
(OP_SVE_VU_BHSD, OP_SVE_VU_HSD, OP_SVE_VU_SD, OP_SVE_VVD_BHS)
(OP_SVE_VVU_BHSD, OP_SVE_VVVU_SD, OP_SVE_VVV_BHSD, OP_SVE_VVV_SD)
(OP_SVE_VV_BHSD, OP_SVE_VV_HSD_BHS, OP_SVE_VV_SD, OP_SVE_VWW_BHSD)
(OP_SVE_VXX_BHSD, OP_SVE_VZVD_BHS, OP_SVE_VZVU_BHSD, OP_SVE_VZVV_BHSD)
(OP_SVE_VZVV_SD, OP_SVE_VZV_SD, OP_SVE_V_SD, OP_SVE_WU, OP_SVE_WV_BHSD)
(OP_SVE_XU, OP_SVE_XUV_BHSD, OP_SVE_XVW_BHSD, OP_SVE_XV_BHSD)
(OP_SVE_XWU, OP_SVE_XXU): New macros.
(aarch64_feature_sve): New variable.
(SVE): New macro.
(_SVE_INSN): Likewise.
(aarch64_opcode_table): Add SVE instructions.
* aarch64-opc.h (extract_fields): Declare.
* aarch64-opc-2.c: Regenerate.
* aarch64-asm.c (do_misc_encoding): Handle the new SVE aarch64_ops.
* aarch64-asm-2.c: Regenerate.
* aarch64-dis.c (extract_fields): Make global.
(do_misc_decoding): Handle the new SVE aarch64_ops.
* aarch64-dis-2.c: Regenerate.
gas/
* doc/c-aarch64.texi: Document the "sve" feature.
* config/tc-aarch64.c (REG_TYPE_R_Z_BHSDQ_VZP): New register type.
(get_reg_expected_msg): Handle it.
(parse_operands): When parsing operands of an SVE instruction,
disallow immediates that match REG_TYPE_R_Z_BHSDQ_VZP.
(aarch64_features): Add an entry for SVE.
2016-09-21 17:58:48 +02:00
|
|
|
|
|
2012-08-13 16:52:54 +02:00
|
|
|
|
case OP_FCVTN:
|
|
|
|
|
case OP_FCVTN2:
|
|
|
|
|
case OP_FCVTL:
|
|
|
|
|
case OP_FCVTL2:
|
|
|
|
|
return decode_asimd_fcvt (inst);
|
[AArch64][SVE 31/32] Add SVE instructions
This patch adds the SVE instruction definitions and associated OP_*
enum values.
include/
* opcode/aarch64.h (AARCH64_FEATURE_SVE): New macro.
(OP_MOV_P_P, OP_MOV_Z_P_Z, OP_MOV_Z_V, OP_MOV_Z_Z, OP_MOV_Z_Zi)
(OP_MOVM_P_P_P, OP_MOVS_P_P, OP_MOVZS_P_P_P, OP_MOVZ_P_P_P)
(OP_NOTS_P_P_P_Z, OP_NOT_P_P_P_Z): New aarch64_ops.
opcodes/
* aarch64-tbl.h (OP_SVE_B, OP_SVE_BB, OP_SVE_BBBU, OP_SVE_BMB)
(OP_SVE_BPB, OP_SVE_BUB, OP_SVE_BUBB, OP_SVE_BUU, OP_SVE_BZ)
(OP_SVE_BZB, OP_SVE_BZBB, OP_SVE_BZU, OP_SVE_DD, OP_SVE_DDD)
(OP_SVE_DMD, OP_SVE_DMH, OP_SVE_DMS, OP_SVE_DU, OP_SVE_DUD, OP_SVE_DUU)
(OP_SVE_DUV_BHS, OP_SVE_DUV_BHSD, OP_SVE_DZD, OP_SVE_DZU, OP_SVE_HB)
(OP_SVE_HMD, OP_SVE_HMS, OP_SVE_HU, OP_SVE_HUU, OP_SVE_HZU, OP_SVE_RR)
(OP_SVE_RURV_BHSD, OP_SVE_RUV_BHSD, OP_SVE_SMD, OP_SVE_SMH, OP_SVE_SMS)
(OP_SVE_SU, OP_SVE_SUS, OP_SVE_SUU, OP_SVE_SZS, OP_SVE_SZU, OP_SVE_UB)
(OP_SVE_UUD, OP_SVE_UUS, OP_SVE_VMR_BHSD, OP_SVE_VMU_SD)
(OP_SVE_VMVD_BHS, OP_SVE_VMVU_BHSD, OP_SVE_VMVU_SD, OP_SVE_VMVV_BHSD)
(OP_SVE_VMVV_SD, OP_SVE_VMV_BHSD, OP_SVE_VMV_HSD, OP_SVE_VMV_SD)
(OP_SVE_VM_SD, OP_SVE_VPU_BHSD, OP_SVE_VPV_BHSD, OP_SVE_VRR_BHSD)
(OP_SVE_VRU_BHSD, OP_SVE_VR_BHSD, OP_SVE_VUR_BHSD, OP_SVE_VUU_BHSD)
(OP_SVE_VUVV_BHSD, OP_SVE_VUVV_SD, OP_SVE_VUV_BHSD, OP_SVE_VUV_SD)
(OP_SVE_VU_BHSD, OP_SVE_VU_HSD, OP_SVE_VU_SD, OP_SVE_VVD_BHS)
(OP_SVE_VVU_BHSD, OP_SVE_VVVU_SD, OP_SVE_VVV_BHSD, OP_SVE_VVV_SD)
(OP_SVE_VV_BHSD, OP_SVE_VV_HSD_BHS, OP_SVE_VV_SD, OP_SVE_VWW_BHSD)
(OP_SVE_VXX_BHSD, OP_SVE_VZVD_BHS, OP_SVE_VZVU_BHSD, OP_SVE_VZVV_BHSD)
(OP_SVE_VZVV_SD, OP_SVE_VZV_SD, OP_SVE_V_SD, OP_SVE_WU, OP_SVE_WV_BHSD)
(OP_SVE_XU, OP_SVE_XUV_BHSD, OP_SVE_XVW_BHSD, OP_SVE_XV_BHSD)
(OP_SVE_XWU, OP_SVE_XXU): New macros.
(aarch64_feature_sve): New variable.
(SVE): New macro.
(_SVE_INSN): Likewise.
(aarch64_opcode_table): Add SVE instructions.
* aarch64-opc.h (extract_fields): Declare.
* aarch64-opc-2.c: Regenerate.
* aarch64-asm.c (do_misc_encoding): Handle the new SVE aarch64_ops.
* aarch64-asm-2.c: Regenerate.
* aarch64-dis.c (extract_fields): Make global.
(do_misc_decoding): Handle the new SVE aarch64_ops.
* aarch64-dis-2.c: Regenerate.
gas/
* doc/c-aarch64.texi: Document the "sve" feature.
* config/tc-aarch64.c (REG_TYPE_R_Z_BHSDQ_VZP): New register type.
(get_reg_expected_msg): Handle it.
(parse_operands): When parsing operands of an SVE instruction,
disallow immediates that match REG_TYPE_R_Z_BHSDQ_VZP.
(aarch64_features): Add an entry for SVE.
2016-09-21 17:58:48 +02:00
|
|
|
|
|
2012-08-13 16:52:54 +02:00
|
|
|
|
case OP_FCVTXN_S:
|
|
|
|
|
return decode_asisd_fcvtxn (inst);
|
[AArch64][SVE 31/32] Add SVE instructions
This patch adds the SVE instruction definitions and associated OP_*
enum values.
include/
* opcode/aarch64.h (AARCH64_FEATURE_SVE): New macro.
(OP_MOV_P_P, OP_MOV_Z_P_Z, OP_MOV_Z_V, OP_MOV_Z_Z, OP_MOV_Z_Zi)
(OP_MOVM_P_P_P, OP_MOVS_P_P, OP_MOVZS_P_P_P, OP_MOVZ_P_P_P)
(OP_NOTS_P_P_P_Z, OP_NOT_P_P_P_Z): New aarch64_ops.
opcodes/
* aarch64-tbl.h (OP_SVE_B, OP_SVE_BB, OP_SVE_BBBU, OP_SVE_BMB)
(OP_SVE_BPB, OP_SVE_BUB, OP_SVE_BUBB, OP_SVE_BUU, OP_SVE_BZ)
(OP_SVE_BZB, OP_SVE_BZBB, OP_SVE_BZU, OP_SVE_DD, OP_SVE_DDD)
(OP_SVE_DMD, OP_SVE_DMH, OP_SVE_DMS, OP_SVE_DU, OP_SVE_DUD, OP_SVE_DUU)
(OP_SVE_DUV_BHS, OP_SVE_DUV_BHSD, OP_SVE_DZD, OP_SVE_DZU, OP_SVE_HB)
(OP_SVE_HMD, OP_SVE_HMS, OP_SVE_HU, OP_SVE_HUU, OP_SVE_HZU, OP_SVE_RR)
(OP_SVE_RURV_BHSD, OP_SVE_RUV_BHSD, OP_SVE_SMD, OP_SVE_SMH, OP_SVE_SMS)
(OP_SVE_SU, OP_SVE_SUS, OP_SVE_SUU, OP_SVE_SZS, OP_SVE_SZU, OP_SVE_UB)
(OP_SVE_UUD, OP_SVE_UUS, OP_SVE_VMR_BHSD, OP_SVE_VMU_SD)
(OP_SVE_VMVD_BHS, OP_SVE_VMVU_BHSD, OP_SVE_VMVU_SD, OP_SVE_VMVV_BHSD)
(OP_SVE_VMVV_SD, OP_SVE_VMV_BHSD, OP_SVE_VMV_HSD, OP_SVE_VMV_SD)
(OP_SVE_VM_SD, OP_SVE_VPU_BHSD, OP_SVE_VPV_BHSD, OP_SVE_VRR_BHSD)
(OP_SVE_VRU_BHSD, OP_SVE_VR_BHSD, OP_SVE_VUR_BHSD, OP_SVE_VUU_BHSD)
(OP_SVE_VUVV_BHSD, OP_SVE_VUVV_SD, OP_SVE_VUV_BHSD, OP_SVE_VUV_SD)
(OP_SVE_VU_BHSD, OP_SVE_VU_HSD, OP_SVE_VU_SD, OP_SVE_VVD_BHS)
(OP_SVE_VVU_BHSD, OP_SVE_VVVU_SD, OP_SVE_VVV_BHSD, OP_SVE_VVV_SD)
(OP_SVE_VV_BHSD, OP_SVE_VV_HSD_BHS, OP_SVE_VV_SD, OP_SVE_VWW_BHSD)
(OP_SVE_VXX_BHSD, OP_SVE_VZVD_BHS, OP_SVE_VZVU_BHSD, OP_SVE_VZVV_BHSD)
(OP_SVE_VZVV_SD, OP_SVE_VZV_SD, OP_SVE_V_SD, OP_SVE_WU, OP_SVE_WV_BHSD)
(OP_SVE_XU, OP_SVE_XUV_BHSD, OP_SVE_XVW_BHSD, OP_SVE_XV_BHSD)
(OP_SVE_XWU, OP_SVE_XXU): New macros.
(aarch64_feature_sve): New variable.
(SVE): New macro.
(_SVE_INSN): Likewise.
(aarch64_opcode_table): Add SVE instructions.
* aarch64-opc.h (extract_fields): Declare.
* aarch64-opc-2.c: Regenerate.
* aarch64-asm.c (do_misc_encoding): Handle the new SVE aarch64_ops.
* aarch64-asm-2.c: Regenerate.
* aarch64-dis.c (extract_fields): Make global.
(do_misc_decoding): Handle the new SVE aarch64_ops.
* aarch64-dis-2.c: Regenerate.
gas/
* doc/c-aarch64.texi: Document the "sve" feature.
* config/tc-aarch64.c (REG_TYPE_R_Z_BHSDQ_VZP): New register type.
(get_reg_expected_msg): Handle it.
(parse_operands): When parsing operands of an SVE instruction,
disallow immediates that match REG_TYPE_R_Z_BHSDQ_VZP.
(aarch64_features): Add an entry for SVE.
2016-09-21 17:58:48 +02:00
|
|
|
|
|
|
|
|
|
case OP_MOV_P_P:
|
|
|
|
|
case OP_MOVS_P_P:
|
|
|
|
|
value = extract_field (FLD_SVE_Pn, inst->value, 0);
|
|
|
|
|
return (value == extract_field (FLD_SVE_Pm, inst->value, 0)
|
|
|
|
|
&& value == extract_field (FLD_SVE_Pg4_10, inst->value, 0));
|
|
|
|
|
|
|
|
|
|
case OP_MOV_Z_P_Z:
|
|
|
|
|
return (extract_field (FLD_SVE_Zd, inst->value, 0)
|
|
|
|
|
== extract_field (FLD_SVE_Zm_16, inst->value, 0));
|
|
|
|
|
|
|
|
|
|
case OP_MOV_Z_V:
|
|
|
|
|
/* Index must be zero. */
|
|
|
|
|
value = extract_fields (inst->value, 0, 2, FLD_SVE_tszh, FLD_imm5);
|
[AArch64] Additional SVE instructions
This patch supports some additions to the SVE architecture prior to
its public release.
include/
* opcode/aarch64.h (AARCH64_OPND_SVE_ADDR_RI_S4x16)
(AARCH64_OPND_SVE_IMM_ROT1, AARCH64_OPND_SVE_IMM_ROT2)
(AARCH64_OPND_SVE_Zm3_INDEX, AARCH64_OPND_SVE_Zm3_22_INDEX)
(AARCH64_OPND_SVE_Zm4_INDEX): New aarch64_opnds.
opcodes/
* aarch64-tbl.h (OP_SVE_HMH, OP_SVE_VMU_HSD, OP_SVE_VMVU_HSD)
(OP_SVE_VMVV_HSD, OP_SVE_VMVVU_HSD, OP_SVE_VM_HSD, OP_SVE_VUVV_HSD)
(OP_SVE_VUV_HSD, OP_SVE_VU_HSD, OP_SVE_VVVU_H, OP_SVE_VVVU_S)
(OP_SVE_VVVU_HSD, OP_SVE_VVV_D, OP_SVE_VVV_D_H, OP_SVE_VVV_H)
(OP_SVE_VVV_HSD, OP_SVE_VVV_S, OP_SVE_VVV_S_B, OP_SVE_VVV_SD_BH)
(OP_SVE_VV_BHSDQ, OP_SVE_VV_HSD, OP_SVE_VZVV_HSD, OP_SVE_VZV_HSD)
(OP_SVE_V_HSD): New macros.
(OP_SVE_VMU_SD, OP_SVE_VMVU_SD, OP_SVE_VM_SD, OP_SVE_VUVV_SD)
(OP_SVE_VU_SD, OP_SVE_VVVU_SD, OP_SVE_VVV_SD, OP_SVE_VZVV_SD)
(OP_SVE_VZV_SD, OP_SVE_V_SD): Delete.
(aarch64_opcode_table): Add new SVE instructions.
(aarch64_opcode_table): Use imm_rotate{1,2} instead of imm_rotate
for rotation operands. Add new SVE operands.
* aarch64-asm.h (ins_sve_addr_ri_s4): New inserter.
(ins_sve_quad_index): Likewise.
(ins_imm_rotate): Split into...
(ins_imm_rotate1, ins_imm_rotate2): ...these two inserters.
* aarch64-asm.c (aarch64_ins_imm_rotate): Split into...
(aarch64_ins_imm_rotate1, aarch64_ins_imm_rotate2): ...these two
functions.
(aarch64_ins_sve_addr_ri_s4): New function.
(aarch64_ins_sve_quad_index): Likewise.
(do_misc_encoding): Handle "MOV Zn.Q, Qm".
* aarch64-asm-2.c: Regenerate.
* aarch64-dis.h (ext_sve_addr_ri_s4): New extractor.
(ext_sve_quad_index): Likewise.
(ext_imm_rotate): Split into...
(ext_imm_rotate1, ext_imm_rotate2): ...these two extractors.
* aarch64-dis.c (aarch64_ext_imm_rotate): Split into...
(aarch64_ext_imm_rotate1, aarch64_ext_imm_rotate2): ...these two
functions.
(aarch64_ext_sve_addr_ri_s4): New function.
(aarch64_ext_sve_quad_index): Likewise.
(aarch64_ext_sve_index): Allow quad indices.
(do_misc_decoding): Likewise.
* aarch64-dis-2.c: Regenerate.
* aarch64-opc.h (FLD_SVE_i3h, FLD_SVE_rot1, FLD_SVE_rot2): New
aarch64_field_kinds.
(OPD_F_OD_MASK): Widen by one bit.
(OPD_F_NO_ZR): Bump accordingly.
(get_operand_field_width): New function.
* aarch64-opc.c (fields): Add new SVE fields.
(operand_general_constraint_met_p): Handle new SVE operands.
(aarch64_print_operand): Likewise.
* aarch64-opc-2.c: Regenerate.
gas/
* doc/c-aarch64.texi: Document that sve implies fp16, simd and compnum.
* config/tc-aarch64.c (parse_vector_type_for_operand): Allow .q
to be used with SVE registers.
(parse_operands): Handle new SVE operands.
(aarch64_features): Make "sve" require F16 rather than FP. Also
require COMPNUM.
* testsuite/gas/aarch64/sve.s: Add tests for new instructions.
Include compnum tests.
* testsuite/gas/aarch64/sve.d: Update accordingly.
* testsuite/gas/aarch64/sve-invalid.s: Add tests for new instructions.
* testsuite/gas/aarch64/sve-invalid.l: Update accordingly. Also
update expected output for new FMOV and MOV alternatives.
2017-02-24 19:29:00 +01:00
|
|
|
|
return value > 0 && value <= 16 && value == (value & -value);
|
[AArch64][SVE 31/32] Add SVE instructions
This patch adds the SVE instruction definitions and associated OP_*
enum values.
include/
* opcode/aarch64.h (AARCH64_FEATURE_SVE): New macro.
(OP_MOV_P_P, OP_MOV_Z_P_Z, OP_MOV_Z_V, OP_MOV_Z_Z, OP_MOV_Z_Zi)
(OP_MOVM_P_P_P, OP_MOVS_P_P, OP_MOVZS_P_P_P, OP_MOVZ_P_P_P)
(OP_NOTS_P_P_P_Z, OP_NOT_P_P_P_Z): New aarch64_ops.
opcodes/
* aarch64-tbl.h (OP_SVE_B, OP_SVE_BB, OP_SVE_BBBU, OP_SVE_BMB)
(OP_SVE_BPB, OP_SVE_BUB, OP_SVE_BUBB, OP_SVE_BUU, OP_SVE_BZ)
(OP_SVE_BZB, OP_SVE_BZBB, OP_SVE_BZU, OP_SVE_DD, OP_SVE_DDD)
(OP_SVE_DMD, OP_SVE_DMH, OP_SVE_DMS, OP_SVE_DU, OP_SVE_DUD, OP_SVE_DUU)
(OP_SVE_DUV_BHS, OP_SVE_DUV_BHSD, OP_SVE_DZD, OP_SVE_DZU, OP_SVE_HB)
(OP_SVE_HMD, OP_SVE_HMS, OP_SVE_HU, OP_SVE_HUU, OP_SVE_HZU, OP_SVE_RR)
(OP_SVE_RURV_BHSD, OP_SVE_RUV_BHSD, OP_SVE_SMD, OP_SVE_SMH, OP_SVE_SMS)
(OP_SVE_SU, OP_SVE_SUS, OP_SVE_SUU, OP_SVE_SZS, OP_SVE_SZU, OP_SVE_UB)
(OP_SVE_UUD, OP_SVE_UUS, OP_SVE_VMR_BHSD, OP_SVE_VMU_SD)
(OP_SVE_VMVD_BHS, OP_SVE_VMVU_BHSD, OP_SVE_VMVU_SD, OP_SVE_VMVV_BHSD)
(OP_SVE_VMVV_SD, OP_SVE_VMV_BHSD, OP_SVE_VMV_HSD, OP_SVE_VMV_SD)
(OP_SVE_VM_SD, OP_SVE_VPU_BHSD, OP_SVE_VPV_BHSD, OP_SVE_VRR_BHSD)
(OP_SVE_VRU_BHSD, OP_SVE_VR_BHSD, OP_SVE_VUR_BHSD, OP_SVE_VUU_BHSD)
(OP_SVE_VUVV_BHSD, OP_SVE_VUVV_SD, OP_SVE_VUV_BHSD, OP_SVE_VUV_SD)
(OP_SVE_VU_BHSD, OP_SVE_VU_HSD, OP_SVE_VU_SD, OP_SVE_VVD_BHS)
(OP_SVE_VVU_BHSD, OP_SVE_VVVU_SD, OP_SVE_VVV_BHSD, OP_SVE_VVV_SD)
(OP_SVE_VV_BHSD, OP_SVE_VV_HSD_BHS, OP_SVE_VV_SD, OP_SVE_VWW_BHSD)
(OP_SVE_VXX_BHSD, OP_SVE_VZVD_BHS, OP_SVE_VZVU_BHSD, OP_SVE_VZVV_BHSD)
(OP_SVE_VZVV_SD, OP_SVE_VZV_SD, OP_SVE_V_SD, OP_SVE_WU, OP_SVE_WV_BHSD)
(OP_SVE_XU, OP_SVE_XUV_BHSD, OP_SVE_XVW_BHSD, OP_SVE_XV_BHSD)
(OP_SVE_XWU, OP_SVE_XXU): New macros.
(aarch64_feature_sve): New variable.
(SVE): New macro.
(_SVE_INSN): Likewise.
(aarch64_opcode_table): Add SVE instructions.
* aarch64-opc.h (extract_fields): Declare.
* aarch64-opc-2.c: Regenerate.
* aarch64-asm.c (do_misc_encoding): Handle the new SVE aarch64_ops.
* aarch64-asm-2.c: Regenerate.
* aarch64-dis.c (extract_fields): Make global.
(do_misc_decoding): Handle the new SVE aarch64_ops.
* aarch64-dis-2.c: Regenerate.
gas/
* doc/c-aarch64.texi: Document the "sve" feature.
* config/tc-aarch64.c (REG_TYPE_R_Z_BHSDQ_VZP): New register type.
(get_reg_expected_msg): Handle it.
(parse_operands): When parsing operands of an SVE instruction,
disallow immediates that match REG_TYPE_R_Z_BHSDQ_VZP.
(aarch64_features): Add an entry for SVE.
2016-09-21 17:58:48 +02:00
|
|
|
|
|
|
|
|
|
case OP_MOV_Z_Z:
|
|
|
|
|
return (extract_field (FLD_SVE_Zn, inst->value, 0)
|
|
|
|
|
== extract_field (FLD_SVE_Zm_16, inst->value, 0));
|
|
|
|
|
|
|
|
|
|
case OP_MOV_Z_Zi:
|
|
|
|
|
/* Index must be nonzero. */
|
|
|
|
|
value = extract_fields (inst->value, 0, 2, FLD_SVE_tszh, FLD_imm5);
|
[AArch64] Additional SVE instructions
This patch supports some additions to the SVE architecture prior to
its public release.
include/
* opcode/aarch64.h (AARCH64_OPND_SVE_ADDR_RI_S4x16)
(AARCH64_OPND_SVE_IMM_ROT1, AARCH64_OPND_SVE_IMM_ROT2)
(AARCH64_OPND_SVE_Zm3_INDEX, AARCH64_OPND_SVE_Zm3_22_INDEX)
(AARCH64_OPND_SVE_Zm4_INDEX): New aarch64_opnds.
opcodes/
* aarch64-tbl.h (OP_SVE_HMH, OP_SVE_VMU_HSD, OP_SVE_VMVU_HSD)
(OP_SVE_VMVV_HSD, OP_SVE_VMVVU_HSD, OP_SVE_VM_HSD, OP_SVE_VUVV_HSD)
(OP_SVE_VUV_HSD, OP_SVE_VU_HSD, OP_SVE_VVVU_H, OP_SVE_VVVU_S)
(OP_SVE_VVVU_HSD, OP_SVE_VVV_D, OP_SVE_VVV_D_H, OP_SVE_VVV_H)
(OP_SVE_VVV_HSD, OP_SVE_VVV_S, OP_SVE_VVV_S_B, OP_SVE_VVV_SD_BH)
(OP_SVE_VV_BHSDQ, OP_SVE_VV_HSD, OP_SVE_VZVV_HSD, OP_SVE_VZV_HSD)
(OP_SVE_V_HSD): New macros.
(OP_SVE_VMU_SD, OP_SVE_VMVU_SD, OP_SVE_VM_SD, OP_SVE_VUVV_SD)
(OP_SVE_VU_SD, OP_SVE_VVVU_SD, OP_SVE_VVV_SD, OP_SVE_VZVV_SD)
(OP_SVE_VZV_SD, OP_SVE_V_SD): Delete.
(aarch64_opcode_table): Add new SVE instructions.
(aarch64_opcode_table): Use imm_rotate{1,2} instead of imm_rotate
for rotation operands. Add new SVE operands.
* aarch64-asm.h (ins_sve_addr_ri_s4): New inserter.
(ins_sve_quad_index): Likewise.
(ins_imm_rotate): Split into...
(ins_imm_rotate1, ins_imm_rotate2): ...these two inserters.
* aarch64-asm.c (aarch64_ins_imm_rotate): Split into...
(aarch64_ins_imm_rotate1, aarch64_ins_imm_rotate2): ...these two
functions.
(aarch64_ins_sve_addr_ri_s4): New function.
(aarch64_ins_sve_quad_index): Likewise.
(do_misc_encoding): Handle "MOV Zn.Q, Qm".
* aarch64-asm-2.c: Regenerate.
* aarch64-dis.h (ext_sve_addr_ri_s4): New extractor.
(ext_sve_quad_index): Likewise.
(ext_imm_rotate): Split into...
(ext_imm_rotate1, ext_imm_rotate2): ...these two extractors.
* aarch64-dis.c (aarch64_ext_imm_rotate): Split into...
(aarch64_ext_imm_rotate1, aarch64_ext_imm_rotate2): ...these two
functions.
(aarch64_ext_sve_addr_ri_s4): New function.
(aarch64_ext_sve_quad_index): Likewise.
(aarch64_ext_sve_index): Allow quad indices.
(do_misc_decoding): Likewise.
* aarch64-dis-2.c: Regenerate.
* aarch64-opc.h (FLD_SVE_i3h, FLD_SVE_rot1, FLD_SVE_rot2): New
aarch64_field_kinds.
(OPD_F_OD_MASK): Widen by one bit.
(OPD_F_NO_ZR): Bump accordingly.
(get_operand_field_width): New function.
* aarch64-opc.c (fields): Add new SVE fields.
(operand_general_constraint_met_p): Handle new SVE operands.
(aarch64_print_operand): Likewise.
* aarch64-opc-2.c: Regenerate.
gas/
* doc/c-aarch64.texi: Document that sve implies fp16, simd and compnum.
* config/tc-aarch64.c (parse_vector_type_for_operand): Allow .q
to be used with SVE registers.
(parse_operands): Handle new SVE operands.
(aarch64_features): Make "sve" require F16 rather than FP. Also
require COMPNUM.
* testsuite/gas/aarch64/sve.s: Add tests for new instructions.
Include compnum tests.
* testsuite/gas/aarch64/sve.d: Update accordingly.
* testsuite/gas/aarch64/sve-invalid.s: Add tests for new instructions.
* testsuite/gas/aarch64/sve-invalid.l: Update accordingly. Also
update expected output for new FMOV and MOV alternatives.
2017-02-24 19:29:00 +01:00
|
|
|
|
return value > 0 && value != (value & -value);
|
[AArch64][SVE 31/32] Add SVE instructions
This patch adds the SVE instruction definitions and associated OP_*
enum values.
include/
* opcode/aarch64.h (AARCH64_FEATURE_SVE): New macro.
(OP_MOV_P_P, OP_MOV_Z_P_Z, OP_MOV_Z_V, OP_MOV_Z_Z, OP_MOV_Z_Zi)
(OP_MOVM_P_P_P, OP_MOVS_P_P, OP_MOVZS_P_P_P, OP_MOVZ_P_P_P)
(OP_NOTS_P_P_P_Z, OP_NOT_P_P_P_Z): New aarch64_ops.
opcodes/
* aarch64-tbl.h (OP_SVE_B, OP_SVE_BB, OP_SVE_BBBU, OP_SVE_BMB)
(OP_SVE_BPB, OP_SVE_BUB, OP_SVE_BUBB, OP_SVE_BUU, OP_SVE_BZ)
(OP_SVE_BZB, OP_SVE_BZBB, OP_SVE_BZU, OP_SVE_DD, OP_SVE_DDD)
(OP_SVE_DMD, OP_SVE_DMH, OP_SVE_DMS, OP_SVE_DU, OP_SVE_DUD, OP_SVE_DUU)
(OP_SVE_DUV_BHS, OP_SVE_DUV_BHSD, OP_SVE_DZD, OP_SVE_DZU, OP_SVE_HB)
(OP_SVE_HMD, OP_SVE_HMS, OP_SVE_HU, OP_SVE_HUU, OP_SVE_HZU, OP_SVE_RR)
(OP_SVE_RURV_BHSD, OP_SVE_RUV_BHSD, OP_SVE_SMD, OP_SVE_SMH, OP_SVE_SMS)
(OP_SVE_SU, OP_SVE_SUS, OP_SVE_SUU, OP_SVE_SZS, OP_SVE_SZU, OP_SVE_UB)
(OP_SVE_UUD, OP_SVE_UUS, OP_SVE_VMR_BHSD, OP_SVE_VMU_SD)
(OP_SVE_VMVD_BHS, OP_SVE_VMVU_BHSD, OP_SVE_VMVU_SD, OP_SVE_VMVV_BHSD)
(OP_SVE_VMVV_SD, OP_SVE_VMV_BHSD, OP_SVE_VMV_HSD, OP_SVE_VMV_SD)
(OP_SVE_VM_SD, OP_SVE_VPU_BHSD, OP_SVE_VPV_BHSD, OP_SVE_VRR_BHSD)
(OP_SVE_VRU_BHSD, OP_SVE_VR_BHSD, OP_SVE_VUR_BHSD, OP_SVE_VUU_BHSD)
(OP_SVE_VUVV_BHSD, OP_SVE_VUVV_SD, OP_SVE_VUV_BHSD, OP_SVE_VUV_SD)
(OP_SVE_VU_BHSD, OP_SVE_VU_HSD, OP_SVE_VU_SD, OP_SVE_VVD_BHS)
(OP_SVE_VVU_BHSD, OP_SVE_VVVU_SD, OP_SVE_VVV_BHSD, OP_SVE_VVV_SD)
(OP_SVE_VV_BHSD, OP_SVE_VV_HSD_BHS, OP_SVE_VV_SD, OP_SVE_VWW_BHSD)
(OP_SVE_VXX_BHSD, OP_SVE_VZVD_BHS, OP_SVE_VZVU_BHSD, OP_SVE_VZVV_BHSD)
(OP_SVE_VZVV_SD, OP_SVE_VZV_SD, OP_SVE_V_SD, OP_SVE_WU, OP_SVE_WV_BHSD)
(OP_SVE_XU, OP_SVE_XUV_BHSD, OP_SVE_XVW_BHSD, OP_SVE_XV_BHSD)
(OP_SVE_XWU, OP_SVE_XXU): New macros.
(aarch64_feature_sve): New variable.
(SVE): New macro.
(_SVE_INSN): Likewise.
(aarch64_opcode_table): Add SVE instructions.
* aarch64-opc.h (extract_fields): Declare.
* aarch64-opc-2.c: Regenerate.
* aarch64-asm.c (do_misc_encoding): Handle the new SVE aarch64_ops.
* aarch64-asm-2.c: Regenerate.
* aarch64-dis.c (extract_fields): Make global.
(do_misc_decoding): Handle the new SVE aarch64_ops.
* aarch64-dis-2.c: Regenerate.
gas/
* doc/c-aarch64.texi: Document the "sve" feature.
* config/tc-aarch64.c (REG_TYPE_R_Z_BHSDQ_VZP): New register type.
(get_reg_expected_msg): Handle it.
(parse_operands): When parsing operands of an SVE instruction,
disallow immediates that match REG_TYPE_R_Z_BHSDQ_VZP.
(aarch64_features): Add an entry for SVE.
2016-09-21 17:58:48 +02:00
|
|
|
|
|
|
|
|
|
case OP_MOVM_P_P_P:
|
|
|
|
|
return (extract_field (FLD_SVE_Pd, inst->value, 0)
|
|
|
|
|
== extract_field (FLD_SVE_Pm, inst->value, 0));
|
|
|
|
|
|
|
|
|
|
case OP_MOVZS_P_P_P:
|
|
|
|
|
case OP_MOVZ_P_P_P:
|
|
|
|
|
return (extract_field (FLD_SVE_Pn, inst->value, 0)
|
|
|
|
|
== extract_field (FLD_SVE_Pm, inst->value, 0));
|
|
|
|
|
|
|
|
|
|
case OP_NOTS_P_P_P_Z:
|
|
|
|
|
case OP_NOT_P_P_P_Z:
|
|
|
|
|
return (extract_field (FLD_SVE_Pm, inst->value, 0)
|
|
|
|
|
== extract_field (FLD_SVE_Pg4_10, inst->value, 0));
|
|
|
|
|
|
2012-08-13 16:52:54 +02:00
|
|
|
|
default:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Opcodes that have fields shared by multiple operands are usually flagged
|
|
|
|
|
with flags. In this function, we detect such flags, decode the related
|
|
|
|
|
field(s) and store the information in one of the related operands. The
|
|
|
|
|
'one' operand is not any operand but one of the operands that can
|
|
|
|
|
accommadate all the information that has been decoded. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
do_special_decoding (aarch64_inst *inst)
|
|
|
|
|
{
|
|
|
|
|
int idx;
|
|
|
|
|
aarch64_insn value;
|
|
|
|
|
/* Condition for truly conditional executed instructions, e.g. b.cond. */
|
|
|
|
|
if (inst->opcode->flags & F_COND)
|
|
|
|
|
{
|
|
|
|
|
value = extract_field (FLD_cond2, inst->value, 0);
|
|
|
|
|
inst->cond = get_cond_from_value (value);
|
|
|
|
|
}
|
|
|
|
|
/* 'sf' field. */
|
|
|
|
|
if (inst->opcode->flags & F_SF)
|
|
|
|
|
{
|
|
|
|
|
idx = select_operand_for_sf_field_coding (inst->opcode);
|
|
|
|
|
value = extract_field (FLD_sf, inst->value, 0);
|
|
|
|
|
inst->operands[idx].qualifier = get_greg_qualifier_from_value (value);
|
|
|
|
|
if ((inst->opcode->flags & F_N)
|
|
|
|
|
&& extract_field (FLD_N, inst->value, 0) != value)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2014-09-03 15:40:41 +02:00
|
|
|
|
/* 'sf' field. */
|
|
|
|
|
if (inst->opcode->flags & F_LSE_SZ)
|
|
|
|
|
{
|
|
|
|
|
idx = select_operand_for_sf_field_coding (inst->opcode);
|
|
|
|
|
value = extract_field (FLD_lse_sz, inst->value, 0);
|
|
|
|
|
inst->operands[idx].qualifier = get_greg_qualifier_from_value (value);
|
|
|
|
|
}
|
2012-08-13 16:52:54 +02:00
|
|
|
|
/* size:Q fields. */
|
|
|
|
|
if (inst->opcode->flags & F_SIZEQ)
|
|
|
|
|
return decode_sizeq (inst);
|
|
|
|
|
|
|
|
|
|
if (inst->opcode->flags & F_FPTYPE)
|
|
|
|
|
{
|
|
|
|
|
idx = select_operand_for_fptype_field_coding (inst->opcode);
|
|
|
|
|
value = extract_field (FLD_type, inst->value, 0);
|
|
|
|
|
switch (value)
|
|
|
|
|
{
|
|
|
|
|
case 0: inst->operands[idx].qualifier = AARCH64_OPND_QLF_S_S; break;
|
|
|
|
|
case 1: inst->operands[idx].qualifier = AARCH64_OPND_QLF_S_D; break;
|
|
|
|
|
case 3: inst->operands[idx].qualifier = AARCH64_OPND_QLF_S_H; break;
|
|
|
|
|
default: return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (inst->opcode->flags & F_SSIZE)
|
|
|
|
|
{
|
|
|
|
|
/* N.B. some opcodes like FCMGT <V><d>, <V><n>, #0 have the size[1] as part
|
|
|
|
|
of the base opcode. */
|
|
|
|
|
aarch64_insn mask;
|
|
|
|
|
enum aarch64_opnd_qualifier candidates[AARCH64_MAX_QLF_SEQ_NUM];
|
|
|
|
|
idx = select_operand_for_scalar_size_field_coding (inst->opcode);
|
|
|
|
|
value = extract_field (FLD_size, inst->value, inst->opcode->mask);
|
|
|
|
|
mask = extract_field (FLD_size, ~inst->opcode->mask, 0);
|
|
|
|
|
/* For most related instruciton, the 'size' field is fully available for
|
|
|
|
|
operand encoding. */
|
|
|
|
|
if (mask == 0x3)
|
|
|
|
|
inst->operands[idx].qualifier = get_sreg_qualifier_from_value (value);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
get_operand_possible_qualifiers (idx, inst->opcode->qualifiers_list,
|
|
|
|
|
candidates);
|
|
|
|
|
inst->operands[idx].qualifier
|
|
|
|
|
= get_qualifier_from_partial_encoding (value, candidates, mask);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (inst->opcode->flags & F_T)
|
|
|
|
|
{
|
|
|
|
|
/* Num of consecutive '0's on the right side of imm5<3:0>. */
|
|
|
|
|
int num = 0;
|
|
|
|
|
unsigned val, Q;
|
|
|
|
|
assert (aarch64_get_operand_class (inst->opcode->operands[0])
|
|
|
|
|
== AARCH64_OPND_CLASS_SIMD_REG);
|
|
|
|
|
/* imm5<3:0> q <t>
|
|
|
|
|
0000 x reserved
|
|
|
|
|
xxx1 0 8b
|
|
|
|
|
xxx1 1 16b
|
|
|
|
|
xx10 0 4h
|
|
|
|
|
xx10 1 8h
|
|
|
|
|
x100 0 2s
|
|
|
|
|
x100 1 4s
|
|
|
|
|
1000 0 reserved
|
|
|
|
|
1000 1 2d */
|
|
|
|
|
val = extract_field (FLD_imm5, inst->value, 0);
|
|
|
|
|
while ((val & 0x1) == 0 && ++num <= 3)
|
|
|
|
|
val >>= 1;
|
|
|
|
|
if (num > 3)
|
|
|
|
|
return 0;
|
|
|
|
|
Q = (unsigned) extract_field (FLD_Q, inst->value, inst->opcode->mask);
|
|
|
|
|
inst->operands[0].qualifier =
|
|
|
|
|
get_vreg_qualifier_from_value ((num << 1) | Q);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (inst->opcode->flags & F_GPRSIZE_IN_Q)
|
|
|
|
|
{
|
|
|
|
|
/* Use Rt to encode in the case of e.g.
|
|
|
|
|
STXP <Ws>, <Xt1>, <Xt2>, [<Xn|SP>{,#0}]. */
|
|
|
|
|
idx = aarch64_operand_index (inst->opcode->operands, AARCH64_OPND_Rt);
|
|
|
|
|
if (idx == -1)
|
|
|
|
|
{
|
|
|
|
|
/* Otherwise use the result operand, which has to be a integer
|
|
|
|
|
register. */
|
|
|
|
|
assert (aarch64_get_operand_class (inst->opcode->operands[0])
|
|
|
|
|
== AARCH64_OPND_CLASS_INT_REG);
|
|
|
|
|
idx = 0;
|
|
|
|
|
}
|
|
|
|
|
assert (idx == 0 || idx == 1);
|
|
|
|
|
value = extract_field (FLD_Q, inst->value, 0);
|
|
|
|
|
inst->operands[idx].qualifier = get_greg_qualifier_from_value (value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (inst->opcode->flags & F_LDS_SIZE)
|
|
|
|
|
{
|
|
|
|
|
aarch64_field field = {0, 0};
|
|
|
|
|
assert (aarch64_get_operand_class (inst->opcode->operands[0])
|
|
|
|
|
== AARCH64_OPND_CLASS_INT_REG);
|
|
|
|
|
gen_sub_field (FLD_opc, 0, 1, &field);
|
|
|
|
|
value = extract_field_2 (&field, inst->value, 0);
|
|
|
|
|
inst->operands[0].qualifier
|
|
|
|
|
= value ? AARCH64_OPND_QLF_W : AARCH64_OPND_QLF_X;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Miscellaneous decoding; done as the last step. */
|
|
|
|
|
if (inst->opcode->flags & F_MISC)
|
|
|
|
|
return do_misc_decoding (inst);
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Converters converting a real opcode instruction to its alias form. */
|
|
|
|
|
|
|
|
|
|
/* ROR <Wd>, <Ws>, #<shift>
|
|
|
|
|
is equivalent to:
|
|
|
|
|
EXTR <Wd>, <Ws>, <Ws>, #<shift>. */
|
|
|
|
|
static int
|
|
|
|
|
convert_extr_to_ror (aarch64_inst *inst)
|
|
|
|
|
{
|
|
|
|
|
if (inst->operands[1].reg.regno == inst->operands[2].reg.regno)
|
|
|
|
|
{
|
|
|
|
|
copy_operand_info (inst, 2, 3);
|
|
|
|
|
inst->operands[3].type = AARCH64_OPND_NIL;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
include/opcode/
2013-01-30 Yufeng Zhang <yufeng.zhang@arm.com>
* aarch64.h (aarch64_op): Add OP_SXTL, OP_SXTL2, OP_UXTL and OP_UXTL2.
opcodes/
2013-01-30 Yufeng Zhang <yufeng.zhang@arm.com>
* aarch64-tbl.h (aarch64_opcode_table): Flag sshll, sshll2, ushll and
ushll2 with F_HAS_ALIAS. Add entries for sxtl, sxtl2, uxtl and uxtl2.
* aarch64-asm.c (convert_xtl_to_shll): New function.
(convert_to_real): Handle OP_SXTL, OP_SXTL2, OP_UXTL and OP_UXTL2 by
calling convert_xtl_to_shll.
* aarch64-dis.c (convert_shll_to_xtl): New function.
(convert_to_alias): Handle OP_SXTL, OP_SXTL2, OP_UXTL and OP_UXTL2 by
calling convert_shll_to_xtl.
* aarch64-gen.c: Update copyright year.
* aarch64-asm-2.c: Re-generate.
* aarch64-dis-2.c: Re-generate.
* aarch64-opc-2.c: Re-generate.
gas/testsuite/
2013-01-30 Yufeng Zhang <yufeng.zhang@arm.com>
* gas/aarch64/alias.s: Add new tests.
* gas/aarch64/alias.d: Update.
* gas/aarch64/no-aliases.d: Update.
2013-01-30 16:43:32 +01:00
|
|
|
|
/* UXTL<Q> <Vd>.<Ta>, <Vn>.<Tb>
|
|
|
|
|
is equivalent to:
|
|
|
|
|
USHLL<Q> <Vd>.<Ta>, <Vn>.<Tb>, #0. */
|
|
|
|
|
static int
|
|
|
|
|
convert_shll_to_xtl (aarch64_inst *inst)
|
|
|
|
|
{
|
|
|
|
|
if (inst->operands[2].imm.value == 0)
|
|
|
|
|
{
|
|
|
|
|
inst->operands[2].type = AARCH64_OPND_NIL;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-13 16:52:54 +02:00
|
|
|
|
/* Convert
|
|
|
|
|
UBFM <Xd>, <Xn>, #<shift>, #63.
|
|
|
|
|
to
|
|
|
|
|
LSR <Xd>, <Xn>, #<shift>. */
|
|
|
|
|
static int
|
|
|
|
|
convert_bfm_to_sr (aarch64_inst *inst)
|
|
|
|
|
{
|
|
|
|
|
int64_t imms, val;
|
|
|
|
|
|
|
|
|
|
imms = inst->operands[3].imm.value;
|
|
|
|
|
val = inst->operands[2].qualifier == AARCH64_OPND_QLF_imm_0_31 ? 31 : 63;
|
|
|
|
|
if (imms == val)
|
|
|
|
|
{
|
|
|
|
|
inst->operands[3].type = AARCH64_OPND_NIL;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Convert MOV to ORR. */
|
|
|
|
|
static int
|
|
|
|
|
convert_orr_to_mov (aarch64_inst *inst)
|
|
|
|
|
{
|
|
|
|
|
/* MOV <Vd>.<T>, <Vn>.<T>
|
|
|
|
|
is equivalent to:
|
|
|
|
|
ORR <Vd>.<T>, <Vn>.<T>, <Vn>.<T>. */
|
|
|
|
|
if (inst->operands[1].reg.regno == inst->operands[2].reg.regno)
|
|
|
|
|
{
|
|
|
|
|
inst->operands[2].type = AARCH64_OPND_NIL;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* When <imms> >= <immr>, the instruction written:
|
|
|
|
|
SBFX <Xd>, <Xn>, #<lsb>, #<width>
|
|
|
|
|
is equivalent to:
|
|
|
|
|
SBFM <Xd>, <Xn>, #<lsb>, #(<lsb>+<width>-1). */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
convert_bfm_to_bfx (aarch64_inst *inst)
|
|
|
|
|
{
|
|
|
|
|
int64_t immr, imms;
|
|
|
|
|
|
|
|
|
|
immr = inst->operands[2].imm.value;
|
|
|
|
|
imms = inst->operands[3].imm.value;
|
|
|
|
|
if (imms >= immr)
|
|
|
|
|
{
|
|
|
|
|
int64_t lsb = immr;
|
|
|
|
|
inst->operands[2].imm.value = lsb;
|
|
|
|
|
inst->operands[3].imm.value = imms + 1 - lsb;
|
|
|
|
|
/* The two opcodes have different qualifiers for
|
|
|
|
|
the immediate operands; reset to help the checking. */
|
|
|
|
|
reset_operand_qualifier (inst, 2);
|
|
|
|
|
reset_operand_qualifier (inst, 3);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* When <imms> < <immr>, the instruction written:
|
|
|
|
|
SBFIZ <Xd>, <Xn>, #<lsb>, #<width>
|
|
|
|
|
is equivalent to:
|
|
|
|
|
SBFM <Xd>, <Xn>, #((64-<lsb>)&0x3f), #(<width>-1). */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
convert_bfm_to_bfi (aarch64_inst *inst)
|
|
|
|
|
{
|
|
|
|
|
int64_t immr, imms, val;
|
|
|
|
|
|
|
|
|
|
immr = inst->operands[2].imm.value;
|
|
|
|
|
imms = inst->operands[3].imm.value;
|
|
|
|
|
val = inst->operands[2].qualifier == AARCH64_OPND_QLF_imm_0_31 ? 32 : 64;
|
|
|
|
|
if (imms < immr)
|
|
|
|
|
{
|
|
|
|
|
inst->operands[2].imm.value = (val - immr) & (val - 1);
|
|
|
|
|
inst->operands[3].imm.value = imms + 1;
|
|
|
|
|
/* The two opcodes have different qualifiers for
|
|
|
|
|
the immediate operands; reset to help the checking. */
|
|
|
|
|
reset_operand_qualifier (inst, 2);
|
|
|
|
|
reset_operand_qualifier (inst, 3);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-27 16:25:08 +01:00
|
|
|
|
/* The instruction written:
|
|
|
|
|
BFC <Xd>, #<lsb>, #<width>
|
|
|
|
|
is equivalent to:
|
|
|
|
|
BFM <Xd>, XZR, #((64-<lsb>)&0x3f), #(<width>-1). */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
convert_bfm_to_bfc (aarch64_inst *inst)
|
|
|
|
|
{
|
|
|
|
|
int64_t immr, imms, val;
|
|
|
|
|
|
|
|
|
|
/* Should have been assured by the base opcode value. */
|
|
|
|
|
assert (inst->operands[1].reg.regno == 0x1f);
|
|
|
|
|
|
|
|
|
|
immr = inst->operands[2].imm.value;
|
|
|
|
|
imms = inst->operands[3].imm.value;
|
|
|
|
|
val = inst->operands[2].qualifier == AARCH64_OPND_QLF_imm_0_31 ? 32 : 64;
|
|
|
|
|
if (imms < immr)
|
|
|
|
|
{
|
|
|
|
|
/* Drop XZR from the second operand. */
|
|
|
|
|
copy_operand_info (inst, 1, 2);
|
|
|
|
|
copy_operand_info (inst, 2, 3);
|
|
|
|
|
inst->operands[3].type = AARCH64_OPND_NIL;
|
|
|
|
|
|
|
|
|
|
/* Recalculate the immediates. */
|
|
|
|
|
inst->operands[1].imm.value = (val - immr) & (val - 1);
|
|
|
|
|
inst->operands[2].imm.value = imms + 1;
|
|
|
|
|
|
|
|
|
|
/* The two opcodes have different qualifiers for the operands; reset to
|
|
|
|
|
help the checking. */
|
|
|
|
|
reset_operand_qualifier (inst, 1);
|
|
|
|
|
reset_operand_qualifier (inst, 2);
|
|
|
|
|
reset_operand_qualifier (inst, 3);
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-13 16:52:54 +02:00
|
|
|
|
/* The instruction written:
|
|
|
|
|
LSL <Xd>, <Xn>, #<shift>
|
|
|
|
|
is equivalent to:
|
|
|
|
|
UBFM <Xd>, <Xn>, #((64-<shift>)&0x3f), #(63-<shift>). */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
convert_ubfm_to_lsl (aarch64_inst *inst)
|
|
|
|
|
{
|
|
|
|
|
int64_t immr = inst->operands[2].imm.value;
|
|
|
|
|
int64_t imms = inst->operands[3].imm.value;
|
|
|
|
|
int64_t val
|
|
|
|
|
= inst->operands[2].qualifier == AARCH64_OPND_QLF_imm_0_31 ? 31 : 63;
|
|
|
|
|
|
|
|
|
|
if ((immr == 0 && imms == val) || immr == imms + 1)
|
|
|
|
|
{
|
|
|
|
|
inst->operands[3].type = AARCH64_OPND_NIL;
|
|
|
|
|
inst->operands[2].imm.value = val - imms;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* CINC <Wd>, <Wn>, <cond>
|
|
|
|
|
is equivalent to:
|
2013-11-05 21:50:18 +01:00
|
|
|
|
CSINC <Wd>, <Wn>, <Wn>, invert(<cond>)
|
|
|
|
|
where <cond> is not AL or NV. */
|
2012-08-13 16:52:54 +02:00
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
convert_from_csel (aarch64_inst *inst)
|
|
|
|
|
{
|
2013-11-05 21:50:18 +01:00
|
|
|
|
if (inst->operands[1].reg.regno == inst->operands[2].reg.regno
|
|
|
|
|
&& (inst->operands[3].cond->value & 0xe) != 0xe)
|
2012-08-13 16:52:54 +02:00
|
|
|
|
{
|
|
|
|
|
copy_operand_info (inst, 2, 3);
|
|
|
|
|
inst->operands[2].cond = get_inverted_cond (inst->operands[3].cond);
|
|
|
|
|
inst->operands[3].type = AARCH64_OPND_NIL;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* CSET <Wd>, <cond>
|
|
|
|
|
is equivalent to:
|
2013-11-05 21:50:18 +01:00
|
|
|
|
CSINC <Wd>, WZR, WZR, invert(<cond>)
|
|
|
|
|
where <cond> is not AL or NV. */
|
2012-08-13 16:52:54 +02:00
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
convert_csinc_to_cset (aarch64_inst *inst)
|
|
|
|
|
{
|
|
|
|
|
if (inst->operands[1].reg.regno == 0x1f
|
2013-11-05 21:50:18 +01:00
|
|
|
|
&& inst->operands[2].reg.regno == 0x1f
|
|
|
|
|
&& (inst->operands[3].cond->value & 0xe) != 0xe)
|
2012-08-13 16:52:54 +02:00
|
|
|
|
{
|
|
|
|
|
copy_operand_info (inst, 1, 3);
|
|
|
|
|
inst->operands[1].cond = get_inverted_cond (inst->operands[3].cond);
|
|
|
|
|
inst->operands[3].type = AARCH64_OPND_NIL;
|
|
|
|
|
inst->operands[2].type = AARCH64_OPND_NIL;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* MOV <Wd>, #<imm>
|
|
|
|
|
is equivalent to:
|
|
|
|
|
MOVZ <Wd>, #<imm16>, LSL #<shift>.
|
|
|
|
|
|
|
|
|
|
A disassembler may output ORR, MOVZ and MOVN as a MOV mnemonic, except when
|
|
|
|
|
ORR has an immediate that could be generated by a MOVZ or MOVN instruction,
|
|
|
|
|
or where a MOVN has an immediate that could be encoded by MOVZ, or where
|
|
|
|
|
MOVZ/MOVN #0 have a shift amount other than LSL #0, in which case the
|
|
|
|
|
machine-instruction mnemonic must be used. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
convert_movewide_to_mov (aarch64_inst *inst)
|
|
|
|
|
{
|
|
|
|
|
uint64_t value = inst->operands[1].imm.value;
|
|
|
|
|
/* MOVZ/MOVN #0 have a shift amount other than LSL #0. */
|
|
|
|
|
if (value == 0 && inst->operands[1].shifter.amount != 0)
|
|
|
|
|
return 0;
|
|
|
|
|
inst->operands[1].type = AARCH64_OPND_IMM_MOV;
|
|
|
|
|
inst->operands[1].shifter.kind = AARCH64_MOD_NONE;
|
|
|
|
|
value <<= inst->operands[1].shifter.amount;
|
|
|
|
|
/* As an alias convertor, it has to be clear that the INST->OPCODE
|
|
|
|
|
is the opcode of the real instruction. */
|
|
|
|
|
if (inst->opcode->op == OP_MOVN)
|
|
|
|
|
{
|
|
|
|
|
int is32 = inst->operands[0].qualifier == AARCH64_OPND_QLF_W;
|
|
|
|
|
value = ~value;
|
|
|
|
|
/* A MOVN has an immediate that could be encoded by MOVZ. */
|
2017-05-18 07:17:40 +02:00
|
|
|
|
if (aarch64_wide_constant_p (value, is32, NULL))
|
2012-08-13 16:52:54 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
inst->operands[1].imm.value = value;
|
|
|
|
|
inst->operands[1].shifter.amount = 0;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* MOV <Wd>, #<imm>
|
|
|
|
|
is equivalent to:
|
|
|
|
|
ORR <Wd>, WZR, #<imm>.
|
|
|
|
|
|
|
|
|
|
A disassembler may output ORR, MOVZ and MOVN as a MOV mnemonic, except when
|
|
|
|
|
ORR has an immediate that could be generated by a MOVZ or MOVN instruction,
|
|
|
|
|
or where a MOVN has an immediate that could be encoded by MOVZ, or where
|
|
|
|
|
MOVZ/MOVN #0 have a shift amount other than LSL #0, in which case the
|
|
|
|
|
machine-instruction mnemonic must be used. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
convert_movebitmask_to_mov (aarch64_inst *inst)
|
|
|
|
|
{
|
|
|
|
|
int is32;
|
|
|
|
|
uint64_t value;
|
|
|
|
|
|
|
|
|
|
/* Should have been assured by the base opcode value. */
|
|
|
|
|
assert (inst->operands[1].reg.regno == 0x1f);
|
|
|
|
|
copy_operand_info (inst, 1, 2);
|
|
|
|
|
is32 = inst->operands[0].qualifier == AARCH64_OPND_QLF_W;
|
|
|
|
|
inst->operands[1].type = AARCH64_OPND_IMM_MOV;
|
|
|
|
|
value = inst->operands[1].imm.value;
|
|
|
|
|
/* ORR has an immediate that could be generated by a MOVZ or MOVN
|
|
|
|
|
instruction. */
|
|
|
|
|
if (inst->operands[0].reg.regno != 0x1f
|
2017-05-18 07:17:40 +02:00
|
|
|
|
&& (aarch64_wide_constant_p (value, is32, NULL)
|
|
|
|
|
|| aarch64_wide_constant_p (~value, is32, NULL)))
|
2012-08-13 16:52:54 +02:00
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
inst->operands[2].type = AARCH64_OPND_NIL;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Some alias opcodes are disassembled by being converted from their real-form.
|
|
|
|
|
N.B. INST->OPCODE is the real opcode rather than the alias. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
convert_to_alias (aarch64_inst *inst, const aarch64_opcode *alias)
|
|
|
|
|
{
|
|
|
|
|
switch (alias->op)
|
|
|
|
|
{
|
|
|
|
|
case OP_ASR_IMM:
|
|
|
|
|
case OP_LSR_IMM:
|
|
|
|
|
return convert_bfm_to_sr (inst);
|
|
|
|
|
case OP_LSL_IMM:
|
|
|
|
|
return convert_ubfm_to_lsl (inst);
|
|
|
|
|
case OP_CINC:
|
|
|
|
|
case OP_CINV:
|
|
|
|
|
case OP_CNEG:
|
|
|
|
|
return convert_from_csel (inst);
|
|
|
|
|
case OP_CSET:
|
|
|
|
|
case OP_CSETM:
|
|
|
|
|
return convert_csinc_to_cset (inst);
|
|
|
|
|
case OP_UBFX:
|
|
|
|
|
case OP_BFXIL:
|
|
|
|
|
case OP_SBFX:
|
|
|
|
|
return convert_bfm_to_bfx (inst);
|
|
|
|
|
case OP_SBFIZ:
|
|
|
|
|
case OP_BFI:
|
|
|
|
|
case OP_UBFIZ:
|
|
|
|
|
return convert_bfm_to_bfi (inst);
|
2015-11-27 16:25:08 +01:00
|
|
|
|
case OP_BFC:
|
|
|
|
|
return convert_bfm_to_bfc (inst);
|
2012-08-13 16:52:54 +02:00
|
|
|
|
case OP_MOV_V:
|
|
|
|
|
return convert_orr_to_mov (inst);
|
|
|
|
|
case OP_MOV_IMM_WIDE:
|
|
|
|
|
case OP_MOV_IMM_WIDEN:
|
|
|
|
|
return convert_movewide_to_mov (inst);
|
|
|
|
|
case OP_MOV_IMM_LOG:
|
|
|
|
|
return convert_movebitmask_to_mov (inst);
|
|
|
|
|
case OP_ROR_IMM:
|
|
|
|
|
return convert_extr_to_ror (inst);
|
include/opcode/
2013-01-30 Yufeng Zhang <yufeng.zhang@arm.com>
* aarch64.h (aarch64_op): Add OP_SXTL, OP_SXTL2, OP_UXTL and OP_UXTL2.
opcodes/
2013-01-30 Yufeng Zhang <yufeng.zhang@arm.com>
* aarch64-tbl.h (aarch64_opcode_table): Flag sshll, sshll2, ushll and
ushll2 with F_HAS_ALIAS. Add entries for sxtl, sxtl2, uxtl and uxtl2.
* aarch64-asm.c (convert_xtl_to_shll): New function.
(convert_to_real): Handle OP_SXTL, OP_SXTL2, OP_UXTL and OP_UXTL2 by
calling convert_xtl_to_shll.
* aarch64-dis.c (convert_shll_to_xtl): New function.
(convert_to_alias): Handle OP_SXTL, OP_SXTL2, OP_UXTL and OP_UXTL2 by
calling convert_shll_to_xtl.
* aarch64-gen.c: Update copyright year.
* aarch64-asm-2.c: Re-generate.
* aarch64-dis-2.c: Re-generate.
* aarch64-opc-2.c: Re-generate.
gas/testsuite/
2013-01-30 Yufeng Zhang <yufeng.zhang@arm.com>
* gas/aarch64/alias.s: Add new tests.
* gas/aarch64/alias.d: Update.
* gas/aarch64/no-aliases.d: Update.
2013-01-30 16:43:32 +01:00
|
|
|
|
case OP_SXTL:
|
|
|
|
|
case OP_SXTL2:
|
|
|
|
|
case OP_UXTL:
|
|
|
|
|
case OP_UXTL2:
|
|
|
|
|
return convert_shll_to_xtl (inst);
|
2012-08-13 16:52:54 +02:00
|
|
|
|
default:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int aarch64_opcode_decode (const aarch64_opcode *, const aarch64_insn,
|
|
|
|
|
aarch64_inst *, int);
|
|
|
|
|
|
|
|
|
|
/* Given the instruction information in *INST, check if the instruction has
|
|
|
|
|
any alias form that can be used to represent *INST. If the answer is yes,
|
|
|
|
|
update *INST to be in the form of the determined alias. */
|
|
|
|
|
|
|
|
|
|
/* In the opcode description table, the following flags are used in opcode
|
|
|
|
|
entries to help establish the relations between the real and alias opcodes:
|
|
|
|
|
|
|
|
|
|
F_ALIAS: opcode is an alias
|
|
|
|
|
F_HAS_ALIAS: opcode has alias(es)
|
|
|
|
|
F_P1
|
|
|
|
|
F_P2
|
|
|
|
|
F_P3: Disassembly preference priority 1-3 (the larger the
|
|
|
|
|
higher). If nothing is specified, it is the priority
|
|
|
|
|
0 by default, i.e. the lowest priority.
|
|
|
|
|
|
|
|
|
|
Although the relation between the machine and the alias instructions are not
|
|
|
|
|
explicitly described, it can be easily determined from the base opcode
|
|
|
|
|
values, masks and the flags F_ALIAS and F_HAS_ALIAS in their opcode
|
|
|
|
|
description entries:
|
|
|
|
|
|
|
|
|
|
The mask of an alias opcode must be equal to or a super-set (i.e. more
|
|
|
|
|
constrained) of that of the aliased opcode; so is the base opcode value.
|
|
|
|
|
|
|
|
|
|
if (opcode_has_alias (real) && alias_opcode_p (opcode)
|
|
|
|
|
&& (opcode->mask & real->mask) == real->mask
|
|
|
|
|
&& (real->mask & opcode->opcode) == (real->mask & real->opcode))
|
|
|
|
|
then OPCODE is an alias of, and only of, the REAL instruction
|
|
|
|
|
|
|
|
|
|
The alias relationship is forced flat-structured to keep related algorithm
|
|
|
|
|
simple; an opcode entry cannot be flagged with both F_ALIAS and F_HAS_ALIAS.
|
|
|
|
|
|
|
|
|
|
During the disassembling, the decoding decision tree (in
|
|
|
|
|
opcodes/aarch64-dis-2.c) always returns an machine instruction opcode entry;
|
|
|
|
|
if the decoding of such a machine instruction succeeds (and -Mno-aliases is
|
|
|
|
|
not specified), the disassembler will check whether there is any alias
|
|
|
|
|
instruction exists for this real instruction. If there is, the disassembler
|
|
|
|
|
will try to disassemble the 32-bit binary again using the alias's rule, or
|
|
|
|
|
try to convert the IR to the form of the alias. In the case of the multiple
|
|
|
|
|
aliases, the aliases are tried one by one from the highest priority
|
|
|
|
|
(currently the flag F_P3) to the lowest priority (no priority flag), and the
|
|
|
|
|
first succeeds first adopted.
|
|
|
|
|
|
|
|
|
|
You may ask why there is a need for the conversion of IR from one form to
|
|
|
|
|
another in handling certain aliases. This is because on one hand it avoids
|
|
|
|
|
adding more operand code to handle unusual encoding/decoding; on other
|
|
|
|
|
hand, during the disassembling, the conversion is an effective approach to
|
|
|
|
|
check the condition of an alias (as an alias may be adopted only if certain
|
|
|
|
|
conditions are met).
|
|
|
|
|
|
|
|
|
|
In order to speed up the alias opcode lookup, aarch64-gen has preprocessed
|
|
|
|
|
aarch64_opcode_table and generated aarch64_find_alias_opcode and
|
|
|
|
|
aarch64_find_next_alias_opcode (in opcodes/aarch64-dis-2.c) to help. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
determine_disassembling_preference (struct aarch64_inst *inst)
|
|
|
|
|
{
|
|
|
|
|
const aarch64_opcode *opcode;
|
|
|
|
|
const aarch64_opcode *alias;
|
|
|
|
|
|
|
|
|
|
opcode = inst->opcode;
|
|
|
|
|
|
|
|
|
|
/* This opcode does not have an alias, so use itself. */
|
2017-05-18 07:17:40 +02:00
|
|
|
|
if (!opcode_has_alias (opcode))
|
2012-08-13 16:52:54 +02:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
alias = aarch64_find_alias_opcode (opcode);
|
|
|
|
|
assert (alias);
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG_AARCH64
|
|
|
|
|
if (debug_dump)
|
|
|
|
|
{
|
|
|
|
|
const aarch64_opcode *tmp = alias;
|
|
|
|
|
printf ("#### LIST orderd: ");
|
|
|
|
|
while (tmp)
|
|
|
|
|
{
|
|
|
|
|
printf ("%s, ", tmp->name);
|
|
|
|
|
tmp = aarch64_find_next_alias_opcode (tmp);
|
|
|
|
|
}
|
|
|
|
|
printf ("\n");
|
|
|
|
|
}
|
|
|
|
|
#endif /* DEBUG_AARCH64 */
|
|
|
|
|
|
|
|
|
|
for (; alias; alias = aarch64_find_next_alias_opcode (alias))
|
|
|
|
|
{
|
|
|
|
|
DEBUG_TRACE ("try %s", alias->name);
|
2015-11-27 16:02:26 +01:00
|
|
|
|
assert (alias_opcode_p (alias) || opcode_has_alias (opcode));
|
2012-08-13 16:52:54 +02:00
|
|
|
|
|
|
|
|
|
/* An alias can be a pseudo opcode which will never be used in the
|
|
|
|
|
disassembly, e.g. BIC logical immediate is such a pseudo opcode
|
|
|
|
|
aliasing AND. */
|
|
|
|
|
if (pseudo_opcode_p (alias))
|
|
|
|
|
{
|
|
|
|
|
DEBUG_TRACE ("skip pseudo %s", alias->name);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((inst->value & alias->mask) != alias->opcode)
|
|
|
|
|
{
|
|
|
|
|
DEBUG_TRACE ("skip %s as base opcode not match", alias->name);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
/* No need to do any complicated transformation on operands, if the alias
|
|
|
|
|
opcode does not have any operand. */
|
|
|
|
|
if (aarch64_num_of_operands (alias) == 0 && alias->opcode == inst->value)
|
|
|
|
|
{
|
|
|
|
|
DEBUG_TRACE ("succeed with 0-operand opcode %s", alias->name);
|
|
|
|
|
aarch64_replace_opcode (inst, alias);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (alias->flags & F_CONV)
|
|
|
|
|
{
|
|
|
|
|
aarch64_inst copy;
|
|
|
|
|
memcpy (©, inst, sizeof (aarch64_inst));
|
|
|
|
|
/* ALIAS is the preference as long as the instruction can be
|
|
|
|
|
successfully converted to the form of ALIAS. */
|
|
|
|
|
if (convert_to_alias (©, alias) == 1)
|
|
|
|
|
{
|
|
|
|
|
aarch64_replace_opcode (©, alias);
|
|
|
|
|
assert (aarch64_match_operands_constraint (©, NULL));
|
|
|
|
|
DEBUG_TRACE ("succeed with %s via conversion", alias->name);
|
|
|
|
|
memcpy (inst, ©, sizeof (aarch64_inst));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Directly decode the alias opcode. */
|
|
|
|
|
aarch64_inst temp;
|
|
|
|
|
memset (&temp, '\0', sizeof (aarch64_inst));
|
|
|
|
|
if (aarch64_opcode_decode (alias, inst->value, &temp, 1) == 1)
|
|
|
|
|
{
|
|
|
|
|
DEBUG_TRACE ("succeed with %s via direct decoding", alias->name);
|
|
|
|
|
memcpy (inst, &temp, sizeof (aarch64_inst));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
[AArch64][SVE 30/32] Add SVE instruction classes
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.
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.
2016-09-21 17:58:22 +02:00
|
|
|
|
/* 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:
|
[AArch64] Additional SVE instructions
This patch supports some additions to the SVE architecture prior to
its public release.
include/
* opcode/aarch64.h (AARCH64_OPND_SVE_ADDR_RI_S4x16)
(AARCH64_OPND_SVE_IMM_ROT1, AARCH64_OPND_SVE_IMM_ROT2)
(AARCH64_OPND_SVE_Zm3_INDEX, AARCH64_OPND_SVE_Zm3_22_INDEX)
(AARCH64_OPND_SVE_Zm4_INDEX): New aarch64_opnds.
opcodes/
* aarch64-tbl.h (OP_SVE_HMH, OP_SVE_VMU_HSD, OP_SVE_VMVU_HSD)
(OP_SVE_VMVV_HSD, OP_SVE_VMVVU_HSD, OP_SVE_VM_HSD, OP_SVE_VUVV_HSD)
(OP_SVE_VUV_HSD, OP_SVE_VU_HSD, OP_SVE_VVVU_H, OP_SVE_VVVU_S)
(OP_SVE_VVVU_HSD, OP_SVE_VVV_D, OP_SVE_VVV_D_H, OP_SVE_VVV_H)
(OP_SVE_VVV_HSD, OP_SVE_VVV_S, OP_SVE_VVV_S_B, OP_SVE_VVV_SD_BH)
(OP_SVE_VV_BHSDQ, OP_SVE_VV_HSD, OP_SVE_VZVV_HSD, OP_SVE_VZV_HSD)
(OP_SVE_V_HSD): New macros.
(OP_SVE_VMU_SD, OP_SVE_VMVU_SD, OP_SVE_VM_SD, OP_SVE_VUVV_SD)
(OP_SVE_VU_SD, OP_SVE_VVVU_SD, OP_SVE_VVV_SD, OP_SVE_VZVV_SD)
(OP_SVE_VZV_SD, OP_SVE_V_SD): Delete.
(aarch64_opcode_table): Add new SVE instructions.
(aarch64_opcode_table): Use imm_rotate{1,2} instead of imm_rotate
for rotation operands. Add new SVE operands.
* aarch64-asm.h (ins_sve_addr_ri_s4): New inserter.
(ins_sve_quad_index): Likewise.
(ins_imm_rotate): Split into...
(ins_imm_rotate1, ins_imm_rotate2): ...these two inserters.
* aarch64-asm.c (aarch64_ins_imm_rotate): Split into...
(aarch64_ins_imm_rotate1, aarch64_ins_imm_rotate2): ...these two
functions.
(aarch64_ins_sve_addr_ri_s4): New function.
(aarch64_ins_sve_quad_index): Likewise.
(do_misc_encoding): Handle "MOV Zn.Q, Qm".
* aarch64-asm-2.c: Regenerate.
* aarch64-dis.h (ext_sve_addr_ri_s4): New extractor.
(ext_sve_quad_index): Likewise.
(ext_imm_rotate): Split into...
(ext_imm_rotate1, ext_imm_rotate2): ...these two extractors.
* aarch64-dis.c (aarch64_ext_imm_rotate): Split into...
(aarch64_ext_imm_rotate1, aarch64_ext_imm_rotate2): ...these two
functions.
(aarch64_ext_sve_addr_ri_s4): New function.
(aarch64_ext_sve_quad_index): Likewise.
(aarch64_ext_sve_index): Allow quad indices.
(do_misc_decoding): Likewise.
* aarch64-dis-2.c: Regenerate.
* aarch64-opc.h (FLD_SVE_i3h, FLD_SVE_rot1, FLD_SVE_rot2): New
aarch64_field_kinds.
(OPD_F_OD_MASK): Widen by one bit.
(OPD_F_NO_ZR): Bump accordingly.
(get_operand_field_width): New function.
* aarch64-opc.c (fields): Add new SVE fields.
(operand_general_constraint_met_p): Handle new SVE operands.
(aarch64_print_operand): Likewise.
* aarch64-opc-2.c: Regenerate.
gas/
* doc/c-aarch64.texi: Document that sve implies fp16, simd and compnum.
* config/tc-aarch64.c (parse_vector_type_for_operand): Allow .q
to be used with SVE registers.
(parse_operands): Handle new SVE operands.
(aarch64_features): Make "sve" require F16 rather than FP. Also
require COMPNUM.
* testsuite/gas/aarch64/sve.s: Add tests for new instructions.
Include compnum tests.
* testsuite/gas/aarch64/sve.d: Update accordingly.
* testsuite/gas/aarch64/sve-invalid.s: Add tests for new instructions.
* testsuite/gas/aarch64/sve-invalid.l: Update accordingly. Also
update expected output for new FMOV and MOV alternatives.
2017-02-24 19:29:00 +01:00
|
|
|
|
i = extract_fields (inst->value, 0, 2, FLD_SVE_tszh, FLD_imm5);
|
|
|
|
|
if ((i & 31) == 0)
|
[AArch64][SVE 30/32] Add SVE instruction classes
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.
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.
2016-09-21 17:58:22 +02:00
|
|
|
|
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;
|
|
|
|
|
}
|
2012-08-13 16:52:54 +02:00
|
|
|
|
/* 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.
|
|
|
|
|
|
|
|
|
|
If OPCODE has alias(es) and NOALIASES_P is 0, an alias opcode may be
|
|
|
|
|
determined and used to disassemble CODE; this is done just before the
|
|
|
|
|
return. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
aarch64_opcode_decode (const aarch64_opcode *opcode, const aarch64_insn code,
|
|
|
|
|
aarch64_inst *inst, int noaliases_p)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
DEBUG_TRACE ("enter with %s", opcode->name);
|
|
|
|
|
|
|
|
|
|
assert (opcode && inst);
|
|
|
|
|
|
|
|
|
|
/* Check the base opcode. */
|
|
|
|
|
if ((code & opcode->mask) != (opcode->opcode & opcode->mask))
|
|
|
|
|
{
|
|
|
|
|
DEBUG_TRACE ("base opcode match FAIL");
|
|
|
|
|
goto decode_fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Clear inst. */
|
|
|
|
|
memset (inst, '\0', sizeof (aarch64_inst));
|
|
|
|
|
|
|
|
|
|
inst->opcode = opcode;
|
|
|
|
|
inst->value = code;
|
|
|
|
|
|
|
|
|
|
/* Assign operand codes and indexes. */
|
|
|
|
|
for (i = 0; i < AARCH64_MAX_OPND_NUM; ++i)
|
|
|
|
|
{
|
|
|
|
|
if (opcode->operands[i] == AARCH64_OPND_NIL)
|
|
|
|
|
break;
|
|
|
|
|
inst->operands[i].type = opcode->operands[i];
|
|
|
|
|
inst->operands[i].idx = i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Call the opcode decoder indicated by flags. */
|
|
|
|
|
if (opcode_has_special_coder (opcode) && do_special_decoding (inst) == 0)
|
|
|
|
|
{
|
|
|
|
|
DEBUG_TRACE ("opcode flag-based decoder FAIL");
|
|
|
|
|
goto decode_fail;
|
|
|
|
|
}
|
|
|
|
|
|
[AArch64][SVE 30/32] Add SVE instruction classes
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.
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.
2016-09-21 17:58:22 +02:00
|
|
|
|
/* 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;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-13 16:52:54 +02:00
|
|
|
|
/* Call operand decoders. */
|
|
|
|
|
for (i = 0; i < AARCH64_MAX_OPND_NUM; ++i)
|
|
|
|
|
{
|
|
|
|
|
const aarch64_operand *opnd;
|
|
|
|
|
enum aarch64_opnd type;
|
2016-04-28 10:11:03 +02:00
|
|
|
|
|
2012-08-13 16:52:54 +02:00
|
|
|
|
type = opcode->operands[i];
|
|
|
|
|
if (type == AARCH64_OPND_NIL)
|
|
|
|
|
break;
|
|
|
|
|
opnd = &aarch64_operands[type];
|
|
|
|
|
if (operand_has_extractor (opnd)
|
|
|
|
|
&& (! aarch64_extract_operand (opnd, &inst->operands[i], code, inst)))
|
|
|
|
|
{
|
|
|
|
|
DEBUG_TRACE ("operand decoder FAIL at operand %d", i);
|
|
|
|
|
goto decode_fail;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-28 10:11:03 +02:00
|
|
|
|
/* If the opcode has a verifier, then check it now. */
|
|
|
|
|
if (opcode->verifier && ! opcode->verifier (opcode, code))
|
|
|
|
|
{
|
|
|
|
|
DEBUG_TRACE ("operand verifier FAIL");
|
|
|
|
|
goto decode_fail;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-13 16:52:54 +02:00
|
|
|
|
/* Match the qualifiers. */
|
|
|
|
|
if (aarch64_match_operands_constraint (inst, NULL) == 1)
|
|
|
|
|
{
|
|
|
|
|
/* Arriving here, the CODE has been determined as a valid instruction
|
|
|
|
|
of OPCODE and *INST has been filled with information of this OPCODE
|
|
|
|
|
instruction. Before the return, check if the instruction has any
|
|
|
|
|
alias and should be disassembled in the form of its alias instead.
|
|
|
|
|
If the answer is yes, *INST will be updated. */
|
|
|
|
|
if (!noaliases_p)
|
|
|
|
|
determine_disassembling_preference (inst);
|
|
|
|
|
DEBUG_TRACE ("SUCCESS");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
DEBUG_TRACE ("constraint matching FAIL");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
decode_fail:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This does some user-friendly fix-up to *INST. It is currently focus on
|
|
|
|
|
the adjustment of qualifiers to help the printed instruction
|
|
|
|
|
recognized/understood more easily. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
user_friendly_fixup (aarch64_inst *inst)
|
|
|
|
|
{
|
|
|
|
|
switch (inst->opcode->iclass)
|
|
|
|
|
{
|
|
|
|
|
case testbranch:
|
|
|
|
|
/* TBNZ Xn|Wn, #uimm6, label
|
|
|
|
|
Test and Branch Not Zero: conditionally jumps to label if bit number
|
|
|
|
|
uimm6 in register Xn is not zero. The bit number implies the width of
|
|
|
|
|
the register, which may be written and should be disassembled as Wn if
|
|
|
|
|
uimm is less than 32. Limited to a branch offset range of +/- 32KiB.
|
|
|
|
|
*/
|
|
|
|
|
if (inst->operands[1].imm.value < 32)
|
|
|
|
|
inst->operands[0].qualifier = AARCH64_OPND_QLF_W;
|
|
|
|
|
break;
|
|
|
|
|
default: break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-05 12:15:58 +02:00
|
|
|
|
/* Decode INSN and fill in *INST the instruction information. An alias
|
|
|
|
|
opcode may be filled in *INSN if NOALIASES_P is FALSE. Return zero on
|
|
|
|
|
success. */
|
2012-08-13 16:52:54 +02:00
|
|
|
|
|
2015-10-02 12:36:00 +02:00
|
|
|
|
int
|
2015-10-05 12:15:58 +02:00
|
|
|
|
aarch64_decode_insn (aarch64_insn insn, aarch64_inst *inst,
|
|
|
|
|
bfd_boolean noaliases_p)
|
2012-08-13 16:52:54 +02:00
|
|
|
|
{
|
|
|
|
|
const aarch64_opcode *opcode = aarch64_opcode_lookup (insn);
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG_AARCH64
|
|
|
|
|
if (debug_dump)
|
|
|
|
|
{
|
|
|
|
|
const aarch64_opcode *tmp = opcode;
|
|
|
|
|
printf ("\n");
|
|
|
|
|
DEBUG_TRACE ("opcode lookup:");
|
|
|
|
|
while (tmp != NULL)
|
|
|
|
|
{
|
|
|
|
|
aarch64_verbose (" %s", tmp->name);
|
|
|
|
|
tmp = aarch64_find_next_opcode (tmp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif /* DEBUG_AARCH64 */
|
|
|
|
|
|
|
|
|
|
/* A list of opcodes may have been found, as aarch64_opcode_lookup cannot
|
|
|
|
|
distinguish some opcodes, e.g. SSHR and MOVI, which almost share the same
|
|
|
|
|
opcode field and value, apart from the difference that one of them has an
|
|
|
|
|
extra field as part of the opcode, but such a field is used for operand
|
|
|
|
|
encoding in other opcode(s) ('immh' in the case of the example). */
|
|
|
|
|
while (opcode != NULL)
|
|
|
|
|
{
|
|
|
|
|
/* But only one opcode can be decoded successfully for, as the
|
|
|
|
|
decoding routine will check the constraint carefully. */
|
2015-10-05 12:15:58 +02:00
|
|
|
|
if (aarch64_opcode_decode (opcode, insn, inst, noaliases_p) == 1)
|
2012-08-13 16:52:54 +02:00
|
|
|
|
return ERR_OK;
|
|
|
|
|
opcode = aarch64_find_next_opcode (opcode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ERR_UND;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Print operands. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
print_operands (bfd_vma pc, const aarch64_opcode *opcode,
|
|
|
|
|
const aarch64_opnd_info *opnds, struct disassemble_info *info)
|
|
|
|
|
{
|
|
|
|
|
int i, pcrel_p, num_printed;
|
|
|
|
|
for (i = 0, num_printed = 0; i < AARCH64_MAX_OPND_NUM; ++i)
|
|
|
|
|
{
|
2016-03-24 22:42:09 +01:00
|
|
|
|
char str[128];
|
2012-08-13 16:52:54 +02:00
|
|
|
|
/* We regard the opcode operand info more, however we also look into
|
|
|
|
|
the inst->operands to support the disassembling of the optional
|
|
|
|
|
operand.
|
|
|
|
|
The two operand code should be the same in all cases, apart from
|
|
|
|
|
when the operand can be optional. */
|
|
|
|
|
if (opcode->operands[i] == AARCH64_OPND_NIL
|
|
|
|
|
|| opnds[i].type == AARCH64_OPND_NIL)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* Generate the operand string in STR. */
|
2016-03-24 22:42:09 +01:00
|
|
|
|
aarch64_print_operand (str, sizeof (str), pc, opcode, opnds, i, &pcrel_p,
|
2012-08-13 16:52:54 +02:00
|
|
|
|
&info->target);
|
|
|
|
|
|
|
|
|
|
/* Print the delimiter (taking account of omitted operand(s)). */
|
|
|
|
|
if (str[0] != '\0')
|
|
|
|
|
(*info->fprintf_func) (info->stream, "%s",
|
|
|
|
|
num_printed++ == 0 ? "\t" : ", ");
|
|
|
|
|
|
|
|
|
|
/* Print the operand. */
|
|
|
|
|
if (pcrel_p)
|
|
|
|
|
(*info->print_address_func) (info->target, info);
|
|
|
|
|
else
|
|
|
|
|
(*info->fprintf_func) (info->stream, "%s", str);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
[AArch64] Add SVE condition codes
SVE defines new names for existing NZCV conditions, to reflect the
result of instructions like PTEST. This patch adds support for these
names.
The patch also adds comments to the disassembly output to show the
alternative names of a condition code. For example:
cinv x0, x1, cc
becomes:
cinv x0, x1, cc // cc = lo, ul, last
and:
b.cc f0 <...>
becomes:
b.cc f0 <...> // b.lo, b.ul, b.last
Doing this for the SVE names follows the practice recommended by the
SVE specification and is definitely useful when reading SVE code.
If the feeling is that it's too distracting elsewhere, we could add
an option to turn it off.
include/
* opcode/aarch64.h (aarch64_cond): Bump array size to 4.
opcodes/
* aarch64-dis.c (remove_dot_suffix): New function, split out from...
(print_mnemonic_name): ...here.
(print_comment): New function.
(print_aarch64_insn): Call it.
* aarch64-opc.c (aarch64_conds): Add SVE names.
(aarch64_print_operand): Print alternative condition names in
a comment.
gas/
* config/tc-aarch64.c (opcode_lookup): Search for the end of
a condition name, rather than assuming that it will have exactly
2 characters.
(parse_operands): Likewise.
* testsuite/gas/aarch64/alias.d: Add new condition-code comments
to the expected output.
* testsuite/gas/aarch64/beq_1.d: Likewise.
* testsuite/gas/aarch64/float-fp16.d: Likewise.
* testsuite/gas/aarch64/int-insns.d: Likewise.
* testsuite/gas/aarch64/no-aliases.d: Likewise.
* testsuite/gas/aarch64/programmer-friendly.d: Likewise.
* testsuite/gas/aarch64/reloc-insn.d: Likewise.
* testsuite/gas/aarch64/b_c_1.d, testsuite/gas/aarch64/b_c_1.s:
New test.
ld/
* testsuite/ld-aarch64/emit-relocs-280.d: Match branch comments.
* testsuite/ld-aarch64/weak-undefined.d: Likewise.
2016-09-21 18:09:59 +02:00
|
|
|
|
/* Set NAME to a copy of INST's mnemonic with the "." suffix removed. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
remove_dot_suffix (char *name, const aarch64_inst *inst)
|
|
|
|
|
{
|
|
|
|
|
char *ptr;
|
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
|
|
ptr = strchr (inst->opcode->name, '.');
|
|
|
|
|
assert (ptr && inst->cond);
|
|
|
|
|
len = ptr - inst->opcode->name;
|
|
|
|
|
assert (len < 8);
|
|
|
|
|
strncpy (name, inst->opcode->name, len);
|
|
|
|
|
name[len] = '\0';
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-13 16:52:54 +02:00
|
|
|
|
/* Print the instruction mnemonic name. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
print_mnemonic_name (const aarch64_inst *inst, struct disassemble_info *info)
|
|
|
|
|
{
|
|
|
|
|
if (inst->opcode->flags & F_COND)
|
|
|
|
|
{
|
|
|
|
|
/* For instructions that are truly conditionally executed, e.g. b.cond,
|
|
|
|
|
prepare the full mnemonic name with the corresponding condition
|
|
|
|
|
suffix. */
|
[AArch64] Add SVE condition codes
SVE defines new names for existing NZCV conditions, to reflect the
result of instructions like PTEST. This patch adds support for these
names.
The patch also adds comments to the disassembly output to show the
alternative names of a condition code. For example:
cinv x0, x1, cc
becomes:
cinv x0, x1, cc // cc = lo, ul, last
and:
b.cc f0 <...>
becomes:
b.cc f0 <...> // b.lo, b.ul, b.last
Doing this for the SVE names follows the practice recommended by the
SVE specification and is definitely useful when reading SVE code.
If the feeling is that it's too distracting elsewhere, we could add
an option to turn it off.
include/
* opcode/aarch64.h (aarch64_cond): Bump array size to 4.
opcodes/
* aarch64-dis.c (remove_dot_suffix): New function, split out from...
(print_mnemonic_name): ...here.
(print_comment): New function.
(print_aarch64_insn): Call it.
* aarch64-opc.c (aarch64_conds): Add SVE names.
(aarch64_print_operand): Print alternative condition names in
a comment.
gas/
* config/tc-aarch64.c (opcode_lookup): Search for the end of
a condition name, rather than assuming that it will have exactly
2 characters.
(parse_operands): Likewise.
* testsuite/gas/aarch64/alias.d: Add new condition-code comments
to the expected output.
* testsuite/gas/aarch64/beq_1.d: Likewise.
* testsuite/gas/aarch64/float-fp16.d: Likewise.
* testsuite/gas/aarch64/int-insns.d: Likewise.
* testsuite/gas/aarch64/no-aliases.d: Likewise.
* testsuite/gas/aarch64/programmer-friendly.d: Likewise.
* testsuite/gas/aarch64/reloc-insn.d: Likewise.
* testsuite/gas/aarch64/b_c_1.d, testsuite/gas/aarch64/b_c_1.s:
New test.
ld/
* testsuite/ld-aarch64/emit-relocs-280.d: Match branch comments.
* testsuite/ld-aarch64/weak-undefined.d: Likewise.
2016-09-21 18:09:59 +02:00
|
|
|
|
char name[8];
|
|
|
|
|
|
|
|
|
|
remove_dot_suffix (name, inst);
|
2012-08-13 16:52:54 +02:00
|
|
|
|
(*info->fprintf_func) (info->stream, "%s.%s", name, inst->cond->names[0]);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
(*info->fprintf_func) (info->stream, "%s", inst->opcode->name);
|
|
|
|
|
}
|
|
|
|
|
|
[AArch64] Add SVE condition codes
SVE defines new names for existing NZCV conditions, to reflect the
result of instructions like PTEST. This patch adds support for these
names.
The patch also adds comments to the disassembly output to show the
alternative names of a condition code. For example:
cinv x0, x1, cc
becomes:
cinv x0, x1, cc // cc = lo, ul, last
and:
b.cc f0 <...>
becomes:
b.cc f0 <...> // b.lo, b.ul, b.last
Doing this for the SVE names follows the practice recommended by the
SVE specification and is definitely useful when reading SVE code.
If the feeling is that it's too distracting elsewhere, we could add
an option to turn it off.
include/
* opcode/aarch64.h (aarch64_cond): Bump array size to 4.
opcodes/
* aarch64-dis.c (remove_dot_suffix): New function, split out from...
(print_mnemonic_name): ...here.
(print_comment): New function.
(print_aarch64_insn): Call it.
* aarch64-opc.c (aarch64_conds): Add SVE names.
(aarch64_print_operand): Print alternative condition names in
a comment.
gas/
* config/tc-aarch64.c (opcode_lookup): Search for the end of
a condition name, rather than assuming that it will have exactly
2 characters.
(parse_operands): Likewise.
* testsuite/gas/aarch64/alias.d: Add new condition-code comments
to the expected output.
* testsuite/gas/aarch64/beq_1.d: Likewise.
* testsuite/gas/aarch64/float-fp16.d: Likewise.
* testsuite/gas/aarch64/int-insns.d: Likewise.
* testsuite/gas/aarch64/no-aliases.d: Likewise.
* testsuite/gas/aarch64/programmer-friendly.d: Likewise.
* testsuite/gas/aarch64/reloc-insn.d: Likewise.
* testsuite/gas/aarch64/b_c_1.d, testsuite/gas/aarch64/b_c_1.s:
New test.
ld/
* testsuite/ld-aarch64/emit-relocs-280.d: Match branch comments.
* testsuite/ld-aarch64/weak-undefined.d: Likewise.
2016-09-21 18:09:59 +02:00
|
|
|
|
/* Decide whether we need to print a comment after the operands of
|
|
|
|
|
instruction INST. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
print_comment (const aarch64_inst *inst, struct disassemble_info *info)
|
|
|
|
|
{
|
|
|
|
|
if (inst->opcode->flags & F_COND)
|
|
|
|
|
{
|
|
|
|
|
char name[8];
|
|
|
|
|
unsigned int i, num_conds;
|
|
|
|
|
|
|
|
|
|
remove_dot_suffix (name, inst);
|
|
|
|
|
num_conds = ARRAY_SIZE (inst->cond->names);
|
|
|
|
|
for (i = 1; i < num_conds && inst->cond->names[i]; ++i)
|
|
|
|
|
(*info->fprintf_func) (info->stream, "%s %s.%s",
|
|
|
|
|
i == 1 ? " //" : ",",
|
|
|
|
|
name, inst->cond->names[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-13 16:52:54 +02:00
|
|
|
|
/* Print the instruction according to *INST. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
print_aarch64_insn (bfd_vma pc, const aarch64_inst *inst,
|
|
|
|
|
struct disassemble_info *info)
|
|
|
|
|
{
|
|
|
|
|
print_mnemonic_name (inst, info);
|
|
|
|
|
print_operands (pc, inst->opcode, inst->operands, info);
|
[AArch64] Add SVE condition codes
SVE defines new names for existing NZCV conditions, to reflect the
result of instructions like PTEST. This patch adds support for these
names.
The patch also adds comments to the disassembly output to show the
alternative names of a condition code. For example:
cinv x0, x1, cc
becomes:
cinv x0, x1, cc // cc = lo, ul, last
and:
b.cc f0 <...>
becomes:
b.cc f0 <...> // b.lo, b.ul, b.last
Doing this for the SVE names follows the practice recommended by the
SVE specification and is definitely useful when reading SVE code.
If the feeling is that it's too distracting elsewhere, we could add
an option to turn it off.
include/
* opcode/aarch64.h (aarch64_cond): Bump array size to 4.
opcodes/
* aarch64-dis.c (remove_dot_suffix): New function, split out from...
(print_mnemonic_name): ...here.
(print_comment): New function.
(print_aarch64_insn): Call it.
* aarch64-opc.c (aarch64_conds): Add SVE names.
(aarch64_print_operand): Print alternative condition names in
a comment.
gas/
* config/tc-aarch64.c (opcode_lookup): Search for the end of
a condition name, rather than assuming that it will have exactly
2 characters.
(parse_operands): Likewise.
* testsuite/gas/aarch64/alias.d: Add new condition-code comments
to the expected output.
* testsuite/gas/aarch64/beq_1.d: Likewise.
* testsuite/gas/aarch64/float-fp16.d: Likewise.
* testsuite/gas/aarch64/int-insns.d: Likewise.
* testsuite/gas/aarch64/no-aliases.d: Likewise.
* testsuite/gas/aarch64/programmer-friendly.d: Likewise.
* testsuite/gas/aarch64/reloc-insn.d: Likewise.
* testsuite/gas/aarch64/b_c_1.d, testsuite/gas/aarch64/b_c_1.s:
New test.
ld/
* testsuite/ld-aarch64/emit-relocs-280.d: Match branch comments.
* testsuite/ld-aarch64/weak-undefined.d: Likewise.
2016-09-21 18:09:59 +02:00
|
|
|
|
print_comment (inst, info);
|
2012-08-13 16:52:54 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Entry-point of the instruction disassembler and printer. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
print_insn_aarch64_word (bfd_vma pc,
|
|
|
|
|
uint32_t word,
|
|
|
|
|
struct disassemble_info *info)
|
|
|
|
|
{
|
|
|
|
|
static const char *err_msg[6] =
|
|
|
|
|
{
|
|
|
|
|
[ERR_OK] = "_",
|
|
|
|
|
[-ERR_UND] = "undefined",
|
|
|
|
|
[-ERR_UNP] = "unpredictable",
|
|
|
|
|
[-ERR_NYI] = "NYI"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
int ret;
|
|
|
|
|
aarch64_inst inst;
|
|
|
|
|
|
|
|
|
|
info->insn_info_valid = 1;
|
|
|
|
|
info->branch_delay_insns = 0;
|
|
|
|
|
info->data_size = 0;
|
|
|
|
|
info->target = 0;
|
|
|
|
|
info->target2 = 0;
|
|
|
|
|
|
|
|
|
|
if (info->flags & INSN_HAS_RELOC)
|
|
|
|
|
/* If the instruction has a reloc associated with it, then
|
|
|
|
|
the offset field in the instruction will actually be the
|
|
|
|
|
addend for the reloc. (If we are using REL type relocs).
|
|
|
|
|
In such cases, we can ignore the pc when computing
|
|
|
|
|
addresses, since the addend is not currently pc-relative. */
|
|
|
|
|
pc = 0;
|
|
|
|
|
|
2015-10-05 12:15:58 +02:00
|
|
|
|
ret = aarch64_decode_insn (word, &inst, no_aliases);
|
2012-08-13 16:52:54 +02:00
|
|
|
|
|
|
|
|
|
if (((word >> 21) & 0x3ff) == 1)
|
|
|
|
|
{
|
|
|
|
|
/* RESERVED for ALES. */
|
|
|
|
|
assert (ret != ERR_OK);
|
|
|
|
|
ret = ERR_NYI;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (ret)
|
|
|
|
|
{
|
|
|
|
|
case ERR_UND:
|
|
|
|
|
case ERR_UNP:
|
|
|
|
|
case ERR_NYI:
|
|
|
|
|
/* Handle undefined instructions. */
|
|
|
|
|
info->insn_type = dis_noninsn;
|
|
|
|
|
(*info->fprintf_func) (info->stream,".inst\t0x%08x ; %s",
|
|
|
|
|
word, err_msg[-ret]);
|
|
|
|
|
break;
|
|
|
|
|
case ERR_OK:
|
|
|
|
|
user_friendly_fixup (&inst);
|
|
|
|
|
print_aarch64_insn (pc, &inst, info);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
abort ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Disallow mapping symbols ($x, $d etc) from
|
|
|
|
|
being displayed in symbol relative addresses. */
|
|
|
|
|
|
|
|
|
|
bfd_boolean
|
|
|
|
|
aarch64_symbol_is_valid (asymbol * sym,
|
|
|
|
|
struct disassemble_info * info ATTRIBUTE_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
const char * name;
|
|
|
|
|
|
|
|
|
|
if (sym == NULL)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
name = bfd_asymbol_name (sym);
|
|
|
|
|
|
|
|
|
|
return name
|
|
|
|
|
&& (name[0] != '$'
|
|
|
|
|
|| (name[1] != 'x' && name[1] != 'd')
|
|
|
|
|
|| (name[2] != '\0' && name[2] != '.'));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Print data bytes on INFO->STREAM. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
print_insn_data (bfd_vma pc ATTRIBUTE_UNUSED,
|
|
|
|
|
uint32_t word,
|
|
|
|
|
struct disassemble_info *info)
|
|
|
|
|
{
|
|
|
|
|
switch (info->bytes_per_chunk)
|
|
|
|
|
{
|
|
|
|
|
case 1:
|
|
|
|
|
info->fprintf_func (info->stream, ".byte\t0x%02x", word);
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
info->fprintf_func (info->stream, ".short\t0x%04x", word);
|
|
|
|
|
break;
|
|
|
|
|
case 4:
|
|
|
|
|
info->fprintf_func (info->stream, ".word\t0x%08x", word);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
abort ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Try to infer the code or data type from a symbol.
|
|
|
|
|
Returns nonzero if *MAP_TYPE was set. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
get_sym_code_type (struct disassemble_info *info, int n,
|
|
|
|
|
enum map_type *map_type)
|
|
|
|
|
{
|
|
|
|
|
elf_symbol_type *es;
|
|
|
|
|
unsigned int type;
|
|
|
|
|
const char *name;
|
|
|
|
|
|
2017-12-11 16:33:18 +01:00
|
|
|
|
/* If the symbol is in a different section, ignore it. */
|
|
|
|
|
if (info->section != NULL && info->section != info->symtab[n]->section)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2012-08-13 16:52:54 +02:00
|
|
|
|
es = *(elf_symbol_type **)(info->symtab + n);
|
|
|
|
|
type = ELF_ST_TYPE (es->internal_elf_sym.st_info);
|
|
|
|
|
|
|
|
|
|
/* If the symbol has function type then use that. */
|
|
|
|
|
if (type == STT_FUNC)
|
|
|
|
|
{
|
|
|
|
|
*map_type = MAP_INSN;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check for mapping symbols. */
|
|
|
|
|
name = bfd_asymbol_name(info->symtab[n]);
|
|
|
|
|
if (name[0] == '$'
|
|
|
|
|
&& (name[1] == 'x' || name[1] == 'd')
|
|
|
|
|
&& (name[2] == '\0' || name[2] == '.'))
|
|
|
|
|
{
|
|
|
|
|
*map_type = (name[1] == 'x' ? MAP_INSN : MAP_DATA);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Entry-point of the AArch64 disassembler. */
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
print_insn_aarch64 (bfd_vma pc,
|
|
|
|
|
struct disassemble_info *info)
|
|
|
|
|
{
|
|
|
|
|
bfd_byte buffer[INSNLEN];
|
|
|
|
|
int status;
|
|
|
|
|
void (*printer) (bfd_vma, uint32_t, struct disassemble_info *);
|
|
|
|
|
bfd_boolean found = FALSE;
|
|
|
|
|
unsigned int size = 4;
|
|
|
|
|
unsigned long data;
|
|
|
|
|
|
|
|
|
|
if (info->disassembler_options)
|
|
|
|
|
{
|
|
|
|
|
set_default_aarch64_dis_options (info);
|
|
|
|
|
|
|
|
|
|
parse_aarch64_dis_options (info->disassembler_options);
|
|
|
|
|
|
|
|
|
|
/* To avoid repeated parsing of these options, we remove them here. */
|
|
|
|
|
info->disassembler_options = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Aarch64 instructions are always little-endian */
|
|
|
|
|
info->endian_code = BFD_ENDIAN_LITTLE;
|
|
|
|
|
|
|
|
|
|
/* First check the full symtab for a mapping symbol, even if there
|
|
|
|
|
are no usable non-mapping symbols for this address. */
|
|
|
|
|
if (info->symtab_size != 0
|
|
|
|
|
&& bfd_asymbol_flavour (*info->symtab) == bfd_target_elf_flavour)
|
|
|
|
|
{
|
|
|
|
|
enum map_type type = MAP_INSN;
|
|
|
|
|
int last_sym = -1;
|
|
|
|
|
bfd_vma addr;
|
|
|
|
|
int n;
|
|
|
|
|
|
|
|
|
|
if (pc <= last_mapping_addr)
|
|
|
|
|
last_mapping_sym = -1;
|
|
|
|
|
|
|
|
|
|
/* Start scanning at the start of the function, or wherever
|
|
|
|
|
we finished last time. */
|
|
|
|
|
n = info->symtab_pos + 1;
|
|
|
|
|
if (n < last_mapping_sym)
|
|
|
|
|
n = last_mapping_sym;
|
|
|
|
|
|
|
|
|
|
/* Scan up to the location being disassembled. */
|
|
|
|
|
for (; n < info->symtab_size; n++)
|
|
|
|
|
{
|
|
|
|
|
addr = bfd_asymbol_value (info->symtab[n]);
|
|
|
|
|
if (addr > pc)
|
|
|
|
|
break;
|
2017-12-11 16:33:18 +01:00
|
|
|
|
if (get_sym_code_type (info, n, &type))
|
2012-08-13 16:52:54 +02:00
|
|
|
|
{
|
|
|
|
|
last_sym = n;
|
|
|
|
|
found = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
|
{
|
|
|
|
|
n = info->symtab_pos;
|
|
|
|
|
if (n < last_mapping_sym)
|
|
|
|
|
n = last_mapping_sym;
|
|
|
|
|
|
|
|
|
|
/* No mapping symbol found at this address. Look backwards
|
|
|
|
|
for a preceeding one. */
|
|
|
|
|
for (; n >= 0; n--)
|
|
|
|
|
{
|
|
|
|
|
if (get_sym_code_type (info, n, &type))
|
|
|
|
|
{
|
|
|
|
|
last_sym = n;
|
|
|
|
|
found = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
last_mapping_sym = last_sym;
|
|
|
|
|
last_type = type;
|
|
|
|
|
|
|
|
|
|
/* Look a little bit ahead to see if we should print out
|
|
|
|
|
less than four bytes of data. If there's a symbol,
|
|
|
|
|
mapping or otherwise, after two bytes then don't
|
|
|
|
|
print more. */
|
|
|
|
|
if (last_type == MAP_DATA)
|
|
|
|
|
{
|
|
|
|
|
size = 4 - (pc & 3);
|
|
|
|
|
for (n = last_sym + 1; n < info->symtab_size; n++)
|
|
|
|
|
{
|
|
|
|
|
addr = bfd_asymbol_value (info->symtab[n]);
|
|
|
|
|
if (addr > pc)
|
|
|
|
|
{
|
|
|
|
|
if (addr - pc < size)
|
|
|
|
|
size = addr - pc;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* If the next symbol is after three bytes, we need to
|
|
|
|
|
print only part of the data, so that we can use either
|
|
|
|
|
.byte or .short. */
|
|
|
|
|
if (size == 3)
|
|
|
|
|
size = (pc & 1) ? 1 : 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (last_type == MAP_DATA)
|
|
|
|
|
{
|
|
|
|
|
/* size was set above. */
|
|
|
|
|
info->bytes_per_chunk = size;
|
|
|
|
|
info->display_endian = info->endian;
|
|
|
|
|
printer = print_insn_data;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
info->bytes_per_chunk = size = INSNLEN;
|
|
|
|
|
info->display_endian = info->endian_code;
|
|
|
|
|
printer = print_insn_aarch64_word;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
status = (*info->read_memory_func) (pc, buffer, size, info);
|
|
|
|
|
if (status != 0)
|
|
|
|
|
{
|
|
|
|
|
(*info->memory_error_func) (status, pc, info);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
data = bfd_get_bits (buffer, size * 8,
|
|
|
|
|
info->display_endian == BFD_ENDIAN_BIG);
|
|
|
|
|
|
|
|
|
|
(*printer) (pc, data, info);
|
|
|
|
|
|
|
|
|
|
return size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
print_aarch64_disassembler_options (FILE *stream)
|
|
|
|
|
{
|
|
|
|
|
fprintf (stream, _("\n\
|
|
|
|
|
The following AARCH64 specific disassembler options are supported for use\n\
|
|
|
|
|
with the -M switch (multiple options should be separated by commas):\n"));
|
|
|
|
|
|
|
|
|
|
fprintf (stream, _("\n\
|
|
|
|
|
no-aliases Don't print instruction aliases.\n"));
|
|
|
|
|
|
|
|
|
|
fprintf (stream, _("\n\
|
|
|
|
|
aliases Do print instruction aliases.\n"));
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG_AARCH64
|
|
|
|
|
fprintf (stream, _("\n\
|
|
|
|
|
debug_dump Temp switch for debug trace.\n"));
|
|
|
|
|
#endif /* DEBUG_AARCH64 */
|
|
|
|
|
|
|
|
|
|
fprintf (stream, _("\n"));
|
|
|
|
|
}
|