? 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, ®type); 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. */ if (regtype == REG_TYPE_NQ) { --- 1579,1593 ---- do { int setmask = 1, addregs = 1; ! ! new_base = arm_typed_reg_parse (str, regtype, ®type, 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. */ 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 and VST 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 and VST 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. , . */ 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. , . */ 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 , , . */ 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 , , . */ 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 , Case 1: VMOV
, */ --- 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 , Case 1: VMOV
, */ *************** 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 or or 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 or or 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.
, */ 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 , , */ 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.
, */ 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 , , */ 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 , , or
, , " ! "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 , , or
, , " ! "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 , , # or
, , # " ! "operands"); } break; --- 9561,9568 ---- else if (RQ(0) && RQ(1) && IM(2)) return NS_QQI; else ! first_error (_("expected , , # or
, , # " ! "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 , , , # or " ! "
, , , # operands"); } break; --- 9573,9580 ---- if (RQ(0) && RQ(1) && RQ(2) && IM(3)) return NS_QQQI; else ! first_error (_("expected , , , # or " ! "
, , , # 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 , , or
, , " ! "operands"); } break; --- 9585,9592 ---- else if (RQ(0) && RQ(1) && SC(2)) return NS_QQS; else ! first_error (_("expected , , or
, , " ! "operands")); } break; *************** neon_check_shape (enum neon_shape req) *** 9088,9094 **** else if (RQ(0) && RQ(1)) return NS_QQ; else ! inst.error = _("expected , or
, operands"); } break; --- 9597,9603 ---- else if (RQ(0) && RQ(1)) return NS_QQ; else ! first_error (_("expected , or
, operands")); } break; *************** neon_check_shape (enum neon_shape req) *** 9099,9105 **** else if (RQ(0) && SC(1)) return NS_QS; else ! inst.error = _("expected , or
, operands"); } break; --- 9608,9614 ---- else if (RQ(0) && SC(1)) return NS_QS; else ! first_error (_("expected , or
, operands")); } break; *************** neon_check_shape (enum neon_shape req) *** 9110,9116 **** else if (RQ(0) && RR(1)) return NS_QR; else ! inst.error = _("expected , or
, operands"); } break; --- 9619,9625 ---- else if (RQ(0) && RR(1)) return NS_QR; else ! first_error (_("expected , or
, operands")); } break; *************** neon_check_shape (enum neon_shape req) *** 9121,9127 **** else if (RQ(0) && IM(1)) return NS_QI; else ! inst.error = _("expected , # or
, # operands"); } break; --- 9630,9636 ---- else if (RQ(0) && IM(1)) return NS_QI; else ! first_error (_("expected , # or
, # 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 **) ®name, 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 **) ®name, 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