public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] ARM Neon instruction set support
@ 2006-04-01  1:40 Julian Brown
  2006-04-01  2:49 ` Paul Brook
  0 siblings, 1 reply; 8+ messages in thread
From: Julian Brown @ 2006-04-01  1:40 UTC (permalink / raw)
  To: binutils; +Cc: Paul Brook, Richard Earnshaw

[-- Attachment #1: Type: text/plain, Size: 12008 bytes --]

Hi,

This patch provides support for ARM's new Advanced SIMD (Neon) 
instruction set, and version 3 of the VFP instruction set. Code using 
Neon instructions can be both assembled and disassembled. The full range 
of SIMD data types is available, and should be correctly type-checked by 
the assembler.

The code currently uses ':' for specifying alignment in element & 
structure load and store instructions rather than '@', since '@' is used 
as a comment character in Gas. This may be subject to change.

A few tests have been added, but they don't nearly cover the new 
functionality (in particular, there are currently no negative/error 
tests and no type checking tests). I mean to add more later.

Tested with "make check" on arm-none-eabi. Some of the VFP tests had to 
be twiddled to use new syntax, where overlaps with Neon instructions 
occur. OK to apply? This patch is against HEAD.

Cheers,

Julian


ChangeLog (gas):

2006-04-01  Julian Brown  <julian@codesourcery.com>

     * config/tc-arm.c (limits.h): Include.
     (fpu_arch_vfp_v3, fpu_vfp_ext_v3, fpu_neon_ext_v1)
     (fpu_vfp_v3_or_neon_ext): Declare constants.
     (neon_el_type): New enumeration of types for Neon vector
     elements.
     (neon_type_el): New struct. Define type and size of a vector
     element.
     (NEON_MAX_TYPE_ELS): Define constant. The maximum number of types
     per instruction.
     (neon_type): Define struct. The type of an instruction.
     (arm_it): Add 'vectype' for the current instruction.
     (isscalar, immisalign, regisimm, isquad): New predicates for
     operands.
     (vfp_sp_reg_pos): Rename to...
     (vfp_reg_pos): ...this, and add VFP_REG_Dd, VFP_REG_Dm, VFP_REG_Dn
     tags.
     (arm_reg_type): Add REG_TYPE_NQ (Neon Q register) and REG_TYPE_NDQ
     (Neon D or Q register).
     (reg_expected_msgs): Sync with above. Allow VFD to mean VFP or Neon
     D register.
     (GE_OPT_PREFIX_BIG): Define constant, for use in...
     (my_get_expression): Allow above constant as argument to accept
     64-bit constants with optional prefix.
     (arm_reg_parse): Add extra argument to return the specific type
     of register in when either a D or Q register (REG_TYPE_NDQ) is
     requested. Can be NULL.
     (parse_scalar): New function. Parse Neon scalar (vector reg and
     index).
     (parse_reg_list): Update for new arm_reg_parse args.
     (parse_vfp_reg_list): Allow parsing of Neon D/Q register lists.
     (parse_neon_el_struct_list): New function. Parse element/structure
     register lists for VLD<n>/VST<n> instructions.
     (s_arm_unwind_save_vfp): Update for new parse_vfp_reg_list args.
     (s_arm_unwind_save_mmxwr): Likewise.
     (s_arm_unwind_save_mmxwcg): Likewise.
     (s_arm_unwind_movsp): Likewise.
     (s_arm_unwind_setfp): Likewise.
     (parse_big_immediate): New function. Parse an immediate, which may
     be 64 bits wide. Put results in inst.operands[i].
     (parse_shift): Update for new arm_reg_parse args.
     (parse_address): Likewise. Add parsing of alignment specifiers.
     (parse_neon_mov): Parse the operands of a VMOV instruction.
     (operand_parse_code): Add OP_RND, OP_RNQ, OP_RNDQ, OP_RNSC,
     OP_NRDLST, OP_NSTRLST, OP_NILO, OP_RNDQ_I0, OP_RR_RNSC,
     OP_RNDQ_RNSC, OP_RND_RNSC, OP_VMOV, OP_RNDQ_IMVNb, OP_RNDQ_I63b,
     OP_I0, OP_I16z, OP_I32z, OP_I64, OP_I64z, OP_oI32b, OP_oRND,
     OP_oRNQ, OP_oRNDQ.
     (parse_operands): Handle new codes above.
     (encode_arm_vfp_sp_reg): Rename to...
     (encode_arm_vfp_reg): ...this. Handle D regs (0-31) too. Complain if
     selected VFP version only supports D0-D15.
     (do_vfp_sp_monadic, do_vfp_sp_dyadic, do_vfp_sp_compare_z)
     (do_vfp_dp_sp_cvt, do_vfp_reg_from_sp, do_vfp_reg2_from_sp2)
     (do_vfp_sp_from_reg, do_vfp_sp2_from_reg2, do_vfp_sp_ldst)
     (do_vfp_dp_ldst, vfp_sp_ldstm, vfp_dp_ldstm): Update for new
     encode_arm_vfp_reg name, and allow 32 D regs.
     (do_vfp_dp_rd_rm, do_vfp_dp_rn_rd, do_vfp_dp_rd_rn)
     (do_vfp_dp_rd_rn_rm, do_vfp_rm_rd_rn): New functions to encode VFP
     insns allowing 32 D regs.
     (do_vfp_sp_const, do_vfp_dp_const, vfp_conv, do_vfp_sp_conv_16)
     (do_vfp_dp_conv_16, do_vfp_sp_conv_32, do_vfp_dp_conv_32): Handle
     constant-load and conversion insns introduced with VFPv3.
     (neon_tab_entry): New struct.
     (NEON_ENC_TAB): Bit patterns for overloaded Neon instructions, and
     those which are the targets of pseudo-instructions.
     (neon_opc): Enumerate opcodes, use as indices into...
     (neon_enc_tab): ...this. Hold data from NEON_ENC_TAB.
     (NEON_ENC_INTEGER, NEON_ENC_ARMREG, NEON_ENC_POLY, NEON_ENC_FLOAT)
     (NEON_ENC_SCALAR, NEON_ENC_IMMED, NEON_ENC_INTERLV, NEON_ENC_LANE)
     (NEON_ENC_DUP): Define meaningful helper macros to look up values in
     neon_enc_tab.
     (neon_shape): Enumerate shapes (permitted register widths, etc.) for
     Neon instructions.
     (neon_type_mask): New. Compact type representation for type
     checking.
     (N_SU_ALL, N_SU_32, N_SU_16_64, N_SUF_32, N_I_ALL, N_IF_32): Common
     permitted type combinations.
     (N_IGNORE_TYPE): New macro.
     (neon_check_shape): New function. Check an instruction shape for
     multiple alternatives. Return the specific shape for the current
     instruction.
     (neon_modify_type_size): New function. Modify a vector type and
     size, depending on the bit mask in argument 1.
     (neon_type_promote): New function. Convert a given "key" type (of an
     operand) into the correct type for a different operand, based on a
     bit mask.
     (type_chk_of_el_type): New function. Convert a type and size into
     the compact representation used for type checking.
     (el_type_of_type_ckh): New function. Reverse of above (only when a
     single bit is set in the bit mask).
     (modify_types_allowed): New function. Alter a mask of allowed types
     based on a bit mask of modifications.
     (neon_check_type): New function. Check the type of the current
     instruction against the variable argument list. The "key" type of
     the instruction is returned.
     (neon_dp_fixup): New function. Fill in and modify instruction bits
     for a Neon data-processing instruction depending on whether we're in
     ARM mode or Thumb-2 mode.
     (neon_logbits): New function.
     (neon_three_same, neon_two_same, do_neon_dyadic_i_su)
     (do_neon_dyadic_i64_su, neon_imm_shift, do_neon_shl_imm)
     (do_neon_qshl_imm, neon_cmode_for_logic_imm)
     (neon_bits_same_in_bytes, neon_squash_bits, neon_is_quarter_float)
     (neon_qfloat_bits, neon_cmode_for_move_imm, neon_write_immbits)
     (neon_invert_size, do_neon_logic, do_neon_bitfield, neon_dyadic)
     (do_neon_dyadic_if_su, do_neon_dyadic_if_su_d, do_neon_dyadic_if_i)
     (do_neon_dyadic_if_i_d, do_neon_addsub_if_i, neon_exchange_operands)
     (neon_compare, do_neon_cmp, do_neon_cmp_inv, do_neon_ceq)
     (neon_scalar_for_mul, neon_mul_mac, do_neon_mac_maybe_scalar)
     (do_neon_tst, do_neon_mul, do_neon_qdmulh, do_neon_fcmp_absolute)
     (do_neon_fcmp_absolute_inv, do_neon_step, do_neon_abs_neg)
     (do_neon_sli, do_neon_sri, do_neon_qshlu_imm, do_neon_qmovn)
     (do_neon_qmovun, do_neon_rshift_sat_narrow)
     (do_neon_rshift_sat_narrow_u, do_neon_movn, do_neon_rshift_narrow)
     (do_neon_shll, neon_cvt_flavour, do_neon_cvt, neon_move_immediate)
     (do_neon_mvn, neon_mixed_length, do_neon_dyadic_long, do_neon_abal)
     (neon_mac_reg_scalar_long, do_neon_mac_maybe_scalar_long)
     (do_neon_dyadic_wide, do_neon_vmull, do_neon_ext, do_neon_rev)
     (do_neon_dup, do_neon_mov, do_neon_rshift_round_imm, do_neon_movl)
     (do_neon_trn, do_neon_zip_uzp, do_neon_sat_abs_neg)
     (do_neon_pair_long, do_neon_recip_est, do_neon_cls, do_neon_clz)
     (do_neon_cnt, do_neon_swp, do_neon_tbl_tbx, do_neon_ldm_stm)
     (do_neon_ldr_str, do_neon_ld_st_interleave, neon_alignment_bit)
     (do_neon_ld_st_lane, do_neon_ld_dup, do_neon_ldx_stx): New
     functions. Neon bit encoding and encoding helpers.
     (parse_neon_type): New function. Parse Neon type specifier.
     (opcode_lookup): Allow parsing of Neon type specifiers.
     (REGNUM2, REGSETH, REGSET2): New macros.
     (reg_names): Add new VFPv3 and Neon registers.
     (NUF, nUF, NCE, nCE): New macros for opcode table.
     (insns): More VFP registers allowed in fcpyd, fmdhr, fmdlr, fmrdh,
     fmrdl, fabsd, fnegd, fsqrtd, faddd, fsubd, fmuld, fdivd, fmacd,
     fmscd, fnmuld, fnmacd, fnmscd, fcmpd, fcmpzd, fcmped, fcmpezd,
     fmdrr, fmrrd. Add Neon instructions vaba, vhadd, vrhadd, vhsub,
     vqadd, vqsub, vrshl, vqrshl, vshl, vqshl{u}, vand, vbic, vorr, vorn,
     veor, vbsl, vbit, vbif, vabd, vmax, vmin, vcge, vcgt, vclt, vcle,
     vceq, vpmax, vpmin, vmla, vmls, vpadd, vadd, vsub, vtst, vmul,
     vqdmulh, vqrdmulh, vacge, vacgt, vaclt, vacle, vrecps, vrsqrts,
     vabs, vneg, v{r}shr,  v{r}sra, vsli, vsri, vqshrn, vq{r}shr{u}n,
     v{r}shrn, vshll, vcvt, vmov, vmvn, vabal, vabdl, vaddl, vsubl,
     vmlal, vmlsl, vaddw, vsubw, v{r}addhn, v{r}subhn, vqdmlal, vqdmlsl,
     vqdmull, vmull, vext, vrev64, vrev32, vrev16, vdup, vmovl, v{q}movn,
     vzip, vuzp, vqabs, vqneg, vpadal, vpaddl, vrecpe, vrsqrte, vcls,
     vclz, vcnt, vswp, vtrn, vtbl, vtbx, vldm, vstm, vldr, vstr,
     vld[1234], vst[1234], fconst[sd], f[us][lh]to[sd], fto[us][lh][sd].
     (tc_arm_regname_to_dw2regnum): Update for arm_reg_parse args.
     (arm_cpu_option_table): Add Neon and VFPv3 to Cortex-A8.
     (arm_option_cpu_value): Add vfp3.

ChangeLog (gas/testsuite):

2006-04-01  Julian Brown  <julian@codesourcery.com>

     * gas/arm/copro.s: Avoid ldcl which encodes as a bad Neon
     instruction.
     * gas/arm/copro.d: Update accordingly.
     * gas/arm/neon-cond.s: New test. Conditional Neon opcodes in ARM
    mode.
     * gas/arm/neon-cond.d: Expected results of above.
     * gas/arm/neon-cov.s: New test. Coverage of Neon instructions.
     * gas/arm/neon-cov.d: Expected results of above.
     * gas/arm/neon-ldst-es.s: New test. Element and structure loads and
     stores.
     * gas/arm/neon-ldst-es.d: Expected results of above.
     * gas/arm/neon-ldst-rm.s: New test. Single and multiple register
     loads and stores.
     * gas/arm/neon-ldst-rm.d: Expected results of above.
     * gas/arm/neon-omit.s: New test. Omission of optional operands.
     * gas/arm/neon-omit.d: Expected results of above.
     * gas/arm/vfp1.d: Expect Neon syntax for some VFP instructions.
     * gas/arm/vfp1_t2.d: Likewise.
     * gas/arm/vfp1xD.d: Likewise.
     * gas/arm/vfp1xD_t2.d: Likewise.
     * gas/arm/vfp2.d: Likewise.
     * gas/arm/vfp2_t2.d: Likewise.
     * gas/arm/vfp3-32drs.s: New test. Extended D register range for VFP
     instructions.
     * gas/arm/vfp3-32drs.d: Expected results of above.
     * gas/arm/vfp3-const-conv.s: New test. VFPv3 constant-load and
     conversion instructions.
     * gas/arm/vfp3-const-conv.d: Expected results of above.

ChangeLog (include):

2006-04-01  Julian Brown  <julian@codesourcery.com>

     * opcode/arm.h (FPU_VFP_EXT_V3): Define constant.
     (FPU_NEON_EXT_V1): Likewise.
     (FPU_VFP_HARD): Update.
     (FPU_ARCH_VFP_V3): Define macro.

ChangeLog (opcodes/arm-dis.c):

2006-04-01  Nathan Sidwell  <nathan@codesourcery.com>
             Julian Brown  <julian@codesourcery.com>

     * opcodes/arm-dis.c (coprocessor_opcodes): Add %A, %B, %k,
     convert %<code>[zy] into %[zy]<code>.  Expand meaning of
     %<bitfield>['`?].
     Add unified load/store instruction names.
     (neon_opcode_table): New.
     (arm_opcodes): Expand meaning of %<bitfield>['`?].
     (arm_decode_bitfield): New.
     (print_insn_coprocessor): Add pc argument. Add %A & %B
     specifiers. Use arm_decode_bitfield and adjust numeric
     specifiers.
     Adjust %z & %y.
     (print_insn_neon): New.
     (print_insn_arm): Adjust print_insn_coprocessor call. Call
     print_insn_neon. Use arm_decode_bitfield and adjust numeric
     specifiers.
     (print_insn_thumb32): Likewise.

[-- Attachment #2: neon-support-2.gz --]
[-- Type: application/x-gzip, Size: 65083 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] ARM Neon instruction set support
  2006-04-01  1:40 [PATCH] ARM Neon instruction set support Julian Brown
@ 2006-04-01  2:49 ` Paul Brook
  2006-04-02 23:30   ` Julian Brown
  0 siblings, 1 reply; 8+ messages in thread
From: Paul Brook @ 2006-04-01  2:49 UTC (permalink / raw)
  To: Julian Brown; +Cc: binutils, Richard Earnshaw

On Saturday 01 April 2006 02:39, Julian Brown wrote:
> Hi,
>
> This patch provides support for ARM's new Advanced SIMD (Neon)
> instruction set, and version 3 of the VFP instruction set. Code using
> Neon instructions can be both assembled and disassembled. The full range
> of SIMD data types is available, and should be correctly type-checked by
> the assembler.

As-is the patch looks generally ok to me, a couple of relatively minor points 
below. Ok for the csl branch once those are resolved.

ARM have also defined all the existing VFP instructions in terms of the vector 
mnemonics. eg. "faddd d0, d0, d0" becomes "vadd.f64 d0, d0, d0).
We probably want to consider the implications of this before applying to 
mainline. Hopefully this will be an incremental change that can be done 
without rewriting everything, but it's best to check :-)

> +   /* Undo polymorphism for Neon D and Q registers.  */
> +   if (reg && type == REG_TYPE_NDQ)
> +     type = (reg->type == REG_TYPE_NQ || reg->type == REG_TYPE_VFD)
> +            ? reg->type : type;

Probably clearer as a single if:

if (reg && type == REG_TYPE_NDQ
    &&(reg->type == REG_TYPE_NQ || reg->type == REG_TYPE_VFD))
  type = reg->type;

> !   /* FIXME: Check if cortex-a8 supports these things!  */
> !   {"cortex-a8",               ARM_ARCH_V7A,    ARM_FEATURE(0, FPU_VFP_V3

Yes it does. You can remove the FIXME.

> +   {"vfp3",              FPU_ARCH_VFP_V3},

You also need to add some way of enabling NEON. I'm not sure if it's best to 
have this as an independent architecture extension (like iWMMXt) or just a 
different type of FPU. Probably the latter.

You also need to set the appropriate EABI build attributes to when NEON and 
VFPv3 instructions are used.

Paul

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] ARM Neon instruction set support
  2006-04-01  2:49 ` Paul Brook
@ 2006-04-02 23:30   ` Julian Brown
  2006-04-19 16:38     ` Julian Brown
  0 siblings, 1 reply; 8+ messages in thread
From: Julian Brown @ 2006-04-02 23:30 UTC (permalink / raw)
  To: Paul Brook; +Cc: binutils, Richard Earnshaw, Julian Brown

[-- Attachment #1: Type: text/plain, Size: 14491 bytes --]

Hi,

Paul Brook wrote:
> On Saturday 01 April 2006 02:39, Julian Brown wrote:
> 
>>Hi,
>>
>>This patch provides support for ARM's new Advanced SIMD (Neon)
>>instruction set, and version 3 of the VFP instruction set. Code using
>>Neon instructions can be both assembled and disassembled. The full range
>>of SIMD data types is available, and should be correctly type-checked by
>>the assembler.
> 
> 
> As-is the patch looks generally ok to me, a couple of relatively minor points 
> below. Ok for the csl branch once those are resolved.
> 
> ARM have also defined all the existing VFP instructions in terms of the vector 
> mnemonics. eg. "faddd d0, d0, d0" becomes "vadd.f64 d0, d0, d0).
> We probably want to consider the implications of this before applying to 
> mainline. Hopefully this will be an incremental change that can be done 
> without rewriting everything, but it's best to check :-)

I've not considered in detail how that bit's going to be done yet, but 
I'll hold off on mainline submission until it's implemented, if that 
seems like a good idea. I think it should be possible without too much 
perturbation though, hopefully.

>>+   /* Undo polymorphism for Neon D and Q registers.  */
>>+   if (reg && type == REG_TYPE_NDQ)
>>+     type = (reg->type == REG_TYPE_NQ || reg->type == REG_TYPE_VFD)
>>+            ? reg->type : type;
> 
> 
> Probably clearer as a single if:
> 
> if (reg && type == REG_TYPE_NDQ
>     &&(reg->type == REG_TYPE_NQ || reg->type == REG_TYPE_VFD))
>   type = reg->type;

Done.

>>!   /* FIXME: Check if cortex-a8 supports these things!  */
>>!   {"cortex-a8",               ARM_ARCH_V7A,    ARM_FEATURE(0, FPU_VFP_V3
> 
> 
> Yes it does. You can remove the FIXME.

Done.

>>+   {"vfp3",              FPU_ARCH_VFP_V3},
> 
> 
> You also need to add some way of enabling NEON. I'm not sure if it's best to 
> have this as an independent architecture extension (like iWMMXt) or just a 
> different type of FPU. Probably the latter.

I've gone with the latter for this version of the patch (against the CSL 
branch this time), though I'm not entirely conviced it's the right way 
to go. The build attribute for Neon is seperate (like the iWMMXt one). 
I've made -mfpu=neon turn on vfp3 too.

> You also need to set the appropriate EABI build attributes to when NEON and 
> VFPv3 instructions are used.

I think I uncovered a bug here: in aeabi_set_public_attributes, 
fpu_arch_vfp_v[12] was used instead of fpu_vfp_ext_v[12], which meant 
that essentially the Tag_VFP_arch tag was never set to 1 (the *arch* 
versions set bits for each VFP version supported, i.e. vfp2 sets vfp1 
and vfp1xd, so when ARM_CPU_HAS_FEATURE asks about vfpv2 and only vfpv1 
instructions were used, the result is wrongly affirmative).

If that is indeed not the desired behaviour, I expect we want that bit 
on mainline too independent of the rest of the patch.

Tested with "make check" crossed to arm-none-eabi. I'll install it on 
the CSL branch shortly. (There might still be an issue with the build 
attribute for VFPv3, but I'm 99% sure it'll be OK. If it's not, I'll 
address that with a followup patch.)

Cheers,

Julian

ChangeLog (binutils):

     * readelf.c (arm_attr_tag_VFP_arch): Add VFPv3.

ChangeLog (gas):

2006-04-01  Julian Brown  <julian@codesourcery.com>

     * config/tc-arm.c (limits.h): Include.
     (fpu_arch_vfp_v3, fpu_vfp_ext_v3, fpu_neon_ext_v1)
     (fpu_vfp_v3_or_neon_ext): Declare constants.
     (neon_el_type): New enumeration of types for Neon vector
     elements.
     (neon_type_el): New struct. Define type and size of a vector
     element.
     (NEON_MAX_TYPE_ELS): Define constant. The maximum number of types
     per instruction.
     (neon_type): Define struct. The type of an instruction.
     (arm_it): Add 'vectype' for the current instruction.
     (isscalar, immisalign, regisimm, isquad): New predicates for
     operands.
     (vfp_sp_reg_pos): Rename to...
     (vfp_reg_pos): ...this, and add VFP_REG_Dd, VFP_REG_Dm, VFP_REG_Dn
     tags.
     (arm_reg_type): Add REG_TYPE_NQ (Neon Q register) and REG_TYPE_NDQ
     (Neon D or Q register).
     (reg_expected_msgs): Sync with above. Allow VFD to mean VFP or Neon
     D register.
     (GE_OPT_PREFIX_BIG): Define constant, for use in...
     (my_get_expression): Allow above constant as argument to accept
     64-bit constants with optional prefix.
     (arm_reg_parse): Add extra argument to return the specific type
     of register in when either a D or Q register (REG_TYPE_NDQ) is
     requested. Can be NULL.
     (parse_scalar): New function. Parse Neon scalar (vector reg and
     index).
     (parse_reg_list): Update for new arm_reg_parse args.
     (parse_vfp_reg_list): Allow parsing of Neon D/Q register lists.
     (parse_neon_el_struct_list): New function. Parse element/structure
     register lists for VLD<n>/VST<n> instructions.
     (s_arm_unwind_save_vfp): Update for new parse_vfp_reg_list args.
     (s_arm_unwind_save_mmxwr): Likewise.
     (s_arm_unwind_save_mmxwcg): Likewise.
     (s_arm_unwind_movsp): Likewise.
     (s_arm_unwind_setfp): Likewise.
     (parse_big_immediate): New function. Parse an immediate, which may
     be 64 bits wide. Put results in inst.operands[i].
     (parse_shift): Update for new arm_reg_parse args.
     (parse_address): Likewise. Add parsing of alignment specifiers.
     (parse_neon_mov): Parse the operands of a VMOV instruction.
     (operand_parse_code): Add OP_RND, OP_RNQ, OP_RNDQ, OP_RNSC,
     OP_NRDLST, OP_NSTRLST, OP_NILO, OP_RNDQ_I0, OP_RR_RNSC,
     OP_RNDQ_RNSC, OP_RND_RNSC, OP_VMOV, OP_RNDQ_IMVNb, OP_RNDQ_I63b,
     OP_I0, OP_I16z, OP_I32z, OP_I64, OP_I64z, OP_oI32b, OP_oRND,
     OP_oRNQ, OP_oRNDQ.
     (parse_operands): Handle new codes above.
     (encode_arm_vfp_sp_reg): Rename to...
     (encode_arm_vfp_reg): ...this. Handle D regs (0-31) too. Complain if
     selected VFP version only supports D0-D15.
     (do_vfp_sp_monadic, do_vfp_sp_dyadic, do_vfp_sp_compare_z)
     (do_vfp_dp_sp_cvt, do_vfp_reg_from_sp, do_vfp_reg2_from_sp2)
     (do_vfp_sp_from_reg, do_vfp_sp2_from_reg2, do_vfp_sp_ldst)
     (do_vfp_dp_ldst, vfp_sp_ldstm, vfp_dp_ldstm): Update for new
     encode_arm_vfp_reg name, and allow 32 D regs.
     (do_vfp_dp_rd_rm, do_vfp_dp_rn_rd, do_vfp_dp_rd_rn)
     (do_vfp_dp_rd_rn_rm, do_vfp_rm_rd_rn): New functions to encode VFP
     insns allowing 32 D regs.
     (do_vfp_sp_const, do_vfp_dp_const, vfp_conv, do_vfp_sp_conv_16)
     (do_vfp_dp_conv_16, do_vfp_sp_conv_32, do_vfp_dp_conv_32): Handle
     constant-load and conversion insns introduced with VFPv3.
     (neon_tab_entry): New struct.
     (NEON_ENC_TAB): Bit patterns for overloaded Neon instructions, and
     those which are the targets of pseudo-instructions.
     (neon_opc): Enumerate opcodes, use as indices into...
     (neon_enc_tab): ...this. Hold data from NEON_ENC_TAB.
     (NEON_ENC_INTEGER, NEON_ENC_ARMREG, NEON_ENC_POLY, NEON_ENC_FLOAT)
     (NEON_ENC_SCALAR, NEON_ENC_IMMED, NEON_ENC_INTERLV, NEON_ENC_LANE)
     (NEON_ENC_DUP): Define meaningful helper macros to look up values in
     neon_enc_tab.
     (neon_shape): Enumerate shapes (permitted register widths, etc.) for
     Neon instructions.
     (neon_type_mask): New. Compact type representation for type
     checking.
     (N_SU_ALL, N_SU_32, N_SU_16_64, N_SUF_32, N_I_ALL, N_IF_32): Common
     permitted type combinations.
     (N_IGNORE_TYPE): New macro.
     (neon_check_shape): New function. Check an instruction shape for
     multiple alternatives. Return the specific shape for the current
     instruction.
     (neon_modify_type_size): New function. Modify a vector type and
     size, depending on the bit mask in argument 1.
     (neon_type_promote): New function. Convert a given "key" type (of an
     operand) into the correct type for a different operand, based on a
     bit mask.
     (type_chk_of_el_type): New function. Convert a type and size into
     the compact representation used for type checking.
     (el_type_of_type_ckh): New function. Reverse of above (only when a
     single bit is set in the bit mask).
     (modify_types_allowed): New function. Alter a mask of allowed types
     based on a bit mask of modifications.
     (neon_check_type): New function. Check the type of the current
     instruction against the variable argument list. The "key" type of
     the instruction is returned.
     (neon_dp_fixup): New function. Fill in and modify instruction bits
     for a Neon data-processing instruction depending on whether we're in
     ARM mode or Thumb-2 mode.
     (neon_logbits): New function.
     (neon_three_same, neon_two_same, do_neon_dyadic_i_su)
     (do_neon_dyadic_i64_su, neon_imm_shift, do_neon_shl_imm)
     (do_neon_qshl_imm, neon_cmode_for_logic_imm)
     (neon_bits_same_in_bytes, neon_squash_bits, neon_is_quarter_float)
     (neon_qfloat_bits, neon_cmode_for_move_imm, neon_write_immbits)
     (neon_invert_size, do_neon_logic, do_neon_bitfield, neon_dyadic)
     (do_neon_dyadic_if_su, do_neon_dyadic_if_su_d, do_neon_dyadic_if_i)
     (do_neon_dyadic_if_i_d, do_neon_addsub_if_i, neon_exchange_operands)
     (neon_compare, do_neon_cmp, do_neon_cmp_inv, do_neon_ceq)
     (neon_scalar_for_mul, neon_mul_mac, do_neon_mac_maybe_scalar)
     (do_neon_tst, do_neon_mul, do_neon_qdmulh, do_neon_fcmp_absolute)
     (do_neon_fcmp_absolute_inv, do_neon_step, do_neon_abs_neg)
     (do_neon_sli, do_neon_sri, do_neon_qshlu_imm, do_neon_qmovn)
     (do_neon_qmovun, do_neon_rshift_sat_narrow)
     (do_neon_rshift_sat_narrow_u, do_neon_movn, do_neon_rshift_narrow)
     (do_neon_shll, neon_cvt_flavour, do_neon_cvt, neon_move_immediate)
     (do_neon_mvn, neon_mixed_length, do_neon_dyadic_long, do_neon_abal)
     (neon_mac_reg_scalar_long, do_neon_mac_maybe_scalar_long)
     (do_neon_dyadic_wide, do_neon_vmull, do_neon_ext, do_neon_rev)
     (do_neon_dup, do_neon_mov, do_neon_rshift_round_imm, do_neon_movl)
     (do_neon_trn, do_neon_zip_uzp, do_neon_sat_abs_neg)
     (do_neon_pair_long, do_neon_recip_est, do_neon_cls, do_neon_clz)
     (do_neon_cnt, do_neon_swp, do_neon_tbl_tbx, do_neon_ldm_stm)
     (do_neon_ldr_str, do_neon_ld_st_interleave, neon_alignment_bit)
     (do_neon_ld_st_lane, do_neon_ld_dup, do_neon_ldx_stx): New
     functions. Neon bit encoding and encoding helpers.
     (parse_neon_type): New function. Parse Neon type specifier.
     (opcode_lookup): Allow parsing of Neon type specifiers.
     (REGNUM2, REGSETH, REGSET2): New macros.
     (reg_names): Add new VFPv3 and Neon registers.
     (NUF, nUF, NCE, nCE): New macros for opcode table.
     (insns): More VFP registers allowed in fcpyd, fmdhr, fmdlr, fmrdh,
     fmrdl, fabsd, fnegd, fsqrtd, faddd, fsubd, fmuld, fdivd, fmacd,
     fmscd, fnmuld, fnmacd, fnmscd, fcmpd, fcmpzd, fcmped, fcmpezd,
     fmdrr, fmrrd. Add Neon instructions vaba, vhadd, vrhadd, vhsub,
     vqadd, vqsub, vrshl, vqrshl, vshl, vqshl{u}, vand, vbic, vorr, vorn,
     veor, vbsl, vbit, vbif, vabd, vmax, vmin, vcge, vcgt, vclt, vcle,
     vceq, vpmax, vpmin, vmla, vmls, vpadd, vadd, vsub, vtst, vmul,
     vqdmulh, vqrdmulh, vacge, vacgt, vaclt, vacle, vrecps, vrsqrts,
     vabs, vneg, v{r}shr,  v{r}sra, vsli, vsri, vqshrn, vq{r}shr{u}n,
     v{r}shrn, vshll, vcvt, vmov, vmvn, vabal, vabdl, vaddl, vsubl,
     vmlal, vmlsl, vaddw, vsubw, v{r}addhn, v{r}subhn, vqdmlal, vqdmlsl,
     vqdmull, vmull, vext, vrev64, vrev32, vrev16, vdup, vmovl, v{q}movn,
     vzip, vuzp, vqabs, vqneg, vpadal, vpaddl, vrecpe, vrsqrte, vcls,
     vclz, vcnt, vswp, vtrn, vtbl, vtbx, vldm, vstm, vldr, vstr,
     vld[1234], vst[1234], fconst[sd], f[us][lh]to[sd], fto[us][lh][sd].
     (tc_arm_regname_to_dw2regnum): Update for arm_reg_parse args.
     (arm_cpu_option_table): Add Neon and VFPv3 to Cortex-A8.
     (arm_option_cpu_value): Add vfp3 and neon.
     (aeabi_set_public_attributes): Support VFPv3 and NEON attributes.
     Fix VFPv1 attribute.


ChangeLog (gas/testsuite):

2006-04-01  Julian Brown  <julian@codesourcery.com>

     * gas/arm/copro.s: Avoid ldcl which encodes as a bad Neon
     instruction.
     * gas/arm/copro.d: Update accordingly.
     * gas/arm/neon-cond.s: New test. Conditional Neon opcodes in ARM
    mode.
     * gas/arm/neon-cond.d: Expected results of above.
     * gas/arm/neon-cov.s: New test. Coverage of Neon instructions.
     * gas/arm/neon-cov.d: Expected results of above.
     * gas/arm/neon-ldst-es.s: New test. Element and structure loads and
     stores.
     * gas/arm/neon-ldst-es.d: Expected results of above.
     * gas/arm/neon-ldst-rm.s: New test. Single and multiple register
     loads and stores.
     * gas/arm/neon-ldst-rm.d: Expected results of above.
     * gas/arm/neon-omit.s: New test. Omission of optional operands.
     * gas/arm/neon-omit.d: Expected results of above.
     * gas/arm/vfp1.d: Expect Neon syntax for some VFP instructions.
     * gas/arm/vfp1_t2.d: Likewise.
     * gas/arm/vfp1xD.d: Likewise.
     * gas/arm/vfp1xD_t2.d: Likewise.
     * gas/arm/vfp2.d: Likewise.
     * gas/arm/vfp2_t2.d: Likewise.
     * gas/arm/vfp3-32drs.s: New test. Extended D register range for VFP
     instructions.
     * gas/arm/vfp3-32drs.d: Expected results of above.
     * gas/arm/vfp3-const-conv.s: New test. VFPv3 constant-load and
     conversion instructions.
     * gas/arm/vfp3-const-conv.d: Expected results of above.

ChangeLog (include):

2006-04-01  Julian Brown  <julian@codesourcery.com>

     * opcode/arm.h (FPU_VFP_EXT_V3): Define constant.
     (FPU_NEON_EXT_V1): Likewise.
     (FPU_VFP_HARD): Update.
     (FPU_VFP_V3): Define macro.
     (FPU_ARCH_VFP_V3, FPU_ARCH_VFP_V3_PLUS_NEON_V1): Define macros.

ChangeLog (opcodes/arm-dis.c):

2006-04-01  Nathan Sidwell  <nathan@codesourcery.com>
             Julian Brown  <julian@codesourcery.com>

     * opcodes/arm-dis.c (coprocessor_opcodes): Add %A, %B, %k,
     convert %<code>[zy] into %[zy]<code>.  Expand meaning of
     %<bitfield>['`?].
     Add unified load/store instruction names.
     (neon_opcode_table): New.
     (arm_opcodes): Expand meaning of %<bitfield>['`?].
     (arm_decode_bitfield): New.
     (print_insn_coprocessor): Add pc argument. Add %A & %B
     specifiers. Use arm_decode_bitfield and adjust numeric
     specifiers.
     Adjust %z & %y.
     (print_insn_neon): New.
     (print_insn_arm): Adjust print_insn_coprocessor call. Call
     print_insn_neon. Use arm_decode_bitfield and adjust numeric
     specifiers.
     (print_insn_thumb32): Likewise.


[-- Attachment #2: neon-support-4.gz --]
[-- Type: application/x-gzip, Size: 65965 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] ARM Neon instruction set support
  2006-04-02 23:30   ` Julian Brown
@ 2006-04-19 16:38     ` Julian Brown
  2006-04-25 19:12       ` Nick Clifton
  2006-04-25 19:20       ` [PATCH] ARM Neon programmers syntax Nick Clifton
  0 siblings, 2 replies; 8+ messages in thread
From: Julian Brown @ 2006-04-19 16:38 UTC (permalink / raw)
  To: Julian Brown; +Cc: Paul Brook, binutils, Richard Earnshaw, nickc

Julian Brown wrote:
> 
> I've not considered in detail how that bit's going to be done yet, but 
> I'll hold off on mainline submission until it's implemented, if that 
> seems like a good idea. I think it should be possible without too much 
> perturbation though, hopefully.

If it's not bad form, I'd like to retract the "holding off on mainline 
submission" part of the above -- this patch is blocking some other 
patches on mainline, so I'd like to commit it now, if possible.

If someone could review this (and the followup patch re: programmers 
syntax), I'd be grateful!

Cheers,

Julian

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] ARM Neon instruction set support
  2006-04-19 16:38     ` Julian Brown
@ 2006-04-25 19:12       ` Nick Clifton
  2006-04-25 19:20       ` [PATCH] ARM Neon programmers syntax Nick Clifton
  1 sibling, 0 replies; 8+ messages in thread
From: Nick Clifton @ 2006-04-25 19:12 UTC (permalink / raw)
  To: Julian Brown; +Cc: Paul Brook, binutils, Richard Earnshaw

Hi Julian,

> If it's not bad form, I'd like to retract the "holding off on mainline 
> submission" part of the above -- this patch is blocking some other 
> patches on mainline, so I'd like to commit it now, if possible.
> 
> If someone could review this

Very well, please consider your patch approved for the mainline as well.
But lets leave it out of the 2_17 branch, OK ?

Cheers
   Nick


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] ARM Neon programmers syntax
  2006-04-19 16:38     ` Julian Brown
  2006-04-25 19:12       ` Nick Clifton
@ 2006-04-25 19:20       ` Nick Clifton
  1 sibling, 0 replies; 8+ messages in thread
From: Nick Clifton @ 2006-04-25 19:20 UTC (permalink / raw)
  To: Julian Brown; +Cc: Paul Brook, binutils, Richard Earnshaw

Hi Julian,

   This patch is approved for the mainline (but not the 2_17 branch).

Cheers
   Nick

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] ARM Neon programmers syntax
  2006-04-06 16:43 Julian Brown
@ 2006-04-06 18:56 ` Paul Brook
  0 siblings, 0 replies; 8+ messages in thread
From: Paul Brook @ 2006-04-06 18:56 UTC (permalink / raw)
  To: binutils; +Cc: Julian Brown

On Thursday 06 April 2006 17:12, Julian Brown wrote:
> This patch implements the Neon "programmers syntax" on top of my
> previous patch here:
>
>    http://sourceware.org/ml/binutils/2006-04/msg00011.html
>
> This allows vector element types to be written after operands rather
> than after the mnemonic, and allows typed register aliases to be defined.
>
> The patch also contains various bug fixes. Tested with "make check",
> with a basic test of the programmers syntax added. OK to apply on
> binutils-csl-2_17-branch?

Ok.

Paul

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH] ARM Neon programmers syntax
@ 2006-04-06 16:43 Julian Brown
  2006-04-06 18:56 ` Paul Brook
  0 siblings, 1 reply; 8+ messages in thread
From: Julian Brown @ 2006-04-06 16:43 UTC (permalink / raw)
  To: binutils; +Cc: Paul Brook

[-- Attachment #1: Type: text/plain, Size: 5553 bytes --]

Hi,

This patch implements the Neon "programmers syntax" on top of my 
previous patch here:

   http://sourceware.org/ml/binutils/2006-04/msg00011.html

This allows vector element types to be written after operands rather 
than after the mnemonic, and allows typed register aliases to be defined.

For the latter, I've used syntax like the following:

foo	.dn	d5.s32

or more generally (excuse the quasi-regexp: | means alternation and {} 
means optional. () brackets are not literal):

<regname>	(.dn|.qn) (<reg>|<int>) {.<type>} {<index>}

This should be basically the same as the ARM assembler's syntax, but 
with the more "gas-like" .dn/.qn substituted for DN/QN.

Typed aliases occupy the same name space as built-in registers and 
aliases defined with ".req".

As extensions, .unreq can be used to undefine typed aliases, and types 
for registers can often be inferred when they're not given (when the 
"key" type -- usually the rightmost operand -- is known).

Unfortunately a couple of very commonly used structures have grown 
slightly (particularly reg_entry), but I don't think this should be a 
major problem.

The patch also contains various bug fixes. Tested with "make check", 
with a basic test of the programmers syntax added. OK to apply on 
binutils-csl-2_17-branch?

Cheers,

Julian

ChangeLog (gas):

     * config/tc-arm.c (neon_el_type): Make NT_invtype be the zero (so
     zero-initialising structures containing it will lead to invalid
     types).
     (arm_it): Add vectype to each operand.
     (NTA_HASTYPE, NTA_HASINDEX): Constants used in neon_typed_alias
     defined field.
     (neon_typed_alias): New structure. Extra information for typed
     register aliases.
     (reg_entry): Add neon type info field.
     (arm_reg_parse): Remove RTYPE argument (revert to previous
     arguments). Break out alternative syntax for coprocessor registers,
     etc. into...
     (arm_reg_alt_syntax): New function. Alternate syntax handling broken
     out from arm_reg_parse.
     (parse_neon_type): Move. Return SUCCESS/FAIL.
     (first_error): New function. Call to ensure first error which
     occurs is reported.
     (parse_neon_operand_type): Parse exactly one type.
     (NEON_ALL_LANES, NEON_INTERLEAVE_LANES): Move.
     (parse_typed_reg_or_scalar): New function. Handle core of both
     arm_typed_reg_parse and parse_scalar.
     (arm_typed_reg_parse): Parse a register with an optional type.
     (NEON_SCALAR_REG, NEON_SCALAR_INDEX): Extract parts of parse_scalar
     result.
     (parse_scalar): Parse a Neon scalar with optional type.
     (parse_reg_list): Use first_error.
     (parse_vfp_reg_list): Use arm_typed_reg_parse instead of
     arm_reg_parse.
     (neon_alias_types_same): New function. Return true if two (alias)
     types are the same.
     (parse_neon_el_struct_list): Use parse_typed_reg_or_scalar. Return
     type of elements.
     (insert_reg_alias): Return new reg_entry not void.
     (insert_neon_reg_alias): New function. Insert type/index information
     as well as register for alias.
     (create_neon_reg_alias): New function. Parse .dn/.qn directives and
     make typed register aliases accordingly.
     (s_dn, s_qn): New functions. Handle incorrectly used .dn/.qn at
     start of line.
     (s_unreq): Delete type information if present.
     (s_arm_unwind_save_mmxwr): Remove arg 3 from arm_reg_parse calls.
     (s_arm_unwind_save_mmxwcg): Likewise.
     (s_arm_unwind_movsp): Likewise.
     (s_arm_unwind_setfp): Likewise.
     (parse_shift): Likewise.
     (parse_shifter_operand): Likewise.
     (parse_address): Likewise.
     (parse_tb): Likewise.
     (tc_arm_regname_to_dw2regnum): Likewise.
     (md_pseudo_table): Add dn, qn.
     (parse_neon_mov): Handle typed operands.
     (parse_operands): Likewise.
     (neon_type_mask): Add N_SIZ.
     (N_ALLMODS): New macro.
     (neon_check_shape): Fix typo in NS_DDD_QQQ case. Use first_error.
     (el_type_of_type_chk): Add some safeguards.
     (modify_types_allowed): Fix logic bug.
     (neon_check_type): Handle operands with types.
     (neon_three_same): Remove redundant optional arg handling.
     (do_neon_dyadic_i64_su, do_neon_shl_imm, do_neon_qshl_imm)
     (do_neon_logic, do_neon_qdmulh, do_neon_fcmp_absolute)
     (do_neon_step): Adjust accordingly.
     (neon_cmode_for_logic_imm): Use first_error.
     (do_neon_bitfield): Call neon_check_type.
     (neon_dyadic): Rename to...
     (neon_dyadic_misc): ...this. New name for neon_dyadic. Add bitfield
     to allow modification of type of the destination.
     (do_neon_dyadic_if_su, do_neon_dyadic_if_i, do_neon_dyadic_if_i_d)
     (do_neon_addsub_if_i, do_neon_mul): Adjust accordingly.
     (do_neon_compare): Make destination be an untyped bitfield.
     (neon_scalar_for_mul): Use NEON_SCALAR_REG, NEON_SCALAR_INDEX.
     (neon_mul_mac): Return early in case of errors.
     (neon_move_immediate): Use first_error.
     (neon_mac_reg_scalar_long): Fix type to include scalar.
     (do_neon_dup): Likewise.
     (do_neon_mov): Likewise (in several places).
     (do_neon_tbl_tbx): Fix type.
     (do_neon_ld_st_interleave, neon_alignment_bit, do_neon_ld_st_lane)
     (do_neon_ld_dup): Exit early in case of errors and/or use
     first_error.
     (opcode_lookup): Update for parse_neon_type returning SUCCESS/FAIL.
     Handle .dn/.qn directives.
     (REGDEF): Add zero for reg_entry neon field.

ChangeLog (gas/testsuite):

     * gas/arm/neon-psyn.s: Basic test of programmers syntax.
     * gas/arm/neon-psyn.d: Expected output of above.

[-- Attachment #2: prog-syntax-6 --]
[-- Type: text/plain, Size: 94436 bytes --]

? bfd/doc/bfd.info
? binutils/doc/binutils.info
? gas/doc/as.info
? ld/ld.info
Index: gas/config/tc-arm.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-arm.c,v
retrieving revision 1.250.2.8
diff -c -p -r1.250.2.8 tc-arm.c
*** gas/config/tc-arm.c	3 Apr 2006 00:03:33 -0000	1.250.2.8
--- gas/config/tc-arm.c	6 Apr 2006 15:13:49 -0000
*************** static bfd_boolean unified_syntax = FALS
*** 265,277 ****
  
  enum neon_el_type
  {
    NT_untyped,
    NT_integer,
    NT_float,
    NT_poly,
    NT_signed,
!   NT_unsigned,
!   NT_invtype
  };
  
  struct neon_type_el
--- 265,277 ----
  
  enum neon_el_type
  {
+   NT_invtype,
    NT_untyped,
    NT_integer,
    NT_float,
    NT_poly,
    NT_signed,
!   NT_unsigned
  };
  
  struct neon_type_el
*************** struct arm_it
*** 310,315 ****
--- 310,316 ----
    {
      unsigned reg;
      signed int imm;
+     struct neon_type_el vectype;
      unsigned present	: 1;  /* Operand present.  */
      unsigned isreg	: 1;  /* Operand was a register.  */
      unsigned immisreg	: 1;  /* .imm field is a second register.  */
*************** enum vfp_ldstm_type
*** 405,410 ****
--- 406,422 ----
    VFP_LDSTMIA, VFP_LDSTMDB, VFP_LDSTMIAX, VFP_LDSTMDBX
  };
  
+ /* Bits for DEFINED field in neon_typed_alias.  */
+ #define NTA_HASTYPE  1
+ #define NTA_HASINDEX 2
+ 
+ struct neon_typed_alias
+ {
+   unsigned char defined;
+   unsigned char index;
+   struct neon_type_el eltype;
+ };
+ 
  /* ARM register categories.  This includes coprocessor numbers and various
     architecture extensions' registers.	*/
  enum arm_reg_type
*************** enum arm_reg_type
*** 430,442 ****
    REG_TYPE_XSCALE,
  };
  
! /* Structure for a hash table entry for a register.  */
  struct reg_entry
  {
!   const char   *name;
!   unsigned char number;
!   unsigned char type;
!   unsigned char builtin;
  };
  
  /* Diagnostics used when we don't get a register of the expected type.	*/
--- 442,458 ----
    REG_TYPE_XSCALE,
  };
  
! /* Structure for a hash table entry for a register.
!    If TYPE is REG_TYPE_VFD or REG_TYPE_NQ, the NEON field can point to extra
!    information which states whether a vector type or index is specified (for a
!    register alias created with .dn or .qn). Otherwise NEON should be NULL.  */
  struct reg_entry
  {
!   const char        *name;
!   unsigned char      number;
!   unsigned char      type;
!   unsigned char      builtin;
!   struct neon_typed_alias *neon;
  };
  
  /* Diagnostics used when we don't get a register of the expected type.	*/
*************** arm_reg_parse_multi (char **ccp)
*** 989,1016 ****
    return reg;
  }
  
