aboutsummaryrefslogtreecommitdiff
path: root/gas/config/tc-aarch64.c
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@arm.com>2016-09-21 16:56:15 +0100
committerRichard Sandiford <richard.sandiford@arm.com>2016-09-21 16:56:15 +0100
commit98907a704908c5877d929c57b2ddb2e5f899d9a9 (patch)
tree66e651a02be2e7d48ebf44cb7f1a2865766461d9 /gas/config/tc-aarch64.c
parent4df068de5214ff55b01ae320ec580f2928eb74e5 (diff)
downloadgdb-98907a704908c5877d929c57b2ddb2e5f899d9a9.zip
gdb-98907a704908c5877d929c57b2ddb2e5f899d9a9.tar.gz
gdb-98907a704908c5877d929c57b2ddb2e5f899d9a9.tar.bz2
[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.
Diffstat (limited to 'gas/config/tc-aarch64.c')
-rw-r--r--gas/config/tc-aarch64.c74
1 files changed, 59 insertions, 15 deletions
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,<expr> */
+ if (imm_shift_mode != SHIFTED_NONE && skip_past_comma (&p))
+ /* [Xn,<expr>,<shifter> */
+ if (! parse_shift (&p, operand, imm_shift_mode))
+ return FALSE;
}
- /* [Xn,<expr> */
}
}
@@ -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<n>{, #imm}]
+ /* [X<n>{, #imm, MUL VL}]
+ [X<n>{, #imm}]
but recognizing SVE registers. */
po_misc_or_fail (parse_sve_address (&str, info, &base_qualifier,
&offset_qualifier));