op = 0xffff << (reg - 1);
if (reg > 0
- || ((mask & op) == (1u << (reg - 1))))
+ && ((mask & op) == (1u << (reg - 1))))
{
op = (1 << (reg + i + 1)) - 1;
op &= ~((1 << reg) - 1);
case OP_NILO:
{
po_reg_or_goto (REG_TYPE_NDQ, try_imm);
+ inst.operands[i].present = 1;
i++;
skip_past_comma (&str);
po_reg_or_goto (REG_TYPE_NDQ, one_reg_only);
neon_dyadic_misc (NT_unsigned, N_SUF_32, 0);
}
-static void
-do_neon_dyadic_if_i (void)
-{
- neon_dyadic_misc (NT_unsigned, N_IF_32, 0);
-}
-
static void
do_neon_dyadic_if_i_d (void)
{
- neon_dyadic_misc (NT_unsigned, N_IF_32, 0);
+ /* The "untyped" case can't happen. Do this to stop the "U" bit being
+ affected if we specify unsigned args. */
+ neon_dyadic_misc (NT_untyped, N_IF_32, 0);
}
enum vfp_or_neon_is_neon_bits
neon_mul_mac (et, neon_quad (rs));
}
else
- do_neon_dyadic_if_i ();
+ {
+ /* The "untyped" case can't happen. Do this to stop the "U" bit being
+ affected if we specify unsigned args. */
+ neon_dyadic_misc (NT_untyped, N_IF_32, 0);
+ }
}
static void
{
struct neon_type_el et = neon_check_type (3, NS_QDD,
N_EQK | N_DBL, N_EQK, N_I16 | N_I32 | N_I64 | N_KEY);
+ /* Operand sign is unimportant, and the U bit is part of the opcode,
+ so force the operand type to integer. */
+ et.type = NT_integer;
neon_mixed_length (et, et.size / 2);
}
const struct asm_opcode *opcode;
const struct asm_cond *cond;
char save[2];
+ bfd_boolean neon_supported;
+
+ neon_supported = ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_v1);
/* Scan up to the end of the mnemonic, which must end in white space,
- '.' (in unified mode only), or end of string. */
+ '.' (in unified mode, or for Neon instructions), or end of string. */
for (base = end = *str; *end != '\0'; end++)
- if (*end == ' ' || (unified_syntax && *end == '.'))
+ if (*end == ' ' || ((unified_syntax || neon_supported) && *end == '.'))
break;
if (end == base)
{
int offset = 2;
- if (end[1] == 'w')
+ /* The .w and .n suffixes are only valid if the unified syntax is in
+ use. */
+ if (unified_syntax && end[1] == 'w')
inst.size_req = 4;
- else if (end[1] == 'n')
+ else if (unified_syntax && end[1] == 'n')
inst.size_req = 2;
else
offset = 0;
if (end[offset] == '.')
{
- /* See if we have a Neon type suffix. */
+ /* See if we have a Neon type suffix (possible in either unified or
+ non-unified ARM syntax mode). */
if (parse_neon_type (&inst.vectype, str) == FAIL)
return 0;
}
ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
arm_ext_v6t2);
}
- else
+ else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1))
{
/* Check that this instruction is supported for this CPU. */
if (!opcode->avariant ||
ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used,
*opcode->avariant);
}
+ else
+ {
+ as_bad (_("attempt to use an ARM instruction on a Thumb-only processor "
+ "-- `%s'"), str);
+ return;
+ }
output_inst (str);
}
UT(cbnz, b900, 2, (RR, EXP), t_czb),
UT(cbz, b100, 2, (RR, EXP), t_czb),
- /* ARM does not really have an IT instruction. */
+ /* ARM does not really have an IT instruction, so always allow it. */
+#undef ARM_VARIANT
+#define ARM_VARIANT &arm_ext_v1
TUE(it, 0, bf08, 1, (COND), it, t_it),
TUE(itt, 0, bf0c, 1, (COND), it, t_it),
TUE(ite, 0, bf04, 1, (COND), it, t_it),
nUF(vcltq, vclt, 3, (RNQ, oRNQ, RNDQ_I0), neon_cmp_inv),
nUF(vcle, vcle, 3, (RNDQ, oRNDQ, RNDQ_I0), neon_cmp_inv),
nUF(vcleq, vcle, 3, (RNQ, oRNQ, RNDQ_I0), neon_cmp_inv),
- /* Comparison. Type I8 I16 I32 F32. Non-immediate -> neon_dyadic_if_i. */
+ /* Comparison. Type I8 I16 I32 F32. */
nUF(vceq, vceq, 3, (RNDQ, oRNDQ, RNDQ_I0), neon_ceq),
nUF(vceqq, vceq, 3, (RNQ, oRNQ, RNDQ_I0), neon_ceq),
/* As above, D registers only. */
nUF(vpmax, vpmax, 3, (RND, oRND, RND), neon_dyadic_if_su_d),
nUF(vpmin, vpmin, 3, (RND, oRND, RND), neon_dyadic_if_su_d),
/* Int and float variants, signedness unimportant. */
- /* If not scalar, fall back to neon_dyadic_if_i. */
nUF(vmlaq, vmla, 3, (RNQ, oRNQ, RNDQ_RNSC), neon_mac_maybe_scalar),
nUF(vmlsq, vmls, 3, (RNQ, oRNQ, RNDQ_RNSC), neon_mac_maybe_scalar),
nUF(vpadd, vpadd, 3, (RND, oRND, RND), neon_dyadic_if_i_d),
abort ();
}
+/* Auto-select Thumb mode if it's the only available instruction set for the
+ given architecture. */
+
+static void
+autoselect_thumb_from_cpu_variant (void)
+{
+ if (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1))
+ opcode_select (16);
+}
+
void
md_begin (void)
{
ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
+ autoselect_thumb_from_cpu_variant ();
+
arm_arch_used = thumb_arch_used = arm_arch_none;
#if defined OBJ_COFF || defined OBJ_ELF