- /* As above, but the register must be of type TYPE, and the return
-    value is the register number or FAIL.
-    If RTYPE is non-zero, return the (possibly restricted) type of the
-    register (e.g. Neon double or quad reg when either has been requested).  */
- 
  static int
! arm_reg_parse (char **ccp, enum arm_reg_type type, enum arm_reg_type *rtype)
  {
-   char *start = *ccp;
-   struct reg_entry *reg = arm_reg_parse_multi (ccp);
- 
-   /* Undo polymorphism for Neon D and Q registers.  */
-   if (reg && type == REG_TYPE_NDQ
-       && (reg->type == REG_TYPE_NQ || reg->type == REG_TYPE_VFD))
-     type = reg->type;
- 
-   if (rtype)
-     *rtype = type;
- 
-   if (reg && reg->type == type)
-     return reg->number;
- 
    /* Alternative syntaxes are accepted for a few register classes.  */
    switch (type)
      {
--- 1005,1014 ----
    return reg;
  }
  
  static int
! arm_reg_alt_syntax (char **ccp, char *start, struct reg_entry *reg,
!                     enum arm_reg_type type)
  {
    /* Alternative syntaxes are accepted for a few register classes.  */
    switch (type)
      {
*************** arm_reg_parse (char **ccp, enum arm_reg_
*** 1042,1089 ****
        break;
      }
  
    *ccp = start;
    return FAIL;
  }
  
  /* Parse a Neon scalar. Most of the time when we're parsing a scalar, we don't
     have enough information to be able to do a good job bounds-checking. So, we
     just do easy checks here, and do further checks later.  */
  
  static int
! parse_scalar (char **ccp, int elsize)
  {
!   int regno, elno;
    char *str = *ccp;
!   expressionS exp;
    
!   if ((regno = arm_reg_parse (&str, REG_TYPE_VFD, NULL)) == FAIL)
!     return FAIL;
    
!   if (skip_past_char (&str, '[') == FAIL)
      return FAIL;
    
!   my_get_expression (&exp, &str, GE_NO_PREFIX);
!   if (exp.X_op != O_constant)
      {
!       inst.error = _("constant expression required");
        return FAIL;
      }
!   elno = exp.X_add_number;
!   
!   if (elno >= 64 / elsize)
      {
!       inst.error = _("scalar index out of range");
        return FAIL;
      }
    
!   if (skip_past_char (&str, ']') == FAIL)
!     return FAIL;
    
-   /* Parsed scalar successfully. Skip over it.  */
    *ccp = str;
    
!   return (regno * 8) + elno;
  }
  
  /* Parse an ARM register list.  Returns the bitmask, or FAIL.  */
--- 1040,1378 ----
        break;
      }
  
+   return FAIL;
+ }
+ 
+ /* As arm_reg_parse_multi, but the register must be of type TYPE, and the
+    return value is the register number or FAIL.  */
+ 
+ static int
+ arm_reg_parse (char **ccp, enum arm_reg_type type)
+ {
+   char *start = *ccp;
+   struct reg_entry *reg = arm_reg_parse_multi (ccp);
+   int ret;
+ 
+   /* Do not allow a scalar (reg+index) to parse as a register.  */
+   if (reg && reg->neon && (reg->neon->defined & NTA_HASINDEX))
+     return FAIL;
+ 
+   if (reg && reg->type == type)
+     return reg->number;
+ 
+   if ((ret = arm_reg_alt_syntax (ccp, start, reg, type)) != FAIL)
+     return ret;
+ 
    *ccp = start;
    return FAIL;
  }
  
