X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=opcodes%2Faarch64-opc.c;h=326b94e71e956980554b22bdaab1247832f2b3c6;hb=2442d8466e221ba6cf4ec4bd2a819fdcb1e5ea7e;hp=6eac70acaaf6f4a3aeb2f3d3b57aec45a4d68a4f;hpb=8a7f0c1b5ae35d041886855ac7ca9b9533e8788a;p=deliverable%2Fbinutils-gdb.git diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c index 6eac70acaa..326b94e71e 100644 --- a/opcodes/aarch64-opc.c +++ b/opcodes/aarch64-opc.c @@ -27,6 +27,7 @@ #include #include "opintl.h" +#include "libiberty.h" #include "aarch64-opc.h" @@ -34,6 +35,70 @@ int debug_dump = FALSE; #endif /* DEBUG_AARCH64 */ +/* The enumeration strings associated with each value of a 5-bit SVE + pattern operand. A null entry indicates a reserved meaning. */ +const char *const aarch64_sve_pattern_array[32] = { + /* 0-7. */ + "pow2", + "vl1", + "vl2", + "vl3", + "vl4", + "vl5", + "vl6", + "vl7", + /* 8-15. */ + "vl8", + "vl16", + "vl32", + "vl64", + "vl128", + "vl256", + 0, + 0, + /* 16-23. */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 24-31. */ + 0, + 0, + 0, + 0, + 0, + "mul4", + "mul3", + "all" +}; + +/* The enumeration strings associated with each value of a 4-bit SVE + prefetch operand. A null entry indicates a reserved meaning. */ +const char *const aarch64_sve_prfop_array[16] = { + /* 0-7. */ + "pldl1keep", + "pldl1strm", + "pldl2keep", + "pldl2strm", + "pldl3keep", + "pldl3strm", + 0, + 0, + /* 8-15. */ + "pstl1keep", + "pstl1strm", + "pstl2keep", + "pstl2strm", + "pstl3keep", + "pstl3strm", + 0, + 0 +}; + /* Helper functions to determine which operand to be used to encode/decode the size:Q fields for AdvSIMD instructions. */ @@ -199,6 +264,25 @@ const aarch64_field fields[] = { 31, 1 }, /* b5: in the test bit and branch instructions. */ { 19, 5 }, /* b40: in the test bit and branch instructions. */ { 10, 6 }, /* scale: in the fixed-point scalar to fp converting inst. */ + { 0, 4 }, /* SVE_Pd: p0-p15, bits [3,0]. */ + { 10, 3 }, /* SVE_Pg3: p0-p7, bits [12,10]. */ + { 5, 4 }, /* SVE_Pg4_5: p0-p15, bits [8,5]. */ + { 10, 4 }, /* SVE_Pg4_10: p0-p15, bits [13,10]. */ + { 16, 4 }, /* SVE_Pg4_16: p0-p15, bits [19,16]. */ + { 16, 4 }, /* SVE_Pm: p0-p15, bits [19,16]. */ + { 5, 4 }, /* SVE_Pn: p0-p15, bits [8,5]. */ + { 0, 4 }, /* SVE_Pt: p0-p15, bits [3,0]. */ + { 5, 5 }, /* SVE_Za_5: SVE vector register, bits [9,5]. */ + { 16, 5 }, /* SVE_Za_16: SVE vector register, bits [20,16]. */ + { 0, 5 }, /* SVE_Zd: SVE vector register. bits [4,0]. */ + { 5, 5 }, /* SVE_Zm_5: SVE vector register, bits [9,5]. */ + { 16, 5 }, /* SVE_Zm_16: SVE vector register, bits [20,16]. */ + { 5, 5 }, /* SVE_Zn: SVE vector register, bits [9,5]. */ + { 0, 5 }, /* SVE_Zt: SVE vector register, bits [4,0]. */ + { 16, 4 }, /* SVE_imm4: 4-bit immediate field. */ + { 5, 5 }, /* SVE_pattern: vector pattern enumeration. */ + { 0, 4 }, /* SVE_prfop: prefetch operation for SVE PRF[BHWD]. */ + { 22, 2 }, /* SVE_tszh: triangular size select high, bits [23,22]. */ }; enum aarch64_operand_class @@ -276,6 +360,7 @@ const struct aarch64_name_value_pair aarch64_operand_modifiers [] = {"sxth", 0x5}, {"sxtw", 0x6}, {"sxtx", 0x7}, + {"mul", 0x0}, {NULL, 0}, }; @@ -587,6 +672,9 @@ struct operand_qualifier_data aarch64_opnd_qualifiers[] = {8, 2, 0x7, "2d", OQK_OPD_VARIANT}, {16, 1, 0x8, "1q", OQK_OPD_VARIANT}, + {0, 0, 0, "z", OQK_OPD_VARIANT}, + {0, 0, 0, "m", OQK_OPD_VARIANT}, + /* Qualifiers constraining the value range. First 3 fields: Lower bound, higher bound, unused. */ @@ -1217,6 +1305,18 @@ set_sft_amount_out_of_range_error (aarch64_operand_error *mismatch_detail, _("shift amount")); } +/* Report that the MUL modifier in operand IDX should be in the range + [LOWER_BOUND, UPPER_BOUND]. */ +static inline void +set_multiplier_out_of_range_error (aarch64_operand_error *mismatch_detail, + int idx, int lower_bound, int upper_bound) +{ + if (mismatch_detail == NULL) + return; + set_out_of_range_error (mismatch_detail, idx, lower_bound, upper_bound, + _("multiplier")); +} + static inline void set_unaligned_error (aarch64_operand_error *mismatch_detail, int idx, int alignment) @@ -1332,6 +1432,43 @@ operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx, } break; + case AARCH64_OPND_CLASS_SVE_REG: + switch (type) + { + case AARCH64_OPND_SVE_Zn_INDEX: + size = aarch64_get_qualifier_esize (opnd->qualifier); + if (!value_in_range_p (opnd->reglane.index, 0, 64 / size - 1)) + { + set_elem_idx_out_of_range_error (mismatch_detail, idx, + 0, 64 / size - 1); + return 0; + } + break; + + case AARCH64_OPND_SVE_ZnxN: + case AARCH64_OPND_SVE_ZtxN: + if (opnd->reglist.num_regs != get_opcode_dependent_value (opcode)) + { + set_other_error (mismatch_detail, idx, + _("invalid register list")); + return 0; + } + break; + + default: + break; + } + break; + + case AARCH64_OPND_CLASS_PRED_REG: + if (opnd->reg.regno >= 8 + && get_operand_fields_width (get_operand_from_code (type)) == 3) + { + set_other_error (mismatch_detail, idx, _("p0-p7 expected")); + return 0; + } + break; + case AARCH64_OPND_CLASS_COND: if (type == AARCH64_OPND_COND1 && (opnds[idx].cond->value & 0xe) == 0xe) @@ -1878,6 +2015,15 @@ operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx, } break; + case AARCH64_OPND_SVE_PATTERN_SCALED: + assert (opnd->shifter.kind == AARCH64_MOD_MUL); + if (!value_in_range_p (opnd->shifter.amount, 1, 16)) + { + set_multiplier_out_of_range_error (mismatch_detail, idx, 1, 16); + return 0; + } + break; + default: break; } @@ -2058,6 +2204,23 @@ aarch64_match_operands_constraint (aarch64_inst *inst, DEBUG_TRACE ("enter"); + /* Check for cases where a source register needs to be the same as the + destination register. Do this before matching qualifiers since if + an instruction has both invalid tying and invalid qualifiers, + the error about qualifiers would suggest several alternative + instructions that also have invalid tying. */ + i = inst->opcode->tied_operand; + if (i > 0 && (inst->operands[0].reg.regno != inst->operands[i].reg.regno)) + { + if (mismatch_detail) + { + mismatch_detail->kind = AARCH64_OPDE_UNTIED_OPERAND; + mismatch_detail->index = i; + mismatch_detail->error = NULL; + } + return 0; + } + /* Match operands' qualifier. *INST has already had qualifier establish for some, if not all, of its operands; we need to find out whether these established @@ -2149,32 +2312,25 @@ aarch64_operand_index (const enum aarch64_opnd *operands, enum aarch64_opnd oper return -1; } +/* R0...R30, followed by FOR31. */ +#define BANK(R, FOR31) \ + { R (0), R (1), R (2), R (3), R (4), R (5), R (6), R (7), \ + R (8), R (9), R (10), R (11), R (12), R (13), R (14), R (15), \ + R (16), R (17), R (18), R (19), R (20), R (21), R (22), R (23), \ + R (24), R (25), R (26), R (27), R (28), R (29), R (30), FOR31 } /* [0][0] 32-bit integer regs with sp Wn [0][1] 64-bit integer regs with sp Xn sf=1 [1][0] 32-bit integer regs with #0 Wn [1][1] 64-bit integer regs with #0 Xn sf=1 */ static const char *int_reg[2][2][32] = { -#define R32 "w" -#define R64 "x" - { { R32 "0", R32 "1", R32 "2", R32 "3", R32 "4", R32 "5", R32 "6", R32 "7", - R32 "8", R32 "9", R32 "10", R32 "11", R32 "12", R32 "13", R32 "14", R32 "15", - R32 "16", R32 "17", R32 "18", R32 "19", R32 "20", R32 "21", R32 "22", R32 "23", - R32 "24", R32 "25", R32 "26", R32 "27", R32 "28", R32 "29", R32 "30", "wsp" }, - { R64 "0", R64 "1", R64 "2", R64 "3", R64 "4", R64 "5", R64 "6", R64 "7", - R64 "8", R64 "9", R64 "10", R64 "11", R64 "12", R64 "13", R64 "14", R64 "15", - R64 "16", R64 "17", R64 "18", R64 "19", R64 "20", R64 "21", R64 "22", R64 "23", - R64 "24", R64 "25", R64 "26", R64 "27", R64 "28", R64 "29", R64 "30", "sp" } }, - { { R32 "0", R32 "1", R32 "2", R32 "3", R32 "4", R32 "5", R32 "6", R32 "7", - R32 "8", R32 "9", R32 "10", R32 "11", R32 "12", R32 "13", R32 "14", R32 "15", - R32 "16", R32 "17", R32 "18", R32 "19", R32 "20", R32 "21", R32 "22", R32 "23", - R32 "24", R32 "25", R32 "26", R32 "27", R32 "28", R32 "29", R32 "30", R32 "zr" }, - { R64 "0", R64 "1", R64 "2", R64 "3", R64 "4", R64 "5", R64 "6", R64 "7", - R64 "8", R64 "9", R64 "10", R64 "11", R64 "12", R64 "13", R64 "14", R64 "15", - R64 "16", R64 "17", R64 "18", R64 "19", R64 "20", R64 "21", R64 "22", R64 "23", - R64 "24", R64 "25", R64 "26", R64 "27", R64 "28", R64 "29", R64 "30", R64 "zr" } } +#define R32(X) "w" #X +#define R64(X) "x" #X + { BANK (R32, "wsp"), BANK (R64, "sp") }, + { BANK (R32, "wzr"), BANK (R64, "xzr") } #undef R64 #undef R32 }; +#undef BANK /* Return the integer register name. if SP_REG_P is not 0, R31 is an SP reg, other R31 is the zero reg. */ @@ -2196,6 +2352,27 @@ get_64bit_int_reg_name (int regno, int sp_reg_p) return int_reg[has_zr][1][regno]; } +/* Get the name of the integer offset register in OPND, using the shift type + to decide whether it's a word or doubleword. */ + +static inline const char * +get_offset_int_reg_name (const aarch64_opnd_info *opnd) +{ + switch (opnd->shifter.kind) + { + case AARCH64_MOD_UXTW: + case AARCH64_MOD_SXTW: + return get_int_reg_name (opnd->addr.offset.regno, AARCH64_OPND_QLF_W, 0); + + case AARCH64_MOD_LSL: + case AARCH64_MOD_SXTX: + return get_int_reg_name (opnd->addr.offset.regno, AARCH64_OPND_QLF_X, 0); + + default: + abort (); + } +} + /* Types for expanding an encoded 8-bit value to a floating-point value. */ typedef union @@ -2318,28 +2495,43 @@ print_register_list (char *buf, size_t size, const aarch64_opnd_info *opnd, } } +/* Print the register+immediate address in OPND to BUF, which has SIZE + characters. BASE is the name of the base register. */ + +static void +print_immediate_offset_address (char *buf, size_t size, + const aarch64_opnd_info *opnd, + const char *base) +{ + if (opnd->addr.writeback) + { + if (opnd->addr.preind) + snprintf (buf, size, "[%s,#%d]!", base, opnd->addr.offset.imm); + else + snprintf (buf, size, "[%s],#%d", base, opnd->addr.offset.imm); + } + else + { + if (opnd->addr.offset.imm) + snprintf (buf, size, "[%s,#%d]", base, opnd->addr.offset.imm); + else + snprintf (buf, size, "[%s]", base); + } +} + /* Produce the string representation of the register offset address operand - *OPND in the buffer pointed by BUF of size SIZE. */ + *OPND in the buffer pointed by BUF of size SIZE. BASE and OFFSET are + the names of the base and offset registers. */ static void print_register_offset_address (char *buf, size_t size, - const aarch64_opnd_info *opnd) + const aarch64_opnd_info *opnd, + const char *base, const char *offset) { char tb[16]; /* Temporary buffer. */ - bfd_boolean lsl_p = FALSE; /* Is LSL shift operator? */ - bfd_boolean wm_p = FALSE; /* Should Rm be Wm? */ bfd_boolean print_extend_p = TRUE; bfd_boolean print_amount_p = TRUE; const char *shift_name = aarch64_operand_modifiers[opnd->shifter.kind].name; - switch (opnd->shifter.kind) - { - case AARCH64_MOD_UXTW: wm_p = TRUE; break; - case AARCH64_MOD_LSL : lsl_p = TRUE; break; - case AARCH64_MOD_SXTW: wm_p = TRUE; break; - case AARCH64_MOD_SXTX: break; - default: assert (0); - } - if (!opnd->shifter.amount && (opnd->qualifier != AARCH64_OPND_QLF_S_B || !opnd->shifter.amount_present)) { @@ -2348,7 +2540,7 @@ print_register_offset_address (char *buf, size_t size, print_amount_p = FALSE; /* Likewise, no need to print the shift operator LSL in such a situation. */ - if (lsl_p) + if (opnd->shifter.kind == AARCH64_MOD_LSL) print_extend_p = FALSE; } @@ -2356,19 +2548,15 @@ print_register_offset_address (char *buf, size_t size, if (print_extend_p) { if (print_amount_p) - snprintf (tb, sizeof (tb), ",%s #%d", shift_name, opnd->shifter.amount); + snprintf (tb, sizeof (tb), ",%s #%" PRIi64, shift_name, + opnd->shifter.amount); else snprintf (tb, sizeof (tb), ",%s", shift_name); } else tb[0] = '\0'; - snprintf (buf, size, "[%s,%s%s]", - get_64bit_int_reg_name (opnd->addr.base_regno, 1), - get_int_reg_name (opnd->addr.offset.regno, - wm_p ? AARCH64_OPND_QLF_W : AARCH64_OPND_QLF_X, - 0 /* sp_reg_p */), - tb); + snprintf (buf, size, "[%s,%s%s]", base, offset, tb); } /* Generate the string representation of the operand OPNDS[IDX] for OPCODE @@ -2392,7 +2580,7 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc, const char *name = NULL; const aarch64_opnd_info *opnd = opnds + idx; enum aarch64_modifier_kind kind; - uint64_t addr; + uint64_t addr, enum_value; buf[0] = '\0'; if (pcrel_p) @@ -2456,7 +2644,7 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc, } } if (opnd->shifter.amount) - snprintf (buf, size, "%s, %s #%d", + snprintf (buf, size, "%s, %s #%" PRIi64, get_int_reg_name (opnd->reg.regno, opnd->qualifier, 0), aarch64_operand_modifiers[kind].name, opnd->shifter.amount); @@ -2473,7 +2661,7 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc, snprintf (buf, size, "%s", get_int_reg_name (opnd->reg.regno, opnd->qualifier, 0)); else - snprintf (buf, size, "%s, %s #%d", + snprintf (buf, size, "%s, %s #%" PRIi64, get_int_reg_name (opnd->reg.regno, opnd->qualifier, 0), aarch64_operand_modifiers[opnd->shifter.kind].name, opnd->shifter.amount); @@ -2519,6 +2707,50 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc, print_register_list (buf, size, opnd, "v"); break; + case AARCH64_OPND_SVE_Pd: + case AARCH64_OPND_SVE_Pg3: + case AARCH64_OPND_SVE_Pg4_5: + case AARCH64_OPND_SVE_Pg4_10: + case AARCH64_OPND_SVE_Pg4_16: + case AARCH64_OPND_SVE_Pm: + case AARCH64_OPND_SVE_Pn: + case AARCH64_OPND_SVE_Pt: + if (opnd->qualifier == AARCH64_OPND_QLF_NIL) + snprintf (buf, size, "p%d", opnd->reg.regno); + else if (opnd->qualifier == AARCH64_OPND_QLF_P_Z + || opnd->qualifier == AARCH64_OPND_QLF_P_M) + snprintf (buf, size, "p%d/%s", opnd->reg.regno, + aarch64_get_qualifier_name (opnd->qualifier)); + else + snprintf (buf, size, "p%d.%s", opnd->reg.regno, + aarch64_get_qualifier_name (opnd->qualifier)); + break; + + case AARCH64_OPND_SVE_Za_5: + case AARCH64_OPND_SVE_Za_16: + case AARCH64_OPND_SVE_Zd: + case AARCH64_OPND_SVE_Zm_5: + case AARCH64_OPND_SVE_Zm_16: + case AARCH64_OPND_SVE_Zn: + case AARCH64_OPND_SVE_Zt: + if (opnd->qualifier == AARCH64_OPND_QLF_NIL) + snprintf (buf, size, "z%d", opnd->reg.regno); + else + snprintf (buf, size, "z%d.%s", opnd->reg.regno, + aarch64_get_qualifier_name (opnd->qualifier)); + break; + + case AARCH64_OPND_SVE_ZnxN: + case AARCH64_OPND_SVE_ZtxN: + print_register_list (buf, size, opnd, "z"); + break; + + case AARCH64_OPND_SVE_Zn_INDEX: + snprintf (buf, size, "z%d.%s[%" PRIi64 "]", opnd->reglane.regno, + aarch64_get_qualifier_name (opnd->qualifier), + opnd->reglane.index); + break; + case AARCH64_OPND_Cn: case AARCH64_OPND_Cm: snprintf (buf, size, "C%d", opnd->reg.regno); @@ -2540,6 +2772,47 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc, snprintf (buf, size, "#%" PRIi64, opnd->imm.value); break; + case AARCH64_OPND_SVE_PATTERN: + if (optional_operand_p (opcode, idx) + && opnd->imm.value == get_optional_operand_default_value (opcode)) + break; + enum_value = opnd->imm.value; + assert (enum_value < ARRAY_SIZE (aarch64_sve_pattern_array)); + if (aarch64_sve_pattern_array[enum_value]) + snprintf (buf, size, "%s", aarch64_sve_pattern_array[enum_value]); + else + snprintf (buf, size, "#%" PRIi64, opnd->imm.value); + break; + + case AARCH64_OPND_SVE_PATTERN_SCALED: + if (optional_operand_p (opcode, idx) + && !opnd->shifter.operator_present + && opnd->imm.value == get_optional_operand_default_value (opcode)) + break; + enum_value = opnd->imm.value; + assert (enum_value < ARRAY_SIZE (aarch64_sve_pattern_array)); + if (aarch64_sve_pattern_array[opnd->imm.value]) + snprintf (buf, size, "%s", aarch64_sve_pattern_array[opnd->imm.value]); + else + snprintf (buf, size, "#%" PRIi64, opnd->imm.value); + if (opnd->shifter.operator_present) + { + size_t len = strlen (buf); + snprintf (buf + len, size - len, ", %s #%" PRIi64, + aarch64_operand_modifiers[opnd->shifter.kind].name, + opnd->shifter.amount); + } + break; + + case AARCH64_OPND_SVE_PRFOP: + enum_value = opnd->imm.value; + assert (enum_value < ARRAY_SIZE (aarch64_sve_prfop_array)); + if (aarch64_sve_prfop_array[enum_value]) + snprintf (buf, size, "%s", aarch64_sve_prfop_array[enum_value]); + else + snprintf (buf, size, "#%" PRIi64, opnd->imm.value); + break; + case AARCH64_OPND_IMM_MOV: switch (aarch64_get_qualifier_esize (opnds[0].qualifier)) { @@ -2565,7 +2838,7 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc, case AARCH64_OPND_AIMM: case AARCH64_OPND_HALF: if (opnd->shifter.amount) - snprintf (buf, size, "#0x%" PRIx64 ", lsl #%d", opnd->imm.value, + snprintf (buf, size, "#0x%" PRIx64 ", lsl #%" PRIi64, opnd->imm.value, opnd->shifter.amount); else snprintf (buf, size, "#0x%" PRIx64, opnd->imm.value); @@ -2577,7 +2850,7 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc, || opnd->shifter.kind == AARCH64_MOD_NONE) snprintf (buf, size, "#0x%" PRIx64, opnd->imm.value); else - snprintf (buf, size, "#0x%" PRIx64 ", %s #%d", opnd->imm.value, + snprintf (buf, size, "#0x%" PRIx64 ", %s #%" PRIi64, opnd->imm.value, aarch64_operand_modifiers[opnd->shifter.kind].name, opnd->shifter.amount); break; @@ -2675,27 +2948,16 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc, break; case AARCH64_OPND_ADDR_REGOFF: - print_register_offset_address (buf, size, opnd); + print_register_offset_address + (buf, size, opnd, get_64bit_int_reg_name (opnd->addr.base_regno, 1), + get_offset_int_reg_name (opnd)); break; case AARCH64_OPND_ADDR_SIMM7: case AARCH64_OPND_ADDR_SIMM9: case AARCH64_OPND_ADDR_SIMM9_2: - name = get_64bit_int_reg_name (opnd->addr.base_regno, 1); - if (opnd->addr.writeback) - { - if (opnd->addr.preind) - snprintf (buf, size, "[%s,#%d]!", name, opnd->addr.offset.imm); - else - snprintf (buf, size, "[%s],#%d", name, opnd->addr.offset.imm); - } - else - { - if (opnd->addr.offset.imm) - snprintf (buf, size, "[%s,#%d]", name, opnd->addr.offset.imm); - else - snprintf (buf, size, "[%s]", name); - } + print_immediate_offset_address + (buf, size, opnd, get_64bit_int_reg_name (opnd->addr.base_regno, 1)); break; case AARCH64_OPND_ADDR_UIMM12: