#define BAD_RANGE _("branch out of range")
#define BAD_FP16 _("selected processor does not support fp16 instruction")
#define UNPRED_REG(R) _("using " R " results in unpredictable behaviour")
+#define THUMB1_RELOC_ONLY _("relocation valid in thumb1 code only")
static struct hash_control * arm_ops_hsh;
static struct hash_control * arm_cond_hsh;
nlen = strlen (newname);
#endif
- nbuf = (char *) alloca (nlen + 1);
+ nbuf = xmalloc (nlen + 1);
memcpy (nbuf, newname, nlen);
nbuf[nlen] = '\0';
the artificial FOO alias because it has already been created by the
first .req. */
if (insert_reg_alias (nbuf, old->number, old->type) == NULL)
- return TRUE;
+ {
+ free (nbuf);
+ return TRUE;
+ }
}
for (p = nbuf; *p; p++)
insert_reg_alias (nbuf, old->number, old->type);
}
+ free (nbuf);
return TRUE;
}
namelen = strlen (newname);
#endif
- namebuf = (char *) alloca (namelen + 1);
+ namebuf = xmalloc (namelen + 1);
strncpy (namebuf, newname, namelen);
namebuf[namelen] = '\0';
insert_neon_reg_alias (namebuf, basereg->number, basetype,
typeinfo.defined != 0 ? &typeinfo : NULL);
+ free (namebuf);
return TRUE;
}
if (S_IS_LOCAL (symbolP) || name[0] == '.')
return symbolP;
- real_start = ACONCAT ((STUB_NAME, name, NULL));
+ real_start = concat (STUB_NAME, name, NULL);
new_target = symbol_find (real_start);
+ free (real_start);
if (new_target == NULL)
{
XXX Surely there is a cleaner way to do this. */
char *p = input_line_pointer;
int offset;
- char *save_buf = (char *) alloca (input_line_pointer - base);
+ char *save_buf = xmalloc (input_line_pointer - base);
+
memcpy (save_buf, base, input_line_pointer - base);
memmove (base + (input_line_pointer - before_reloc),
base, before_reloc - base);
memset (p, 0, nbytes);
fix_new_exp (frag_now, p - frag_now->fr_literal + offset,
size, &exp, 0, (enum bfd_reloc_code_real) reloc);
+ free (save_buf);
}
}
}
static void
do_arit (void)
{
+ constraint (inst.reloc.type >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
+ && inst.reloc.type <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC ,
+ THUMB1_RELOC_ONLY);
if (!inst.operands[1].present)
inst.operands[1].reg = inst.operands[0].reg;
inst.instruction |= inst.operands[0].reg << 12;
static void
do_mov (void)
{
+ constraint (inst.reloc.type >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
+ && inst.reloc.type <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC ,
+ THUMB1_RELOC_ONLY);
inst.instruction |= inst.operands[0].reg << 12;
encode_arm_shifter_operand (1);
}
inst.instruction |= (Rd << 4) | Rs;
if (inst.reloc.type < BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
|| inst.reloc.type > BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC)
- inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
- if (inst.size_req != 2)
- inst.relax = opcode;
+ {
+ if (inst.size_req == 2)
+ inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
+ else
+ inst.relax = opcode;
+ }
}
else
constraint (inst.size_req == 2, BAD_HIREG);
if (inst.size_req == 4
|| (inst.size_req != 2 && !opcode))
{
+ constraint (inst.reloc.type >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
+ && inst.reloc.type <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC ,
+ THUMB1_RELOC_ONLY);
if (Rd == REG_PC)
{
constraint (add, BAD_PC);
{
inst.instruction = THUMB_OP16 (opcode);
inst.instruction |= Rn << 8;
- if (inst.size_req == 2)
+ if (inst.reloc.type < BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
+ || inst.reloc.type > BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC)
{
- if (inst.reloc.type < BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
- || inst.reloc.type > BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC)
+ if (inst.size_req == 2)
inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM;
+ else
+ inst.relax = opcode;
}
- else
- inst.relax = opcode;
}
else
{
+ constraint (inst.reloc.type >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
+ && inst.reloc.type <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC ,
+ THUMB1_RELOC_ONLY);
+
inst.instruction = THUMB_OP32 (inst.instruction);
inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
inst.instruction |= Rn << r0off;
#define N_SU_ALL (N_S8 | N_S16 | N_S32 | N_S64 | N_U8 | N_U16 | N_U32 | N_U64)
#define N_SU_32 (N_S8 | N_S16 | N_S32 | N_U8 | N_U16 | N_U32)
#define N_SU_16_64 (N_S16 | N_S32 | N_S64 | N_U16 | N_U32 | N_U64)
-#define N_SUF_32 (N_SU_32 | N_F32)
+#define N_S_32 (N_S8 | N_S16 | N_S32)
+#define N_F_16_32 (N_F16 | N_F32)
+#define N_SUF_32 (N_SU_32 | N_F_16_32)
#define N_I_ALL (N_I8 | N_I16 | N_I32 | N_I64)
-#define N_IF_32 (N_I8 | N_I16 | N_I32 | N_F32)
+#define N_IF_32 (N_I8 | N_I16 | N_I32 | N_F16 | N_F32)
#define N_F_ALL (N_F16 | N_F32 | N_F64)
/* Pass this as the first type argument to neon_check_type to ignore types
k_type = g_type;
k_size = g_size;
key_allowed = thisarg & ~N_KEY;
+
+ /* Check architecture constraint on FP16 extension. */
+ if (k_size == 16
+ && k_type == NT_float
+ && ! ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_fp16))
+ {
+ inst.error = _(BAD_FP16);
+ return badtype;
+ }
}
}
else
if (et.type == NT_float)
{
NEON_ENCODE (FLOAT, inst);
- neon_three_same (neon_quad (rs), 0, -1);
+ neon_three_same (neon_quad (rs), 0, et.size == 16 ? (int) et.size : -1);
}
else
{
static void
neon_exchange_operands (void)
{
- void *scratch = alloca (sizeof (inst.operands[0]));
if (inst.operands[1].present)
{
+ void *scratch = xmalloc (sizeof (inst.operands[0]));
+
/* Swap operands[1] and operands[2]. */
memcpy (scratch, &inst.operands[1], sizeof (inst.operands[0]));
inst.operands[1] = inst.operands[2];
memcpy (&inst.operands[2], scratch, sizeof (inst.operands[0]));
+ free (scratch);
}
else
{
static void
do_neon_cmp (void)
{
- neon_compare (N_SUF_32, N_S8 | N_S16 | N_S32 | N_F32, FALSE);
+ neon_compare (N_SUF_32, N_S_32 | N_F_16_32, FALSE);
}
static void
do_neon_cmp_inv (void)
{
- neon_compare (N_SUF_32, N_S8 | N_S16 | N_S32 | N_F32, TRUE);
+ neon_compare (N_SUF_32, N_S_32 | N_F_16_32, TRUE);
}
static void
if (inst.operands[2].isscalar)
do_neon_mac_maybe_scalar ();
else
- neon_dyadic_misc (NT_poly, N_I8 | N_I16 | N_I32 | N_F32 | N_P8, 0);
+ neon_dyadic_misc (NT_poly, N_I8 | N_I16 | N_I32 | N_F16 | N_F32 | N_P8, 0);
}
static void
do_neon_fcmp_absolute (void)
{
enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
- neon_check_type (3, rs, N_EQK, N_EQK, N_F32 | N_KEY);
+ struct neon_type_el et = neon_check_type (3, rs, N_EQK, N_EQK,
+ N_F_16_32 | N_KEY);
/* Size field comes from bit mask. */
- neon_three_same (neon_quad (rs), 1, -1);
+ neon_three_same (neon_quad (rs), 1, et.size == 16 ? (int) et.size : -1);
}
static void
do_neon_step (void)
{
enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
- neon_check_type (3, rs, N_EQK, N_EQK, N_F32 | N_KEY);
- neon_three_same (neon_quad (rs), 0, -1);
+ struct neon_type_el et = neon_check_type (3, rs, N_EQK, N_EQK,
+ N_F_16_32 | N_KEY);
+ neon_three_same (neon_quad (rs), 0, et.size == 16 ? (int) et.size : -1);
}
static void
return;
rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
- et = neon_check_type (2, rs, N_EQK, N_S8 | N_S16 | N_S32 | N_F32 | N_KEY);
+ et = neon_check_type (2, rs, N_EQK, N_S_32 | N_F_16_32 | N_KEY);
inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
inst.instruction |= HI1 (inst.operands[0].reg) << 22;
CVT_VAR (f32_s32, N_F32, N_S32, whole_reg, "fsltos", "fsitos", NULL) \
CVT_VAR (f32_u32, N_F32, N_U32, whole_reg, "fultos", "fuitos", NULL) \
/* Half-precision conversions. */ \
+ CVT_VAR (s16_f16, N_S16, N_F16 | N_KEY, whole_reg, NULL, NULL, NULL) \
+ CVT_VAR (u16_f16, N_U16, N_F16 | N_KEY, whole_reg, NULL, NULL, NULL) \
+ CVT_VAR (f16_s16, N_F16 | N_KEY, N_S16, whole_reg, NULL, NULL, NULL) \
+ CVT_VAR (f16_u16, N_F16 | N_KEY, N_U16, whole_reg, NULL, NULL, NULL) \
CVT_VAR (f32_f16, N_F32, N_F16, whole_reg, NULL, NULL, NULL) \
CVT_VAR (f16_f32, N_F16, N_F32, whole_reg, NULL, NULL, NULL) \
/* New VCVT instructions introduced by ARMv8.2 fp16 extension. \
NS_NULL);
enum neon_cvt_flavour flavour = get_neon_cvt_flavour (rs);
+ if (flavour == neon_cvt_flavour_invalid)
+ return;
+
/* PR11109: Handle round-to-zero for VCVT conversions. */
if (mode == neon_cvt_mode_z
&& ARM_CPU_HAS_FEATURE (cpu_variant, fpu_arch_vfp_v2)
- && (flavour == neon_cvt_flavour_s32_f32
+ && (flavour == neon_cvt_flavour_s16_f16
+ || flavour == neon_cvt_flavour_u16_f16
+ || flavour == neon_cvt_flavour_s32_f32
|| flavour == neon_cvt_flavour_u32_f32
|| flavour == neon_cvt_flavour_s32_f64
|| flavour == neon_cvt_flavour_u32_f64)
case NS_QQI:
{
unsigned immbits;
- unsigned enctab[] = { 0x0000100, 0x1000100, 0x0, 0x1000000 };
+ unsigned enctab[] = {0x0000100, 0x1000100, 0x0, 0x1000000,
+ 0x0000100, 0x1000100, 0x0, 0x1000000};
if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
return;
integer conversion. */
if (inst.operands[2].present && inst.operands[2].imm == 0)
goto int_encode;
- immbits = 32 - inst.operands[2].imm;
NEON_ENCODE (IMMED, inst);
if (flavour != neon_cvt_flavour_invalid)
inst.instruction |= enctab[flavour];
inst.instruction |= HI1 (inst.operands[1].reg) << 5;
inst.instruction |= neon_quad (rs) << 6;
inst.instruction |= 1 << 21;
- inst.instruction |= immbits << 16;
+ if (flavour < neon_cvt_flavour_s16_f16)
+ {
+ inst.instruction |= 1 << 21;
+ immbits = 32 - inst.operands[2].imm;
+ inst.instruction |= immbits << 16;
+ }
+ else
+ {
+ inst.instruction |= 3 << 20;
+ immbits = 16 - inst.operands[2].imm;
+ inst.instruction |= immbits << 16;
+ inst.instruction &= ~(1 << 9);
+ }
neon_dp_fixup (&inst);
}
inst.instruction |= LOW4 (inst.operands[1].reg);
inst.instruction |= HI1 (inst.operands[1].reg) << 5;
inst.instruction |= neon_quad (rs) << 6;
- inst.instruction |= (flavour == neon_cvt_flavour_u32_f32) << 7;
+ inst.instruction |= (flavour == neon_cvt_flavour_u16_f16
+ || flavour == neon_cvt_flavour_u32_f32) << 7;
inst.instruction |= mode << 8;
+ if (flavour == neon_cvt_flavour_u16_f16
+ || flavour == neon_cvt_flavour_s16_f16)
+ /* Mask off the original size bits and reencode them. */
+ inst.instruction = ((inst.instruction & 0xfff3ffff) | (1 << 18));
+
if (thumb_mode)
inst.instruction |= 0xfc000000;
else
{
int_encode:
{
- unsigned enctab[] = { 0x100, 0x180, 0x0, 0x080 };
+ unsigned enctab[] = { 0x100, 0x180, 0x0, 0x080,
+ 0x100, 0x180, 0x0, 0x080};
NEON_ENCODE (INTEGER, inst);
inst.instruction |= LOW4 (inst.operands[1].reg);
inst.instruction |= HI1 (inst.operands[1].reg) << 5;
inst.instruction |= neon_quad (rs) << 6;
- inst.instruction |= 2 << 18;
+ if (flavour >= neon_cvt_flavour_s16_f16
+ && flavour <= neon_cvt_flavour_f16_u16)
+ /* Half precision. */
+ inst.instruction |= 1 << 18;
+ else
+ inst.instruction |= 2 << 18;
neon_dp_fixup (&inst);
}
{
enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
struct neon_type_el et = neon_check_type (2, rs,
- N_EQK | N_FLT, N_F32 | N_U32 | N_KEY);
+ N_EQK | N_FLT, N_F_16_32 | N_U32 | N_KEY);
inst.instruction |= (et.type == NT_float) << 8;
neon_two_same (neon_quad (rs), 1, et.size);
}
if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH8) == FAIL)
return;
- neon_dyadic_misc (NT_untyped, N_F32, 0);
+ neon_dyadic_misc (NT_untyped, N_F_16_32, 0);
}
static void
{
/* Neon encodings (or something broken...). */
inst.error = NULL;
- et = neon_check_type (2, rs, N_EQK, N_F32 | N_KEY);
+ et = neon_check_type (2, rs, N_EQK, N_F_16_32 | N_KEY);
if (et.type == NT_invtype)
return;
inst.instruction |= LOW4 (inst.operands[1].reg);
inst.instruction |= HI1 (inst.operands[1].reg) << 5;
inst.instruction |= neon_quad (rs) << 6;
+ /* Mask off the original size bits and reencode them. */
+ inst.instruction = ((inst.instruction & 0xfff3ffff)
+ | neon_logbits (et.size) << 18);
+
switch (mode)
{
case neon_cvt_mode_z: inst.instruction |= 3 << 7; break;
NUF(vbitq, 1200110, 3, (RNQ, RNQ, RNQ), neon_bitfield),
NUF(vbif, 1300110, 3, (RNDQ, RNDQ, RNDQ), neon_bitfield),
NUF(vbifq, 1300110, 3, (RNQ, RNQ, RNQ), neon_bitfield),
- /* Int and float variants, types S8 S16 S32 U8 U16 U32 F32. */
+ /* Int and float variants, types S8 S16 S32 U8 U16 U32 F16 F32. */
nUF(vabd, _vabd, 3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_if_su),
nUF(vabdq, _vabd, 3, (RNQ, oRNQ, RNQ), neon_dyadic_if_su),
nUF(vmax, _vmax, 3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_if_su),
NUF(vpadalq, 1b00600, 2, (RNQ, RNQ), neon_pair_long),
NUF(vpaddl, 1b00200, 2, (RNDQ, RNDQ), neon_pair_long),
NUF(vpaddlq, 1b00200, 2, (RNQ, RNQ), neon_pair_long),
- /* Reciprocal estimates. Types U32 F32. */
+ /* Reciprocal estimates. Types U32 F16 F32. */
NUF(vrecpe, 1b30400, 2, (RNDQ, RNDQ), neon_recip_est),
NUF(vrecpeq, 1b30400, 2, (RNQ, RNQ), neon_recip_est),
NUF(vrsqrte, 1b30480, 2, (RNDQ, RNDQ), neon_recip_est),
{
const char * option; /* Substring to match. */
const char * help; /* Help information. */
- int (* func) (char * subopt); /* Function to decode sub-option. */
+ int (* func) (const char * subopt); /* Function to decode sub-option. */
const char * deprecated; /* If non-null, print this message. */
};
static bfd_boolean
-arm_parse_extension (char *str, const arm_feature_set **opt_p)
+arm_parse_extension (const char *str, const arm_feature_set **opt_p)
{
arm_feature_set *ext_set = (arm_feature_set *)
xmalloc (sizeof (arm_feature_set));
while (str != NULL && *str != 0)
{
- char *ext;
+ const char *ext;
size_t len;
if (*str != '+')
}
static bfd_boolean
-arm_parse_cpu (char *str)
+arm_parse_cpu (const char *str)
{
const struct arm_cpu_option_table *opt;
- char *ext = strchr (str, '+');
+ const char *ext = strchr (str, '+');
size_t len;
if (ext != NULL)
}
static bfd_boolean
-arm_parse_arch (char *str)
+arm_parse_arch (const char *str)
{
const struct arm_arch_option_table *opt;
- char *ext = strchr (str, '+');
+ const char *ext = strchr (str, '+');
size_t len;
if (ext != NULL)
}
static bfd_boolean
-arm_parse_fpu (char * str)
+arm_parse_fpu (const char * str)
{
const struct arm_option_fpu_value_table * opt;
}
static bfd_boolean
-arm_parse_float_abi (char * str)
+arm_parse_float_abi (const char * str)
{
const struct arm_option_value_table * opt;
#ifdef OBJ_ELF
static bfd_boolean
-arm_parse_eabi (char * str)
+arm_parse_eabi (const char * str)
{
const struct arm_option_value_table *opt;
#endif
static bfd_boolean
-arm_parse_it_mode (char * str)
+arm_parse_it_mode (const char * str)
{
bfd_boolean ret = TRUE;
}
static bfd_boolean
-arm_ccs_mode (char * unused ATTRIBUTE_UNUSED)
+arm_ccs_mode (const char * unused ATTRIBUTE_UNUSED)
{
codecomposer_syntax = TRUE;
arm_comment_chars[0] = ';';
};
int
-md_parse_option (int c, char * arg)
+md_parse_option (int c, const char * arg)
{
struct arm_option_table *opt;
const struct arm_legacy_option_table *fopt;