static bfd_boolean
using_thumb_only (struct elf32_arm_link_hash_table *globals)
{
- int arch = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC,
- Tag_CPU_arch);
- int profile;
++ int arch;
+ int profile = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC,
+ Tag_CPU_arch_profile);
- return profile == 'M';
- if (arch == TAG_CPU_ARCH_V6_M || arch == TAG_CPU_ARCH_V6S_M)
- return TRUE;
++ if (profile)
++ return profile == 'M';
+
- if (arch != TAG_CPU_ARCH_V7 && arch != TAG_CPU_ARCH_V7E_M)
- return FALSE;
++ arch = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC, Tag_CPU_arch);
+
- profile = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC,
- Tag_CPU_arch_profile);
++ if (arch == TAG_CPU_ARCH_V6_M
++ || arch == TAG_CPU_ARCH_V6S_M
++ || arch == TAG_CPU_ARCH_V7E_M
++ || arch == TAG_CPU_ARCH_V8M_BASE
++ || arch == TAG_CPU_ARCH_V8M_MAIN)
++ return TRUE;
+
- return profile == 'M';
++ return FALSE;
}
/* Determine if we're dealing with a Thumb-2 object. */
T(V8), /* V7E_M. */
T(V8) /* V8. */
};
- T(V8M_BASE), /* V8-M BASELINE. */
+ const int v8m_baseline[] =
+ {
+ -1, /* PRE_V4. */
+ -1, /* V4. */
+ -1, /* V4T. */
+ -1, /* V5T. */
+ -1, /* V5TE. */
+ -1, /* V5TEJ. */
+ -1, /* V6. */
+ -1, /* V6KZ. */
+ -1, /* V6T2. */
+ -1, /* V6K. */
+ -1, /* V7. */
+ T(V8M_BASE), /* V6_M. */
+ T(V8M_BASE), /* V6S_M. */
+ -1, /* V7E_M. */
+ -1, /* V8. */
+ -1,
- T(V8M_MAIN), /* V8-M MAINLINE. */
++ T(V8M_BASE) /* V8-M BASELINE. */
+ };
+ const int v8m_mainline[] =
+ {
+ -1, /* PRE_V4. */
+ -1, /* V4. */
+ -1, /* V4T. */
+ -1, /* V5T. */
+ -1, /* V5TE. */
+ -1, /* V5TEJ. */
+ -1, /* V6. */
+ -1, /* V6KZ. */
+ -1, /* V6T2. */
+ -1, /* V6K. */
+ T(V8M_MAIN), /* V7. */
+ T(V8M_MAIN), /* V6_M. */
+ T(V8M_MAIN), /* V6S_M. */
+ T(V8M_MAIN), /* V7E_M. */
+ -1, /* V8. */
+ -1,
+ T(V8M_MAIN), /* V8-M BASELINE. */
++ T(V8M_MAIN) /* V8-M MAINLINE. */
+ };
const int v4t_plus_v6_m[] =
{
-1, /* PRE_V4. */
T(V6S_M), /* V6S_M. */
T(V7E_M), /* V7E_M. */
T(V8), /* V8. */
- T(V4T_PLUS_V6_M), /* V4T plus V6_M. */
- -1, /* V8-M BASELINE. */
- -1 /* V8-M MAINLINE. */
++ -1, /* Unused. */
++ T(V8M_BASE), /* V8-M BASELINE. */
++ T(V8M_MAIN), /* V8-M MAINLINE. */
+ T(V4T_PLUS_V6_M) /* V4T plus V6_M. */
};
const int *comb[] =
{
v6s_m,
v7e_m,
v8,
- v4t_plus_v6_m, /* Pseudo-architecture. */
++ NULL,
+ v8m_baseline,
+ v8m_mainline,
+ /* Pseudo-architecture. */
+ v4t_plus_v6_m
};
/* Check we've not got a higher architecture than we know about. */
if (tagh <= TAG_CPU_ARCH_V6KZ)
return result;
-- result = comb[tagh - T(V6T2)][tagl];
++ result = comb[tagh - T(V6T2)] ? comb[tagh - T(V6T2)][tagl] : -1;
/* Use Tag_CPU_arch == V4T and Tag_also_compatible_with (Tag_CPU_arch V6_M)
as the canonical version. */
return now_it.state != OUTSIDE_IT_BLOCK;
}
- /* Given an OPCODE that is valid in at least one architecture that is not a
- superset of ARMv6t2, returns whether it only has wide encoding(s). */
++/* Whether OPCODE only has T32 encoding. Since this function is only used by
++ t32_insn_ok, OPCODE enabled by v6t2 extension bit do not need to be listed
++ here, hence the "known" in the function name. */
+
+static bfd_boolean
- non_v6t2_wide_only_insn (const struct asm_opcode *opcode)
++known_t32_only_insn (const struct asm_opcode *opcode)
+{
- /* Wide instruction that have always been in Thumb-1 ISA. */
++ /* Original Thumb-1 wide instruction. */
+ if (opcode->tencode == do_t_blx
+ || opcode->tencode == do_t_branch23
+ || ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_msr)
+ || ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_barrier))
+ return TRUE;
+
+ /* Wide-only instruction added to ARMv8-M. */
+ if (ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_v8m)
+ || ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_atomics)
+ || ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_v6t2_v8m)
+ || ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_div))
+ return TRUE;
+
+ return FALSE;
+}
+
+/* Whether wide instruction variant can be used if available for a valid OPCODE
+ in ARCH. */
+
+static bfd_boolean
- wide_insn_ok (arm_feature_set arch, const struct asm_opcode *opcode)
++t32_insn_ok (arm_feature_set arch, const struct asm_opcode *opcode)
+{
- if (non_v6t2_wide_only_insn (opcode))
++ if (known_t32_only_insn (opcode))
+ return TRUE;
+
+ /* Instruction with narrow and wide encoding added to ARMv8-M. Availability
+ of variant T3 of B.W is checked in do_t_branch. */
+ if (ARM_CPU_HAS_FEATURE (arch, arm_ext_v8m)
+ && opcode->tencode == do_t_branch)
+ return TRUE;
+
+ /* Wide instruction variants of all instructions with narrow *and* wide
+ variants become available with ARMv6t2. Other opcodes are either
+ narrow-only or wide-only and are thus available if OPCODE is valid. */
+ if (ARM_CPU_HAS_FEATURE (arch, arm_ext_v6t2))
+ return TRUE;
+
+ /* OPCODE with narrow only instruction variant or wide variant not
+ available. */
+ return FALSE;
+}
+
void
md_assemble (char *str)
{
return;
}
- if (!ARM_CPU_HAS_FEATURE (variant, arm_ext_v6t2))
+ /* Two things are addressed here:
+ 1) Implicit require narrow instructions on Thumb-1.
+ This avoids relaxation accidentally introducing Thumb-2
+ instructions.
+ 2) Reject wide instructions in non Thumb-2 cores.
+
+ Only instructions with narrow and wide variants need to be handled
+ but selecting all non wide-only instructions is easier. */
+ if (!ARM_CPU_HAS_FEATURE (variant, arm_ext_v6t2)
- && !wide_insn_ok (variant, opcode))
++ && !t32_insn_ok (variant, opcode))
{
- if (opcode->tencode != do_t_blx && opcode->tencode != do_t_branch23
- && !(ARM_CPU_HAS_FEATURE(*opcode->tvariant, arm_ext_msr)
- || ARM_CPU_HAS_FEATURE(*opcode->tvariant, arm_ext_barrier)))
+ if (inst.size_req == 0)
+ inst.size_req = 2;
+ else if (inst.size_req == 4)
{
- /* Two things are addressed here.
- 1) Implicit require narrow instructions on Thumb-1.
- This avoids relaxation accidentally introducing Thumb-2
- instructions.
- 2) Reject wide instructions in non Thumb-2 cores. */
- if (inst.size_req == 0)
- inst.size_req = 2;
- else if (inst.size_req == 4)
- {
- as_bad (_("selected processor does not support `%s' in Thumb-2 mode"), str);
- return;
- }
+ if (ARM_CPU_HAS_FEATURE (variant, arm_ext_v8m))
+ as_bad (_("selected processor does not support 32bit wide "
+ "variant of instruction `%s'"), str);
+ else
+ as_bad (_("selected processor does not support `%s' in "
+ "Thumb-2 mode"), str);
+ return;
}
}
ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
*opcode->tvariant);
/* Many Thumb-2 instructions also have Thumb-1 variants, so explicitly
- set those bits when Thumb-2 32-bit instructions are seen. ie.
- anything other than bl/blx and v6-M instructions.
- The impact of relaxable instructions will be considered later after we
- finish all relaxation. */
- if ((inst.size == 4 && (inst.instruction & 0xf800e800) != 0xf000e800)
- && !(ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_msr)
- || ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_barrier)))
+ set those bits when Thumb-2 32-bit instructions are seen. The impact
+ of relaxable instructions will be considered later after we finish all
+ relaxation. */
+ if (ARM_FEATURE_CORE_EQUAL (cpu_variant, arm_arch_any))
+ variant = arm_arch_none;
+ else
+ variant = cpu_variant;
- if (inst.size == 4 && !wide_insn_ok (variant, opcode))
++ if (inst.size == 4 && !t32_insn_ok (variant, opcode))
ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
arm_ext_v6t2);
actually used. Perhaps we should separate out the specified
and implicit cases. Avoid taking this path for -march=all by
checking for contradictory v7-A / v7-M features. */
-- if (arch == 10
++ if (arch == TAG_CPU_ARCH_V7
&& !ARM_CPU_HAS_FEATURE (flags, arm_ext_v7a)
&& ARM_CPU_HAS_FEATURE (flags, arm_ext_v7m)
&& ARM_CPU_HAS_FEATURE (flags, arm_ext_v6_dsp))
- arch = 13;
+ {
- arch = 13;
++ arch = TAG_CPU_ARCH_V7E_M;
+ arm_arch = (arm_feature_set) ARM_ARCH_V7EM;
+ }
+
+ ARM_CLEAR_FEATURE (tmp, flags, arm_arch_v8m_base);
- if (arch == 16 && ARM_CPU_HAS_FEATURE (tmp, arm_arch_any))
++ if (arch == TAG_CPU_ARCH_V8M_BASE && ARM_CPU_HAS_FEATURE (tmp, arm_arch_any))
+ {
- arch = 17;
++ arch = TAG_CPU_ARCH_V8M_MAIN;
+ arm_arch = (arm_feature_set) ARM_ARCH_V8M_MAIN;
+ }
+
+ /* In cpu_arch_ver ARMv8-A is before ARMv8-M for atomics to be detected as
+ coming from ARMv8-A. However, since ARMv8-A has more instructions than
+ ARMv8-M, -march=all must be detected as ARMv8-A. */
- if (arch == 17 && ARM_FEATURE_CORE_EQUAL (selected_cpu, arm_arch_any))
++ if (arch == TAG_CPU_ARCH_V8M_MAIN
++ && ARM_FEATURE_CORE_EQUAL (selected_cpu, arm_arch_any))
+ {
- arch = 14;
++ arch = TAG_CPU_ARCH_V8;
+ arm_arch = (arm_feature_set) ARM_ARCH_V8A;
+ }
/* Tag_CPU_name. */
if (selected_cpu_name[0])
#define ARM_EXT_V5J 0x00000800 /* Jazelle extension. */
#define ARM_EXT_V6 0x00001000 /* ARM V6. */
#define ARM_EXT_V6K 0x00002000 /* ARM V6K. */
--/* 0x00004000 Was ARM V6Z. */
- #define ARM_EXT_V8 0x00004000 /* is now ARMv8 w/o atomics. */
-#define ARM_EXT_V8 0x00004000 /* is now ARMv8. */
++#define ARM_EXT_V8 0x00004000 /* ARMv8 w/o atomics. */
#define ARM_EXT_V6T2 0x00008000 /* Thumb-2. */
#define ARM_EXT_DIV 0x00010000 /* Integer division. */
/* The 'M' in Arm V7M stands for Microcontroller.
#define ARM_ARCH_V6K ARM_FEATURE_CORE_LOW (ARM_AEXT_V6K)
#define ARM_ARCH_V6Z ARM_FEATURE_CORE_LOW (ARM_AEXT_V6Z)
#define ARM_ARCH_V6KZ ARM_FEATURE_CORE_LOW (ARM_AEXT_V6KZ)
-#define ARM_ARCH_V6T2 ARM_FEATURE_CORE_LOW (ARM_AEXT_V6T2)
-#define ARM_ARCH_V6KT2 ARM_FEATURE_CORE_LOW (ARM_AEXT_V6KT2)
-#define ARM_ARCH_V6ZT2 ARM_FEATURE_CORE_LOW (ARM_AEXT_V6ZT2)
-#define ARM_ARCH_V6KZT2 ARM_FEATURE_CORE_LOW (ARM_AEXT_V6KZT2)
+#define ARM_ARCH_V6T2 ARM_FEATURE_CORE (ARM_AEXT_V6T2, ARM_EXT2_V6T2_V8M)
+#define ARM_ARCH_V6KT2 ARM_FEATURE_CORE (ARM_AEXT_V6KT2, ARM_EXT2_V6T2_V8M)
+#define ARM_ARCH_V6ZT2 ARM_FEATURE_CORE (ARM_AEXT_V6ZT2, ARM_EXT2_V6T2_V8M)
+#define ARM_ARCH_V6KZT2 ARM_FEATURE_CORE (ARM_AEXT_V6KZT2, ARM_EXT2_V6T2_V8M)
#define ARM_ARCH_V6M ARM_FEATURE_CORE_LOW (ARM_AEXT_V6M)
#define ARM_ARCH_V6SM ARM_FEATURE_CORE_LOW (ARM_AEXT_V6SM)
-#define ARM_ARCH_V7 ARM_FEATURE_CORE_LOW (ARM_AEXT_V7)
-#define ARM_ARCH_V7A ARM_FEATURE_CORE_LOW (ARM_AEXT_V7A)
-#define ARM_ARCH_V7VE ARM_FEATURE_CORE_LOW (ARM_AEXT_V7VE)
-#define ARM_ARCH_V7R ARM_FEATURE_CORE_LOW (ARM_AEXT_V7R)
-#define ARM_ARCH_V7M ARM_FEATURE_CORE_LOW (ARM_AEXT_V7M)
-#define ARM_ARCH_V7EM ARM_FEATURE_CORE_LOW (ARM_AEXT_V7EM)
-#define ARM_ARCH_V8A ARM_FEATURE_CORE_LOW (ARM_AEXT_V8A)
-#define ARM_ARCH_V8_1A ARM_FEATURE_CORE (ARM_AEXT_V8A, ARM_EXT2_PAN)
+#define ARM_ARCH_V7 ARM_FEATURE_CORE (ARM_AEXT_V7, ARM_EXT2_V6T2_V8M)
+#define ARM_ARCH_V7A ARM_FEATURE_CORE (ARM_AEXT_V7A, ARM_EXT2_V6T2_V8M)
+#define ARM_ARCH_V7VE ARM_FEATURE_CORE (ARM_AEXT_V7VE, ARM_EXT2_V6T2_V8M)
+#define ARM_ARCH_V7R ARM_FEATURE_CORE (ARM_AEXT_V7R, ARM_EXT2_V6T2_V8M)
+#define ARM_ARCH_V7M ARM_FEATURE_CORE (ARM_AEXT_V7M, ARM_EXT2_V6T2_V8M)
+#define ARM_ARCH_V7EM ARM_FEATURE_CORE (ARM_AEXT_V7EM, ARM_EXT2_V6T2_V8M)
+#define ARM_ARCH_V8A ARM_FEATURE_CORE (ARM_AEXT_V8A, ARM_AEXT2_V8A)
- #define ARM_ARCH_V8_1A ARM_FEATURE_CORE (ARM_AEXT_V8A, ARM_AEXT2_V8_1A)
++#define ARM_ARCH_V8_1A ARM_FEATURE (ARM_AEXT_V8A, ARM_AEXT2_V8_1A, \
++ CRC_EXT_ARMV8)
+#define ARM_ARCH_V8M_BASE ARM_FEATURE_CORE (ARM_AEXT_V8M_BASE, ARM_AEXT2_V8M)
+#define ARM_ARCH_V8M_MAIN ARM_FEATURE_CORE (ARM_AEXT_V8M_MAIN, ARM_AEXT2_V8M)
/* Some useful combinations: */
#define ARM_ARCH_NONE ARM_FEATURE_LOW (0, 0)