X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-arm.c;h=8ea3ad198b7be1d4455bfdd44e85d12dd97c9331;hb=945c025aafa9f4f36cdc5bb2f1dad083fa34a6d2;hp=a0d3a6319ffac7e4e53e3f8726a7c2f33fb1ab77;hpb=f0927246c4fb95097b42d1e8ce6a79ba51f67e5a;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c index a0d3a6319f..8ea3ad198b 100644 --- a/gas/config/tc-arm.c +++ b/gas/config/tc-arm.c @@ -42,8 +42,7 @@ #include "dwarf2dbg.h" -/* XXX Set this to 1 after the next binutils release. */ -#define WARN_DEPRECATED 0 +#define WARN_DEPRECATED 1 #ifdef OBJ_ELF /* Must be at least the size of the largest unwind opcode (currently two). */ @@ -156,6 +155,7 @@ static const arm_feature_set *mcpu_fpu_opt = NULL; static const arm_feature_set *march_cpu_opt = NULL; static const arm_feature_set *march_fpu_opt = NULL; static const arm_feature_set *mfpu_opt = NULL; +static const arm_feature_set *object_arch = NULL; /* Constants for known architecture features. */ static const arm_feature_set fpu_default = FPU_DEFAULT; @@ -202,6 +202,8 @@ static const arm_feature_set arm_arch_full = ARM_FEATURE (-1, -1); static const arm_feature_set arm_arch_t2 = ARM_ARCH_THUMB2; static const arm_feature_set arm_arch_none = ARM_ARCH_NONE; +static const arm_feature_set arm_cext_iwmmxt2 = + ARM_FEATURE (0, ARM_CEXT_IWMMXT2); static const arm_feature_set arm_cext_iwmmxt = ARM_FEATURE (0, ARM_CEXT_IWMMXT); static const arm_feature_set arm_cext_xscale = @@ -230,6 +232,12 @@ static int meabi_flags = EABI_DEFAULT; # else static int meabi_flags = EF_ARM_EABI_UNKNOWN; # endif + +bfd_boolean +arm_is_eabi(void) +{ + return (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4); +} #endif #ifdef OBJ_ELF @@ -1262,7 +1270,9 @@ parse_typed_reg_or_scalar (char **ccp, enum arm_reg_type type, && (reg->type == REG_TYPE_VFS || reg->type == REG_TYPE_VFD)) || (type == REG_TYPE_NSDQ && (reg->type == REG_TYPE_VFS || reg->type == REG_TYPE_VFD - || reg->type == REG_TYPE_NQ))) + || reg->type == REG_TYPE_NQ)) + || (type == REG_TYPE_MMXWC + && (reg->type == REG_TYPE_MMXWCG))) type = reg->type; if (type != reg->type) @@ -2278,7 +2288,7 @@ s_unreq (int a ATTRIBUTE_UNUSED) static enum mstate mapstate = MAP_UNDEFINED; -static void +void mapping_state (enum mstate state) { symbolS * symbolP; @@ -3449,7 +3459,7 @@ s_arm_unwind_save_mmxwr (void) 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); @@ -3627,6 +3637,7 @@ s_arm_unwind_movsp (int ignored ATTRIBUTE_UNUSED) { int reg; valueT op; + int offset; reg = arm_reg_parse (&input_line_pointer, REG_TYPE_RN); if (reg == FAIL) @@ -3635,6 +3646,16 @@ s_arm_unwind_movsp (int ignored ATTRIBUTE_UNUSED) ignore_rest_of_line (); return; } + + /* Optional constant. */ + if (skip_past_comma (&input_line_pointer) != FAIL) + { + if (immediate_for_directive (&offset) == FAIL) + return; + } + else + offset = 0; + demand_empty_rest_of_line (); if (reg == REG_SP || reg == REG_PC) @@ -3652,7 +3673,7 @@ s_arm_unwind_movsp (int ignored ATTRIBUTE_UNUSED) /* Record the information for later. */ unwind.fp_reg = reg; - unwind.fp_offset = unwind.frame_size; + unwind.fp_offset = unwind.frame_size - offset; unwind.sp_restored = 1; } @@ -3876,6 +3897,7 @@ bad: #endif /* OBJ_ELF */ static void s_arm_arch (int); +static void s_arm_object_arch (int); static void s_arm_cpu (int); static void s_arm_fpu (int); @@ -3929,6 +3951,7 @@ const pseudo_typeS md_pseudo_table[] = { "syntax", s_syntax, 0 }, { "cpu", s_arm_cpu, 0 }, { "arch", s_arm_arch, 0 }, + { "object_arch", s_arm_object_arch, 0 }, { "fpu", s_arm_fpu, 0 }, #ifdef OBJ_ELF { "word", s_arm_elf_cons, 4 }, @@ -3999,7 +4022,7 @@ parse_immediate (char **str, int *val, int min, int max, } /* Less-generic immediate-value read function with the possibility of loading a - big (64-bit) immediate, as required by Neon VMOV and VMVN immediate + big (64-bit) immediate, as required by Neon VMOV, VMVN and logic immediate instructions. Puts the result directly in inst.operands[i]. */ static int @@ -4011,7 +4034,18 @@ parse_big_immediate (char **str, int i) my_get_expression (&exp, &ptr, GE_OPT_PREFIX_BIG); if (exp.X_op == O_constant) - inst.operands[i].imm = exp.X_add_number; + { + inst.operands[i].imm = exp.X_add_number & 0xffffffff; + /* If we're on a 64-bit host, then a 64-bit number can be returned using + O_constant. We have to be careful not to break compilation for + 32-bit X_add_number, though. */ + if ((exp.X_add_number & ~0xffffffffl) != 0) + { + /* X >> 32 is illegal if sizeof (exp.X_add_number) == 4. */ + inst.operands[i].reg = ((exp.X_add_number >> 16) >> 16) & 0xffffffff; + inst.operands[i].regisimm = 1; + } + } else if (exp.X_op == O_big && LITTLENUM_NUMBER_OF_BITS * exp.X_add_number > 32 && LITTLENUM_NUMBER_OF_BITS * exp.X_add_number <= 64) @@ -5359,6 +5393,7 @@ enum operand_parse_code OP_VMOV, /* Neon VMOV operands. */ OP_RNDQ_IMVNb,/* Neon D or Q reg, or immediate good for 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_I0, /* immediate zero */ OP_I7, /* immediate value 0 .. 7 */ @@ -5567,6 +5602,7 @@ parse_operands (char *str, const unsigned char *pattern) 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); @@ -5579,8 +5615,13 @@ parse_operands (char *str, const unsigned char *pattern) inst.operands[i-1].present = 0; break; try_imm: - /* Immediate gets verified properly later, so accept any now. */ - po_imm_or_fail (INT_MIN, INT_MAX, TRUE); + /* There's a possibility of getting a 64-bit immediate here, so + we need special handling. */ + if (parse_big_immediate (&str, i) == FAIL) + { + inst.error = _("immediate value is out of range"); + goto failure; + } } break; @@ -5780,6 +5821,9 @@ parse_operands (char *str, const unsigned char *pattern) inst.operands[i].isreg = 1; break; + case OP_RIWR_I32z: po_reg_or_goto (REG_TYPE_MMXWR, I32z); break; + I32z: po_imm_or_fail (0, 32, FALSE); break; + /* Two kinds of register */ case OP_RIWR_RIWC: { @@ -7681,16 +7725,16 @@ static void do_vfp_sp_const (void) { encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd); - inst.instruction |= (inst.operands[1].imm & 15) << 16; - inst.instruction |= (inst.operands[1].imm >> 4); + inst.instruction |= (inst.operands[1].imm & 0xf0) << 12; + inst.instruction |= (inst.operands[1].imm & 0x0f); } static void do_vfp_dp_const (void) { encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd); - inst.instruction |= (inst.operands[1].imm & 15) << 16; - inst.instruction |= (inst.operands[1].imm >> 4); + inst.instruction |= (inst.operands[1].imm & 0xf0) << 12; + inst.instruction |= (inst.operands[1].imm & 0x0f); } static void @@ -7827,6 +7871,15 @@ do_iwmmxt_waligni (void) inst.instruction |= inst.operands[3].imm << 20; } +static void +do_iwmmxt_wmerge (void) +{ + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].reg << 16; + inst.instruction |= inst.operands[2].reg; + inst.instruction |= inst.operands[3].imm << 21; +} + static void do_iwmmxt_wmov (void) { @@ -7866,7 +7919,23 @@ static void do_iwmmxt_wldstd (void) { inst.instruction |= inst.operands[0].reg << 12; - encode_arm_cp_address (1, TRUE, FALSE, 0); + if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt2) + && inst.operands[1].immisreg) + { + inst.instruction &= ~0x1a000ff; + inst.instruction |= (0xf << 28); + if (inst.operands[1].preind) + inst.instruction |= PRE_INDEX; + if (!inst.operands[1].negative) + inst.instruction |= INDEX_UP; + if (inst.operands[1].writeback) + inst.instruction |= WRITE_BACK; + inst.instruction |= inst.operands[1].reg << 16; + inst.instruction |= inst.reloc.exp.X_add_number << 4; + inst.instruction |= inst.operands[1].imm; + } + else + encode_arm_cp_address (1, TRUE, FALSE, 0); } static void @@ -7886,6 +7955,56 @@ do_iwmmxt_wzero (void) inst.instruction |= inst.operands[0].reg << 12; inst.instruction |= inst.operands[0].reg << 16; } + +static void +do_iwmmxt_wrwrwr_or_imm5 (void) +{ + if (inst.operands[2].isreg) + do_rd_rn_rm (); + else { + constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt2), + _("immediate operand requires iWMMXt2")); + do_rd_rn (); + if (inst.operands[2].imm == 0) + { + switch ((inst.instruction >> 20) & 0xf) + { + case 4: + case 5: + case 6: + case 7: + /* w...h wrd, wrn, #0 -> wrorh wrd, wrn, #16. */ + inst.operands[2].imm = 16; + inst.instruction = (inst.instruction & 0xff0fffff) | (0x7 << 20); + break; + case 8: + case 9: + case 10: + case 11: + /* w...w wrd, wrn, #0 -> wrorw wrd, wrn, #32. */ + inst.operands[2].imm = 32; + inst.instruction = (inst.instruction & 0xff0fffff) | (0xb << 20); + break; + case 12: + case 13: + case 14: + case 15: + { + /* w...d wrd, wrn, #0 -> wor wrd, wrn, wrn. */ + unsigned long wrn; + wrn = (inst.instruction >> 16) & 0xf; + inst.instruction &= 0xff0fff0f; + inst.instruction |= wrn; + /* Bail out here; the instruction is now assembled. */ + return; + } + } + } + /* Map 32 -> 0, etc. */ + inst.operands[2].imm &= 0x1f; + inst.instruction |= (0xf << 28) | ((inst.operands[2].imm & 0x10) << 4) | (inst.operands[2].imm & 0xf); + } +} /* Cirrus Maverick instructions. Simple 2-, 3-, and 4-register operations first, then control, shift, and load/store. */ @@ -8857,7 +8976,7 @@ do_t_cpy (void) } static void -do_t_czb (void) +do_t_cbz (void) { constraint (current_it_mask, BAD_NOT_IT); constraint (inst.operands[0].reg > 7, BAD_HIREG); @@ -11303,45 +11422,52 @@ do_neon_qshl_imm (void) static int neon_cmode_for_logic_imm (unsigned immediate, unsigned *immbits, int size) { - /* Handle .I8 and .I64 as pseudo-instructions. */ - switch (size) + /* Handle .I8 pseudo-instructions. */ + if (size == 8) { - case 8: /* Unfortunately, this will make everything apart from zero out-of-range. FIXME is this the intended semantics? There doesn't seem much point in accepting .I8 if so. */ immediate |= immediate << 8; size = 16; - break; - case 64: - /* Similarly, anything other than zero will be replicated in bits [63:32], - which probably isn't want we want if we specified .I64. */ - if (immediate != 0) - goto bad_immediate; - size = 32; - break; - default: ; + } + + if (size >= 32) + { + if (immediate == (immediate & 0x000000ff)) + { + *immbits = immediate; + return 0x1; + } + else if (immediate == (immediate & 0x0000ff00)) + { + *immbits = immediate >> 8; + return 0x3; + } + else if (immediate == (immediate & 0x00ff0000)) + { + *immbits = immediate >> 16; + return 0x5; + } + else if (immediate == (immediate & 0xff000000)) + { + *immbits = immediate >> 24; + return 0x7; + } + if ((immediate & 0xffff) != (immediate >> 16)) + goto bad_immediate; + immediate &= 0xffff; } if (immediate == (immediate & 0x000000ff)) { *immbits = immediate; - return (size == 16) ? 0x9 : 0x1; + return 0x9; } else if (immediate == (immediate & 0x0000ff00)) { *immbits = immediate >> 8; - return (size == 16) ? 0xb : 0x3; - } - else if (immediate == (immediate & 0x00ff0000)) - { - *immbits = immediate >> 16; - return 0x5; - } - else if (immediate == (immediate & 0xff000000)) - { - *immbits = immediate >> 24; - return 0x7; + return 0xb; } bad_immediate: @@ -11382,7 +11508,8 @@ neon_qfloat_bits (unsigned imm) the instruction. *OP is passed as the initial value of the op field, and may be set to a different value depending on the constant (i.e. "MOV I64, 0bAAAAAAAABBBB..." which uses OP = 1 despite being MOV not - MVN). */ + MVN). If the immediate looks like a repeated parttern then also + try smaller element sizes. */ static int neon_cmode_for_move_imm (unsigned immlo, unsigned immhi, unsigned *immbits, @@ -11395,63 +11522,87 @@ neon_cmode_for_move_imm (unsigned immlo, unsigned immhi, unsigned *immbits, *immbits = neon_qfloat_bits (immlo); return 0xf; } - else if (size == 64 && neon_bits_same_in_bytes (immhi) - && neon_bits_same_in_bytes (immlo)) - { - /* Check this one first so we don't have to bother with immhi in later - tests. */ - if (*op == 1) - return FAIL; - *immbits = (neon_squash_bits (immhi) << 4) | neon_squash_bits (immlo); - *op = 1; - return 0xe; - } - else if (immhi != 0) - return FAIL; - else if (immlo == (immlo & 0x000000ff)) - { - /* 64-bit case was already handled. Don't allow MVN with 8-bit - immediate. */ - if ((size != 8 && size != 16 && size != 32) - || (size == 8 && *op == 1)) - return FAIL; - *immbits = immlo; - return (size == 8) ? 0xe : (size == 16) ? 0x8 : 0x0; - } - else if (immlo == (immlo & 0x0000ff00)) - { - if (size != 16 && size != 32) - return FAIL; - *immbits = immlo >> 8; - return (size == 16) ? 0xa : 0x2; - } - else if (immlo == (immlo & 0x00ff0000)) + + if (size == 64) { - if (size != 32) - return FAIL; - *immbits = immlo >> 16; - return 0x4; + if (neon_bits_same_in_bytes (immhi) + && neon_bits_same_in_bytes (immlo)) + { + if (*op == 1) + return FAIL; + *immbits = (neon_squash_bits (immhi) << 4) + | neon_squash_bits (immlo); + *op = 1; + return 0xe; + } + + if (immhi != immlo) + return FAIL; } - else if (immlo == (immlo & 0xff000000)) + + if (size >= 32) { - if (size != 32) - return FAIL; - *immbits = immlo >> 24; - return 0x6; + if (immlo == (immlo & 0x000000ff)) + { + *immbits = immlo; + return 0x0; + } + else if (immlo == (immlo & 0x0000ff00)) + { + *immbits = immlo >> 8; + return 0x2; + } + else if (immlo == (immlo & 0x00ff0000)) + { + *immbits = immlo >> 16; + return 0x4; + } + else if (immlo == (immlo & 0xff000000)) + { + *immbits = immlo >> 24; + return 0x6; + } + else if (immlo == ((immlo & 0x0000ff00) | 0x000000ff)) + { + *immbits = (immlo >> 8) & 0xff; + return 0xc; + } + else if (immlo == ((immlo & 0x00ff0000) | 0x0000ffff)) + { + *immbits = (immlo >> 16) & 0xff; + return 0xd; + } + + if ((immlo & 0xffff) != (immlo >> 16)) + return FAIL; + immlo &= 0xffff; } - else if (immlo == ((immlo & 0x0000ff00) | 0x000000ff)) + + if (size >= 16) { - if (size != 32) - return FAIL; - *immbits = (immlo >> 8) & 0xff; - return 0xc; + if (immlo == (immlo & 0x000000ff)) + { + *immbits = immlo; + return 0x8; + } + else if (immlo == (immlo & 0x0000ff00)) + { + *immbits = immlo >> 8; + return 0xa; + } + + if ((immlo & 0xff) != (immlo >> 8)) + return FAIL; + immlo &= 0xff; } - else if (immlo == ((immlo & 0x00ff0000) | 0x0000ffff)) + + if (immlo == (immlo & 0x000000ff)) { - if (size != 32) - return FAIL; - *immbits = (immlo >> 16) & 0xff; - return 0xd; + /* Don't allow MVN with 8-bit immediate. */ + if (*op == 1) + return FAIL; + *immbits = immlo; + return 0xe; } return FAIL; @@ -11534,28 +11685,37 @@ do_neon_logic (void) inst.instruction = NEON_ENC_IMMED (inst.instruction); + immbits = inst.operands[1].imm; + if (et.size == 64) + { + /* .i64 is a pseudo-op, so the immediate must be a repeating + pattern. */ + if (immbits != (inst.operands[1].regisimm ? + inst.operands[1].reg : 0)) + { + /* Set immbits to an invalid constant. */ + immbits = 0xdeadbeef; + } + } + switch (opcode) { case N_MNEM_vbic: - cmode = neon_cmode_for_logic_imm (inst.operands[1].imm, &immbits, - et.size); + cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size); break; case N_MNEM_vorr: - cmode = neon_cmode_for_logic_imm (inst.operands[1].imm, &immbits, - et.size); + cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size); break; case N_MNEM_vand: /* Pseudo-instruction for VBIC. */ - immbits = inst.operands[1].imm; neon_invert_size (&immbits, 0, et.size); cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size); break; case N_MNEM_vorn: /* Pseudo-instruction for VORR. */ - immbits = inst.operands[1].imm; neon_invert_size (&immbits, 0, et.size); cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size); break; @@ -11618,16 +11778,12 @@ do_neon_dyadic_if_su_d (void) 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 @@ -11842,7 +11998,11 @@ do_neon_mac_maybe_scalar (void) 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 @@ -12493,6 +12653,9 @@ do_neon_dyadic_narrow (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); } @@ -13583,11 +13746,14 @@ opcode_lookup (char **str) 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) @@ -13598,9 +13764,11 @@ opcode_lookup (char **str) { 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; @@ -13611,7 +13779,8 @@ opcode_lookup (char **str) 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; } @@ -13839,7 +14008,7 @@ md_assemble (char *str) 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 || @@ -13872,6 +14041,12 @@ md_assemble (char *str) 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); } @@ -14811,9 +14986,11 @@ static const struct asm_opcode insns[] = TC3(ldrsbt, 03000d0, f9100e00, 2, (RR, ADDR), ldsttv4, t_ldstt), TC3(strht, 02000b0, f8200e00, 2, (RR, ADDR), ldsttv4, t_ldstt), - UT(cbnz, b900, 2, (RR, EXP), t_czb), - UT(cbz, b100, 2, (RR, EXP), t_czb), - /* ARM does not really have an IT instruction. */ + UT(cbnz, b900, 2, (RR, EXP), t_cbz), + UT(cbz, b100, 2, (RR, EXP), t_cbz), + /* 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), @@ -15522,14 +15699,13 @@ static const struct asm_opcode insns[] = 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), @@ -15840,34 +16016,34 @@ static const struct asm_opcode insns[] = cCE(wpackwus, e900080, 3, (RIWR, RIWR, RIWR), rd_rn_rm), cCE(wpackdss, ef00080, 3, (RIWR, RIWR, RIWR), rd_rn_rm), cCE(wpackdus, ed00080, 3, (RIWR, RIWR, RIWR), rd_rn_rm), - cCE(wrorh, e700040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wrorh, e700040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5), cCE(wrorhg, e700148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), - cCE(wrorw, eb00040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wrorw, eb00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5), cCE(wrorwg, eb00148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), - cCE(wrord, ef00040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wrord, ef00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5), cCE(wrordg, ef00148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), cCE(wsadb, e000120, 3, (RIWR, RIWR, RIWR), rd_rn_rm), cCE(wsadbz, e100120, 3, (RIWR, RIWR, RIWR), rd_rn_rm), cCE(wsadh, e400120, 3, (RIWR, RIWR, RIWR), rd_rn_rm), cCE(wsadhz, e500120, 3, (RIWR, RIWR, RIWR), rd_rn_rm), cCE(wshufh, e0001e0, 3, (RIWR, RIWR, I255), iwmmxt_wshufh), - cCE(wsllh, e500040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wsllh, e500040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5), cCE(wsllhg, e500148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), - cCE(wsllw, e900040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wsllw, e900040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5), cCE(wsllwg, e900148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), - cCE(wslld, ed00040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wslld, ed00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5), cCE(wslldg, ed00148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), - cCE(wsrah, e400040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wsrah, e400040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5), cCE(wsrahg, e400148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), - cCE(wsraw, e800040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wsraw, e800040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5), cCE(wsrawg, e800148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), - cCE(wsrad, ec00040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wsrad, ec00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5), cCE(wsradg, ec00148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), - cCE(wsrlh, e600040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wsrlh, e600040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5), cCE(wsrlhg, e600148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), - cCE(wsrlw, ea00040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wsrlw, ea00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5), cCE(wsrlwg, ea00148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), - cCE(wsrld, ee00040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wsrld, ee00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5), cCE(wsrldg, ee00148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), cCE(wstrb, c000000, 2, (RIWR, ADDR), iwmmxt_wldstbh), cCE(wstrh, c400000, 2, (RIWR, ADDR), iwmmxt_wldstbh), @@ -15903,6 +16079,66 @@ static const struct asm_opcode insns[] = cCE(wxor, e100000, 3, (RIWR, RIWR, RIWR), rd_rn_rm), cCE(wzero, e300000, 1, (RIWR), iwmmxt_wzero), +#undef ARM_VARIANT +#define ARM_VARIANT &arm_cext_iwmmxt2 /* Intel Wireless MMX technology, version 2. */ + cCE(torvscb, e13f190, 1, (RR), iwmmxt_tandorc), + cCE(torvsch, e53f190, 1, (RR), iwmmxt_tandorc), + cCE(torvscw, e93f190, 1, (RR), iwmmxt_tandorc), + cCE(wabsb, e2001c0, 2, (RIWR, RIWR), rd_rn), + cCE(wabsh, e6001c0, 2, (RIWR, RIWR), rd_rn), + cCE(wabsw, ea001c0, 2, (RIWR, RIWR), rd_rn), + cCE(wabsdiffb, e1001c0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wabsdiffh, e5001c0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wabsdiffw, e9001c0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(waddbhusl, e2001a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(waddbhusm, e6001a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(waddhc, e600180, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(waddwc, ea00180, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(waddsubhx, ea001a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wavg4, e400000, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wavg4r, e500000, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmaddsn, ee00100, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmaddsx, eb00100, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmaddun, ec00100, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmaddux, e900100, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmerge, e000080, 4, (RIWR, RIWR, RIWR, I7), iwmmxt_wmerge), + cCE(wmiabb, e0000a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmiabt, e1000a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmiatb, e2000a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmiatt, e3000a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmiabbn, e4000a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmiabtn, e5000a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmiatbn, e6000a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmiattn, e7000a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmiawbb, e800120, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmiawbt, e900120, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmiawtb, ea00120, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmiawtt, eb00120, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmiawbbn, ec00120, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmiawbtn, ed00120, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmiawtbn, ee00120, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmiawttn, ef00120, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmulsmr, ef00100, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmulumr, ed00100, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmulwumr, ec000c0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmulwsmr, ee000c0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmulwum, ed000c0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmulwsm, ef000c0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wmulwl, eb000c0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wqmiabb, e8000a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wqmiabt, e9000a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wqmiatb, ea000a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wqmiatt, eb000a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wqmiabbn, ec000a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wqmiabtn, ed000a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wqmiatbn, ee000a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wqmiattn, ef000a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wqmulm, e100080, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wqmulmr, e300080, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wqmulwm, ec000e0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wqmulwmr, ee000e0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + cCE(wsubaddhx, ed001c0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + #undef ARM_VARIANT #define ARM_VARIANT &arm_cext_maverick /* Cirrus Maverick instructions. */ cCE(cfldrs, c100400, 2, (RMF, ADDRGLDC), rd_cpaddr), @@ -17218,11 +17454,11 @@ negate_data_op (unsigned long * instruction, /* Like negate_data_op, but for Thumb-2. */ static unsigned int -thumb32_negate_data_op (offsetT *instruction, offsetT value) +thumb32_negate_data_op (offsetT *instruction, unsigned int value) { int op, new_inst; int rd; - offsetT negated, inverted; + unsigned int negated, inverted; negated = encode_thumb32_immediate (-value); inverted = encode_thumb32_immediate (~value); @@ -17283,7 +17519,7 @@ thumb32_negate_data_op (offsetT *instruction, offsetT value) return FAIL; } - if (value == FAIL) + if (value == (unsigned int)FAIL) return FAIL; *instruction &= T2_OPCODE_MASK; @@ -17797,8 +18033,8 @@ md_apply_fix (fixS * fixP, } break; - case BFD_RELOC_THUMB_PCREL_BRANCH7: /* CZB */ - /* CZB can only branch forward. */ + case BFD_RELOC_THUMB_PCREL_BRANCH7: /* CBZ */ + /* CBZ can only branch forward. */ if (value & ~0x7e) as_bad_where (fixP->fx_file, fixP->fx_line, _("branch out of range")); @@ -17992,8 +18228,6 @@ md_apply_fix (fixS * fixP, newval = get_thumb32_insn (buf); newval &= 0xff7fff00; newval |= (value >> 2) | (sign ? INDEX_UP : 0); - if (value == 0) - newval &= ~WRITE_BACK; if (fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM || fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM_S2) md_number_to_chars (buf, newval, INSN_SIZE); @@ -18731,36 +18965,7 @@ arm_force_relocation (struct fix * fixp) return generic_force_reloc (fixp); } -#ifdef OBJ_COFF -bfd_boolean -arm_fix_adjustable (fixS * fixP) -{ - /* This is a little hack to help the gas/arm/adrl.s test. It prevents - local labels from being added to the output symbol table when they - are used with the ADRL pseudo op. The ADRL relocation should always - be resolved before the binbary is emitted, so it is safe to say that - it is adjustable. */ - if (fixP->fx_r_type == BFD_RELOC_ARM_ADRL_IMMEDIATE) - return 1; - - /* This is a hack for the gas/all/redef2.s test. This test causes symbols - to be cloned, and without this test relocs would still be generated - against the original, pre-cloned symbol. Such symbols would not appear - in the symbol table however, and so a valid reloc could not be - generated. So check to see if the fixup is against a symbol which has - been removed from the symbol chain, and if it is, then allow it to be - adjusted into a reloc against a section symbol. */ - if (fixP->fx_addsy != NULL - && ! S_IS_LOCAL (fixP->fx_addsy) - && symbol_next (fixP->fx_addsy) == NULL - && symbol_next (fixP->fx_addsy) == symbol_previous (fixP->fx_addsy)) - return 1; - - return 0; -} -#endif - -#ifdef OBJ_ELF +#if defined (OBJ_ELF) || defined (OBJ_COFF) /* Relocations against function names must be left unadjusted, so that the linker can use this information to generate interworking stubs. The MIPS version of this function @@ -18813,6 +19018,9 @@ arm_fix_adjustable (fixS * fixP) return 1; } +#endif /* defined (OBJ_ELF) || defined (OBJ_COFF) */ + +#ifdef OBJ_ELF const char * elf32_arm_target_format (void) @@ -18931,7 +19139,7 @@ arm_adjust_symtab (void) if (THUMB_IS_FUNC (sym)) elf_sym->internal_elf_sym.st_info = ELF_ST_INFO (bind, STT_ARM_TFUNC); - else + else if (EF_ARM_EABI_VERSION (meabi_flags) < EF_ARM_EABI_VER4) elf_sym->internal_elf_sym.st_info = ELF_ST_INFO (bind, STT_ARM_16BIT); } @@ -18952,6 +19160,16 @@ set_constant_flonums (void) 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) { @@ -19052,6 +19270,8 @@ 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 @@ -19127,7 +19347,9 @@ md_begin (void) #endif /* Record the CPU type as well. */ - if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt)) + if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt2)) + mach = bfd_mach_arm_iWMMXt2; + else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt)) mach = bfd_mach_arm_iWMMXt; else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_xscale)) mach = bfd_mach_arm_XScale; @@ -19506,6 +19728,7 @@ static const struct arm_cpu_option_table arm_cpus[] = {"xscale", ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL}, /* ??? iwmmxt is not a processor. */ {"iwmmxt", ARM_ARCH_IWMMXT, FPU_ARCH_VFP_V2, NULL}, + {"iwmmxt2", ARM_ARCH_IWMMXT2,FPU_ARCH_VFP_V2, NULL}, {"i80200", ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL}, /* Maverick */ {"ep9312", ARM_FEATURE(ARM_AEXT_V4T, ARM_CEXT_MAVERICK), FPU_ARCH_MAVERICK, "ARM920T"}, @@ -19555,6 +19778,7 @@ static const struct arm_arch_option_table arm_archs[] = {"armv7m", ARM_ARCH_V7M, FPU_ARCH_VFP}, {"xscale", ARM_ARCH_XSCALE, FPU_ARCH_VFP}, {"iwmmxt", ARM_ARCH_IWMMXT, FPU_ARCH_VFP}, + {"iwmmxt2", ARM_ARCH_IWMMXT2,FPU_ARCH_VFP}, {NULL, ARM_ARCH_NONE, ARM_ARCH_NONE} }; @@ -19570,6 +19794,7 @@ static const struct arm_option_cpu_value_table arm_extensions[] = {"maverick", ARM_FEATURE (0, ARM_CEXT_MAVERICK)}, {"xscale", ARM_FEATURE (0, ARM_CEXT_XSCALE)}, {"iwmmxt", ARM_FEATURE (0, ARM_CEXT_IWMMXT)}, + {"iwmmxt2", ARM_FEATURE (0, ARM_CEXT_IWMMXT2)}, {NULL, ARM_ARCH_NONE} }; @@ -19994,7 +20219,13 @@ aeabi_set_public_attributes (void) ARM_MERGE_FEATURE_SETS (flags, arm_arch_used, thumb_arch_used); ARM_MERGE_FEATURE_SETS (flags, flags, *mfpu_opt); ARM_MERGE_FEATURE_SETS (flags, flags, selected_cpu); - + /*Allow the user to override the reported architecture. */ + if (object_arch) + { + ARM_CLEAR_FEATURE (flags, flags, arm_arch_any); + ARM_MERGE_FEATURE_SETS (flags, flags, *object_arch); + } + tmp = flags; arch = 0; for (p = cpu_arch_ver; p->val; p++) @@ -20158,6 +20389,37 @@ s_arm_arch (int ignored ATTRIBUTE_UNUSED) } +/* Parse a .object_arch directive. */ + +static void +s_arm_object_arch (int ignored ATTRIBUTE_UNUSED) +{ + const struct arm_arch_option_table *opt; + char saved_char; + char *name; + + name = input_line_pointer; + while (*input_line_pointer && !ISSPACE(*input_line_pointer)) + input_line_pointer++; + saved_char = *input_line_pointer; + *input_line_pointer = 0; + + /* Skip the first "all" entry. */ + for (opt = arm_archs + 1; opt->name != NULL; opt++) + if (streq (opt->name, name)) + { + object_arch = &opt->value; + *input_line_pointer = saved_char; + demand_empty_rest_of_line (); + return; + } + + as_bad (_("unknown architecture `%s'\n"), name); + *input_line_pointer = saved_char; + ignore_rest_of_line (); +} + + /* Parse a .fpu directive. */ static void