From 98907a704908c5877d929c57b2ddb2e5f899d9a9 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Wed, 21 Sep 2016 16:56:15 +0100 Subject: [AArch64][SVE 26/32] Add SVE MUL VL addressing modes This patch adds support for addresses of the form: [, #, 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. --- gas/ChangeLog | 9 ++++++ gas/config/tc-aarch64.c | 74 +++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 68 insertions(+), 15 deletions(-) (limited to 'gas') diff --git a/gas/ChangeLog b/gas/ChangeLog index c1f4152..4593a78 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,5 +1,14 @@ 2016-09-21 Richard Sandiford + * 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 Richard Sandiford + * config/tc-aarch64.c (REG_TYPE_SVE_BASE, REG_TYPE_SVE_OFFSET): New register types. (get_reg_expected_msg): Handle them. diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c index e59333f..930b07a 100644 --- a/gas/config/tc-aarch64.c +++ b/gas/config/tc-aarch64.c @@ -2922,6 +2922,7 @@ find_reloc_table_entry (char **str) /* Mode argument to parse_shift and parser_shifter_operand. */ enum parse_shift_mode { + SHIFTED_NONE, /* no shifter allowed */ SHIFTED_ARITH_IMM, /* "rn{,lsl|lsr|asl|asr|uxt|sxt #n}" or "#imm{,lsl #n}" */ SHIFTED_LOGIC_IMM, /* "rn{,lsl|lsr|asl|asr|ror #n}" or @@ -2929,6 +2930,7 @@ enum parse_shift_mode SHIFTED_LSL, /* bare "lsl #n" */ SHIFTED_MUL, /* bare "mul #n" */ SHIFTED_LSL_MSL, /* "lsl|msl #n" */ + SHIFTED_MUL_VL, /* "mul vl" */ SHIFTED_REG_OFFSET /* [su]xtw|sxtx {#n} or lsl #n */ }; @@ -2970,7 +2972,8 @@ parse_shift (char **str, aarch64_opnd_info *operand, enum parse_shift_mode mode) } if (kind == AARCH64_MOD_MUL - && mode != SHIFTED_MUL) + && mode != SHIFTED_MUL + && mode != SHIFTED_MUL_VL) { set_syntax_error (_("invalid use of 'MUL'")); return FALSE; @@ -3010,6 +3013,22 @@ parse_shift (char **str, aarch64_opnd_info *operand, enum parse_shift_mode mode) } break; + case SHIFTED_MUL_VL: + /* "MUL VL" consists of two separate tokens. Require the first + token to be "MUL" and look for a following "VL". */ + if (kind == AARCH64_MOD_MUL) + { + skip_whitespace (p); + if (strncasecmp (p, "vl", 2) == 0 && !ISALPHA (p[2])) + { + p += 2; + kind = AARCH64_MOD_MUL_VL; + break; + } + } + set_syntax_error (_("only 'MUL VL' is permitted")); + return FALSE; + case SHIFTED_REG_OFFSET: if (kind != AARCH64_MOD_UXTW && kind != AARCH64_MOD_LSL && kind != AARCH64_MOD_SXTW && kind != AARCH64_MOD_SXTX) @@ -3037,7 +3056,7 @@ parse_shift (char **str, aarch64_opnd_info *operand, enum parse_shift_mode mode) /* Parse shift amount. */ exp_has_prefix = 0; - if (mode == SHIFTED_REG_OFFSET && *p == ']') + if ((mode == SHIFTED_REG_OFFSET && *p == ']') || kind == AARCH64_MOD_MUL_VL) exp.X_op = O_absent; else { @@ -3048,7 +3067,11 @@ parse_shift (char **str, aarch64_opnd_info *operand, enum parse_shift_mode mode) } my_get_expression (&exp, &p, GE_NO_PREFIX, 0); } - if (exp.X_op == O_absent) + if (kind == AARCH64_MOD_MUL_VL) + /* For consistency, give MUL VL the same shift amount as an implicit + MUL #1. */ + operand->shifter.amount = 1; + else if (exp.X_op == O_absent) { if (aarch64_extend_operator_p (kind) == FALSE || exp_has_prefix) { @@ -3268,6 +3291,7 @@ parse_shifter_operand_reloc (char **str, aarch64_opnd_info *operand, PC-relative (literal) label SVE: + [base,#imm,MUL VL] [base,Zm.D{,LSL #imm}] [base,Zm.S,(S|U)XTW {#imm}] [base,Zm.D,(S|U)XTW {#imm}] // ignores top 32 bits of Zm.D elements @@ -3307,15 +3331,20 @@ parse_shifter_operand_reloc (char **str, aarch64_opnd_info *operand, corresponding register. BASE_TYPE says which types of base register should be accepted and - OFFSET_TYPE says the same for offset registers. In all other respects, - it is the caller's responsibility to check for addressing modes not - supported by the instruction, and to set inst.reloc.type. */ + OFFSET_TYPE says the same for offset registers. IMM_SHIFT_MODE + is the type of shifter that is allowed for immediate offsets, + or SHIFTED_NONE if none. + + In all other respects, it is the caller's responsibility to check + for addressing modes not supported by the instruction, and to set + inst.reloc.type. */ static bfd_boolean parse_address_main (char **str, aarch64_opnd_info *operand, aarch64_opnd_qualifier_t *base_qualifier, aarch64_opnd_qualifier_t *offset_qualifier, - aarch64_reg_type base_type, aarch64_reg_type offset_type) + aarch64_reg_type base_type, aarch64_reg_type offset_type, + enum parse_shift_mode imm_shift_mode) { char *p = *str; const reg_entry *reg; @@ -3497,12 +3526,19 @@ parse_address_main (char **str, aarch64_opnd_info *operand, inst.reloc.type = entry->ldst_type; inst.reloc.pc_rel = entry->pc_rel; } - else if (! my_get_expression (exp, &p, GE_OPT_PREFIX, 1)) + else { - set_syntax_error (_("invalid expression in the address")); - return FALSE; + if (! my_get_expression (exp, &p, GE_OPT_PREFIX, 1)) + { + set_syntax_error (_("invalid expression in the address")); + return FALSE; + } + /* [Xn, */ + if (imm_shift_mode != SHIFTED_NONE && skip_past_comma (&p)) + /* [Xn,, */ + if (! parse_shift (&p, operand, imm_shift_mode)) + return FALSE; } - /* [Xn, */ } } @@ -3582,10 +3618,10 @@ parse_address (char **str, aarch64_opnd_info *operand) { aarch64_opnd_qualifier_t base_qualifier, offset_qualifier; return parse_address_main (str, operand, &base_qualifier, &offset_qualifier, - REG_TYPE_R64_SP, REG_TYPE_R_Z); + REG_TYPE_R64_SP, REG_TYPE_R_Z, SHIFTED_NONE); } -/* Parse an address in which SVE vector registers are allowed. +/* Parse an address in which SVE vector registers and MUL VL are allowed. The arguments have the same meaning as for parse_address_main. Return TRUE on success. */ static bfd_boolean @@ -3594,7 +3630,8 @@ parse_sve_address (char **str, aarch64_opnd_info *operand, aarch64_opnd_qualifier_t *offset_qualifier) { return parse_address_main (str, operand, base_qualifier, offset_qualifier, - REG_TYPE_SVE_BASE, REG_TYPE_SVE_OFFSET); + REG_TYPE_SVE_BASE, REG_TYPE_SVE_OFFSET, + SHIFTED_MUL_VL); } /* Parse an operand for a MOVZ, MOVN or MOVK instruction. @@ -5938,11 +5975,18 @@ parse_operands (char *str, const aarch64_opcode *opcode) /* No qualifier. */ break; + case AARCH64_OPND_SVE_ADDR_RI_S4xVL: + case AARCH64_OPND_SVE_ADDR_RI_S4x2xVL: + case AARCH64_OPND_SVE_ADDR_RI_S4x3xVL: + case AARCH64_OPND_SVE_ADDR_RI_S4x4xVL: + case AARCH64_OPND_SVE_ADDR_RI_S6xVL: + case AARCH64_OPND_SVE_ADDR_RI_S9xVL: case AARCH64_OPND_SVE_ADDR_RI_U6: case AARCH64_OPND_SVE_ADDR_RI_U6x2: case AARCH64_OPND_SVE_ADDR_RI_U6x4: case AARCH64_OPND_SVE_ADDR_RI_U6x8: - /* [X{, #imm}] + /* [X{, #imm, MUL VL}] + [X{, #imm}] but recognizing SVE registers. */ po_misc_or_fail (parse_sve_address (&str, info, &base_qualifier, &offset_qualifier)); -- cgit v1.1