diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c index 98b5cfd5845e9c5ecb16493a5e20662288676959..f9e3756950d08dc5162bf97fd831315b4cef2873 100644 --- a/gas/config/tc-arm.c +++ b/gas/config/tc-arm.c @@ -1609,7 +1609,7 @@ parse_typed_reg_or_scalar (char **ccp, enum arm_reg_type type, return reg->number; } -/* Like arm_reg_parse, but allow allow the following extra features: +/* Like arm_reg_parse, but also allow the following extra features: - If RTYPE is non-zero, return the (possibly restricted) type of the register (e.g. Neon double or quad reg when either has been requested). - If this is a Neon vector type with additional type information, fill @@ -1695,7 +1695,9 @@ enum reg_list_els REGLIST_RN, REGLIST_CLRM, REGLIST_VFP_S, + REGLIST_VFP_S_VPR, REGLIST_VFP_D, + REGLIST_VFP_D_VPR, REGLIST_NEON_D }; @@ -1869,7 +1871,8 @@ parse_reg_list (char ** strp, enum reg_list_els etype) bug. */ static int -parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype) +parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype, + bfd_boolean *partial_match) { char *str = *ccp; int base_reg; @@ -1880,6 +1883,9 @@ parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype) int warned = 0; unsigned long mask = 0; int i; + bfd_boolean vpr_seen = FALSE; + bfd_boolean expect_vpr = + (etype == REGLIST_VFP_S_VPR) || (etype == REGLIST_VFP_D_VPR); if (skip_past_char (&str, '{') == FAIL) { @@ -1890,11 +1896,13 @@ parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype) switch (etype) { case REGLIST_VFP_S: + case REGLIST_VFP_S_VPR: regtype = REG_TYPE_VFS; max_regs = 32; break; case REGLIST_VFP_D: + case REGLIST_VFP_D_VPR: regtype = REG_TYPE_VFD; break; @@ -1906,7 +1914,7 @@ parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype) gas_assert (0); } - if (etype != REGLIST_VFP_S) + if (etype != REGLIST_VFP_S && etype != REGLIST_VFP_S_VPR) { /* VFPv3 allows 32 D registers, except for the VFPv3-D16 variant. */ if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_d32)) @@ -1924,19 +1932,54 @@ parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype) } base_reg = max_regs; + *partial_match = FALSE; do { int setmask = 1, addregs = 1; + const char vpr_str[] = "vpr"; + int vpr_str_len = strlen (vpr_str); new_base = arm_typed_reg_parse (&str, regtype, ®type, NULL); - if (new_base == FAIL) + if (expect_vpr) + { + if (new_base == FAIL + && !strncasecmp (str, vpr_str, vpr_str_len) + && !ISALPHA (*(str + vpr_str_len)) + && !vpr_seen) + { + vpr_seen = TRUE; + str += vpr_str_len; + if (count == 0) + base_reg = 0; /* Canonicalize VPR only on d0 with 0 regs. */ + } + else if (vpr_seen) + { + first_error (_("VPR expected last")); + return FAIL; + } + else if (new_base == FAIL) + { + if (regtype == REG_TYPE_VFS) + first_error (_("VFP single precision register or VPR " + "expected")); + else /* regtype == REG_TYPE_VFD. */ + first_error (_("VFP/Neon double precision register or VPR " + "expected")); + return FAIL; + } + } + else if (new_base == FAIL) { first_error (_(reg_expected_msgs[regtype])); return FAIL; } + *partial_match = TRUE; + if (vpr_seen) + continue; + if (new_base >= max_regs) { first_error (_("register out of range in list")); @@ -1959,7 +2002,7 @@ parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype) return FAIL; } - if ((mask >> new_base) != 0 && ! warned) + if ((mask >> new_base) != 0 && ! warned && !vpr_seen) { as_tsktsk (_("register list not in ascending order")); warned = 1; @@ -2014,11 +2057,17 @@ parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype) str++; /* Sanity check -- should have raised a parse error above. */ - if (count == 0 || count > max_regs) + if ((!vpr_seen && count == 0) || count > max_regs) abort (); *pbase = base_reg; + if (expect_vpr && !vpr_seen) + { + first_error (_("VPR expected last")); + return FAIL; + } + /* Final test -- the registers must be consecutive. */ mask >>= base_reg; for (i = 0; i < count; i++) @@ -4146,8 +4195,10 @@ s_arm_unwind_save_vfp_armv6 (void) valueT op; int num_vfpv3_regs = 0; int num_regs_below_16; + bfd_boolean partial_match; - count = parse_vfp_reg_list (&input_line_pointer, &start, REGLIST_VFP_D); + count = parse_vfp_reg_list (&input_line_pointer, &start, REGLIST_VFP_D, + &partial_match); if (count == FAIL) { as_bad (_("expected register list")); @@ -4194,8 +4245,10 @@ s_arm_unwind_save_vfp (void) int count; unsigned int reg; valueT op; + bfd_boolean partial_match; - count = parse_vfp_reg_list (&input_line_pointer, ®, REGLIST_VFP_D); + count = parse_vfp_reg_list (&input_line_pointer, ®, REGLIST_VFP_D, + &partial_match); if (count == FAIL) { as_bad (_("expected register list")); @@ -6585,6 +6638,7 @@ enum operand_parse_code OP_VRSDLST, /* VFP single or double-precision register list (& quad) */ OP_NRDLST, /* Neon double-precision register list (d0-d31, qN aliases) */ OP_NSTRLST, /* Neon element/structure list */ + OP_VRSDVLST, /* VFP single or double-precision register list and VPR */ OP_RNDQ_I0, /* Neon D or Q reg, or immediate zero. */ OP_RVSD_I0, /* VFP S or D reg, or immediate zero. */ @@ -6694,6 +6748,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb) enum arm_reg_type rtype; parse_operand_result result; unsigned int op_parse_code; + bfd_boolean partial_match; #define po_char_or_fail(chr) \ do \ @@ -7218,29 +7273,43 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb) break; case OP_VRSLST: - val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_S); + val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_S, + &partial_match); break; case OP_VRDLST: - val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_D); + val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_D, + &partial_match); break; case OP_VRSDLST: /* Allow Q registers too. */ val = parse_vfp_reg_list (&str, &inst.operands[i].reg, - REGLIST_NEON_D); + REGLIST_NEON_D, &partial_match); if (val == FAIL) { inst.error = NULL; val = parse_vfp_reg_list (&str, &inst.operands[i].reg, - REGLIST_VFP_S); + REGLIST_VFP_S, &partial_match); + inst.operands[i].issingle = 1; + } + break; + + case OP_VRSDVLST: + val = parse_vfp_reg_list (&str, &inst.operands[i].reg, + REGLIST_VFP_D_VPR, &partial_match); + if (val == FAIL && !partial_match) + { + inst.error = NULL; + val = parse_vfp_reg_list (&str, &inst.operands[i].reg, + REGLIST_VFP_S_VPR, &partial_match); inst.operands[i].issingle = 1; } break; case OP_NRDLST: val = parse_vfp_reg_list (&str, &inst.operands[i].reg, - REGLIST_NEON_D); + REGLIST_NEON_D, &partial_match); break; case OP_NSTRLST: @@ -7344,6 +7413,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb) case OP_VRSLST: case OP_VRDLST: case OP_VRSDLST: + case OP_VRSDVLST: case OP_NRDLST: case OP_NSTRLST: if (val == FAIL) @@ -12814,6 +12884,24 @@ do_t_clrm (void) } } +static void +do_t_vscclrm (void) +{ + if (inst.operands[0].issingle) + { + inst.instruction |= (inst.operands[0].reg & 0x1) << 22; + inst.instruction |= (inst.operands[0].reg & 0x1e) << 11; + inst.instruction |= inst.operands[0].imm; + } + else + { + inst.instruction |= (inst.operands[0].reg & 0x10) << 18; + inst.instruction |= (inst.operands[0].reg & 0xf) << 12; + inst.instruction |= 1 << 8; + inst.instruction |= inst.operands[0].imm << 1; + } +} + static void do_t_rbit (void) { @@ -21889,7 +21977,8 @@ static const struct asm_opcode insns[] = toU("wls", _wls, 3, (LR, RRnpcsp, EXP), t_loloop), toU("le", _le, 2, (oLR, EXP), t_loloop), - ToC("clrm", e89f0000, 1, (CLRMLST), t_clrm) + ToC("clrm", e89f0000, 1, (CLRMLST), t_clrm), + ToC("vscclrm", ec9f0a00, 1, (VRSDVLST), t_vscclrm) }; #undef ARM_VARIANT #undef THUMB_VARIANT diff --git a/gas/testsuite/gas/arm/archv8m_1m-cmse-main-bad.l b/gas/testsuite/gas/arm/archv8m_1m-cmse-main-bad.l index ed440bf2baa36e0f60cccff417d8148a17749f44..b64937d27f2af469daac5e3feb9167dccde0a986 100644 --- a/gas/testsuite/gas/arm/archv8m_1m-cmse-main-bad.l +++ b/gas/testsuite/gas/arm/archv8m_1m-cmse-main-bad.l @@ -2,3 +2,7 @@ [^:]*:6: Error: r0-r12, lr or APSR expected -- `clrm {}' [^:]*:7: Error: r0-r12, lr or APSR expected -- `clrm {sp}' [^:]*:8: Error: r0-r12, lr or APSR expected -- `clrm {pc}' +[^:]*:10: Error: VFP single precision register or VPR expected -- `vscclrm {}' +[^:]*:11: Error: VPR expected last -- `vscclrm {s0}' +[^:]*:12: Error: VFP single precision register or VPR expected -- `vscclrm {s1,d1,VPR}' +[^:]*:13: Error: VFP single precision register expected -- `vscclrm {s1-d1,VPR}' diff --git a/gas/testsuite/gas/arm/archv8m_1m-cmse-main-bad.s b/gas/testsuite/gas/arm/archv8m_1m-cmse-main-bad.s index c991a559093fd5da79f8eb54c02fde13208a8071..f4baefe73f84a0c93a9ab992b80a9f0b3644d051 100644 --- a/gas/testsuite/gas/arm/archv8m_1m-cmse-main-bad.s +++ b/gas/testsuite/gas/arm/archv8m_1m-cmse-main-bad.s @@ -6,3 +6,8 @@ T: clrm {} @ Rejects empty list clrm {sp} @ Rejects SP in list clrm {pc} @ Reject PC in list + +vscclrm {} @ Rejects empty list +vscclrm {s0} @ Rejects list without VPR +vscclrm {s1, d1, VPR} @ Reject mix of single and double-precision VFP registers +vscclrm {s1-d1, VPR} @ Likewise when using a range diff --git a/gas/testsuite/gas/arm/archv8m_1m-cmse-main.d b/gas/testsuite/gas/arm/archv8m_1m-cmse-main.d index b082ff7e6451186763dd55cf96f9205d2f5ce4d8..866adc9cb0db7a8c0f6061c3829ac07f3d5233f3 100644 --- a/gas/testsuite/gas/arm/archv8m_1m-cmse-main.d +++ b/gas/testsuite/gas/arm/archv8m_1m-cmse-main.d @@ -11,4 +11,13 @@ Disassembly of section .text: 0+.* <[^>]*> e89f 8008 clrm {r3, APSR} 0+.* <[^>]*> bf08 it eq 0+.* <[^>]*> e89f 0010 clrmeq {r4} +0+.* <[^>]*> ec9f 0b00 vscclrm {VPR} +0+.* <[^>]*> ec9f fa01 vscclrm {s30, VPR} +0+.* <[^>]*> ec9f eb02 vscclrm {d14, VPR} +0+.* <[^>]*> ecdf 0a04 vscclrm {s1-s4, VPR} +0+.* <[^>]*> ec9f 1b08 vscclrm {d1-d4, VPR} +0+.* <[^>]*> ec9f 0a20 vscclrm {s0-s31, VPR} +0+.* <[^>]*> ec9f 0b20 vscclrm {d0-d15, VPR} +0+.* <[^>]*> bf18 it ne +0+.* <[^>]*> ecdf 1a01 vscclrmne {s3, VPR} #... diff --git a/gas/testsuite/gas/arm/archv8m_1m-cmse-main.s b/gas/testsuite/gas/arm/archv8m_1m-cmse-main.s index 084d83b88b63bb4f55fd9ab2388b80b91696f763..f4df2dbb2f7666c4c762a9b62463d809ba91577e 100644 --- a/gas/testsuite/gas/arm/archv8m_1m-cmse-main.s +++ b/gas/testsuite/gas/arm/archv8m_1m-cmse-main.s @@ -7,3 +7,14 @@ clrm {r0, r2} @ Accepts list without APSR clrm {APSR} @ Accepts APSR alone clrm {r3, APSR} @ Accepts core register and APSR together clrmeq {r4} @ Accepts conditional execution + +vscclrm {VPR} @ Accepts list with only VPR +vscclrm {s30, VPR} @ Accept single-precision VFP register and VPR together +vscclrm {d14, VPR} @ Likewise for double-precision VFP register +vscclrm {s1-s4, VPR} @ Accept range of single-precision VFP registers + @ and VPR together +vscclrm {d1-d4, VPR} @ Likewise for double-precision VFP registers +vscclrm {s0-s31, VPR} @ Accept all single-precision VFP registers and VPR + @ together +vscclrm {d0-d15, VPR} @ Likewise for double-precision VFP registers +vscclrmne {s3, VPR} @ Accepts conditional execution diff --git a/opcodes/arm-dis.c b/opcodes/arm-dis.c index d41de41002519b459bb16dd0e00e1025848e5b37..cf11e616eaa50acdc546adfd9c92740770b27177 100644 --- a/opcodes/arm-dis.c +++ b/opcodes/arm-dis.c @@ -110,6 +110,7 @@ struct opcode16 UNPREDICTABLE if not AL in Thumb) %A print address for ldc/stc/ldf/stf instruction %B print vstm/vldm register list + %C print vscclrm register list %I print cirrus signed shift immediate: bits 0..3|4..6 %F print the COUNT field of a LFM/SFM instruction. %P print floating point precision in arithmetic insn @@ -426,6 +427,12 @@ static const struct sopcode32 coprocessor_opcodes[] = {ANY, ARM_FEATURE_COPROC (FPU_FPA_EXT_V2), 0x0c100200, 0x0e100f00, "lfm%c\t%12-14f, %F, %A"}, + /* Armv8.1-M Mainline instructions. */ + {T32, ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_1M_MAIN), + 0xec9f0b00, 0xffbf0f01, "vscclrm%c\t%C"}, + {T32, ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_1M_MAIN), + 0xec9f0a00, 0xffbf0f00, "vscclrm%c\t%C"}, + /* ARMv8-M Mainline Security Extensions instructions. */ {ANY, ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M_MAIN), 0xec300a00, 0xfff0ffff, "vlldm\t%16-19r"}, @@ -3643,6 +3650,31 @@ print_insn_coprocessor (bfd_vma pc, } break; + case 'C': + { + bfd_boolean single = ((given >> 8) & 1) == 0; + char reg_prefix = single ? 's' : 'd'; + int Dreg = (given >> 22) & 0x1; + int Vdreg = (given >> 12) & 0xf; + int reg = single ? ((Vdreg << 1) | Dreg) + : ((Dreg << 4) | Vdreg); + int num = (given >> (single ? 0 : 1)) & 0x7f; + int maxreg = single ? 31 : 15; + int topreg = reg + num - 1; + + if (!num) + func (stream, "{VPR}"); + else if (num == 1) + func (stream, "{%c%d, VPR}", reg_prefix, reg); + else if (topreg > maxreg) + func (stream, "{%c%d-> 1 : topreg); + else + func (stream, "{%c%d-%c%d, VPR}", reg_prefix, reg, + reg_prefix, topreg); + } + break; + case 'u': if (cond != COND_UNCOND) is_unpredictable = TRUE;