diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 540b9f71c181841ea782c63d87d0d5271c864966..13af0beade1ee1521be7db8307e5fa2e025594b2 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -3722,6 +3722,7 @@ pc-relative or some form of GOT-indirect relocation. */ BFD_RELOC_ARM_CP_OFF_IMM_S2, BFD_RELOC_ARM_T32_CP_OFF_IMM, BFD_RELOC_ARM_T32_CP_OFF_IMM_S2, + BFD_RELOC_ARM_T32_VLDR_VSTR_OFF_IMM, BFD_RELOC_ARM_ADR_IMM, BFD_RELOC_ARM_LDR_IMM, BFD_RELOC_ARM_LITERAL, diff --git a/bfd/libbfd.h b/bfd/libbfd.h index f64a8f3892ad3aff5c4570f0281875bce35846a6..b51df73179fd1d3185f904466fd995f113a22835 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -1634,6 +1634,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_ARM_CP_OFF_IMM_S2", "BFD_RELOC_ARM_T32_CP_OFF_IMM", "BFD_RELOC_ARM_T32_CP_OFF_IMM_S2", + "BFD_RELOC_ARM_T32_VLDR_VSTR_OFF_IMM", "BFD_RELOC_ARM_ADR_IMM", "BFD_RELOC_ARM_LDR_IMM", "BFD_RELOC_ARM_LITERAL", diff --git a/bfd/reloc.c b/bfd/reloc.c index e6ba9e265027a6c34a8ad183dd5825a9af9c1f82..9615279833228cff4cb7f4cd77e930b2ad7cf4ab 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -3292,6 +3292,8 @@ ENUMX BFD_RELOC_ARM_T32_CP_OFF_IMM ENUMX BFD_RELOC_ARM_T32_CP_OFF_IMM_S2 +ENUMX + BFD_RELOC_ARM_T32_VLDR_VSTR_OFF_IMM ENUMX BFD_RELOC_ARM_ADR_IMM ENUMX diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c index f3fe397d37460b47dc634214a3a3e4c167ff3bfe..8035fa1db4dcf88393c96f8d54a55766ca1ab580 100644 --- a/gas/config/tc-arm.c +++ b/gas/config/tc-arm.c @@ -6128,6 +6128,39 @@ check_suffix: return FAIL; } +static int +parse_sys_vldr_vstr (char **str) +{ + unsigned i; + int val = FAIL; + struct { + const char *name; + int regl; + int regh; + } sysregs[] = { + {"FPSCR", 0x1, 0x0}, + {"FPSCR_nzcvqc", 0x2, 0x0}, + {"VPR", 0x4, 0x1}, + {"P0", 0x5, 0x1}, + {"FPCXTNS", 0x6, 0x1}, + {"FPCXTS", 0x7, 0x1} + }; + char *op_end = strchr (*str, ','); + size_t op_strlen = op_end - *str; + + for (i = 0; i < sizeof (sysregs) / sizeof (sysregs[0]); i++) + { + if (!strncmp (*str, sysregs[i].name, op_strlen)) + { + val = sysregs[i].regl | (sysregs[i].regh << 3); + *str = op_end; + break; + } + } + + return val; +} + /* Parse the flags argument to CPSI[ED]. Returns FAIL on error, or a value suitable for splatting into the AIF field of the instruction. */ @@ -6652,6 +6685,7 @@ enum operand_parse_code OP_RNDQ_Ibig, /* Neon D or Q reg, or big immediate for logic and VMVN. */ OP_RNDQ_I63b, /* Neon D or Q reg, or immediate for shift. */ OP_RIWR_I32z, /* iWMMXt wR register, or immediate 0 .. 32 for iWMMXt2. */ + OP_VLDR, /* VLDR operand. */ OP_I0, /* immediate zero */ OP_I7, /* immediate value 0 .. 7 */ @@ -7225,6 +7259,13 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb) val = parse_psr (&str, op_parse_code == OP_wPSR); break; + case OP_VLDR: + po_reg_or_goto (REG_TYPE_VFSD, try_sysreg); + break; + try_sysreg: + val = parse_sys_vldr_vstr (&str); + break; + case OP_APSR_RR: po_reg_or_goto (REG_TYPE_RN, try_apsr); break; @@ -7401,6 +7442,10 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb) inst.error = BAD_PC; break; + case OP_VLDR: + if (inst.operands[i].isreg) + break; + /* fall through. */ case OP_CPSF: case OP_ENDI: case OP_oROR: @@ -17397,6 +17442,55 @@ do_neon_ldr_str (void) } } +static void +do_t_vldr_vstr_sysreg (void) +{ + int fp_vldr_bitno = 20, sysreg_vldr_bitno = 20; + bfd_boolean is_vldr = ((inst.instruction & (1 << fp_vldr_bitno)) != 0); + + /* Use of PC is UNPREDICTABLE. */ + if (inst.operands[1].reg == REG_PC) + inst.error = _("Use of PC here is UNPREDICTABLE"); + + if (inst.operands[1].immisreg) + inst.error = _("instruction does not accept register index"); + + if (!inst.operands[1].isreg) + inst.error = _("instruction does not accept PC-relative addressing"); + + if (abs (inst.operands[1].imm) >= (1 << 7)) + inst.error = _("immediate value out of range"); + + inst.instruction = 0xec000f80; + if (is_vldr) + inst.instruction |= 1 << sysreg_vldr_bitno; + encode_arm_cp_address (1, TRUE, FALSE, BFD_RELOC_ARM_T32_VLDR_VSTR_OFF_IMM); + inst.instruction |= (inst.operands[0].imm & 0x7) << 13; + inst.instruction |= (inst.operands[0].imm & 0x8) << 19; +} + +static void +do_vldr_vstr (void) +{ + bfd_boolean sysreg_op = !inst.operands[0].isreg; + + /* VLDR/VSTR (System Register). */ + if (sysreg_op) + { + if (!mark_feature_used (&arm_ext_v8_1m_main)) + as_bad (_("Instruction not permitted on this architecture")); + + do_t_vldr_vstr_sysreg (); + } + /* VLDR/VSTR. */ + else + { + if (!mark_feature_used (&fpu_vfp_ext_v1xd)) + as_bad (_("Instruction not permitted on this architecture")); + do_neon_ldr_str (); + } +} + /* "interleave" version also handles non-interleaving register VLD1/VST1 instructions. */ @@ -21284,8 +21378,6 @@ static const struct asm_opcode insns[] = NCE(vstm, c800b00, 2, (RRnpctw, VRSDLST), neon_ldm_stm), NCE(vstmia, c800b00, 2, (RRnpctw, VRSDLST), neon_ldm_stm), NCE(vstmdb, d000b00, 2, (RRnpctw, VRSDLST), neon_ldm_stm), - NCE(vldr, d100b00, 2, (RVSD, ADDRGLDC), neon_ldr_str), - NCE(vstr, d000b00, 2, (RVSD, ADDRGLDC), neon_ldr_str), nCEF(vcvt, _vcvt, 3, (RNSDQ, RNSDQ, oI32z), neon_cvt), nCEF(vcvtr, _vcvt, 2, (RNSDQ, RNSDQ), neon_cvtr), @@ -21297,6 +21389,15 @@ static const struct asm_opcode insns[] = NCE(vmov, 0, 1, (VMOV), neon_mov), NCE(vmovq, 0, 1, (VMOV), neon_mov), +#undef THUMB_VARIANT +/* Could be either VLDR/VSTR or VLDR/VSTR (system register) which are guarded + by different feature bits. Since we are setting the Thumb guard, we can + require Thumb-1 which makes it a nop guard and set the right feature bit in + do_vldr_vstr (). */ +#define THUMB_VARIANT & arm_ext_v4t + NCE(vldr, d100b00, 2, (VLDR, ADDRGLDC), vldr_vstr), + NCE(vstr, d000b00, 2, (VLDR, ADDRGLDC), vldr_vstr), + #undef ARM_VARIANT #define ARM_VARIANT & arm_ext_fp16 #undef THUMB_VARIANT @@ -24548,6 +24649,7 @@ md_apply_fix (fixS * fixP, case BFD_RELOC_ARM_CP_OFF_IMM: case BFD_RELOC_ARM_T32_CP_OFF_IMM: + case BFD_RELOC_ARM_T32_VLDR_VSTR_OFF_IMM: if (fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM) newval = md_chars_to_number (buf, INSN_SIZE); else @@ -24561,6 +24663,12 @@ md_apply_fix (fixS * fixP, as_bad_where (fixP->fx_file, fixP->fx_line, _("co-processor offset out of range")); } + else if ((newval & 0xfe001f80) == 0xec000f80) + { + if (value < -511 || value > 512 || (value & 3)) + as_bad_where (fixP->fx_file, fixP->fx_line, + _("co-processor offset out of range")); + } else if (value < -1023 || value > 1023 || (value & 3)) as_bad_where (fixP->fx_file, fixP->fx_line, _("co-processor offset out of range")); @@ -24574,10 +24682,18 @@ md_apply_fix (fixS * fixP, else newval = get_thumb32_insn (buf); if (value == 0) - newval &= 0xffffff00; + { + if (fixP->fx_r_type == BFD_RELOC_ARM_T32_VLDR_VSTR_OFF_IMM) + newval &= 0xffffff80; + else + newval &= 0xffffff00; + } else { - newval &= 0xff7fff00; + if (fixP->fx_r_type == BFD_RELOC_ARM_T32_VLDR_VSTR_OFF_IMM) + newval &= 0xff7fff80; + else + newval &= 0xff7fff00; if ((newval & 0x0f200f00) == 0x0d000900) { /* This is a fp16 vstr/vldr. 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 b64937d27f2af469daac5e3feb9167dccde0a986..979982dd9f3bc2059ea059db37dd655c4140b8f5 100644 --- a/gas/testsuite/gas/arm/archv8m_1m-cmse-main-bad.l +++ b/gas/testsuite/gas/arm/archv8m_1m-cmse-main-bad.l @@ -6,3 +6,11 @@ [^:]*: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}' +[^:]*:15: Error: syntax error -- `vldr APSR,\[r2\]' +[^:]*:20: Error: syntax error -- `vstr APSR,\[r2\]' +[^:]*:16: Error: co-processor offset out of range +[^:]*:17: Error: co-processor offset out of range +[^:]*:18: Error: co-processor offset out of range +[^:]*:21: Error: co-processor offset out of range +[^:]*:22: Error: co-processor offset out of range +[^:]*:23: Error: co-processor offset out of range 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 f4baefe73f84a0c93a9ab992b80a9f0b3644d051..894e8b2b8f03cef09bfe33dcf238af68fb07f95d 100644 --- a/gas/testsuite/gas/arm/archv8m_1m-cmse-main-bad.s +++ b/gas/testsuite/gas/arm/archv8m_1m-cmse-main-bad.s @@ -11,3 +11,13 @@ 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 + +vldr APSR, [r2] @ Rejects incorrect system register +vldr FPSCR, [r2, #2] @ Rejects invalid immediate for offset variant +vldr FPSCR, [r2, #2]! @ Likewise for pre-index variant +vldr FPSCR, [r2], #2 @ Likewise for post-index variant + +vstr APSR, [r2] @ Rejects incorrect system register +vstr FPSCR, [r2, #2] @ Rejects invalid immediate for offset variant +vstr FPSCR, [r2, #2]! @ Likewise for pre-index variant +vstr FPSCR, [r2], #2 @ Likewise for post-index variant diff --git a/gas/testsuite/gas/arm/archv8m_1m-cmse-main.d b/gas/testsuite/gas/arm/archv8m_1m-cmse-main.d index 866adc9cb0db7a8c0f6061c3829ac07f3d5233f3..1ed543a04e8602a0c6dfed28c0ec6ae455722af0 100644 --- a/gas/testsuite/gas/arm/archv8m_1m-cmse-main.d +++ b/gas/testsuite/gas/arm/archv8m_1m-cmse-main.d @@ -20,4 +20,38 @@ Disassembly of section .text: 0+.* <[^>]*> ec9f 0b20 vscclrm {d0-d15, VPR} 0+.* <[^>]*> bf18 it ne 0+.* <[^>]*> ecdf 1a01 vscclrmne {s3, VPR} +0+.* <[^>]*> ed92 2f80 vldr FPSCR, \[r2\] +0+.* <[^>]*> ed92 2f82 vldr FPSCR, \[r2, #8\] +0+.* <[^>]*> ed92 2f82 vldr FPSCR, \[r2, #8\] +0+.* <[^>]*> ed12 2f82 vldr FPSCR, \[r2, #-8\] +0+.* <[^>]*> edb2 2f82 vldr FPSCR, \[r2, #8\]! +0+.* <[^>]*> edb2 2f82 vldr FPSCR, \[r2, #8\]! +0+.* <[^>]*> ed32 2f82 vldr FPSCR, \[r2, #-8\]! +0+.* <[^>]*> ecb2 2f82 vldr FPSCR, \[r2\], #8 +0+.* <[^>]*> ecb2 2f82 vldr FPSCR, \[r2\], #8 +0+.* <[^>]*> ec32 2f82 vldr FPSCR, \[r2\], #-8 +0+.* <[^>]*> ed93 4f80 vldr FPSCR_nzcvqc, \[r3\] +0+.* <[^>]*> edd3 8f80 vldr VPR, \[r3\] +0+.* <[^>]*> edd3 af80 vldr P0, \[r3\] +0+.* <[^>]*> edd3 cf80 vldr FPCXTNS, \[r3\] +0+.* <[^>]*> edd3 ef80 vldr FPCXTS, \[r3\] +0+.* <[^>]*> bfa8 it ge +0+.* <[^>]*> edd3 ef80 vldrge FPCXTS, \[r3\] +0+.* <[^>]*> ed82 2f80 vstr FPSCR, \[r2\] +0+.* <[^>]*> ed82 2f82 vstr FPSCR, \[r2, #8\] +0+.* <[^>]*> ed82 2f82 vstr FPSCR, \[r2, #8\] +0+.* <[^>]*> ed02 2f82 vstr FPSCR, \[r2, #-8\] +0+.* <[^>]*> eda2 2f82 vstr FPSCR, \[r2, #8\]! +0+.* <[^>]*> eda2 2f82 vstr FPSCR, \[r2, #8\]! +0+.* <[^>]*> ed22 2f82 vstr FPSCR, \[r2, #-8\]! +0+.* <[^>]*> eca2 2f82 vstr FPSCR, \[r2\], #8 +0+.* <[^>]*> eca2 2f82 vstr FPSCR, \[r2\], #8 +0+.* <[^>]*> ec22 2f82 vstr FPSCR, \[r2\], #-8 +0+.* <[^>]*> ed83 4f80 vstr FPSCR_nzcvqc, \[r3\] +0+.* <[^>]*> edc3 8f80 vstr VPR, \[r3\] +0+.* <[^>]*> edc3 af80 vstr P0, \[r3\] +0+.* <[^>]*> edc3 cf80 vstr FPCXTNS, \[r3\] +0+.* <[^>]*> edc3 ef80 vstr FPCXTS, \[r3\] +0+.* <[^>]*> bfa8 it ge +0+.* <[^>]*> edc3 ef80 vstrge FPCXTS, \[r3\] #... diff --git a/gas/testsuite/gas/arm/archv8m_1m-cmse-main.s b/gas/testsuite/gas/arm/archv8m_1m-cmse-main.s index f4df2dbb2f7666c4c762a9b62463d809ba91577e..9a20e1e4fe7ab1e497d83da13f288f1efcfc6a0c 100644 --- a/gas/testsuite/gas/arm/archv8m_1m-cmse-main.s +++ b/gas/testsuite/gas/arm/archv8m_1m-cmse-main.s @@ -18,3 +18,37 @@ 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 + +vldr FPSCR, [r2] @ Accepts offset variant without immediate +vldr FPSCR, [r2, #8] @ Likewise but with immediate without sign +vldr FPSCR, [r2, #+8] @ Likewise but with positive sign +vldr FPSCR, [r2, #-8] @ Likewise but with negative sign +vldr FPSCR, [r2, #8]! @ Accepts pre-index variant with immediate without sign +vldr FPSCR, [r2, #+8]! @ Likewise but with positive sign +vldr FPSCR, [r2, #-8]! @ Likewise but with negative sign +vldr FPSCR, [r2], #8 @ Accepts post-index variant with immediate without sign +vldr FPSCR, [r2], #+8 @ Likewise but with positive sign +vldr FPSCR, [r2], #-8 @ Likewise but with negative sign +vldr FPSCR_nzcvqc, [r3] @ Accepts FPSCR_nzcvqc system register +vldr VPR, [r3] @ Accepts VPR system register +vldr P0, [r3] @ Accepts P0 system register +vldr FPCXTNS, [r3] @ Accepts FPCXTNS system register +vldr FPCXTS, [r3] @ Accepts FPCXTS system register +vldrge FPCXTS, [r3] @ Accepts conditional execution + +vstr FPSCR, [r2] @ Accepts offset variant without immediate +vstr FPSCR, [r2, #8] @ Likewise but with immediate without sign +vstr FPSCR, [r2, #+8] @ Likewise but with positive sign +vstr FPSCR, [r2, #-8] @ Likewise but with negative sign +vstr FPSCR, [r2, #8]! @ Accepts pre-index variant with immediate without sign +vstr FPSCR, [r2, #+8]! @ Likewise but with positive sign +vstr FPSCR, [r2, #-8]! @ Likewise but with negative sign +vstr FPSCR, [r2], #8 @ Accepts post-index variant with immediate without sign +vstr FPSCR, [r2], #+8 @ Likewise but with positive sign +vstr FPSCR, [r2], #-8 @ Likewise but with negative sign +vstr FPSCR_nzcvqc, [r3] @ Accepts FPSCR_nzcvqc system register +vstr VPR, [r3] @ Accepts VPR system register +vstr P0, [r3] @ Accepts P0 system register +vstr FPCXTNS, [r3] @ Accepts FPCXTNS system register +vstr FPCXTS, [r3] @ Accepts FPCXTS system register +vstrge FPCXTS, [r3] @ Accepts conditional execution diff --git a/opcodes/arm-dis.c b/opcodes/arm-dis.c index cf11e616eaa50acdc546adfd9c92740770b27177..6a02ad0b3d92903a03b5d2e6b49c0a1b643f5008 100644 --- a/opcodes/arm-dis.c +++ b/opcodes/arm-dis.c @@ -112,6 +112,8 @@ struct opcode16 %B print vstm/vldm register list %C print vscclrm register list %I print cirrus signed shift immediate: bits 0..3|4..6 + %J print register for VLDR instruction + %K print address for VLDR instruction %F print the COUNT field of a LFM/SFM instruction. %P print floating point precision in arithmetic insn %Q print floating point precision in ldf/stf insn @@ -472,6 +474,10 @@ static const struct sopcode32 coprocessor_opcodes[] = 0x0d000a00, 0x0f300f00, "vstr%c\t%y1, %A"}, {ANY, ARM_FEATURE_COPROC (FPU_VFP_EXT_V1xD), 0x0d100a00, 0x0f300f00, "vldr%c\t%y1, %A"}, + {ANY, ARM_FEATURE_COPROC (ARM_EXT2_V8_1M_MAIN), + 0xec100f80, 0xfe101f80, "vldr%c\t%J, %K"}, + {ANY, ARM_FEATURE_COPROC (ARM_EXT2_V8_1M_MAIN), + 0xec000f80, 0xfe101f80, "vstr%c\t%J, %K"}, {ANY, ARM_FEATURE_COPROC (FPU_VFP_EXT_V1xD), 0x0d200b01, 0x0fb00f01, "fstmdbx%c\t%16-19r!, %z3\t;@ Deprecated"}, @@ -3463,6 +3469,8 @@ print_insn_coprocessor (bfd_vma pc, int cp_num; struct arm_private_data *private_data = info->private_data; arm_feature_set allowed_arches = ARM_ARCH_NONE; + arm_feature_set arm_ext_v8_1m_main = + ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_1M_MAIN); allowed_arches = private_data->features; @@ -3558,23 +3566,34 @@ print_insn_coprocessor (bfd_vma pc, /* Floating-point instructions. */ if (cp_num == 9 || cp_num == 10 || cp_num == 11) continue; + + /* Armv8.1-M Mainline FP & MVE instructions. */ + if (ARM_CPU_HAS_FEATURE (arm_ext_v8_1m_main, allowed_arches) + && !ARM_CPU_IS_ANY (allowed_arches) + && (cp_num == 8 || cp_num == 14 || cp_num == 15)) + continue; } for (c = insn->assembler; *c; c++) { if (*c == '%') { - switch (*++c) + const char mod = *++c; + switch (mod) { case '%': func (stream, "%%"); break; case 'A': + case 'K': { int rn = (given >> 16) & 0xf; bfd_vma offset = given & 0xff; + if (mod == 'K') + offset = given & 0x7f; + func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]); if (PRE_BIT_SET || WRITEBACK_BIT_SET) @@ -3706,6 +3725,37 @@ print_insn_coprocessor (bfd_vma pc, break; + case 'J': + { + int regno = ((given >> 19) & 0x8) | ((given >> 13) & 0x7); + + switch (regno) + { + case 0x1: + func (stream, "FPSCR"); + break; + case 0x2: + func (stream, "FPSCR_nzcvqc"); + break; + case 0xc: + func (stream, "VPR"); + break; + case 0xd: + func (stream, "P0"); + break; + case 0xe: + func (stream, "FPCXTNS"); + break; + case 0xf: + func (stream, "FPCXTS"); + break; + default: + func (stream, "", regno); + break; + } + } + break; + case 'F': switch (given & 0x00408000) {