/* aarch64-opc.c -- AArch64 opcode support.
- Copyright (C) 2009-2018 Free Software Foundation, Inc.
+ Copyright (C) 2009-2019 Free Software Foundation, Inc.
Contributed by ARM Ltd.
This file is part of the GNU opcodes library.
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
-#include <stdint.h>
+#include "bfd_stdint.h"
#include <stdarg.h>
#include <inttypes.h>
{ 15, 6 }, /* imm6_2: in rmif instructions. */
{ 11, 4 }, /* imm4: in advsimd ext and advsimd ins instructions. */
{ 0, 4 }, /* imm4_2: in rmif instructions. */
+ { 10, 4 }, /* imm4_3: in adddg/subg instructions. */
{ 16, 5 }, /* imm5: in conditional compare (immediate) instructions. */
{ 15, 7 }, /* imm7: in load/store pair pre/post index instructions. */
{ 13, 8 }, /* imm8: in floating-point scalar move immediate inst. */
{ 13, 2 }, /* rotate2: Indexed element FCMLA immediate rotate. */
{ 12, 1 }, /* rotate3: FCADD immediate rotate. */
{ 12, 2 }, /* SM3: Indexed element SM3 2 bits index immediate. */
+ { 22, 1 }, /* sz: 1-bit element size select. */
};
enum aarch64_operand_class
{4, 1, 0x2, "s", OQK_OPD_VARIANT},
{8, 1, 0x3, "d", OQK_OPD_VARIANT},
{16, 1, 0x4, "q", OQK_OPD_VARIANT},
- {1, 4, 0x0, "4b", OQK_OPD_VARIANT},
+ {4, 1, 0x0, "4b", OQK_OPD_VARIANT},
{1, 4, 0x0, "4b", OQK_OPD_VARIANT},
{1, 8, 0x0, "8b", OQK_OPD_VARIANT},
{0, 0, 0, "z", OQK_OPD_VARIANT},
{0, 0, 0, "m", OQK_OPD_VARIANT},
+ /* Qualifier for scaled immediate for Tag granule (stg,st2g,etc). */
+ {16, 0, 0, "tag", OQK_OPD_VARIANT},
+
/* Qualifiers constraining the value range.
First 3 fields:
Lower bound, higher bound, unused. */
}
break;
+ case AARCH64_OPND_ADDR_SIMM11:
+ /* Signed 11 bits immediate offset (multiple of 16). */
+ if (!value_in_range_p (opnd->addr.offset.imm, -1024, 1008))
+ {
+ set_offset_out_of_range_error (mismatch_detail, idx, -1024, 1008);
+ return 0;
+ }
+
+ if (!value_aligned_p (opnd->addr.offset.imm, 16))
+ {
+ set_unaligned_error (mismatch_detail, idx, 16);
+ return 0;
+ }
+ break;
+
+ case AARCH64_OPND_ADDR_SIMM13:
+ /* Signed 13 bits immediate offset (multiple of 16). */
+ if (!value_in_range_p (opnd->addr.offset.imm, -4096, 4080))
+ {
+ set_offset_out_of_range_error (mismatch_detail, idx, -4096, 4080);
+ return 0;
+ }
+
+ if (!value_aligned_p (opnd->addr.offset.imm, 16))
+ {
+ set_unaligned_error (mismatch_detail, idx, 16);
+ return 0;
+ }
+ break;
+
case AARCH64_OPND_SIMD_ADDR_POST:
/* AdvSIMD load/store multiple structures, post-index. */
assert (idx == 1);
case AARCH64_OPND_CCMP_IMM:
case AARCH64_OPND_EXCEPTION:
case AARCH64_OPND_UIMM4:
+ case AARCH64_OPND_UIMM4_ADDG:
case AARCH64_OPND_UIMM7:
case AARCH64_OPND_UIMM3_OP1:
case AARCH64_OPND_UIMM3_OP2:
}
break;
+ case AARCH64_OPND_UIMM10:
+ /* Scaled unsigned 10 bits immediate offset. */
+ if (!value_in_range_p (opnd->imm.value, 0, 1008))
+ {
+ set_imm_out_of_range_error (mismatch_detail, idx, 0, 1008);
+ return 0;
+ }
+
+ if (!value_aligned_p (opnd->imm.value, 16))
+ {
+ set_unaligned_error (mismatch_detail, idx, 16);
+ return 0;
+ }
+ break;
+
case AARCH64_OPND_SIMM5:
case AARCH64_OPND_SVE_SIMM5:
case AARCH64_OPND_SVE_SIMM5B:
assert (idx == 0 && opnds[1].type == AARCH64_OPND_UIMM4);
/* MSR UAO, #uimm4
MSR PAN, #uimm4
+ MSR SSBS,#uimm4
The immediate must be #0 or #1. */
if ((opnd->pstatefield == 0x03 /* UAO. */
|| opnd->pstatefield == 0x04 /* PAN. */
+ || opnd->pstatefield == 0x19 /* SSBS. */
|| opnd->pstatefield == 0x1a) /* DIT. */
&& opnds[1].imm.value > 1)
{
else
num = 16;
num = num / aarch64_get_qualifier_esize (qualifier) - 1;
+ assert (aarch64_get_qualifier_nelem (qualifier) == 1);
/* Index out-of-range. */
if (!value_in_range_p (opnd->reglane.index, 0, num))
case AARCH64_OPND_NZCV:
case AARCH64_OPND_EXCEPTION:
case AARCH64_OPND_UIMM4:
+ case AARCH64_OPND_UIMM4_ADDG:
case AARCH64_OPND_UIMM7:
+ case AARCH64_OPND_UIMM10:
if (optional_operand_p (opcode, idx) == TRUE
&& (opnd->imm.value ==
(int64_t) get_optional_operand_default_value (opcode)))
case AARCH64_OPND_ADDR_SIMM9:
case AARCH64_OPND_ADDR_SIMM9_2:
case AARCH64_OPND_ADDR_SIMM10:
+ case AARCH64_OPND_ADDR_SIMM11:
+ case AARCH64_OPND_ADDR_SIMM13:
case AARCH64_OPND_ADDR_OFFSET:
case AARCH64_OPND_SVE_ADDR_RI_S4x16:
case AARCH64_OPND_SVE_ADDR_RI_S4xVL:
{ "pan", CPEN_(0,C2,3), F_ARCHEXT },
{ "uao", CPEN_ (0, C2, 4), F_ARCHEXT },
{ "nzcv", CPEN_(3,C2,0), 0 },
+ { "ssbs", CPEN_(3,C2,6), F_ARCHEXT },
{ "fpcr", CPEN_(3,C4,0), 0 },
{ "fpsr", CPEN_(3,C4,1), 0 },
{ "dspsr_el0", CPEN_(3,C5,0), 0 },
{ "contextidr_el12", CPENC (3, 5, C13, C0, 1), F_ARCHEXT },
{ "rndr", CPENC(3,3,C2,C4,0), F_ARCHEXT | F_REG_READ }, /* RO */
{ "rndrrs", CPENC(3,3,C2,C4,1), F_ARCHEXT | F_REG_READ }, /* RO */
+ { "tco", CPENC(3,3,C4,C2,7), F_ARCHEXT },
+ { "tfsre0_el1", CPENC(3,0,C6,C6,1), F_ARCHEXT },
+ { "tfsr_el1", CPENC(3,0,C6,C5,0), F_ARCHEXT },
+ { "tfsr_el2", CPENC(3,4,C6,C5,0), F_ARCHEXT },
+ { "tfsr_el3", CPENC(3,6,C6,C6,0), F_ARCHEXT },
+ { "tfsr_el12", CPENC(3,5,C6,C6,0), F_ARCHEXT },
+ { "rgsr_el1", CPENC(3,0,C1,C0,5), F_ARCHEXT },
+ { "gcr_el1", CPENC(3,0,C1,C0,6), F_ARCHEXT },
{ "tpidr_el0", CPENC(3,3,C13,C0,2), 0 },
{ "tpidrro_el0", CPENC(3,3,C13,C0,3), 0 }, /* RW */
{ "tpidr_el1", CPENC(3,0,C13,C0,4), 0 },
&& !AARCH64_CPU_HAS_FEATURE (features, AARCH64_FEATURE_ID_PFR2))
return FALSE;
+ /* SSBS. Values are from aarch64_sys_regs. */
+ if (reg->value == CPEN_(3,C2,6)
+ && !AARCH64_CPU_HAS_FEATURE (features, AARCH64_FEATURE_SSBS))
+ return FALSE;
+
/* Virtualization host extensions: system registers. */
if ((reg->value == CPENC (3, 4, C2, C0, 1)
|| reg->value == CPENC (3, 4, C13, C0, 1)
&& AARCH64_CPU_HAS_FEATURE (features, AARCH64_FEATURE_V8_5)))
return FALSE;
+ /* System Registers in ARMv8.5-A with AARCH64_FEATURE_MEMTAG. */
+ if ((reg->value == CPENC (3, 3, C4, C2, 7)
+ || reg->value == CPENC (3, 0, C6, C6, 1)
+ || reg->value == CPENC (3, 0, C6, C5, 0)
+ || reg->value == CPENC (3, 4, C6, C5, 0)
+ || reg->value == CPENC (3, 6, C6, C6, 0)
+ || reg->value == CPENC (3, 5, C6, C6, 0)
+ || reg->value == CPENC (3, 0, C1, C0, 5)
+ || reg->value == CPENC (3, 0, C1, C0, 6))
+ && !(AARCH64_CPU_HAS_FEATURE (features, AARCH64_FEATURE_MEMTAG)))
+ return FALSE;
+
return TRUE;
}
{ "daifclr", 0x1f, 0 },
{ "pan", 0x04, F_ARCHEXT },
{ "uao", 0x03, F_ARCHEXT },
+ { "ssbs", 0x19, F_ARCHEXT },
{ "dit", 0x1a, F_ARCHEXT },
+ { "tco", 0x1c, F_ARCHEXT },
{ 0, CPENC(0,0,0,0,0), 0 },
};
&& !AARCH64_CPU_HAS_FEATURE (features, AARCH64_FEATURE_V8_2))
return FALSE;
+ /* SSBS. Values are from aarch64_pstatefields. */
+ if (reg->value == 0x19
+ && !AARCH64_CPU_HAS_FEATURE (features, AARCH64_FEATURE_SSBS))
+ return FALSE;
+
/* DIT. Values are from aarch64_pstatefields. */
if (reg->value == 0x1a
&& !AARCH64_CPU_HAS_FEATURE (features, AARCH64_FEATURE_V8_4))
return FALSE;
+ /* TCO. Values are from aarch64_pstatefields. */
+ if (reg->value == 0x1c
+ && !AARCH64_CPU_HAS_FEATURE (features, AARCH64_FEATURE_MEMTAG))
+ return FALSE;
+
return TRUE;
}
const aarch64_sys_ins_reg aarch64_sys_regs_dc[] =
{
{ "zva", CPENS (3, C7, C4, 1), F_HASXT },
+ { "gva", CPENS (3, C7, C4, 3), F_HASXT | F_ARCHEXT },
+ { "gzva", CPENS (3, C7, C4, 4), F_HASXT | F_ARCHEXT },
{ "ivac", CPENS (0, C7, C6, 1), F_HASXT },
+ { "igvac", CPENS (0, C7, C6, 3), F_HASXT | F_ARCHEXT },
+ { "igsw", CPENS (0, C7, C6, 4), F_HASXT | F_ARCHEXT },
{ "isw", CPENS (0, C7, C6, 2), F_HASXT },
+ { "igdvac", CPENS (0, C7, C6, 5), F_HASXT | F_ARCHEXT },
+ { "igdsw", CPENS (0, C7, C6, 6), F_HASXT | F_ARCHEXT },
{ "cvac", CPENS (3, C7, C10, 1), F_HASXT },
+ { "cgvac", CPENS (3, C7, C10, 3), F_HASXT | F_ARCHEXT },
+ { "cgdvac", CPENS (3, C7, C10, 5), F_HASXT | F_ARCHEXT },
{ "csw", CPENS (0, C7, C10, 2), F_HASXT },
+ { "cgsw", CPENS (0, C7, C10, 4), F_HASXT | F_ARCHEXT },
+ { "cgdsw", CPENS (0, C7, C10, 6), F_HASXT | F_ARCHEXT },
{ "cvau", CPENS (3, C7, C11, 1), F_HASXT },
{ "cvap", CPENS (3, C7, C12, 1), F_HASXT | F_ARCHEXT },
+ { "cgvap", CPENS (3, C7, C12, 3), F_HASXT | F_ARCHEXT },
+ { "cgdvap", CPENS (3, C7, C12, 5), F_HASXT | F_ARCHEXT },
{ "cvadp", CPENS (3, C7, C13, 1), F_HASXT | F_ARCHEXT },
+ { "cgvadp", CPENS (3, C7, C13, 3), F_HASXT | F_ARCHEXT },
+ { "cgdvadp", CPENS (3, C7, C13, 5), F_HASXT | F_ARCHEXT },
{ "civac", CPENS (3, C7, C14, 1), F_HASXT },
+ { "cigvac", CPENS (3, C7, C14, 3), F_HASXT | F_ARCHEXT },
+ { "cigdvac", CPENS (3, C7, C14, 5), F_HASXT | F_ARCHEXT },
{ "cisw", CPENS (0, C7, C14, 2), F_HASXT },
+ { "cigsw", CPENS (0, C7, C14, 4), F_HASXT | F_ARCHEXT },
+ { "cigdsw", CPENS (0, C7, C14, 6), F_HASXT | F_ARCHEXT },
{ 0, CPENS(0,0,0,0), 0 }
};
&& !AARCH64_CPU_HAS_FEATURE (features, AARCH64_FEATURE_CVADP))
return FALSE;
+ /* DC <dc_op> for ARMv8.5-A Memory Tagging Extension. */
+ if ((reg->value == CPENS (0, C7, C6, 3)
+ || reg->value == CPENS (0, C7, C6, 4)
+ || reg->value == CPENS (0, C7, C10, 4)
+ || reg->value == CPENS (0, C7, C14, 4)
+ || reg->value == CPENS (3, C7, C10, 3)
+ || reg->value == CPENS (3, C7, C12, 3)
+ || reg->value == CPENS (3, C7, C13, 3)
+ || reg->value == CPENS (3, C7, C14, 3)
+ || reg->value == CPENS (3, C7, C4, 3)
+ || reg->value == CPENS (0, C7, C6, 5)
+ || reg->value == CPENS (0, C7, C6, 6)
+ || reg->value == CPENS (0, C7, C10, 6)
+ || reg->value == CPENS (0, C7, C14, 6)
+ || reg->value == CPENS (3, C7, C10, 5)
+ || reg->value == CPENS (3, C7, C12, 5)
+ || reg->value == CPENS (3, C7, C13, 5)
+ || reg->value == CPENS (3, C7, C14, 5)
+ || reg->value == CPENS (3, C7, C4, 4))
+ && !AARCH64_CPU_HAS_FEATURE (features, AARCH64_FEATURE_MEMTAG))
+ return FALSE;
+
/* AT S1E1RP, AT S1E1WP. Values are from aarch64_sys_regs_at. */
if ((reg->value == CPENS (0, C7, C9, 0)
|| reg->value == CPENS (0, C7, C9, 1))
return ERR_OK;
}
+/* Verifier for vector by element 3 operands functions where the
+ conditions `if sz:L == 11 then UNDEFINED` holds. */
+
+static enum err_type
+verify_elem_sd (const struct aarch64_inst *inst, const aarch64_insn insn,
+ bfd_vma pc ATTRIBUTE_UNUSED, bfd_boolean encoding,
+ aarch64_operand_error *mismatch_detail ATTRIBUTE_UNUSED,
+ aarch64_instr_sequence *insn_sequence ATTRIBUTE_UNUSED)
+{
+ const aarch64_insn undef_pattern = 0x3;
+ aarch64_insn value;
+
+ assert (inst->opcode);
+ assert (inst->opcode->operands[2] == AARCH64_OPND_Em);
+ value = encoding ? inst->value : insn;
+ assert (value);
+
+ if (undef_pattern == extract_fields (value, 0, 2, FLD_sz, FLD_L))
+ return ERR_UND;
+
+ return ERR_OK;
+}
+
/* Initialize an instruction sequence insn_sequence with the instruction INST.
If INST is NULL the given insn_sequence is cleared and the sequence is left
uninitialized. */