This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] ARM Neon programmers syntax


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.
? 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

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]