+ /* Parse a Neon type specifier. *STR should point at the leading '.'
+    character. Does no verification at this stage that the type fits the opcode
+    properly. E.g.,
+ 
+      .i32.i32.s16
+      .s32.f32
+      .u16
+ 
+    Can all be legally parsed by this function.
+ 
+    Fills in neon_type struct pointer with parsed information, and updates STR
+    to point after the parsed type specifier. Returns SUCCESS if this was a legal
+    type, FAIL if not.  */
+ 
+ static int
+ parse_neon_type (struct neon_type *type, char **str)
+ {
+   char *ptr = *str;
+ 
+   if (type)
+     type->elems = 0;
+ 
+   while (type->elems < NEON_MAX_TYPE_ELS)
+     {
+       enum neon_el_type thistype = NT_untyped;
+       unsigned thissize = -1u;
+ 
+       if (*ptr != '.')
+ 	break;
+ 
+       ptr++;
+ 
+       /* Just a size without an explicit type.  */
+       if (ISDIGIT (*ptr))
+ 	goto parsesize;
+ 
+       switch (TOLOWER (*ptr))
+ 	{
+ 	case 'i': thistype = NT_integer; break;
+ 	case 'f': thistype = NT_float; break;
+ 	case 'p': thistype = NT_poly; break;
+ 	case 's': thistype = NT_signed; break;
+ 	case 'u': thistype = NT_unsigned; break;
+ 	default:
+ 	  as_bad (_("unexpected character `%c' in type specifier"), *ptr);
+ 	  return FAIL;
+ 	}
+ 
+       ptr++;
+ 
+       /* .f is an abbreviation for .f32.  */
+       if (thistype == NT_float && !ISDIGIT (*ptr))
+ 	thissize = 32;
+       else
+ 	{
+ 	parsesize:
+ 	  thissize = strtoul (ptr, &ptr, 10);
+ 
+ 	  if (thissize != 8 && thissize != 16 && thissize != 32
+               && thissize != 64)
+             {
+               as_bad (_("bad size %d in type specifier"), thissize);
+ 	      return FAIL;
+ 	    }
+ 	}
+ 
+       if (type)
+         {
+           type->el[type->elems].type = thistype;
+ 	  type->el[type->elems].size = thissize;
+ 	  type->elems++;
+ 	}
+     }
+ 
+   /* Empty/missing type is not a successful parse.  */
+   if (type->elems == 0)
+     return FAIL;
+ 
+   *str = ptr;
+ 
+   return SUCCESS;
+ }
+ 
+ /* Errors may be set multiple times during parsing or bit encoding
+    (particularly in the Neon bits), but usually the earliest error which is set
+    will be the most meaningful. Avoid overwriting it with later (cascading)
+    errors by calling this function.  */
+ 
+ static void
+ first_error (const char *err)
+ {
+   if (!inst.error)
+     inst.error = err;
+ }
+ 
+ /* Parse a single type, e.g. ".s32", leading period included.  */
+ static int
+ parse_neon_operand_type (struct neon_type_el *vectype, char **ccp)
+ {
+   char *str = *ccp;
+   struct neon_type optype;
+ 
+   if (*str == '.')
+     {
+       if (parse_neon_type (&optype, &str) == SUCCESS)
+         {
+           if (optype.elems == 1)
+             *vectype = optype.el[0];
+           else
+             {
+               first_error (_("only one type should be specified for operand"));
+               return FAIL;
+             }
+         }
+       else
+         {
+           first_error (_("vector type expected"));
+           return FAIL;
+         }
+     }
+   else
+     return FAIL;
+   
+   *ccp = str;
+   
+   return SUCCESS;
+ }
+ 
+ /* Special meanings for indices (which have a range of 0-7), which will fit into
+    a 4-bit integer.  */
+ 
+ #define NEON_ALL_LANES		15
+ #define NEON_INTERLEAVE_LANES	14
+ 
+ /* Parse either a register or a scalar, with an optional type. Return the
+    register number, and optionally fill in the actual type of the register
+    when multiple alternatives were given (NEON_TYPE_NDQ) in *RTYPE, and
+    type/index information in *TYPEINFO.  */
+ 
+ static int
+ parse_typed_reg_or_scalar (char **ccp, enum arm_reg_type type,
+                            enum arm_reg_type *rtype,
+                            struct neon_typed_alias *typeinfo)
+ {
+   char *str = *ccp;
+   struct reg_entry *reg = arm_reg_parse_multi (&str);
+   struct neon_typed_alias atype;
+   struct neon_type_el parsetype;
+ 
+   atype.defined = 0;
+   atype.index = -1;
+   atype.eltype.type = NT_invtype;
+   atype.eltype.size = -1;
+ 
+   /* Try alternate syntax for some types of register. Note these are mutually
+      exclusive with the Neon syntax extensions.  */
+   if (reg == NULL)
+     {
+       int altreg = arm_reg_alt_syntax (&str, *ccp, reg, type);
+       if (altreg != FAIL)
+         *ccp = str;
+       if (typeinfo)
+         *typeinfo = atype;
+       return altreg;
+     }
+ 
+   /* Undo polymorphism for Neon D and Q registers.  */
+   if (type == REG_TYPE_NDQ
+       && (reg->type == REG_TYPE_NQ || reg->type == REG_TYPE_VFD))
+     type = reg->type;
+ 
+   if (type != reg->type)
+     return FAIL;
+ 
+   if (reg->neon)
+     atype = *reg->neon;
+   
+   if (parse_neon_operand_type (&parsetype, &str) == SUCCESS)
+     {
+       if ((atype.defined & NTA_HASTYPE) != 0)
+         {
+           first_error (_("can't redefine type for operand"));
+           return FAIL;
+         }
+       atype.defined |= NTA_HASTYPE;
+       atype.eltype = parsetype;
+     }
+     
+   if (skip_past_char (&str, '[') == SUCCESS)
+     {
+       if (type != REG_TYPE_VFD)
+         {
+           first_error (_("only D registers may be indexed"));
+           return FAIL;
+         }
+     
+       if ((atype.defined & NTA_HASINDEX) != 0)
+         {
+           first_error (_("can't change index for operand"));
+           return FAIL;
+         }
+ 
+       atype.defined |= NTA_HASINDEX;
+ 
+       if (skip_past_char (&str, ']') == SUCCESS)
+         atype.index = NEON_ALL_LANES;
+       else
+         {
+           expressionS exp;
+ 
+           my_get_expression (&exp, &str, GE_NO_PREFIX);
+ 
+           if (exp.X_op != O_constant)
+             {
+               first_error (_("constant expression required"));
+               return FAIL;
+             }
+ 
+           if (skip_past_char (&str, ']') == FAIL)
+             return FAIL;
+ 
+           atype.index = exp.X_add_number;
+         }
+     }
+   
+   if (typeinfo)
+     *typeinfo = atype;
+   
+   if (rtype)
+     *rtype = type;
+   
+   *ccp = str;
+   
+   return reg->number;
+ }
+ 
+ /* Like arm_reg_parse, but allow allow the following extra features:
+     - If RTYPE is non-zero, return the (possibly restricted) type of the
+       register (e.g. Neon double or quad reg when either has been requested).
+     - If this is a Neon vector type with additional type information, fill
+       in the struct pointed to by VECTYPE (if non-NULL).
+    This function will fault on encountering a scalar.
+ */
+ 
+ static int
+ arm_typed_reg_parse (char **ccp, enum arm_reg_type type,
+                      enum arm_reg_type *rtype, struct neon_type_el *vectype)
+ {
+   struct neon_typed_alias atype;
+   char *str = *ccp;
+   int reg = parse_typed_reg_or_scalar (&str, type, rtype, &atype);
+ 
+   if (reg == FAIL)
+     return FAIL;
+ 
+   /* Do not allow a scalar (reg+index) to parse as a register.  */
+   if ((atype.defined & NTA_HASINDEX) != 0)
+     {
+       first_error (_("register operand expected, but got scalar"));
+       return FAIL;
+     }
+ 
+   if (vectype)
+     *vectype = atype.eltype;
+ 
+   *ccp = str;
+ 
+   return reg;
+ }
+ 
+ #define NEON_SCALAR_REG(X)	((X) >> 4)
+ #define NEON_SCALAR_INDEX(X)	((X) & 15)
+ 
  /* Parse a Neon scalar. Most of the time when we're parsing a scalar, we don't
     have enough information to be able to do a good job bounds-checking. So, we
     just do easy checks here, and do further checks later.  */
  
  static int
! parse_scalar (char **ccp, int elsize, struct neon_type_el *type)
  {
!   int reg;
    char *str = *ccp;
!   struct neon_typed_alias atype;
    
!   reg = parse_typed_reg_or_scalar (&str, REG_TYPE_VFD, NULL, &atype);
    
!   if (reg == FAIL || (atype.defined & NTA_HASINDEX) == 0)
      return FAIL;
    
!   if (atype.index == NEON_ALL_LANES)
      {
!       first_error (_("scalar must have an index"));
        return FAIL;
      }
!   else if (atype.index >= 64 / elsize)
      {
!       first_error (_("scalar index out of range"));
        return FAIL;
      }
    
!   if (type)
!     *type = atype.eltype;
    
    *ccp = str;
    
!   return reg * 16 + atype.index;
  }
  
  /* Parse an ARM register list.  Returns the bitmask, or FAIL.  */
*************** parse_reg_list (char ** strp)
*** 1109,1117 ****
  	    {
  	      int reg;
  
! 	      if ((reg = arm_reg_parse (&str, REG_TYPE_RN, NULL)) == FAIL)
  		{
! 		  inst.error = _(reg_expected_msgs[REG_TYPE_RN]);
  		  return FAIL;
  		}
  
--- 1398,1406 ----
  	    {
  	      int reg;
  
! 	      if ((reg = arm_reg_parse (&str, REG_TYPE_RN)) == FAIL)
  		{
! 		  first_error (_(reg_expected_msgs[REG_TYPE_RN]));
  		  return FAIL;
  		}
  
*************** parse_reg_list (char ** strp)
*** 1121,1127 ****
  
  		  if (reg <= cur_reg)
  		    {
! 		      inst.error = _("bad range in register list");
  		      return FAIL;
  		    }
  
--- 1410,1416 ----
  
  		  if (reg <= cur_reg)
  		    {
! 		      first_error (_("bad range in register list"));
  		      return FAIL;
  		    }
  
*************** parse_reg_list (char ** strp)
*** 1152,1158 ****
  
  	  if (*str++ != '}')
  	    {
! 	      inst.error = _("missing `}'");
  	      return FAIL;
  	    }
  	}
--- 1441,1447 ----
  
  	  if (*str++ != '}')
  	    {
! 	      first_error (_("missing `}'"));
  	      return FAIL;
  	    }
  	}
*************** enum reg_list_els
*** 1231,1237 ****
             vtbl.8 d3,d4,d5
           This could be done (the meaning isn't really ambiguous), but doesn't
           fit in well with the current parsing framework.
!      - 32 D registers may be used (also true for VFPv3).  */
  
  static int
  parse_vfp_reg_list (char **str, unsigned int *pbase, enum reg_list_els etype)
--- 1520,1528 ----
             vtbl.8 d3,d4,d5
           This could be done (the meaning isn't really ambiguous), but doesn't
           fit in well with the current parsing framework.
!      - 32 D registers may be used (also true for VFPv3).
!    FIXME: Types are ignored in these register lists, which is probably a
!    bug.  */
  
  static int
  parse_vfp_reg_list (char **str, unsigned int *pbase, enum reg_list_els etype)
*************** parse_vfp_reg_list (char **str, unsigned
*** 1288,1300 ****
    do
      {
        int setmask = 1, addregs = 1;
!       new_base = arm_reg_parse (str, regtype, &regtype);
        if (new_base == FAIL)
  	{
! 	  inst.error = gettext (reg_expected_msgs[regtype]);
  	  return FAIL;
  	}
! 
        /* Note: a value of 2 * n is returned for the register Q<n>.  */
        if (regtype == REG_TYPE_NQ)
          {
--- 1579,1593 ----
    do
      {
        int setmask = 1, addregs = 1;
! 
!       new_base = arm_typed_reg_parse (str, regtype, &regtype, NULL);
! 
        if (new_base == FAIL)
  	{
! 	  first_error (_(reg_expected_msgs[regtype]));
  	  return FAIL;
  	}
!  
        /* Note: a value of 2 * n is returned for the register Q<n>.  */
        if (regtype == REG_TYPE_NQ)
          {
*************** parse_vfp_reg_list (char **str, unsigned
*** 1307,1313 ****
  
        if (mask & (setmask << new_base))
  	{
! 	  inst.error = _("invalid register list");
  	  return FAIL;
  	}
  
--- 1600,1606 ----
  
        if (mask & (setmask << new_base))
  	{
! 	  first_error (_("invalid register list"));
  	  return FAIL;
  	}
  
*************** parse_vfp_reg_list (char **str, unsigned
*** 1326,1332 ****
  
  	  (*str)++;
  
! 	  if ((high_range = arm_reg_parse (str, regtype, NULL)) == FAIL)
  	    {
  	      inst.error = gettext (reg_expected_msgs[regtype]);
  	      return FAIL;
--- 1619,1626 ----
  
  	  (*str)++;
  
! 	  if ((high_range = arm_typed_reg_parse (str, regtype, NULL, NULL))
!               == FAIL)
  	    {
  	      inst.error = gettext (reg_expected_msgs[regtype]);
  	      return FAIL;
*************** parse_vfp_reg_list (char **str, unsigned
*** 1378,1398 ****
    return count;
  }
  
  /* Parse element/structure lists for Neon VLD<n> and VST<n> instructions.
     The base register is put in *PBASE.
!    The lane (or one of the #defined constants below) is placed in bits [3:0] of
     the return value.
     The register stride (minus one) is put in bit 4 of the return value.
!    Bits [6:5] encode the list length (minus one).  */
  
- #define NEON_ALL_LANES		15
- #define NEON_INTERLEAVE_LANES	14
  #define NEON_LANE(X)		((X) & 0xf)
! #define NEON_REG_STRIDE(X)	(((X) & (1 << 4)) ? 2 : 1)
  #define NEON_REGLIST_LENGTH(X)	((((X) >> 5) & 3) + 1)
  
  static int
! parse_neon_el_struct_list (char **str, unsigned *pbase)
  {
    char *ptr = *str;
    int base_reg = -1;
--- 1672,1718 ----
    return count;
  }
  
+ /* True if two alias types are the same.  */
+ 
+ static int
+ neon_alias_types_same (struct neon_typed_alias *a, struct neon_typed_alias *b)
+ {
+   if (!a && !b)
+     return 1;
+     
+   if (!a || !b)
+     return 0;
+ 
+   if (a->defined != b->defined)
+     return 0;
+   
+   if ((a->defined & NTA_HASTYPE) != 0
+       && (a->eltype.type != b->eltype.type
+           || a->eltype.size != b->eltype.size))
+     return 0;
+ 
+   if ((a->defined & NTA_HASINDEX) != 0
+       && (a->index != b->index))
+     return 0;
+   
+   return 1;
+ }
+ 
  /* Parse element/structure lists for Neon VLD<n> and VST<n> instructions.
     The base register is put in *PBASE.
!    The lane (or one of the NEON_*_LANES constants) is placed in bits [3:0] of
     the return value.
     The register stride (minus one) is put in bit 4 of the return value.
!    Bits [6:5] encode the list length (minus one).
!    The type of the list elements is put in *ELTYPE, if non-NULL.  */
  
  #define NEON_LANE(X)		((X) & 0xf)
! #define NEON_REG_STRIDE(X)	((((X) >> 4) & 1) + 1)
  #define NEON_REGLIST_LENGTH(X)	((((X) >> 5) & 3) + 1)
  
  static int
! parse_neon_el_struct_list (char **str, unsigned *pbase,
!                            struct neon_type_el *eltype)
  {
    char *ptr = *str;
    int base_reg = -1;
*************** parse_neon_el_struct_list (char **str, u
*** 1404,1419 ****
    int addregs = 1;
    const char *const incr_error = "register stride must be 1 or 2";
    const char *const type_error = "mismatched element/structure types in list";
    
    if (skip_past_char (&ptr, '{') == SUCCESS)
      leading_brace = 1;
    
    do
      {
!       int getreg = arm_reg_parse (&ptr, rtype, &rtype);
        if (getreg == FAIL)
          {
!           inst.error = _(reg_expected_msgs[rtype]);
            return FAIL;
          }
        
--- 1724,1742 ----
    int addregs = 1;
    const char *const incr_error = "register stride must be 1 or 2";
    const char *const type_error = "mismatched element/structure types in list";
+   struct neon_typed_alias firsttype;
    
    if (skip_past_char (&ptr, '{') == SUCCESS)
      leading_brace = 1;
    
    do
      {
!       struct neon_typed_alias atype;
!       int getreg = parse_typed_reg_or_scalar (&ptr, rtype, &rtype, &atype);
! 
        if (getreg == FAIL)
          {
!           first_error (_(reg_expected_msgs[rtype]));
            return FAIL;
          }
        
*************** parse_neon_el_struct_list (char **str, u
*** 1425,1443 ****
                reg_incr = 1;
                addregs = 2;
              }
          }
        else if (reg_incr == -1)
          {
            reg_incr = getreg - base_reg;
            if (reg_incr < 1 || reg_incr > 2)
              {
!               inst.error = _(incr_error);
                return FAIL;
              }
          }
        else if (getreg != base_reg + reg_incr * count)
          {
!           inst.error = _(incr_error);
            return FAIL;
          }
        
--- 1748,1773 ----
                reg_incr = 1;
                addregs = 2;
              }
+           firsttype = atype;
          }
        else if (reg_incr == -1)
          {
            reg_incr = getreg - base_reg;
            if (reg_incr < 1 || reg_incr > 2)
              {
!               first_error (_(incr_error));
                return FAIL;
              }
          }
        else if (getreg != base_reg + reg_incr * count)
          {
!           first_error (_(incr_error));
!           return FAIL;
!         }
! 
!       if (!neon_alias_types_same (&atype, &firsttype))
!         {
!           first_error (_(type_error));
            return FAIL;
          }
        
*************** parse_neon_el_struct_list (char **str, u
*** 1445,1470 ****
           modes.  */
        if (ptr[0] == '-')
          {
            int hireg, dregs = (rtype == REG_TYPE_NQ) ? 2 : 1;
            if (lane == -1)
              lane = NEON_INTERLEAVE_LANES;
            else if (lane != NEON_INTERLEAVE_LANES)
              {
!               inst.error = _(type_error);
                return FAIL;
              }
            if (reg_incr == -1)
              reg_incr = 1;
            else if (reg_incr != 1)
              {
!               inst.error = _("don't use Rn-Rm syntax with non-unit stride");
                return FAIL;
              }
            ptr++;
!           hireg = arm_reg_parse (&ptr, rtype, NULL);
            if (hireg == FAIL)
              {
!               inst.error = _(reg_expected_msgs[rtype]);
                return FAIL;
              }
            count += hireg + dregs - getreg;
--- 1775,1806 ----
           modes.  */
        if (ptr[0] == '-')
          {
+           struct neon_typed_alias htype;
            int hireg, dregs = (rtype == REG_TYPE_NQ) ? 2 : 1;
            if (lane == -1)
              lane = NEON_INTERLEAVE_LANES;
            else if (lane != NEON_INTERLEAVE_LANES)
              {
!               first_error (_(type_error));
                return FAIL;
              }
            if (reg_incr == -1)
              reg_incr = 1;
            else if (reg_incr != 1)
              {
!               first_error (_("don't use Rn-Rm syntax with non-unit stride"));
                return FAIL;
              }
            ptr++;
!           hireg = parse_typed_reg_or_scalar (&ptr, rtype, NULL, &htype);
            if (hireg == FAIL)
              {
!               first_error (_(reg_expected_msgs[rtype]));
!               return FAIL;
!             }
!           if (!neon_alias_types_same (&htype, &firsttype))
!             {
!               first_error (_(type_error));
                return FAIL;
              }
            count += hireg + dregs - getreg;
*************** parse_neon_el_struct_list (char **str, u
*** 1478,1524 ****
            continue;
          }
        
!       if (skip_past_char (&ptr, '[') == SUCCESS)
          {
!           if (skip_past_char (&ptr, ']') == SUCCESS)
!             {
!               if (lane == -1)
!                 lane = NEON_ALL_LANES;
!               else if (lane != NEON_ALL_LANES)
!                 {
!                   inst.error = _(type_error);
!                   return FAIL;
!                 }
!             }
!           else
              {
!               expressionS exp;
!               my_get_expression (&exp, &ptr, GE_NO_PREFIX);
!               if (exp.X_op != O_constant)
!                 {
!                   inst.error = _("constant expression required");
!                   return FAIL;
!                 }
!               if (lane == -1)
!                 lane = exp.X_add_number;
!               else if (lane != exp.X_add_number)
!                 {
!                   inst.error = _(type_error);
!                   return FAIL;
!                 }
!               
!               if (skip_past_char (&ptr, ']') == FAIL)
!                 {
!                   inst.error = _("expected ]");
!                   return FAIL;
!                 }
              }
          }
        else if (lane == -1)
          lane = NEON_INTERLEAVE_LANES;
        else if (lane != NEON_INTERLEAVE_LANES)
          {
!           inst.error = _(type_error);
            return FAIL;
          }
        count++;
--- 1814,1834 ----
            continue;
          }
        
!       if ((atype.defined & NTA_HASINDEX) != 0)
          {
!           if (lane == -1)
!             lane = atype.index;
!           else if (lane != atype.index)
              {
!               first_error (_(type_error));
!               return FAIL;
              }
          }
        else if (lane == -1)
          lane = NEON_INTERLEAVE_LANES;
        else if (lane != NEON_INTERLEAVE_LANES)
          {
!           first_error (_(type_error));
            return FAIL;
          }
        count++;
*************** parse_neon_el_struct_list (char **str, u
*** 1533,1551 ****
    if (lane == -1 || base_reg == -1 || count < 1 || count > 4
        || (count > 1 && reg_incr == -1))
      {
!       inst.error = _("error parsing element/structure list");
        return FAIL;
      }
  
    if ((count > 1 || leading_brace) && skip_past_char (&ptr, '}') == FAIL)
      {
!       inst.error = _("expected }");
        return FAIL;
      }
    
    if (reg_incr == -1)
      reg_incr = 1;
  
    *pbase = base_reg;
    *str = ptr;
    
--- 1843,1864 ----
    if (lane == -1 || base_reg == -1 || count < 1 || count > 4
        || (count > 1 && reg_incr == -1))
      {
!       first_error (_("error parsing element/structure list"));
        return FAIL;
      }
  
    if ((count > 1 || leading_brace) && skip_past_char (&ptr, '}') == FAIL)
      {
!       first_error (_("expected }"));
        return FAIL;
      }
    
    if (reg_incr == -1)
      reg_incr = 1;
  
+   if (eltype)
+     *eltype = firsttype.eltype;
+ 
    *pbase = base_reg;
    *str = ptr;
    
*************** parse_reloc (char **str)
*** 1583,1589 ****
  
  /* Directives: register aliases.  */
  
! static void
  insert_reg_alias (char *str, int number, int type)
  {
    struct reg_entry *new;
--- 1896,1902 ----
  
  /* Directives: register aliases.  */
  
! static struct reg_entry *
  insert_reg_alias (char *str, int number, int type)
  {
    struct reg_entry *new;
*************** insert_reg_alias (char *str, int number,
*** 1599,1605 ****
        else if (new->number != number || new->type != type)
  	as_warn (_("ignoring redefinition of register alias '%s'"), str);
  
!       return;
      }
  
    name = xstrdup (str);
--- 1912,1918 ----
        else if (new->number != number || new->type != type)
  	as_warn (_("ignoring redefinition of register alias '%s'"), str);
  
!       return 0;
      }
  
    name = xstrdup (str);
*************** insert_reg_alias (char *str, int number,
*** 1609,1617 ****
--- 1922,1952 ----
    new->number = number;
    new->type = type;
    new->builtin = FALSE;
+   new->neon = NULL;
  
    if (hash_insert (arm_reg_hsh, name, (PTR) new))
      abort ();
+   
+   return new;
+ }
+ 
+ static void
+ insert_neon_reg_alias (char *str, int number, int type,
+                        struct neon_typed_alias *atype)
+ {
+   struct reg_entry *reg = insert_reg_alias (str, number, type);
+   
+   if (!reg)
+     {
+       first_error (_("attempt to redefine typed alias"));
+       return;
+     }
+   
+   if (atype)
+     {
+       reg->neon = xmalloc (sizeof (struct neon_typed_alias));
+       *reg->neon = *atype;
+     }
  }
  
  /* Look for the .req directive.	 This is of the form:
*************** create_register_alias (char * newname, c
*** 1679,1684 ****
--- 2014,2161 ----
    return 1;
  }
  
+ /* Create a Neon typed/indexed register alias using directives, e.g.:
+      X .dn d5.s32[1]
+      Y .qn 6.s16
+      Z .dn d7
+      T .dn Z[0]
+    These typed registers can be used instead of the types specified after the
+    Neon mnemonic, so long as all operands given have types. Types can also be
+    specified directly, e.g.:
+      vadd d0.s32, d1.s32, d2.s32
+ */
+ 
+ static int
+ create_neon_reg_alias (char *newname, char *p)
+ {
+   enum arm_reg_type basetype;
+   struct reg_entry *basereg;
+   struct reg_entry mybasereg;
+   struct neon_type ntype;
+   struct neon_typed_alias typeinfo;
+   char *namebuf, *nameend;
+   int namelen;
+   
+   typeinfo.defined = 0;
+   typeinfo.eltype.type = NT_invtype;
+   typeinfo.eltype.size = -1;
+   typeinfo.index = -1;
+   
+   nameend = p;
+   
+   if (strncmp (p, " .dn ", 5) == 0)
+     basetype = REG_TYPE_VFD;
+   else if (strncmp (p, " .qn ", 5) == 0)
+     basetype = REG_TYPE_NQ;
+   else
+     return 0;
+   
+   p += 5;
+   
+   if (*p == '\0')
+     return 0;
+   
+   basereg = arm_reg_parse_multi (&p);
+ 
+   if (basereg && basereg->type != basetype)
+     {
+       as_bad (_("bad type for register"));
+       return 0;
+     }
+ 
+   if (basereg == NULL)
+     {
+       expressionS exp;
+       /* Try parsing as an integer.  */
+       my_get_expression (&exp, &p, GE_NO_PREFIX);
+       if (exp.X_op != O_constant)
+         {
+           as_bad (_("expression must be constant"));
+           return 0;
+         }
+       basereg = &mybasereg;
+       basereg->number = (basetype == REG_TYPE_NQ) ? exp.X_add_number * 2
+                                                   : exp.X_add_number;
+       basereg->neon = 0;
+     }
+ 
+   if (basereg->neon)
+     typeinfo = *basereg->neon;
+ 
+   if (parse_neon_type (&ntype, &p) == SUCCESS)
+     {
+       /* We got a type.  */
+       if (typeinfo.defined & NTA_HASTYPE)
+         {
+           as_bad (_("can't redefine the type of a register alias"));
+           return 0;
+         }
+       
+       typeinfo.defined |= NTA_HASTYPE;
+       if (ntype.elems != 1)
+         {
+           as_bad (_("you must specify a single type only"));
+           return 0;
+         }
+       typeinfo.eltype = ntype.el[0];
+     }
+   
+   if (skip_past_char (&p, '[') == SUCCESS)
+     {
+       expressionS exp;
+       /* We got a scalar index.  */
+     
+       if (typeinfo.defined & NTA_HASINDEX)
+         {
+           as_bad (_("can't redefine the index of a scalar alias"));
+           return 0;
+         }
+     
+       my_get_expression (&exp, &p, GE_NO_PREFIX);
+     
+       if (exp.X_op != O_constant)
+         {
+           as_bad (_("scalar index must be constant"));
+           return 0;
+         }
+       
+       typeinfo.defined |= NTA_HASINDEX;
+       typeinfo.index = exp.X_add_number;
+     
+       if (skip_past_char (&p, ']') == FAIL)
+         {
+           as_bad (_("expecting ]"));
+           return 0;
+         }
+     }
+ 
+   namelen = nameend - newname;
+   namebuf = alloca (namelen + 1);
+   strncpy (namebuf, newname, namelen);
+   namebuf[namelen] = '\0';
+   
+   insert_neon_reg_alias (namebuf, basereg->number, basetype,
+                          typeinfo.defined != 0 ? &typeinfo : NULL);
+     
+   /* Insert name in all uppercase.  */
+   for (p = namebuf; *p; p++)
+     *p = TOUPPER (*p);
+   
+   if (strncmp (namebuf, newname, namelen))
+     insert_neon_reg_alias (namebuf, basereg->number, basetype,
+                            typeinfo.defined != 0 ? &typeinfo : NULL);
+   
+   /* Insert name in all lowercase.  */
+   for (p = namebuf; *p; p++)
+     *p = TOLOWER (*p);
+   
+   if (strncmp (namebuf, newname, namelen))
+     insert_neon_reg_alias (namebuf, basereg->number, basetype,
+                            typeinfo.defined != 0 ? &typeinfo : NULL);
+   
+   return 1;
+ }
+ 
  /* Should never be called, as .req goes between the alias and the
     register name, not at the beginning of the line.  */
  static void
*************** s_req (int a ATTRIBUTE_UNUSED)
*** 1687,1692 ****
--- 2164,2181 ----
    as_bad (_("invalid syntax for .req directive"));
  }
  
+ static void
+ s_dn (int a ATTRIBUTE_UNUSED)
+ {
+   as_bad (_("invalid syntax for .dn directive"));
+ }
+ 
+ static void
+ s_qn (int a ATTRIBUTE_UNUSED)
+ {
+   as_bad (_("invalid syntax for .qn directive"));
+ }
+ 
  /* The .unreq directive deletes an alias which was previously defined
     by .req.  For example:
  
*************** s_unreq (int a ATTRIBUTE_UNUSED)
*** 1724,1729 ****
--- 2213,2220 ----
  	{
  	  hash_delete (arm_reg_hsh, name);
  	  free ((char *) reg->name);
+           if (reg->neon)
+             free (reg->neon);
  	  free (reg);
  	}
      }
*************** s_arm_unwind_save_mmxwr (void)
*** 2790,2796 ****
  
    do
      {
!       reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWR, NULL);
  
        if (reg == FAIL)
  	{
--- 3281,3287 ----
  
    do
      {
!       reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWR);
  
        if (reg == FAIL)
  	{
*************** s_arm_unwind_save_mmxwr (void)
*** 2805,2811 ****
        if (*input_line_pointer == '-')
  	{
  	  input_line_pointer++;
! 	  hi_reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWR, NULL);
  	  if (hi_reg == FAIL)
  	    {
  	      as_bad (_(reg_expected_msgs[REG_TYPE_MMXWR]));
--- 3296,3302 ----
        if (*input_line_pointer == '-')
  	{
  	  input_line_pointer++;
! 	  hi_reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWR);
  	  if (hi_reg == FAIL)
  	    {
  	      as_bad (_(reg_expected_msgs[REG_TYPE_MMXWR]));
*************** s_arm_unwind_save_mmxwcg (void)
*** 2922,2928 ****
  
    do
      {
!       reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWCG, NULL);
  
        if (reg == FAIL)
  	{
--- 3413,3419 ----
  
    do
      {
!       reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWCG);
  
        if (reg == FAIL)
  	{
*************** s_arm_unwind_save_mmxwcg (void)
*** 2938,2944 ****
        if (*input_line_pointer == '-')
  	{
  	  input_line_pointer++;
! 	  hi_reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWCG, NULL);
  	  if (hi_reg == FAIL)
  	    {
  	      as_bad (_(reg_expected_msgs[REG_TYPE_MMXWCG]));
--- 3429,3435 ----
        if (*input_line_pointer == '-')
  	{
  	  input_line_pointer++;
! 	  hi_reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWCG);
  	  if (hi_reg == FAIL)
  	    {
  	      as_bad (_(reg_expected_msgs[REG_TYPE_MMXWCG]));
*************** s_arm_unwind_movsp (int ignored ATTRIBUT
*** 3036,3042 ****
    int reg;
    valueT op;
  
!   reg = arm_reg_parse (&input_line_pointer, REG_TYPE_RN, NULL);
    if (reg == FAIL)
      {
        as_bad (_(reg_expected_msgs[REG_TYPE_RN]));
--- 3527,3533 ----
    int reg;
    valueT op;
  
!   reg = arm_reg_parse (&input_line_pointer, REG_TYPE_RN);
    if (reg == FAIL)
      {
        as_bad (_(reg_expected_msgs[REG_TYPE_RN]));
*************** s_arm_unwind_setfp (int ignored ATTRIBUT
*** 3097,3107 ****
    int fp_reg;
    int offset;
  
!   fp_reg = arm_reg_parse (&input_line_pointer, REG_TYPE_RN, NULL);
    if (skip_past_comma (&input_line_pointer) == FAIL)
      sp_reg = FAIL;
    else
!     sp_reg = arm_reg_parse (&input_line_pointer, REG_TYPE_RN, NULL);
  
    if (fp_reg == FAIL || sp_reg == FAIL)
      {
--- 3588,3598 ----
    int fp_reg;
    int offset;
  
!   fp_reg = arm_reg_parse (&input_line_pointer, REG_TYPE_RN);
    if (skip_past_comma (&input_line_pointer) == FAIL)
      sp_reg = FAIL;
    else
!     sp_reg = arm_reg_parse (&input_line_pointer, REG_TYPE_RN);
  
    if (fp_reg == FAIL || sp_reg == FAIL)
      {
*************** const pseudo_typeS md_pseudo_table[] =
*** 3297,3302 ****
--- 3788,3796 ----
  {
    /* Never called because '.req' does not start a line.	 */
    { "req",	   s_req,	  0 },
+   /* Following two are likewise never called.  */
+   { "dn",	   s_dn,          0 },
+   { "qn",          s_qn,          0 },
    { "unreq",	   s_unreq,	  0 },
    { "bss",	   s_bss,	  0 },
    { "align",	   s_align,	  0 },
*************** parse_shift (char **str, int i, enum par
*** 3598,3604 ****
        skip_whitespace (p);
  
        if (mode == NO_SHIFT_RESTRICT
! 	  && (reg = arm_reg_parse (&p, REG_TYPE_RN, NULL)) != FAIL)
  	{
  	  inst.operands[i].imm = reg;
  	  inst.operands[i].immisreg = 1;
--- 4092,4098 ----
        skip_whitespace (p);
  
        if (mode == NO_SHIFT_RESTRICT
! 	  && (reg = arm_reg_parse (&p, REG_TYPE_RN)) != FAIL)
  	{
  	  inst.operands[i].imm = reg;
  	  inst.operands[i].immisreg = 1;
*************** parse_shifter_operand (char **str, int i
*** 3629,3635 ****
    int value;
    expressionS expr;
  
!   if ((value = arm_reg_parse (str, REG_TYPE_RN, NULL)) != FAIL)
      {
        inst.operands[i].reg = value;
        inst.operands[i].isreg = 1;
--- 4123,4129 ----
    int value;
    expressionS expr;
  
!   if ((value = arm_reg_parse (str, REG_TYPE_RN)) != FAIL)
      {
        inst.operands[i].reg = value;
        inst.operands[i].isreg = 1;
*************** parse_address (char **str, int i)
*** 3740,3746 ****
        return SUCCESS;
      }
  
!   if ((reg = arm_reg_parse (&p, REG_TYPE_RN, NULL)) == FAIL)
      {
        inst.error = _(reg_expected_msgs[REG_TYPE_RN]);
        return FAIL;
--- 4234,4240 ----
        return SUCCESS;
      }
  
!   if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) == FAIL)
      {
        inst.error = _(reg_expected_msgs[REG_TYPE_RN]);
        return FAIL;
*************** parse_address (char **str, int i)
*** 3755,3761 ****
        if (*p == '+') p++;
        else if (*p == '-') p++, inst.operands[i].negative = 1;
  
!       if ((reg = arm_reg_parse (&p, REG_TYPE_RN, NULL)) != FAIL)
  	{
  	  inst.operands[i].imm = reg;
  	  inst.operands[i].immisreg = 1;
--- 4249,4255 ----
        if (*p == '+') p++;
        else if (*p == '-') p++, inst.operands[i].negative = 1;
  
!       if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) != FAIL)
  	{
  	  inst.operands[i].imm = reg;
  	  inst.operands[i].immisreg = 1;
*************** parse_address (char **str, int i)
*** 3838,3844 ****
  	  if (*p == '+') p++;
  	  else if (*p == '-') p++, inst.operands[i].negative = 1;
  
! 	  if ((reg = arm_reg_parse (&p, REG_TYPE_RN, NULL)) != FAIL)
  	    {
                /* We might be using the immediate for alignment already. If we
                   are, OR the register number into the low-order bits.  */
--- 4332,4338 ----
  	  if (*p == '+') p++;
  	  else if (*p == '-') p++, inst.operands[i].negative = 1;
  
! 	  if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) != FAIL)
  	    {
                /* We might be using the immediate for alignment already. If we
                   are, OR the register number into the low-order bits.  */
*************** parse_tb (char **str)
*** 4099,4105 ****
        return FAIL;
      }
  
!   if ((reg = arm_reg_parse (&p, REG_TYPE_RN, NULL)) == FAIL)
      {
        inst.error = _(reg_expected_msgs[REG_TYPE_RN]);
        return FAIL;
--- 4593,4599 ----
        return FAIL;
      }
  
!   if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) == FAIL)
      {
        inst.error = _(reg_expected_msgs[REG_TYPE_RN]);
        return FAIL;
*************** parse_tb (char **str)
*** 4112,4118 ****
        return FAIL;
      }
    
!   if ((reg = arm_reg_parse (&p, REG_TYPE_RN, NULL)) == FAIL)
      {
        inst.error = _(reg_expected_msgs[REG_TYPE_RN]);
        return FAIL;
--- 4606,4612 ----
        return FAIL;
      }
    
!   if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) == FAIL)
      {
        inst.error = _(reg_expected_msgs[REG_TYPE_RN]);
        return FAIL;
*************** parse_neon_mov (char **str, int *which_o
*** 4154,4178 ****
    int i = *which_operand, val;
    enum arm_reg_type rtype;
    char *ptr = *str;
    
!   if ((val = parse_scalar (&ptr, 8)) != FAIL)
      {
        /* Case 4: VMOV<c><q>.<size> <Dn[x]>, <Rd>.  */
        inst.operands[i].reg = val;
        inst.operands[i].isscalar = 1;
        inst.operands[i++].present = 1;
  
        if (skip_past_comma (&ptr) == FAIL)
          goto wanted_comma;
        
!       if ((val = arm_reg_parse (&ptr, REG_TYPE_RN, NULL)) == FAIL)
          goto wanted_arm;
        
        inst.operands[i].reg = val;
        inst.operands[i].isreg = 1;
        inst.operands[i].present = 1;
      }
!   else if ((val = arm_reg_parse (&ptr, REG_TYPE_NDQ, &rtype)) != FAIL)
      {
        /* Cases 0, 1, 2, 3, 5 (D only).  */
        if (skip_past_comma (&ptr) == FAIL)
--- 4648,4675 ----
    int i = *which_operand, val;
    enum arm_reg_type rtype;
    char *ptr = *str;
+   struct neon_type_el optype;
    
!   if ((val = parse_scalar (&ptr, 8, &optype)) != FAIL)
      {
        /* Case 4: VMOV<c><q>.<size> <Dn[x]>, <Rd>.  */
        inst.operands[i].reg = val;
        inst.operands[i].isscalar = 1;
+       inst.operands[i].vectype = optype;
        inst.operands[i++].present = 1;
  
        if (skip_past_comma (&ptr) == FAIL)
          goto wanted_comma;
        
!       if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) == FAIL)
          goto wanted_arm;
        
        inst.operands[i].reg = val;
        inst.operands[i].isreg = 1;
        inst.operands[i].present = 1;
      }
!   else if ((val = arm_typed_reg_parse (&ptr, REG_TYPE_NDQ, &rtype, &optype))
!            != FAIL)
      {
        /* Cases 0, 1, 2, 3, 5 (D only).  */
        if (skip_past_comma (&ptr) == FAIL)
*************** parse_neon_mov (char **str, int *which_o
*** 4181,4189 ****
        inst.operands[i].reg = val;
        inst.operands[i].isreg = 1;
        inst.operands[i].isquad = (rtype == REG_TYPE_NQ);
        inst.operands[i++].present = 1;
  
!       if ((val = arm_reg_parse (&ptr, REG_TYPE_RN, NULL)) != FAIL)
          {
            /* Case 5: VMOV<c><q> <Dm>, <Rd>, <Rn>.  */
            inst.operands[i-1].regisimm = 1;
--- 4678,4687 ----
        inst.operands[i].reg = val;
        inst.operands[i].isreg = 1;
        inst.operands[i].isquad = (rtype == REG_TYPE_NQ);
+       inst.operands[i].vectype = optype;
        inst.operands[i++].present = 1;
  
!       if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) != FAIL)
          {
            /* Case 5: VMOV<c><q> <Dm>, <Rd>, <Rn>.  */
            inst.operands[i-1].regisimm = 1;
*************** parse_neon_mov (char **str, int *which_o
*** 4193,4204 ****
  
            if (rtype == REG_TYPE_NQ)
              {
!               inst.error = _("can't use Neon quad register here");
                return FAIL;
              }
            if (skip_past_comma (&ptr) == FAIL)
              goto wanted_comma;
!           if ((val = arm_reg_parse (&ptr, REG_TYPE_RN, NULL)) == FAIL)
              goto wanted_arm;
            inst.operands[i].reg = val;
            inst.operands[i].isreg = 1;
--- 4691,4702 ----
  
            if (rtype == REG_TYPE_NQ)
              {
!               first_error (_("can't use Neon quad register here"));
                return FAIL;
              }
            if (skip_past_comma (&ptr) == FAIL)
              goto wanted_comma;
!           if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) == FAIL)
              goto wanted_arm;
            inst.operands[i].reg = val;
            inst.operands[i].isreg = 1;
*************** parse_neon_mov (char **str, int *which_o
*** 4211,4217 ****
            if (!thumb_mode && (inst.instruction & 0xf0000000) != 0xe0000000)
              goto bad_cond;
          }
!       else if ((val = arm_reg_parse (&ptr, REG_TYPE_NDQ, &rtype)) != FAIL)
          {
            /* Case 0: VMOV<c><q> <Qd>, <Qm>
               Case 1: VMOV<c><q> <Dd>, <Dm>  */
--- 4709,4716 ----
            if (!thumb_mode && (inst.instruction & 0xf0000000) != 0xe0000000)
              goto bad_cond;
          }
!       else if ((val = arm_typed_reg_parse (&ptr, REG_TYPE_NDQ, &rtype, &optype))
!                != FAIL)
          {
            /* Case 0: VMOV<c><q> <Qd>, <Qm>
               Case 1: VMOV<c><q> <Dd>, <Dm>  */
*************** parse_neon_mov (char **str, int *which_o
*** 4221,4235 ****
            inst.operands[i].reg = val;
            inst.operands[i].isreg = 1;
            inst.operands[i].isquad = (rtype == REG_TYPE_NQ);
            inst.operands[i].present = 1;
          }
        else
          {
!           inst.error = _("expected <Rm> or <Dm> or <Qm> operand");
            return FAIL;
          }
      }
!   else if ((val = arm_reg_parse (&ptr, REG_TYPE_RN, NULL)) != FAIL)
      {
        /* Cases 6, 7.  */
        inst.operands[i].reg = val;
--- 4720,4735 ----
            inst.operands[i].reg = val;
            inst.operands[i].isreg = 1;
            inst.operands[i].isquad = (rtype == REG_TYPE_NQ);
+           inst.operands[i].vectype = optype;
            inst.operands[i].present = 1;
          }
        else
          {
!           first_error (_("expected <Rm> or <Dm> or <Qm> operand"));
            return FAIL;
          }
      }
!   else if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) != FAIL)
      {
        /* Cases 6, 7.  */
        inst.operands[i].reg = val;
*************** parse_neon_mov (char **str, int *which_o
*** 4239,4252 ****
        if (skip_past_comma (&ptr) == FAIL)
          goto wanted_comma;
        
!       if ((val = parse_scalar (&ptr, 8)) != FAIL)
          {
            /* Case 6: VMOV<c><q>.<dt> <Rd>, <Dn[x]>  */
            inst.operands[i].reg = val;
            inst.operands[i].isscalar = 1;
            inst.operands[i].present = 1;
          }
!       else if ((val = arm_reg_parse (&ptr, REG_TYPE_RN, NULL)) != FAIL)
          {
            /* Case 7: VMOV<c><q> <Rd>, <Rn>, <Dm>  */
            inst.operands[i].reg = val;
--- 4739,4753 ----
        if (skip_past_comma (&ptr) == FAIL)
          goto wanted_comma;
        
!       if ((val = parse_scalar (&ptr, 8, &optype)) != FAIL)
          {
            /* Case 6: VMOV<c><q>.<dt> <Rd>, <Dn[x]>  */
            inst.operands[i].reg = val;
            inst.operands[i].isscalar = 1;
            inst.operands[i].present = 1;
+           inst.operands[i].vectype = optype;
          }
!       else if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) != FAIL)
          {
            /* Case 7: VMOV<c><q> <Rd>, <Rn>, <Dm>  */
            inst.operands[i].reg = val;
*************** parse_neon_mov (char **str, int *which_o
*** 4256,4276 ****
            if (skip_past_comma (&ptr) == FAIL)
              goto wanted_comma;
            
!           if ((val = arm_reg_parse (&ptr, REG_TYPE_VFD, NULL)) == FAIL)
              {
!               inst.error = _(reg_expected_msgs[REG_TYPE_VFD]);
                return FAIL;
              }
  
            inst.operands[i].reg = val;
            inst.operands[i].isreg = 1;
            inst.operands[i].regisimm = 1;
            inst.operands[i].present = 1;
          }
      }
    else
      {
!       inst.error = _("parse error");
        return FAIL;
      }
  
--- 4757,4779 ----
            if (skip_past_comma (&ptr) == FAIL)
              goto wanted_comma;
            
!           if ((val = arm_typed_reg_parse (&ptr, REG_TYPE_VFD, NULL, &optype))
!               == FAIL)
              {
!               first_error (_(reg_expected_msgs[REG_TYPE_VFD]));
                return FAIL;
              }
  
            inst.operands[i].reg = val;
            inst.operands[i].isreg = 1;
            inst.operands[i].regisimm = 1;
+           inst.operands[i].vectype = optype;
            inst.operands[i].present = 1;
          }
      }
    else
      {
!       first_error (_("parse error"));
        return FAIL;
      }
  
*************** parse_neon_mov (char **str, int *which_o
*** 4280,4294 ****
    return SUCCESS;
  
    wanted_comma:
!   inst.error = _("expected comma");
    return FAIL;
    
    wanted_arm:
!   inst.error = _(reg_expected_msgs[REG_TYPE_RN]);
    return FAIL;
  
    bad_cond:
!   inst.error = _("instruction cannot be conditionalized");
    return FAIL;
  }
  
--- 4783,4797 ----
    return SUCCESS;
  
    wanted_comma:
!   first_error (_("expected comma"));
    return FAIL;
    
    wanted_arm:
!   first_error (_(reg_expected_msgs[REG_TYPE_RN]));
    return FAIL;
  
    bad_cond:
!   first_error (_("instruction cannot be conditionalized"));
    return FAIL;
  }
  
*************** parse_operands (char *str, const unsigne
*** 4415,4440 ****
      goto bad_args;				\
  } while (0)
  
! #define po_reg_or_fail(regtype) do {			\
!   val = arm_reg_parse (&str, regtype, &rtype);		\
!   if (val == FAIL)					\
!     {							\
!       inst.error = _(reg_expected_msgs[regtype]);	\
!       goto failure;					\
!     }							\
!   inst.operands[i].reg = val;				\
!   inst.operands[i].isreg = 1;				\
!   inst.operands[i].isquad = (rtype == REG_TYPE_NQ);	\
  } while (0)
  
! #define po_reg_or_goto(regtype, label) do {		\
!   val = arm_reg_parse (&str, regtype, &rtype);		\
!   if (val == FAIL)					\
!     goto label;						\
! 							\
!   inst.operands[i].reg = val;				\
!   inst.operands[i].isreg = 1;				\
!   inst.operands[i].isquad = (rtype == REG_TYPE_NQ);	\
  } while (0)
  
  #define po_imm_or_fail(min, max, popt) do {			\
--- 4918,4945 ----
      goto bad_args;				\
  } while (0)
  
! #define po_reg_or_fail(regtype) do {				\
!   val = arm_typed_reg_parse (&str, regtype, &rtype,		\
!   			     &inst.operands[i].vectype);	\
!   if (val == FAIL)						\
!     {								\
!       first_error (_(reg_expected_msgs[regtype]));		\
!       goto failure;						\
!     }								\
!   inst.operands[i].reg = val;					\
!   inst.operands[i].isreg = 1;					\
!   inst.operands[i].isquad = (rtype == REG_TYPE_NQ);		\
  } while (0)
  
! #define po_reg_or_goto(regtype, label) do {			\
!   val = arm_typed_reg_parse (&str, regtype, &rtype,		\
!                              &inst.operands[i].vectype);	\
!   if (val == FAIL)						\
!     goto label;							\
! 								\
!   inst.operands[i].reg = val;					\
!   inst.operands[i].isreg = 1;					\
!   inst.operands[i].isquad = (rtype == REG_TYPE_NQ);		\
  } while (0)
  
  #define po_imm_or_fail(min, max, popt) do {			\
*************** parse_operands (char *str, const unsigne
*** 4443,4454 ****
    inst.operands[i].imm = val;					\
  } while (0)
  
! #define po_scalar_or_goto(elsz, label) do {	\
!   val = parse_scalar (&str, elsz);		\
!   if (val == FAIL)				\
!     goto label;					\
!   inst.operands[i].reg = val;			\
!   inst.operands[i].isscalar = 1;		\
  } while (0)
  
  #define po_misc_or_fail(expr) do {		\
--- 4948,4959 ----
    inst.operands[i].imm = val;					\
  } while (0)
  
! #define po_scalar_or_goto(elsz, label) do {			\
!   val = parse_scalar (&str, elsz, &inst.operands[i].vectype);	\
!   if (val == FAIL)						\
!     goto label;							\
!   inst.operands[i].reg = val;					\
!   inst.operands[i].isscalar = 1;				\
  } while (0)
  
  #define po_misc_or_fail(expr) do {		\
*************** parse_operands (char *str, const unsigne
*** 4761,4767 ****
            break;
  
  	case OP_NSTRLST:
!           val = parse_neon_el_struct_list (&str, &inst.operands[i].reg);
            break;
  
  	  /* Addressing modes */
--- 5266,5273 ----
            break;
  
  	case OP_NSTRLST:
!           val = parse_neon_el_struct_list (&str, &inst.operands[i].reg,
!                                            &inst.operands[i].vectype);
            break;
  
  	  /* Addressing modes */
*************** encode_arm_vfp_reg (int reg, enum vfp_re
*** 4949,4955 ****
          }
        else
          {
!           inst.error = _("D register out of range for selected VFP version");
            return;
          }
      }
--- 5455,5461 ----
          }
        else
          {
!           first_error (_("D register out of range for selected VFP version"));
            return;
          }
      }
*************** enum neon_type_mask
*** 8996,9005 ****
--- 9502,9514 ----
    N_UNS  = 0x000008, /* if N_EQK, this operand is forced to be unsigned.  */
    N_INT  = 0x000010, /* if N_EQK, this operand is forced to be integer.  */
    N_FLT  = 0x000020, /* if N_EQK, this operand is forced to be float.  */
+   N_SIZ  = 0x000040, /* if N_EQK, this operand is forced to be size-only.  */
    N_UTYP = 0,
    N_MAX_NONSPECIAL = N_F32
  };
  
+ #define N_ALLMODS  (N_DBL | N_HLF | N_SGN | N_UNS | N_INT | N_FLT | N_SIZ)
+ 
  #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)
*************** neon_check_shape (enum neon_shape req)
*** 9037,9047 ****
        {
          if (RD(0) && RD(1) && RD(2))
            return NS_DDD;
!         else if (RQ(0) && RQ(1) && RQ(1))
            return NS_QQQ;
          else
!           inst.error = _("expected <Qd>, <Qn>, <Qm> or <Dd>, <Dn>, <Dm> "
!                          "operands");
        }
        break;
      
--- 9546,9556 ----
        {
          if (RD(0) && RD(1) && RD(2))
            return NS_DDD;
!         else if (RQ(0) && RQ(1) && RQ(2))
            return NS_QQQ;
          else
!           first_error (_("expected <Qd>, <Qn>, <Qm> or <Dd>, <Dn>, <Dm> "
!                          "operands"));
        }
        break;
      
*************** neon_check_shape (enum neon_shape req)
*** 9052,9059 ****
          else if (RQ(0) && RQ(1) && IM(2))
            return NS_QQI;
          else
!           inst.error = _("expected <Qd>, <Qn>, #<imm> or <Dd>, <Dn>, #<imm> "
!                          "operands");
        }
          break;
    
--- 9561,9568 ----
          else if (RQ(0) && RQ(1) && IM(2))
            return NS_QQI;
          else
!           first_error (_("expected <Qd>, <Qn>, #<imm> or <Dd>, <Dn>, #<imm> "
!                          "operands"));
        }
          break;
    
*************** neon_check_shape (enum neon_shape req)
*** 9064,9071 ****
          if (RQ(0) && RQ(1) && RQ(2) && IM(3))
            return NS_QQQI;
          else
!           inst.error = _("expected <Qd>, <Qn>, <Qm>, #<imm> or "
!                          "<Dd>, <Dn>, <Dm>, #<imm> operands");
        }
          break;
    
--- 9573,9580 ----
          if (RQ(0) && RQ(1) && RQ(2) && IM(3))
            return NS_QQQI;
          else
!           first_error (_("expected <Qd>, <Qn>, <Qm>, #<imm> or "
!                          "<Dd>, <Dn>, <Dm>, #<imm> operands"));
        }
          break;
    
*************** neon_check_shape (enum neon_shape req)
*** 9076,9083 ****
          else if (RQ(0) && RQ(1) && SC(2))
            return NS_QQS;
          else
!           inst.error = _("expected <Qd>, <Qn>, <Dm[x]> or <Dd>, <Dn>, <Dm[x]> "
!                          "operands");
        }
        break;
    
--- 9585,9592 ----
          else if (RQ(0) && RQ(1) && SC(2))
            return NS_QQS;
          else
!           first_error (_("expected <Qd>, <Qn>, <Dm[x]> or <Dd>, <Dn>, <Dm[x]> "
!                          "operands"));
        }
        break;
    
*************** neon_check_shape (enum neon_shape req)
*** 9088,9094 ****
          else if (RQ(0) && RQ(1))
            return NS_QQ;
          else
!           inst.error = _("expected <Qd>, <Qm> or <Dd>, <Dm> operands");
        }
        break;
    
--- 9597,9603 ----
          else if (RQ(0) && RQ(1))
            return NS_QQ;
          else
!           first_error (_("expected <Qd>, <Qm> or <Dd>, <Dm> operands"));
        }
        break;
    
*************** neon_check_shape (enum neon_shape req)
*** 9099,9105 ****
          else if (RQ(0) && SC(1))
            return NS_QS;
          else
!           inst.error = _("expected <Qd>, <Dm[x]> or <Dd>, <Dm[x]> operands");
        }
        break;
  
--- 9608,9614 ----
          else if (RQ(0) && SC(1))
            return NS_QS;
          else
!           first_error (_("expected <Qd>, <Dm[x]> or <Dd>, <Dm[x]> operands"));
        }
        break;
  
*************** neon_check_shape (enum neon_shape req)
*** 9110,9116 ****
          else if (RQ(0) && RR(1))
            return NS_QR;
          else
!           inst.error = _("expected <Qd>, <Rm> or <Dd>, <Rm> operands");
        }
        break;
  
--- 9619,9625 ----
          else if (RQ(0) && RR(1))
            return NS_QR;
          else
!           first_error (_("expected <Qd>, <Rm> or <Dd>, <Rm> operands"));
        }
        break;
  
*************** neon_check_shape (enum neon_shape req)
*** 9121,9127 ****
          else if (RQ(0) && IM(1))
            return NS_QI;
          else
!           inst.error = _("expected <Qd>, #<imm> or <Dd>, #<imm> operands");
        }
        break;
     
--- 9630,9636 ----
          else if (RQ(0) && IM(1))
            return NS_QI;
          else
!           first_error (_("expected <Qd>, #<imm> or <Dd>, #<imm> operands"));
        }
        break;
     
*************** neon_modify_type_size (unsigned typebits
*** 9157,9162 ****
--- 9666,9673 ----
          *g_type = NT_integer;
        else if ((typebits & N_FLT) != 0)
          *g_type = NT_float;
+       else if ((typebits & N_SIZ) != 0)
+         *g_type = NT_untyped;
      }
  }
    
*************** type_chk_of_el_type (enum neon_el_type t
*** 9250,9279 ****
  /* Convert compact Neon bitmask type representation to a type and size. Only
     handles the case where a single bit is set in the mask.  */
  
! static void
  el_type_of_type_chk (enum neon_el_type *type, unsigned *size,
                       enum neon_type_mask mask)
  {
    if ((mask & (N_S8 | N_U8 | N_I8 | N_8 | N_P8)) != 0)
      *size = 8;
!   if ((mask & (N_S16 | N_U16 | N_I16 | N_16 | N_P16)) != 0)
      *size = 16;
!   if ((mask & (N_S32 | N_U32 | N_I32 | N_32 | N_F32)) != 0)
      *size = 32;
!   if ((mask & (N_S64 | N_U64 | N_I64 | N_64)) != 0)
      *size = 64;
    if ((mask & (N_S8 | N_S16 | N_S32 | N_S64)) != 0)
      *type = NT_signed;
!   if ((mask & (N_U8 | N_U16 | N_U32 | N_U64)) != 0)
      *type = NT_unsigned;
!   if ((mask & (N_I8 | N_I16 | N_I32 | N_I64)) != 0)
      *type = NT_integer;
!   if ((mask & (N_8 | N_16 | N_32 | N_64)) != 0)
      *type = NT_untyped;
!   if ((mask & (N_P8 | N_P16)) != 0)
      *type = NT_poly;
!   if ((mask & N_F32) != 0)
      *type = NT_float;
  }
  
  /* Modify a bitmask of allowed types. This is only needed for type
--- 9761,9800 ----
  /* Convert compact Neon bitmask type representation to a type and size. Only
     handles the case where a single bit is set in the mask.  */
  
! static int
  el_type_of_type_chk (enum neon_el_type *type, unsigned *size,
                       enum neon_type_mask mask)
  {
+   if ((mask & N_EQK) != 0)
+     return FAIL;
+ 
    if ((mask & (N_S8 | N_U8 | N_I8 | N_8 | N_P8)) != 0)
      *size = 8;
!   else if ((mask & (N_S16 | N_U16 | N_I16 | N_16 | N_P16)) != 0)
      *size = 16;
!   else if ((mask & (N_S32 | N_U32 | N_I32 | N_32 | N_F32)) != 0)
      *size = 32;
!   else if ((mask & (N_S64 | N_U64 | N_I64 | N_64)) != 0)
      *size = 64;
+   else
+     return FAIL;
+ 
    if ((mask & (N_S8 | N_S16 | N_S32 | N_S64)) != 0)
      *type = NT_signed;
!   else if ((mask & (N_U8 | N_U16 | N_U32 | N_U64)) != 0)
      *type = NT_unsigned;
!   else if ((mask & (N_I8 | N_I16 | N_I32 | N_I64)) != 0)
      *type = NT_integer;
!   else if ((mask & (N_8 | N_16 | N_32 | N_64)) != 0)
      *type = NT_untyped;
!   else if ((mask & (N_P8 | N_P16)) != 0)
      *type = NT_poly;
!   else if ((mask & N_F32) != 0)
      *type = NT_float;
+   else
+     return FAIL;
+   
+   return SUCCESS;
  }
  
  /* Modify a bitmask of allowed types. This is only needed for type
*************** modify_types_allowed (unsigned allowed, 
*** 9291,9299 ****
    
    for (i = 1; i <= N_MAX_NONSPECIAL; i <<= 1)
      {
!       el_type_of_type_chk (&type, &size, allowed & i);
!       neon_modify_type_size (mods, &type, &size);
!       destmask |= type_chk_of_el_type (type, size);
      }
    
    return destmask;
--- 9812,9822 ----
    
    for (i = 1; i <= N_MAX_NONSPECIAL; i <<= 1)
      {
!       if (el_type_of_type_chk (&type, &size, allowed & i) == SUCCESS)
!         {
!           neon_modify_type_size (mods, &type, &size);
!           destmask |= type_chk_of_el_type (type, size);
!         }
      }
    
    return destmask;
*************** neon_check_type (unsigned els, enum neon
*** 9344,9349 ****
--- 9867,9880 ----
      }
    va_end (ap);
  
+   if (inst.vectype.elems > 0)
+     for (i = 0; i < els; i++)
+       if (inst.operands[i].vectype.type != NT_invtype)
+         {
+           first_error (_("types specified in both the mnemonic and operands"));
+           return badtype;
+         }
+ 
    /* Duplicate inst.vectype elements here as necessary.
       FIXME: No idea if this is exactly the same as the ARM assembler,
       particularly when an insn takes one register and one non-register
*************** neon_check_type (unsigned els, enum neon
*** 9354,9368 ****
        inst.vectype.elems = els;
        inst.vectype.el[key_el] = inst.vectype.el[0];
        for (j = 0; j < els; j++)
          {
!           if (j != key_el)
!             inst.vectype.el[j] = neon_type_promote (&inst.vectype.el[key_el],
!                                                     types[j]);
          }
      }
    else if (inst.vectype.elems != els)
      {
!       inst.error = _("type specifier has the wrong number of parts");
        return badtype;
      }
  
--- 9885,9920 ----
        inst.vectype.elems = els;
        inst.vectype.el[key_el] = inst.vectype.el[0];
        for (j = 0; j < els; j++)
+         if (j != key_el)
+           inst.vectype.el[j] = neon_type_promote (&inst.vectype.el[key_el],
+                                                   types[j]);
+     }
+   else if (inst.vectype.elems == 0 && els > 0)
+     {
+       unsigned j;
+       /* No types were given after the mnemonic, so look for types specified
+          after each operand. We allow some flexibility here; as long as the
+          "key" operand has a type, we can infer the others.  */
+       for (j = 0; j < els; j++)
+         if (inst.operands[j].vectype.type != NT_invtype)
+           inst.vectype.el[j] = inst.operands[j].vectype;
+ 
+       if (inst.operands[key_el].vectype.type != NT_invtype)
          {
!           for (j = 0; j < els; j++)
!             if (inst.operands[j].vectype.type == NT_invtype)
!               inst.vectype.el[j] = neon_type_promote (&inst.vectype.el[key_el],
!                                                       types[j]);
!         }
!       else
!         {
!           first_error (_("operand types can't be inferred"));
!           return badtype;
          }
      }
    else if (inst.vectype.elems != els)
      {
!       first_error (_("type specifier has the wrong number of parts"));
        return badtype;
      }
  
*************** neon_check_type (unsigned els, enum neon
*** 9408,9414 ****
  
                    if ((given_type & types_allowed) == 0)
                      {
! 	              inst.error = _("bad type in Neon instruction");
  	              return badtype;
                      }
                  }
--- 9960,9966 ----
  
                    if ((given_type & types_allowed) == 0)
                      {
! 	              first_error (_("bad type in Neon instruction"));
  	              return badtype;
                      }
                  }
*************** neon_check_type (unsigned els, enum neon
*** 9419,9425 ****
                    neon_modify_type_size (thisarg, &mod_k_type, &mod_k_size);
                    if (g_type != mod_k_type || g_size != mod_k_size)
                      {
!                       inst.error = _("inconsistent types in Neon instruction");
                        return badtype;
                      }
                  }
--- 9971,9977 ----
                    neon_modify_type_size (thisarg, &mod_k_type, &mod_k_size);
                    if (g_type != mod_k_type || g_size != mod_k_size)
                      {
!                       first_error (_("inconsistent types in Neon instruction"));
                        return badtype;
                      }
                  }
*************** neon_logbits (unsigned x)
*** 9473,9484 ****
    different meaning for some instruction.  */
  
  static void
! neon_three_same (int first_optional, int isquad, int ubit, int size)
  {
-   /* FIXME optional argument handling.  */
-   if (first_optional && !inst.operands[0].present)
-     inst.operands[0].reg = inst.operands[1].reg;
- 
    inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
    inst.instruction |= HI1 (inst.operands[0].reg) << 22;
    inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
--- 10025,10032 ----
    different meaning for some instruction.  */
  
  static void
! neon_three_same (int isquad, int ubit, int size)
  {
    inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
    inst.instruction |= HI1 (inst.operands[0].reg) << 22;
    inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
*************** do_neon_dyadic_i_su (void)
*** 9524,9530 ****
    enum neon_shape rs = neon_check_shape (NS_DDD_QQQ);
    struct neon_type_el et = neon_check_type (3, rs,
      N_EQK, N_EQK, N_SU_32 | N_KEY);
!   neon_three_same (TRUE, rs == NS_QQQ, et.type == NT_unsigned, et.size);
  }
  
  static void
--- 10072,10078 ----
    enum neon_shape rs = neon_check_shape (NS_DDD_QQQ);
    struct neon_type_el et = neon_check_type (3, rs,
      N_EQK, N_EQK, N_SU_32 | N_KEY);
!   neon_three_same (rs == NS_QQQ, et.type == NT_unsigned, et.size);
  }
  
  static void
*************** do_neon_dyadic_i64_su (void)
*** 9533,9539 ****
    enum neon_shape rs = neon_check_shape (NS_DDD_QQQ);
    struct neon_type_el et = neon_check_type (3, rs,
      N_EQK, N_EQK, N_SU_ALL | N_KEY);
!   neon_three_same (TRUE, rs == NS_QQQ, et.type == NT_unsigned, et.size);
  }
  
  static void
--- 10081,10087 ----
    enum neon_shape rs = neon_check_shape (NS_DDD_QQQ);
    struct neon_type_el et = neon_check_type (3, rs,
      N_EQK, N_EQK, N_SU_ALL | N_KEY);
!   neon_three_same (rs == NS_QQQ, et.type == NT_unsigned, et.size);
  }
  
  static void
*************** do_neon_shl_imm (void)
*** 9571,9577 ****
        struct neon_type_el et = neon_check_type (3, rs,
          N_EQK, N_SU_ALL | N_KEY, N_EQK | N_SGN);
        inst.instruction = NEON_ENC_INTEGER (inst.instruction);
!       neon_three_same (TRUE, rs == NS_QQQ, et.type == NT_unsigned, et.size);
      }
  }
  
--- 10119,10125 ----
        struct neon_type_el et = neon_check_type (3, rs,
          N_EQK, N_SU_ALL | N_KEY, N_EQK | N_SGN);
        inst.instruction = NEON_ENC_INTEGER (inst.instruction);
!       neon_three_same (rs == NS_QQQ, et.type == NT_unsigned, et.size);
      }
  }
  
*************** do_neon_qshl_imm (void)
*** 9592,9598 ****
        struct neon_type_el et = neon_check_type (3, rs,
          N_EQK, N_SU_ALL | N_KEY, N_EQK | N_SGN);
        inst.instruction = NEON_ENC_INTEGER (inst.instruction);
!       neon_three_same (TRUE, rs == NS_QQQ, et.type == NT_unsigned, et.size);
      }
  }
  
--- 10140,10146 ----
        struct neon_type_el et = neon_check_type (3, rs,
          N_EQK, N_SU_ALL | N_KEY, N_EQK | N_SGN);
        inst.instruction = NEON_ENC_INTEGER (inst.instruction);
!       neon_three_same (rs == NS_QQQ, et.type == NT_unsigned, et.size);
      }
  }
  
*************** neon_cmode_for_logic_imm (unsigned immed
*** 9641,9647 ****
      }
  
    bad_immediate:
!   inst.error = _("immediate value out of range");
    return FAIL;
  }
  
--- 10189,10195 ----
      }
  
    bad_immediate:
!   first_error (_("immediate value out of range"));
    return FAIL;
  }
  
*************** do_neon_logic (void)
*** 9827,9833 ****
        neon_check_type (3, rs, N_IGNORE_TYPE);
        /* U bit and size field were set as part of the bitmask.  */
        inst.instruction = NEON_ENC_INTEGER (inst.instruction);
!       neon_three_same (TRUE, rs == NS_QQQ, 0, -1);
      }
    else
      {
--- 10375,10381 ----
        neon_check_type (3, rs, N_IGNORE_TYPE);
        /* U bit and size field were set as part of the bitmask.  */
        inst.instruction = NEON_ENC_INTEGER (inst.instruction);
!       neon_three_same (rs == NS_QQQ, 0, -1);
      }
    else
      {
*************** static void
*** 9890,9920 ****
  do_neon_bitfield (void)
  {
    enum neon_shape rs = neon_check_shape (NS_DDD_QQQ);
!   /* FIXME: Check that no type was given.  */
!   neon_three_same (FALSE, rs == NS_QQQ, 0, -1);
  }
  
  static void
! neon_dyadic (enum neon_el_type ubit_meaning, unsigned types)
  {
    enum neon_shape rs = neon_check_shape (NS_DDD_QQQ);
!   struct neon_type_el et = neon_check_type (3, rs, N_EQK, N_EQK, types | N_KEY);
    if (et.type == NT_float)
      {
        inst.instruction = NEON_ENC_FLOAT (inst.instruction);
!       neon_three_same (TRUE, rs == NS_QQQ, 0, -1);
      }
    else
      {
        inst.instruction = NEON_ENC_INTEGER (inst.instruction);
!       neon_three_same (TRUE, rs == NS_QQQ, et.type == ubit_meaning, et.size);
      }
  }
  
  static void
  do_neon_dyadic_if_su (void)
  {
!   neon_dyadic (NT_unsigned, N_SUF_32);
  }
  
  static void
--- 10438,10470 ----
  do_neon_bitfield (void)
  {
    enum neon_shape rs = neon_check_shape (NS_DDD_QQQ);
!   neon_check_type (3, rs, N_IGNORE_TYPE);
!   neon_three_same (rs == NS_QQQ, 0, -1);
  }
  
  static void
! neon_dyadic_misc (enum neon_el_type ubit_meaning, unsigned types,
!                   unsigned destbits)
  {
    enum neon_shape rs = neon_check_shape (NS_DDD_QQQ);
!   struct neon_type_el et = neon_check_type (3, rs, N_EQK | destbits, N_EQK,
!                                             types | N_KEY);
    if (et.type == NT_float)
      {
        inst.instruction = NEON_ENC_FLOAT (inst.instruction);
!       neon_three_same (rs == NS_QQQ, 0, -1);
      }
    else
      {
        inst.instruction = NEON_ENC_INTEGER (inst.instruction);
!       neon_three_same (rs == NS_QQQ, et.type == ubit_meaning, et.size);
      }
  }
  
  static void
  do_neon_dyadic_if_su (void)
  {
!   neon_dyadic_misc (NT_unsigned, N_SUF_32, 0);
  }
  
  static void
*************** do_neon_dyadic_if_su_d (void)
*** 9922,9940 ****
  {
    /* This version only allow D registers, but that constraint is enforced during
       operand parsing so we don't need to do anything extra here.  */
!   neon_dyadic (NT_unsigned, N_SUF_32);
  }
  
  static void
  do_neon_dyadic_if_i (void)
  {
!   neon_dyadic (NT_unsigned, N_IF_32);
  }
  
  static void
  do_neon_dyadic_if_i_d (void)
  {
!   neon_dyadic (NT_unsigned, N_IF_32);
  }
  
  static void
--- 10472,10490 ----
  {
    /* This version only allow D registers, but that constraint is enforced during
       operand parsing so we don't need to do anything extra here.  */
!   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);
  }
  
  static void
*************** do_neon_addsub_if_i (void)
*** 9942,9948 ****
  {
    /* The "untyped" case can't happen. Do this to stop the "U" bit being
       affected if we specify unsigned args.  */
!   neon_dyadic (NT_untyped, N_IF_32 | N_I64);
  }
  
  /* Swaps operands 1 and 2. If operand 1 (optional arg) was omitted, we want the
--- 10492,10498 ----
  {
    /* 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 | N_I64, 0);
  }
  
  /* Swaps operands 1 and 2. If operand 1 (optional arg) was omitted, we want the
*************** neon_compare (unsigned regtypes, unsigne
*** 9979,9990 ****
      {
        if (invert)
          neon_exchange_operands ();
!       neon_dyadic (NT_unsigned, regtypes);
      }
    else
      {
        enum neon_shape rs = neon_check_shape (NS_DDI_QQI);
!       struct neon_type_el et = neon_check_type (2, rs, N_EQK, immtypes | N_KEY);
  
        inst.instruction = NEON_ENC_IMMED (inst.instruction);
        inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
--- 10529,10541 ----
      {
        if (invert)
          neon_exchange_operands ();
!       neon_dyadic_misc (NT_unsigned, regtypes, N_SIZ);
      }
    else
      {
        enum neon_shape rs = neon_check_shape (NS_DDI_QQI);
!       struct neon_type_el et = neon_check_type (2, rs,
!         N_EQK | N_SIZ, immtypes | N_KEY);
  
        inst.instruction = NEON_ENC_IMMED (inst.instruction);
        inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
*************** do_neon_ceq (void)
*** 10026,10033 ****
  static unsigned
  neon_scalar_for_mul (unsigned scalar, unsigned elsize)
  {
!   unsigned regno = scalar >> 3;
!   unsigned elno = scalar & 7;
  
    switch (elsize)
      {
--- 10577,10584 ----
  static unsigned
  neon_scalar_for_mul (unsigned scalar, unsigned elsize)
  {
!   unsigned regno = NEON_SCALAR_REG (scalar);
!   unsigned elno = NEON_SCALAR_INDEX (scalar);
  
    switch (elsize)
      {
*************** neon_scalar_for_mul (unsigned scalar, un
*** 10043,10049 ****
  
      default:
      bad_scalar:
!       as_bad (_("Scalar out of range for multiply instruction"));
      }
  
    return 0;
--- 10594,10600 ----
  
      default:
      bad_scalar:
!       first_error (_("scalar out of range for multiply instruction"));
      }
  
    return 0;
*************** neon_scalar_for_mul (unsigned scalar, un
*** 10054,10060 ****
  static void
  neon_mul_mac (struct neon_type_el et, int ubit)
  {
!   unsigned scalar = neon_scalar_for_mul (inst.operands[2].reg, et.size);
    inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
    inst.instruction |= HI1 (inst.operands[0].reg) << 22;
    inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
--- 10605,10617 ----
  static void
  neon_mul_mac (struct neon_type_el et, int ubit)
  {
!   unsigned scalar;
! 
!   /* Give a more helpful error message if we have an invalid type.  */
!   if (et.type == NT_invtype)
!     return;
!   
!   scalar = neon_scalar_for_mul (inst.operands[2].reg, et.size);
    inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
    inst.instruction |= HI1 (inst.operands[0].reg) << 22;
    inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
*************** do_neon_tst (void)
*** 10089,10095 ****
    enum neon_shape rs = neon_check_shape (NS_DDD_QQQ);
    struct neon_type_el et = neon_check_type (3, rs,
      N_EQK, N_EQK, N_8 | N_16 | N_32 | N_KEY);
!   neon_three_same (TRUE, rs == NS_QQQ, 0, et.size);
  }
  
  /* VMUL with 3 registers allows the P8 type. The scalar version supports the
--- 10646,10652 ----
    enum neon_shape rs = neon_check_shape (NS_DDD_QQQ);
    struct neon_type_el et = neon_check_type (3, rs,
      N_EQK, N_EQK, N_8 | N_16 | N_32 | N_KEY);
!   neon_three_same (rs == NS_QQQ, 0, et.size);
  }
  
  /* VMUL with 3 registers allows the P8 type. The scalar version supports the
*************** do_neon_mul (void)
*** 10102,10108 ****
    if (inst.operands[2].isscalar)
      do_neon_mac_maybe_scalar ();
    else
!     neon_dyadic (NT_poly, N_I8 | N_I16 | N_I32 | N_F32 | N_P8);
  }
  
  static void
--- 10659,10665 ----
    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);
  }
  
  static void
*************** do_neon_qdmulh (void)
*** 10123,10129 ****
          N_EQK, N_EQK, N_S16 | N_S32 | N_KEY);
        inst.instruction = NEON_ENC_INTEGER (inst.instruction);
        /* The U bit (rounding) comes from bit mask.  */
!       neon_three_same (TRUE, rs == NS_QQQ, 0, et.size);
      }
  }
  
--- 10680,10686 ----
          N_EQK, N_EQK, N_S16 | N_S32 | N_KEY);
        inst.instruction = NEON_ENC_INTEGER (inst.instruction);
        /* The U bit (rounding) comes from bit mask.  */
!       neon_three_same (rs == NS_QQQ, 0, et.size);
      }
  }
  
*************** do_neon_fcmp_absolute (void)
*** 10133,10139 ****
    enum neon_shape rs = neon_check_shape (NS_DDD_QQQ);
    neon_check_type (3, rs, N_EQK, N_EQK, N_F32 | N_KEY);
    /* Size field comes from bit mask.  */
!   neon_three_same (TRUE, rs == NS_QQQ, 1, -1);
  }
  
  static void
--- 10690,10696 ----
    enum neon_shape rs = neon_check_shape (NS_DDD_QQQ);
    neon_check_type (3, rs, N_EQK, N_EQK, N_F32 | N_KEY);
    /* Size field comes from bit mask.  */
!   neon_three_same (rs == NS_QQQ, 1, -1);
  }
  
  static void
*************** do_neon_step (void)
*** 10148,10154 ****
  {
    enum neon_shape rs = neon_check_shape (NS_DDD_QQQ);
    neon_check_type (3, rs, N_EQK, N_EQK, N_F32 | N_KEY);
!   neon_three_same (TRUE, rs == NS_QQQ, 0, -1);
  }
  
  static void
--- 10705,10711 ----
  {
    enum neon_shape rs = neon_check_shape (NS_DDD_QQQ);
    neon_check_type (3, rs, N_EQK, N_EQK, N_F32 | N_KEY);
!   neon_three_same (rs == NS_QQQ, 0, -1);
  }
  
  static void
*************** neon_move_immediate (void)
*** 10450,10456 ****
        if ((cmode = neon_cmode_for_move_imm (immlo, immhi, &immbits, &op,
                                              et.size)) == FAIL)
          {
!           inst.error = _("immediate out of range");
            return;
          }
      }
--- 11007,11013 ----
        if ((cmode = neon_cmode_for_move_imm (immlo, immhi, &immbits, &op,
                                              et.size)) == FAIL)
          {
!           first_error (_("immediate out of range"));
            return;
          }
      }
*************** neon_mac_reg_scalar_long (unsigned regty
*** 10533,10540 ****
  {
    if (inst.operands[2].isscalar)
      {
!       struct neon_type_el et = neon_check_type (2, NS_QDS,
!         N_EQK | N_DBL, regtypes | N_KEY);
        inst.instruction = NEON_ENC_SCALAR (inst.instruction);
        neon_mul_mac (et, et.type == NT_unsigned);
      }
--- 11090,11097 ----
  {
    if (inst.operands[2].isscalar)
      {
!       struct neon_type_el et = neon_check_type (3, NS_QDS,
!         N_EQK | N_DBL, N_EQK, regtypes | N_KEY);
        inst.instruction = NEON_ENC_SCALAR (inst.instruction);
        neon_mul_mac (et, et.type == NT_unsigned);
      }
*************** do_neon_dup (void)
*** 10636,10646 ****
    if (inst.operands[1].isscalar)
      {
        enum neon_shape rs = neon_check_shape (NS_DS_QS);
!       struct neon_type_el et = neon_check_type (1, rs, N_8 | N_16 | N_32);
        unsigned sizebits = et.size >> 3;
!       unsigned dm = inst.operands[1].reg >> 3;
        int logsize = neon_logbits (et.size);
!       unsigned x = (inst.operands[1].reg & 7) << logsize;
        inst.instruction = NEON_ENC_SCALAR (inst.instruction);
        inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
        inst.instruction |= HI1 (inst.operands[0].reg) << 22;
--- 11193,11204 ----
    if (inst.operands[1].isscalar)
      {
        enum neon_shape rs = neon_check_shape (NS_DS_QS);
!       struct neon_type_el et = neon_check_type (2, rs,
!         N_EQK, N_8 | N_16 | N_32 | N_KEY);
        unsigned sizebits = et.size >> 3;
!       unsigned dm = NEON_SCALAR_REG (inst.operands[1].reg);
        int logsize = neon_logbits (et.size);
!       unsigned x = NEON_SCALAR_INDEX (inst.operands[1].reg) << logsize;
        inst.instruction = NEON_ENC_SCALAR (inst.instruction);
        inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
        inst.instruction |= HI1 (inst.operands[0].reg) << 22;
*************** do_neon_dup (void)
*** 10655,10661 ****
    else
      {
        enum neon_shape rs = neon_check_shape (NS_DR_QR);
!       struct neon_type_el et = neon_check_type (1, rs, N_8 | N_16 | N_32);
        unsigned save_cond = inst.instruction & 0xf0000000;
        /* Duplicate ARM register to lanes of vector.  */
        inst.instruction = NEON_ENC_ARMREG (inst.instruction);
--- 11213,11220 ----
    else
      {
        enum neon_shape rs = neon_check_shape (NS_DR_QR);
!       struct neon_type_el et = neon_check_type (1, rs,
!         N_8 | N_16 | N_32 | N_KEY);
        unsigned save_cond = inst.instruction & 0xf0000000;
        /* Duplicate ARM register to lanes of vector.  */
        inst.instruction = NEON_ENC_ARMREG (inst.instruction);
*************** do_neon_mov (void)
*** 10720,10732 ****
        if (inst.operands[1].isscalar)
          {
            /* Case 6.  */
!           struct neon_type_el et = neon_check_type (1, NS_IGNORE,
!             N_S8 | N_S16 | N_U8 | N_U16 | N_32);
            unsigned logsize = neon_logbits (et.size);
!           unsigned dn = inst.operands[1].reg >> 3;
!           unsigned x = inst.operands[1].reg & 7;
            unsigned abcdebits = 0;
  
            constraint (x >= 64 / et.size, _("scalar index out of range"));
  
            switch (et.size)
--- 11279,11292 ----
        if (inst.operands[1].isscalar)
          {
            /* Case 6.  */
!           struct neon_type_el et = neon_check_type (2, NS_IGNORE,
!             N_EQK, N_S8 | N_S16 | N_U8 | N_U16 | N_32 | N_KEY);
            unsigned logsize = neon_logbits (et.size);
!           unsigned dn = NEON_SCALAR_REG (inst.operands[1].reg);
!           unsigned x = NEON_SCALAR_INDEX (inst.operands[1].reg);
            unsigned abcdebits = 0;
  
+           constraint (et.type == NT_invtype, _("bad type for scalar"));
            constraint (x >= 64 / et.size, _("scalar index out of range"));
  
            switch (et.size)
*************** do_neon_mov (void)
*** 10753,10764 ****
              {
                /* Case 4.  */
                unsigned bcdebits = 0;
!               struct neon_type_el et = neon_check_type (1, NS_IGNORE,
!                                                         N_8 | N_16 | N_32);
                int logsize = neon_logbits (et.size);
!               unsigned dn = inst.operands[0].reg >> 3;
!               unsigned x = inst.operands[0].reg & 7;
  
                constraint (x >= 64 / et.size, _("scalar index out of range"));
  
                switch (et.size)
--- 11313,11325 ----
              {
                /* Case 4.  */
                unsigned bcdebits = 0;
!               struct neon_type_el et = neon_check_type (2, NS_IGNORE,
!                 N_8 | N_16 | N_32 | N_KEY, N_EQK);
                int logsize = neon_logbits (et.size);
!               unsigned dn = NEON_SCALAR_REG (inst.operands[0].reg);
!               unsigned x = NEON_SCALAR_INDEX (inst.operands[0].reg);
  
+               constraint (et.type == NT_invtype, _("bad type for scalar"));
                constraint (x >= 64 / et.size, _("scalar index out of range"));
  
                switch (et.size)
*************** static void
*** 10959,10969 ****
  do_neon_tbl_tbx (void)
  {
    unsigned listlenbits;
!   neon_check_type (1, NS_DLD, N_8);
    
    if (inst.operands[1].imm < 1 || inst.operands[1].imm > 4)
      {
!       inst.error = _("bad list length for table lookup");
        return;
      }
    
--- 11520,11530 ----
  do_neon_tbl_tbx (void)
  {
    unsigned listlenbits;
!   neon_check_type (3, NS_DLD, N_EQK, N_EQK, N_8 | N_KEY);
    
    if (inst.operands[1].imm < 1 || inst.operands[1].imm > 4)
      {
!       first_error (_("bad list length for table lookup"));
        return;
      }
    
*************** do_neon_ld_st_interleave (void)
*** 11080,11085 ****
--- 11641,11649 ----
      };
    int typebits;
  
+   if (et.type == NT_invtype)
+     return;
+ 
    if (inst.operands[1].immisalign)
      switch (inst.operands[1].imm >> 8)
        {
*************** do_neon_ld_st_interleave (void)
*** 11096,11102 ****
          break;
        default:
        bad_alignment:
!         inst.error = _("bad alignment");
          return;
        }
  
--- 11660,11666 ----
          break;
        default:
        bad_alignment:
!         first_error (_("bad alignment"));
          return;
        }
  
*************** neon_alignment_bit (int size, int align,
*** 11155,11161 ****
    if (result == SUCCESS)
      *do_align = 1;
    else
!     inst.error = _("unsupported alignment for instruction");
      
    return result;
  }
--- 11719,11725 ----
    if (result == SUCCESS)
      *do_align = 1;
    else
!     first_error (_("unsupported alignment for instruction"));
      
    return result;
  }
*************** do_neon_ld_st_lane (void)
*** 11170,11175 ****
--- 11734,11742 ----
    int n = (inst.instruction >> 8) & 3;
    int max_el = 64 / et.size;
    
+   if (et.type == NT_invtype)
+     return;
+   
    constraint (NEON_REGLIST_LENGTH (inst.operands[0].imm) != n + 1,
                _("bad list length"));
    constraint (NEON_LANE (inst.operands[0].imm) >= max_el,
*************** do_neon_ld_dup (void)
*** 11250,11255 ****
--- 11817,11825 ----
    struct neon_type_el et = neon_check_type (1, NS_IGNORE, N_8 | N_16 | N_32);
    int align_good, do_align = 0;
  
+   if (et.type == NT_invtype)
+     return;
+ 
    switch ((inst.instruction >> 8) & 3)
      {
      case 0:  /* VLD1.  */
*************** do_neon_ld_dup (void)
*** 11262,11268 ****
          {
          case 1: break;
          case 2: inst.instruction |= 1 << 5; break;
!         default: inst.error = _("bad list length"); return;
          }
        inst.instruction |= neon_logbits (et.size) << 6;
        break;
--- 11832,11838 ----
          {
          case 1: break;
          case 2: inst.instruction |= 1 << 5; break;
!         default: first_error (_("bad list length")); return;
          }
        inst.instruction |= neon_logbits (et.size) << 6;
        break;
*************** output_inst (const char * str)
*** 11488,11572 ****
  #endif
  }
  
- /* Parse a Neon type specifier. *STR should point at the leading '.'
-    character. Does no verification at this stage that the type fits the opcode
-    properly. E.g.,
- 
-      .i32.i32.s16
-      .s32.f32
-      .u16
- 
-    Can all be legally parsed by this function.
- 
-    Fills in neon_type struct pointer with parsed information, and updates STR
-    to point after the parsed type specifier. Returns TRUE if this was a legal
-    type, FALSE if not.  */
- 
- static bfd_boolean
- parse_neon_type (struct neon_type *type, char **str)
- {
-   char *ptr = *str;
- 
-   if (type)
-     type->elems = 0;
- 
-   while (type->elems < NEON_MAX_TYPE_ELS)
-     {
-       enum neon_el_type thistype = NT_untyped;
-       unsigned thissize = -1u;
- 
-       if (*ptr != '.')
- 	break;
- 
-       ptr++;
- 
-       /* Just a size without an explicit type.  */
-       if (ISDIGIT (*ptr))
- 	goto parsesize;
- 
-       switch (*ptr)
- 	{
- 	case 'i': thistype = NT_integer; break;
- 	case 'f': thistype = NT_float; break;
- 	case 'p': thistype = NT_poly; break;
- 	case 's': thistype = NT_signed; break;
- 	case 'u': thistype = NT_unsigned; break;
- 	default:
- 	  as_bad (_("Unexpected character `%c' in type specifier"), *ptr);
- 	  return 0;
- 	}
- 
-       ptr++;
- 
-       /* .f is an abbreviation for .f32.  */
-       if (thistype == NT_float && !ISDIGIT (*ptr))
- 	thissize = 32;
-       else
- 	{
- 	parsesize:
- 	  thissize = strtoul (ptr, &ptr, 10);
- 
- 	  if (thissize != 8 && thissize != 16 && thissize != 32
-               && thissize != 64)
-             {
-               as_bad (_("Bad size %d in type specifier"), thissize);
- 	      return 0;
- 	    }
- 	}
- 
-       if (type)
-         {
-           type->el[type->elems].type = thistype;
- 	  type->el[type->elems].size = thissize;
- 	  type->elems++;
- 	}
-     }
- 
-   *str = ptr;
- 
-   return 1;
- }
- 
  /* Tag values used in struct asm_opcode's tag field.  */
  enum opcode_tag
  {
--- 12058,12063 ----
*************** opcode_lookup (char **str)
*** 11685,11691 ****
        if (end[offset] == '.')      
  	{
  	  /* See if we have a Neon type suffix.  */
!           if (!parse_neon_type (&inst.vectype, str))
  	    return 0;
          }
        else if (end[offset] != '\0' && end[offset] != ' ')
--- 12176,12182 ----
        if (end[offset] == '.')      
  	{
  	  /* See if we have a Neon type suffix.  */
!           if (parse_neon_type (&inst.vectype, str) == FAIL)
  	    return 0;
          }
        else if (end[offset] != '\0' && end[offset] != ' ')
*************** md_assemble (char *str)
*** 11815,11822 ****
    if (!opcode)
      {
        /* It wasn't an instruction, but it might be a register alias of
! 	 the form alias .req reg.  */
!       if (!create_register_alias (str, p))
  	as_bad (_("bad instruction `%s'"), str);
  
        return;
--- 12306,12314 ----
    if (!opcode)
      {
        /* It wasn't an instruction, but it might be a register alias of
! 	 the form alias .req reg, or a Neon .dn/.qn directive.  */
!       if (!create_register_alias (str, p)
!           && !create_neon_reg_alias (str, p))
  	as_bad (_("bad instruction `%s'"), str);
  
        return;
*************** arm_canonicalize_symbol_name (char * nam
*** 12031,12037 ****
     should appear in both upper and lowercase variants.	Some registers
     also have mixed-case names.	*/
  
! #define REGDEF(s,n,t) { #s, n, REG_TYPE_##t, TRUE }
  #define REGNUM(p,n,t) REGDEF(p##n, n, t)
  #define REGNUM2(p,n,t) REGDEF(p##n, 2 * n, t)
  #define REGSET(p,t) \
--- 12523,12529 ----
     should appear in both upper and lowercase variants.	Some registers
     also have mixed-case names.	*/
  
! #define REGDEF(s,n,t) { #s, n, REG_TYPE_##t, TRUE, 0 }
  #define REGNUM(p,n,t) REGDEF(p##n, n, t)
  #define REGNUM2(p,n,t) REGDEF(p##n, 2 * n, t)
  #define REGSET(p,t) \
*************** create_unwind_entry (int have_data)
*** 14932,14938 ****
  int
  tc_arm_regname_to_dw2regnum (const char *regname)
  {
!   int reg = arm_reg_parse ((char **) &regname, REG_TYPE_RN, NULL);
  
    if (reg == FAIL)
      return -1;
--- 15424,15430 ----
  int
  tc_arm_regname_to_dw2regnum (const char *regname)
  {
!   int reg = arm_reg_parse ((char **) &regname, REG_TYPE_RN);
  
    if (reg == FAIL)
      return -1;
Index: gas/testsuite/gas/arm/neon-psyn.d
===================================================================
RCS file: gas/testsuite/gas/arm/neon-psyn.d
diff -N gas/testsuite/gas/arm/neon-psyn.d
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- gas/testsuite/gas/arm/neon-psyn.d	6 Apr 2006 15:13:49 -0000
***************
*** 0 ****
--- 1,37 ----
+ # name: Neon programmers syntax
+ # as: -mfpu=neon
+ # objdump: -dr --prefix-addresses --show-raw-insn
+ 
+ .*: +file format .*arm.*
+ 
+ Disassembly of section .text:
+ 0[0-9a-f]+ <[^>]+> f2144954 	vmul\.i16	q2, q2, q2
+ 0[0-9a-f]+ <[^>]+> f2a33862 	vmul\.i32	d3, d3, d2\[1\]
+ 0[0-9a-f]+ <[^>]+> f2233912 	vmul\.i32	d3, d3, d2
+ 0[0-9a-f]+ <[^>]+> f2222803 	vadd\.i32	d2, d2, d3
+ 0[0-9a-f]+ <[^>]+> f3924a4a 	vmull\.u16	q2, d2, d2\[1\]
+ 0[0-9a-f]+ <[^>]+> f2910061 	vmla\.i16	d0, d1, d1\[2\]
+ 0[0-9a-f]+ <[^>]+> f2910061 	vmla\.i16	d0, d1, d1\[2\]
+ 0[0-9a-f]+ <[^>]+> f2255805 	vadd\.i32	d5, d5, d5
+ 0[0-9a-f]+ <[^>]+> f2275117 	vorr	d5, d7, d7
+ 0[0-9a-f]+ <[^>]+> ee021b70 	vmov\.16	d2\[1\], r1
+ 0[0-9a-f]+ <[^>]+> ee251b10 	vmov\.32	d5\[1\], r1
+ 0[0-9a-f]+ <[^>]+> ec432b15 	vmov	d5, r2, r3
+ 0[0-9a-f]+ <[^>]+> ee554b30 	vmov\.s8	r4, d5\[1\]
+ 0[0-9a-f]+ <[^>]+> ec565b15 	vmov	r5, r6, d5
+ 0[0-9a-f]+ <[^>]+> f396a507 	vabal\.u16	q5, d6, d7
+ 0[0-9a-f]+ <[^>]+> f3bb2744 	vcvt\.s32\.f32	q1, q2
+ 0[0-9a-f]+ <[^>]+> f3bb4e15 	vcvt\.f32\.u32	d4, d5, #5
+ 0[0-9a-f]+ <[^>]+> f3bc7c05 	vdup\.32	d7, d5\[1\]
+ 0[0-9a-f]+ <[^>]+> f3ba1904 	vtbl\.8	d1, {d10-d11}, d4
+ 0[0-9a-f]+ <[^>]+> f4aa698f 	vld2\.32	{d6\[1\],d7\[1\]}, \[sl\]
+ 0[0-9a-f]+ <[^>]+> f4aa476f 	vld4\.16	{d4\[1\],d6\[1\],d8\[1\],d10\[1\]}, \[sl\]
+ 0[0-9a-f]+ <[^>]+> f4aa6e4f 	vld3\.16	{d6\[\]-d8\[\]}, \[sl\]
+ 0[0-9a-f]+ <[^>]+> ee100b30 	vmov\.s16	r0, d0\[0\]
+ 0[0-9a-f]+ <[^>]+> f42a604f 	vld4\.16	{d6-d9}, \[sl\]
+ 0[0-9a-f]+ <[^>]+> f4aa266f 	vld3\.16	{d2\[1\],d4\[1\],d6\[1\]}, \[sl\]
+ 0[0-9a-f]+ <[^>]+> f3b47908 	vtbl\.8	d7, {d4-d5}, d8
+ 0[0-9a-f]+ <[^>]+> f3142156 	vbsl	q1, q2, q3
+ 0[0-9a-f]+ <[^>]+> f3032e04 	vcge\.f32	d2, d3, d4
+ 0[0-9a-f]+ <[^>]+> f3b52083 	vcge\.s16	d2, d3, #0
+ 0[0-9a-f]+ <[^>]+> ee823b30 	vdup\.16	d2, r3
Index: gas/testsuite/gas/arm/neon-psyn.s
===================================================================
RCS file: gas/testsuite/gas/arm/neon-psyn.s
diff -N gas/testsuite/gas/arm/neon-psyn.s
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- gas/testsuite/gas/arm/neon-psyn.s	6 Apr 2006 15:13:49 -0000
***************
*** 0 ****
--- 1,78 ----
+ 	.arm
+ 	.syntax unified
+ 
+ fish	.qn	q2
+ cow	.dn	d2[1]
+ chips	.dn	d2
+ banana	.dn	d3
+ 
+ 	vmul fish.s16, fish.s16, fish.s16
+ 
+ 	vmul banana, banana, cow.s32
+ 	vmul d3.s32, d3.s32, d2.s32
+ 	vadd d2.s32, d3.s32
+ 	vmull fish.u32, chips.u16, chips.u16[1]
+ 
+ X	.dn D0.S16
+ Y	.dn D1.S16
+ Z 	.dn Y[2]
+ 
+ 	VMLA X, Y, Z
+ 	VMLA X, Y, Y[2]
+ 
+ foo	.dn d5
+ bar	.dn d7
+ foos	.dn foo[1]
+ 
+ 	vadd foo, foo, foo.u32
+ 
+ 	vmov foo, bar
+ 	vmov d2.s16[1], r1
+ 	vmov d5.s32[1], r1
+ 	vmov foo, r2, r3
+ 	vmov r4, foos.s8
+ 	vmov r5, r6, foo
+ 
+ baa	.qn	q5
+ moo	.dn	d6
+ sheep	.dn	d7
+ chicken	.dn	d8
+ 
+ 	vabal baa, moo.u16, sheep.u16
+ 
+ 	vcvt q1.s32, q2.f32
+ 	vcvt d4.f, d5.u32, #5
+ 
+ 	vdup bar, foos.32
+ 	vtbl d1, {baa}, d4.8
+ 
+ el1	.dn	d4.16[1]
+ el2	.dn	d6.16[1]
+ el3	.dn	d8.16[1]
+ el4	.dn	d10.16[1]
+ 
+ 	vld2 {moo.32[1], sheep.32[1]}, [r10]
+ 	vld4 {el1, el2, el3, el4}, [r10]
+ 	vld3 {moo.16[], sheep.16[], chicken.16[]}, [r10]
+ 
+ 	vmov r0,d0.s16[0]
+ 
+ el5	.qn	q3.16
+ el6	.qn	q4.16
+ 
+ 	vld4 {el5,el6}, [r10]
+ 
+ 	vld3 {d2.s16[1], d4.s16[1], d6.s16[1]}, [r10]
+ 
+ chicken8	.dn	chicken.8
+ 
+ 	vtbl d7.8, {d4, d5}, chicken8
+ 
+ 	vbsl q1.8, q2.16, q3.8
+ 
+ 	vcge d2.32, d3.f, d4.f
+ 	vcge d2.16, d3.s16, #0
+ 
+ dupme	.dn	d2.s16
+ 
+ 	vdup dupme, r3

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2006-04-25 17:33 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-04-01  1:40 [PATCH] ARM Neon instruction set support Julian Brown
2006-04-01  2:49 ` Paul Brook
2006-04-02 23:30   ` Julian Brown
2006-04-19 16:38     ` Julian Brown
2006-04-25 19:12       ` Nick Clifton
2006-04-25 19:20       ` [PATCH] ARM Neon programmers syntax Nick Clifton
2006-04-06 16:43 Julian Brown
2006-04-06 18:56 ` Paul Brook

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).