[ARM][gas] Fix warnings about uninitialised uses and unused const variables
[deliverable/binutils-gdb.git] / gas / config / tc-arm.c
index ff4d090f9264cda5e1f0f4945623768995b8d279..6b004db0d955c934d60be832a2135e2f855e9029 100644 (file)
@@ -1,7 +1,5 @@
 /* tc-arm.c -- Assemble for the ARM
-   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
-   2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
-   Free Software Foundation, Inc.
+   Copyright (C) 1994-2016 Free Software Foundation, Inc.
    Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
        Modified by David Taylor (dtaylor@armltd.co.uk)
        Cirrus coprocessor mods by Aldy Hernandez (aldyh@redhat.com)
@@ -32,7 +30,7 @@
 #include "safe-ctype.h"
 #include "subsegs.h"
 #include "obstack.h"
-
+#include "libiberty.h"
 #include "opcode/arm.h"
 
 #ifdef OBJ_ELF
@@ -98,7 +96,7 @@ enum arm_float_abi
 /* Types of processor to assemble for. */
 #ifndef CPU_DEFAULT
 /* The code that was here used to select a default CPU depending on compiler
-   pre-defines which were only present when doing native builds, thus 
+   pre-defines which were only present when doing native builds, thus
    changing gas' default behaviour depending upon the build host.
 
    If you have a target that requires a default CPU option then the you
@@ -139,6 +137,8 @@ static int fix_v4bx      = FALSE;
 /* Warn on using deprecated features.  */
 static int warn_on_deprecated = TRUE;
 
+/* Understand CodeComposer Studio assembly syntax.  */
+bfd_boolean codecomposer_syntax = FALSE;
 
 /* Variables that we set while parsing command-line options.  Once all
    options have been read we re-process these values to set the real
@@ -155,10 +155,10 @@ static const arm_feature_set *object_arch = NULL;
 
 /* Constants for known architecture features.  */
 static const arm_feature_set fpu_default = FPU_DEFAULT;
-static const arm_feature_set fpu_arch_vfp_v1 = FPU_ARCH_VFP_V1;
+static const arm_feature_set fpu_arch_vfp_v1 ATTRIBUTE_UNUSED = FPU_ARCH_VFP_V1;
 static const arm_feature_set fpu_arch_vfp_v2 = FPU_ARCH_VFP_V2;
-static const arm_feature_set fpu_arch_vfp_v3 = FPU_ARCH_VFP_V3;
-static const arm_feature_set fpu_arch_neon_v1 = FPU_ARCH_NEON_V1;
+static const arm_feature_set fpu_arch_vfp_v3 ATTRIBUTE_UNUSED = FPU_ARCH_VFP_V3;
+static const arm_feature_set fpu_arch_neon_v1 ATTRIBUTE_UNUSED = FPU_ARCH_NEON_V1;
 static const arm_feature_set fpu_arch_fpa = FPU_ARCH_FPA;
 static const arm_feature_set fpu_any_hard = FPU_ANY_HARD;
 static const arm_feature_set fpu_arch_maverick = FPU_ARCH_MAVERICK;
@@ -168,77 +168,126 @@ static const arm_feature_set fpu_endian_pure = FPU_ARCH_ENDIAN_PURE;
 static const arm_feature_set cpu_default = CPU_DEFAULT;
 #endif
 
-static const arm_feature_set arm_ext_v1 = ARM_FEATURE (ARM_EXT_V1, 0);
-static const arm_feature_set arm_ext_v2 = ARM_FEATURE (ARM_EXT_V1, 0);
-static const arm_feature_set arm_ext_v2s = ARM_FEATURE (ARM_EXT_V2S, 0);
-static const arm_feature_set arm_ext_v3 = ARM_FEATURE (ARM_EXT_V3, 0);
-static const arm_feature_set arm_ext_v3m = ARM_FEATURE (ARM_EXT_V3M, 0);
-static const arm_feature_set arm_ext_v4 = ARM_FEATURE (ARM_EXT_V4, 0);
-static const arm_feature_set arm_ext_v4t = ARM_FEATURE (ARM_EXT_V4T, 0);
-static const arm_feature_set arm_ext_v5 = ARM_FEATURE (ARM_EXT_V5, 0);
+static const arm_feature_set arm_ext_v1 = ARM_FEATURE_CORE_LOW (ARM_EXT_V1);
+static const arm_feature_set arm_ext_v2 = ARM_FEATURE_CORE_LOW (ARM_EXT_V1);
+static const arm_feature_set arm_ext_v2s = ARM_FEATURE_CORE_LOW (ARM_EXT_V2S);
+static const arm_feature_set arm_ext_v3 = ARM_FEATURE_CORE_LOW (ARM_EXT_V3);
+static const arm_feature_set arm_ext_v3m = ARM_FEATURE_CORE_LOW (ARM_EXT_V3M);
+static const arm_feature_set arm_ext_v4 = ARM_FEATURE_CORE_LOW (ARM_EXT_V4);
+static const arm_feature_set arm_ext_v4t = ARM_FEATURE_CORE_LOW (ARM_EXT_V4T);
+static const arm_feature_set arm_ext_v5 = ARM_FEATURE_CORE_LOW (ARM_EXT_V5);
 static const arm_feature_set arm_ext_v4t_5 =
-  ARM_FEATURE (ARM_EXT_V4T | ARM_EXT_V5, 0);
-static const arm_feature_set arm_ext_v5t = ARM_FEATURE (ARM_EXT_V5T, 0);
-static const arm_feature_set arm_ext_v5e = ARM_FEATURE (ARM_EXT_V5E, 0);
-static const arm_feature_set arm_ext_v5exp = ARM_FEATURE (ARM_EXT_V5ExP, 0);
-static const arm_feature_set arm_ext_v5j = ARM_FEATURE (ARM_EXT_V5J, 0);
-static const arm_feature_set arm_ext_v6 = ARM_FEATURE (ARM_EXT_V6, 0);
-static const arm_feature_set arm_ext_v6k = ARM_FEATURE (ARM_EXT_V6K, 0);
-static const arm_feature_set arm_ext_v6t2 = ARM_FEATURE (ARM_EXT_V6T2, 0);
-static const arm_feature_set arm_ext_v6m = ARM_FEATURE (ARM_EXT_V6M, 0);
-static const arm_feature_set arm_ext_v6_notm = ARM_FEATURE (ARM_EXT_V6_NOTM, 0);
-static const arm_feature_set arm_ext_v6_dsp = ARM_FEATURE (ARM_EXT_V6_DSP, 0);
-static const arm_feature_set arm_ext_barrier = ARM_FEATURE (ARM_EXT_BARRIER, 0);
-static const arm_feature_set arm_ext_msr = ARM_FEATURE (ARM_EXT_THUMB_MSR, 0);
-static const arm_feature_set arm_ext_div = ARM_FEATURE (ARM_EXT_DIV, 0);
-static const arm_feature_set arm_ext_v7 = ARM_FEATURE (ARM_EXT_V7, 0);
-static const arm_feature_set arm_ext_v7a = ARM_FEATURE (ARM_EXT_V7A, 0);
-static const arm_feature_set arm_ext_v7r = ARM_FEATURE (ARM_EXT_V7R, 0);
-static const arm_feature_set arm_ext_v7m = ARM_FEATURE (ARM_EXT_V7M, 0);
+  ARM_FEATURE_CORE_LOW (ARM_EXT_V4T | ARM_EXT_V5);
+static const arm_feature_set arm_ext_v5t = ARM_FEATURE_CORE_LOW (ARM_EXT_V5T);
+static const arm_feature_set arm_ext_v5e = ARM_FEATURE_CORE_LOW (ARM_EXT_V5E);
+static const arm_feature_set arm_ext_v5exp = ARM_FEATURE_CORE_LOW (ARM_EXT_V5ExP);
+static const arm_feature_set arm_ext_v5j = ARM_FEATURE_CORE_LOW (ARM_EXT_V5J);
+static const arm_feature_set arm_ext_v6 = ARM_FEATURE_CORE_LOW (ARM_EXT_V6);
+static const arm_feature_set arm_ext_v6k = ARM_FEATURE_CORE_LOW (ARM_EXT_V6K);
+static const arm_feature_set arm_ext_v6t2 = ARM_FEATURE_CORE_LOW (ARM_EXT_V6T2);
+static const arm_feature_set arm_ext_v6m = ARM_FEATURE_CORE_LOW (ARM_EXT_V6M);
+static const arm_feature_set arm_ext_v6_notm =
+  ARM_FEATURE_CORE_LOW (ARM_EXT_V6_NOTM);
+static const arm_feature_set arm_ext_v6_dsp =
+  ARM_FEATURE_CORE_LOW (ARM_EXT_V6_DSP);
+static const arm_feature_set arm_ext_barrier =
+  ARM_FEATURE_CORE_LOW (ARM_EXT_BARRIER);
+static const arm_feature_set arm_ext_msr =
+  ARM_FEATURE_CORE_LOW (ARM_EXT_THUMB_MSR);
+static const arm_feature_set arm_ext_div = ARM_FEATURE_CORE_LOW (ARM_EXT_DIV);
+static const arm_feature_set arm_ext_v7 = ARM_FEATURE_CORE_LOW (ARM_EXT_V7);
+static const arm_feature_set arm_ext_v7a = ARM_FEATURE_CORE_LOW (ARM_EXT_V7A);
+static const arm_feature_set arm_ext_v7r = ARM_FEATURE_CORE_LOW (ARM_EXT_V7R);
+static const arm_feature_set arm_ext_v7m = ARM_FEATURE_CORE_LOW (ARM_EXT_V7M);
+static const arm_feature_set arm_ext_v8 = ARM_FEATURE_CORE_LOW (ARM_EXT_V8);
 static const arm_feature_set arm_ext_m =
-  ARM_FEATURE (ARM_EXT_V6M | ARM_EXT_OS | ARM_EXT_V7M, 0);
-static const arm_feature_set arm_ext_mp = ARM_FEATURE (ARM_EXT_MP, 0);
-static const arm_feature_set arm_ext_sec = ARM_FEATURE (ARM_EXT_SEC, 0);
-static const arm_feature_set arm_ext_os = ARM_FEATURE (ARM_EXT_OS, 0);
-static const arm_feature_set arm_ext_adiv = ARM_FEATURE (ARM_EXT_ADIV, 0);
-static const arm_feature_set arm_ext_virt = ARM_FEATURE (ARM_EXT_VIRT, 0);
+  ARM_FEATURE_CORE (ARM_EXT_V6M | ARM_EXT_OS | ARM_EXT_V7M, ARM_EXT2_V8M);
+static const arm_feature_set arm_ext_mp = ARM_FEATURE_CORE_LOW (ARM_EXT_MP);
+static const arm_feature_set arm_ext_sec = ARM_FEATURE_CORE_LOW (ARM_EXT_SEC);
+static const arm_feature_set arm_ext_os = ARM_FEATURE_CORE_LOW (ARM_EXT_OS);
+static const arm_feature_set arm_ext_adiv = ARM_FEATURE_CORE_LOW (ARM_EXT_ADIV);
+static const arm_feature_set arm_ext_virt = ARM_FEATURE_CORE_LOW (ARM_EXT_VIRT);
+static const arm_feature_set arm_ext_pan = ARM_FEATURE_CORE_HIGH (ARM_EXT2_PAN);
+static const arm_feature_set arm_ext_v8m = ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M);
+static const arm_feature_set arm_ext_v6t2_v8m =
+  ARM_FEATURE_CORE_HIGH (ARM_EXT2_V6T2_V8M);
+/* Instructions shared between ARMv8-A and ARMv8-M.  */
+static const arm_feature_set arm_ext_atomics =
+  ARM_FEATURE_CORE_HIGH (ARM_EXT2_ATOMICS);
+static const arm_feature_set arm_ext_v8_2 =
+  ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_2A);
+/* FP16 instructions.  */
+static const arm_feature_set arm_ext_fp16 =
+  ARM_FEATURE_CORE_HIGH (ARM_EXT2_FP16_INST);
 
 static const arm_feature_set arm_arch_any = ARM_ANY;
-static const arm_feature_set arm_arch_full = ARM_FEATURE (-1, -1);
+static const arm_feature_set arm_arch_full ATTRIBUTE_UNUSED = ARM_FEATURE (-1, -1, -1);
 static const arm_feature_set arm_arch_t2 = ARM_ARCH_THUMB2;
 static const arm_feature_set arm_arch_none = ARM_ARCH_NONE;
 static const arm_feature_set arm_arch_v6m_only = ARM_ARCH_V6M_ONLY;
 
 static const arm_feature_set arm_cext_iwmmxt2 =
-  ARM_FEATURE (0, ARM_CEXT_IWMMXT2);
+  ARM_FEATURE_COPROC (ARM_CEXT_IWMMXT2);
 static const arm_feature_set arm_cext_iwmmxt =
-  ARM_FEATURE (0, ARM_CEXT_IWMMXT);
+  ARM_FEATURE_COPROC (ARM_CEXT_IWMMXT);
 static const arm_feature_set arm_cext_xscale =
-  ARM_FEATURE (0, ARM_CEXT_XSCALE);
+  ARM_FEATURE_COPROC (ARM_CEXT_XSCALE);
 static const arm_feature_set arm_cext_maverick =
-  ARM_FEATURE (0, ARM_CEXT_MAVERICK);
-static const arm_feature_set fpu_fpa_ext_v1 = ARM_FEATURE (0, FPU_FPA_EXT_V1);
-static const arm_feature_set fpu_fpa_ext_v2 = ARM_FEATURE (0, FPU_FPA_EXT_V2);
+  ARM_FEATURE_COPROC (ARM_CEXT_MAVERICK);
+static const arm_feature_set fpu_fpa_ext_v1 =
+  ARM_FEATURE_COPROC (FPU_FPA_EXT_V1);
+static const arm_feature_set fpu_fpa_ext_v2 =
+  ARM_FEATURE_COPROC (FPU_FPA_EXT_V2);
 static const arm_feature_set fpu_vfp_ext_v1xd =
-  ARM_FEATURE (0, FPU_VFP_EXT_V1xD);
-static const arm_feature_set fpu_vfp_ext_v1 = ARM_FEATURE (0, FPU_VFP_EXT_V1);
-static const arm_feature_set fpu_vfp_ext_v2 = ARM_FEATURE (0, FPU_VFP_EXT_V2);
-static const arm_feature_set fpu_vfp_ext_v3xd = ARM_FEATURE (0, FPU_VFP_EXT_V3xD);
-static const arm_feature_set fpu_vfp_ext_v3 = ARM_FEATURE (0, FPU_VFP_EXT_V3);
+  ARM_FEATURE_COPROC (FPU_VFP_EXT_V1xD);
+static const arm_feature_set fpu_vfp_ext_v1 =
+  ARM_FEATURE_COPROC (FPU_VFP_EXT_V1);
+static const arm_feature_set fpu_vfp_ext_v2 =
+  ARM_FEATURE_COPROC (FPU_VFP_EXT_V2);
+static const arm_feature_set fpu_vfp_ext_v3xd =
+  ARM_FEATURE_COPROC (FPU_VFP_EXT_V3xD);
+static const arm_feature_set fpu_vfp_ext_v3 =
+  ARM_FEATURE_COPROC (FPU_VFP_EXT_V3);
 static const arm_feature_set fpu_vfp_ext_d32 =
-  ARM_FEATURE (0, FPU_VFP_EXT_D32);
-static const arm_feature_set fpu_neon_ext_v1 = ARM_FEATURE (0, FPU_NEON_EXT_V1);
+  ARM_FEATURE_COPROC (FPU_VFP_EXT_D32);
+static const arm_feature_set fpu_neon_ext_v1 =
+  ARM_FEATURE_COPROC (FPU_NEON_EXT_V1);
 static const arm_feature_set fpu_vfp_v3_or_neon_ext =
-  ARM_FEATURE (0, FPU_NEON_EXT_V1 | FPU_VFP_EXT_V3);
-static const arm_feature_set fpu_vfp_fp16 = ARM_FEATURE (0, FPU_VFP_EXT_FP16);
-static const arm_feature_set fpu_neon_ext_fma = ARM_FEATURE (0, FPU_NEON_EXT_FMA);
-static const arm_feature_set fpu_vfp_ext_fma = ARM_FEATURE (0, FPU_VFP_EXT_FMA);
+  ARM_FEATURE_COPROC (FPU_NEON_EXT_V1 | FPU_VFP_EXT_V3);
+static const arm_feature_set fpu_vfp_fp16 =
+  ARM_FEATURE_COPROC (FPU_VFP_EXT_FP16);
+static const arm_feature_set fpu_neon_ext_fma =
+  ARM_FEATURE_COPROC (FPU_NEON_EXT_FMA);
+static const arm_feature_set fpu_vfp_ext_fma =
+  ARM_FEATURE_COPROC (FPU_VFP_EXT_FMA);
+static const arm_feature_set fpu_vfp_ext_armv8 =
+  ARM_FEATURE_COPROC (FPU_VFP_EXT_ARMV8);
+static const arm_feature_set fpu_vfp_ext_armv8xd =
+  ARM_FEATURE_COPROC (FPU_VFP_EXT_ARMV8xD);
+static const arm_feature_set fpu_neon_ext_armv8 =
+  ARM_FEATURE_COPROC (FPU_NEON_EXT_ARMV8);
+static const arm_feature_set fpu_crypto_ext_armv8 =
+  ARM_FEATURE_COPROC (FPU_CRYPTO_EXT_ARMV8);
+static const arm_feature_set crc_ext_armv8 =
+  ARM_FEATURE_COPROC (CRC_EXT_ARMV8);
+static const arm_feature_set fpu_neon_ext_v8_1 =
+  ARM_FEATURE_COPROC (FPU_NEON_EXT_RDMA);
 
 static int mfloat_abi_opt = -1;
 /* Record user cpu selection for object attributes.  */
 static arm_feature_set selected_cpu = ARM_ARCH_NONE;
 /* Must be long enough to hold any of the names in arm_cpus.  */
-static char selected_cpu_name[16];
+static char selected_cpu_name[20];
+
+extern FLONUM_TYPE generic_floating_point_number;
+
+/* Return if no cpu was selected on command-line.  */
+static bfd_boolean
+no_cpu_selected (void)
+{
+  return ARM_FEATURE_EQUAL (selected_cpu, arm_arch_none);
+}
+
 #ifdef OBJ_ELF
 # ifdef EABI_DEFAULT
 static int meabi_flags = EABI_DEFAULT;
@@ -305,6 +354,12 @@ static int implicit_it_mode = IMPLICIT_IT_MODE_ARM;
 
 static bfd_boolean unified_syntax = FALSE;
 
+/* An immediate operand can start with #, and ld*, st*, pld operands
+   can contain [ and ].  We need to tell APP not to elide whitespace
+   before a [, which can appear as the first operand for pld.
+   Likewise, a { can appear as the first operand for push, pop, vld*, etc.  */
+const char arm_symbol_chars[] = "#[]{}";
+
 enum neon_el_type
 {
   NT_invtype,
@@ -336,12 +391,15 @@ enum it_instruction_type
    INSIDE_IT_INSN,
    INSIDE_IT_LAST_INSN,
    IF_INSIDE_IT_LAST_INSN, /* Either outside or inside;
-                              if inside, should be the last one.  */
+                             if inside, should be the last one.  */
    NEUTRAL_IT_INSN,        /* This could be either inside or outside,
-                              i.e. BKPT and NOP.  */
+                             i.e. BKPT and NOP.  */
    IT_INSN                 /* The IT insn has been parsed.  */
 };
 
+/* The maximum number of operands we need.  */
+#define ARM_IT_MAX_OPERANDS 6
+
 struct arm_it
 {
   const char * error;
@@ -393,7 +451,7 @@ struct arm_it
     unsigned negative  : 1;  /* Index register was negated.  */
     unsigned shifted   : 1;  /* Shift applied to operation.  */
     unsigned shift_kind : 3;  /* Shift operation (enum shift_kind).  */
-  } operands[6];
+  } operands[ARM_IT_MAX_OPERANDS];
 };
 
 static struct arm_it inst;
@@ -442,8 +500,9 @@ struct asm_psr
 
 struct asm_barrier_opt
 {
-  const char *   template_name;
-  unsigned long  value;
+  const char *    template_name;
+  unsigned long   value;
+  const arm_feature_set arch;
 };
 
 /* The bit that distinguishes CPSR and SPSR.  */
@@ -457,7 +516,7 @@ struct asm_barrier_opt
 
 struct reloc_entry
 {
-  char *                    name;
+  const char *                    name;
   bfd_reloc_code_real_type  reloc;
 };
 
@@ -551,6 +610,7 @@ const char * const reg_expected_msgs[] =
 };
 
 /* Some well known registers that we refer to directly elsewhere.  */
+#define REG_R12        12
 #define REG_SP 13
 #define REG_LR 14
 #define REG_PC 15
@@ -601,6 +661,7 @@ struct asm_opcode
 #define LITERAL_MASK   0xf000f000
 #define OPCODE_MASK    0xfe1fffff
 #define V4_STR_BIT     0x00000020
+#define VLDR_VMOV_SAME 0x0040f000
 
 #define T2_SUBS_PC_LR  0xf3de8f00
 
@@ -609,6 +670,14 @@ struct asm_opcode
 #define T2_OPCODE_MASK 0xfe1fffff
 #define T2_DATA_OP_SHIFT 21
 
+#define A_COND_MASK         0xf0000000
+#define A_PUSH_POP_OP_MASK  0x0fff0000
+
+/* Opcodes for pushing/poping registers to/from the stack.  */
+#define A1_OPCODE_PUSH    0x092d0000
+#define A2_OPCODE_PUSH    0x052d0004
+#define A2_OPCODE_POP     0x049d0004
+
 /* Codes to distinguish the arithmetic instructions.  */
 #define OPCODE_AND     0
 #define OPCODE_EOR     1
@@ -715,6 +784,10 @@ struct asm_opcode
        _("cannot use register index with PC-relative addressing")
 #define BAD_PC_WRITEBACK \
        _("cannot use writeback with PC-relative addressing")
+#define BAD_RANGE      _("branch out of range")
+#define BAD_FP16       _("selected processor does not support fp16 instruction")
+#define UNPRED_REG(R)  _("using " R " results in unpredictable behaviour")
+#define THUMB1_RELOC_ONLY  _("relocation valid in thumb1 code only")
 
 static struct hash_control * arm_ops_hsh;
 static struct hash_control * arm_cond_hsh;
@@ -749,12 +822,25 @@ typedef struct literal_pool
   symbolS *             symbol;
   segT                  section;
   subsegT               sub_section;
+#ifdef OBJ_ELF
+  struct dwarf2_line_info locs [MAX_LITERAL_POOL_SIZE];
+#endif
   struct literal_pool *  next;
+  unsigned int          alignment;
 } literal_pool;
 
 /* Pointer to a linked list of literal pools.  */
 literal_pool * list_of_pools = NULL;
 
+typedef enum asmfunc_states
+{
+  OUTSIDE_ASMFUNC,
+  WAITING_ASMFUNC_NAME,
+  WAITING_ENDASMFUNC
+} asmfunc_states;
+
+static asmfunc_states asmfunc_state = OUTSIDE_ASMFUNC;
+
 #ifdef OBJ_ELF
 #  define now_it seg_info (now_seg)->tc_segment_info_data.current_it
 #else
@@ -786,7 +872,7 @@ static void it_fsm_post_encode (void);
     {                                          \
       inst.it_insn_type = type;                        \
       if (handle_it_state () == FAIL)          \
-        return;                                        \
+       return;                                 \
     }                                          \
   while (0)
 
@@ -795,7 +881,7 @@ static void it_fsm_post_encode (void);
     {                                           \
       inst.it_insn_type = type;                        \
       if (handle_it_state () == FAIL)          \
-        return failret;                                \
+       return failret;                         \
     }                                          \
   while(0)
 
@@ -803,9 +889,9 @@ static void it_fsm_post_encode (void);
   do                                                   \
     {                                                  \
       if (inst.cond == COND_ALWAYS)                    \
-        set_it_insn_type (IF_INSIDE_IT_LAST_INSN);     \
+       set_it_insn_type (IF_INSIDE_IT_LAST_INSN);      \
       else                                             \
-        set_it_insn_type (INSIDE_IT_LAST_INSN);                \
+       set_it_insn_type (INSIDE_IT_LAST_INSN);         \
     }                                                  \
   while (0)
 
@@ -813,7 +899,7 @@ static void it_fsm_post_encode (void);
 
 /* This array holds the chars that always start a comment.  If the
    pre-processor is disabled, these aren't very useful.         */
-const char comment_chars[] = "@";
+char arm_comment_chars[] = "@";
 
 /* This array holds the chars that only start a comment at the beginning of
    a line.  If the line seems to have the form '# 123 filename'
@@ -824,7 +910,7 @@ const char comment_chars[] = "@";
 /* Also note that comments like this one will always work.  */
 const char line_comment_chars[] = "#";
 
-const char line_separator_chars[] = ";";
+char arm_line_separator_chars[] = ";";
 
 /* Chars that can be used to separate mant
    from exp in floating point numbers. */
@@ -847,6 +933,9 @@ const char FLT_CHARS[] = "rRsSfFdDxXeEpP";
 static inline int
 skip_past_char (char ** str, char c)
 {
+  /* PR gas/14987: Allow for whitespace before the expected character.  */
+  skip_whitespace (*str);
+
   if (**str == c)
     {
       (*str)++;
@@ -897,7 +986,7 @@ my_get_expression (expressionS * ep, char ** str, int prefix_mode)
   /* In unified syntax, all prefixes are optional.  */
   if (unified_syntax)
     prefix_mode = (prefix_mode == GE_OPT_PREFIX_BIG) ? prefix_mode
-                  : GE_OPT_PREFIX;
+                 : GE_OPT_PREFIX;
 
   switch (prefix_mode)
     {
@@ -958,9 +1047,9 @@ my_get_expression (expressionS * ep, char ** str, int prefix_mode)
      in instructions, which is where this routine is always called.  */
   if (prefix_mode != GE_OPT_PREFIX_BIG
       && (ep->X_op == O_big
-          || (ep->X_add_symbol
+         || (ep->X_add_symbol
              && (walk_no_bignums (ep->X_add_symbol)
-                 || (ep->X_op_symbol
+                 || (ep->X_op_symbol
                      && walk_no_bignums (ep->X_op_symbol))))))
     {
       inst.error = _("invalid constant");
@@ -988,7 +1077,7 @@ my_get_expression (expressionS * ep, char ** str, int prefix_mode)
 
    ??? The format of 12 byte floats is uncertain according to gcc's arm.h.  */
 
-char *
+const char *
 md_atof (int type, char * litP, int * sizeP)
 {
   int prec;
@@ -1116,6 +1205,8 @@ arm_reg_parse_multi (char **ccp)
   char *p;
   struct reg_entry *reg;
 
+  skip_whitespace (start);
+
 #ifdef REGISTER_PREFIX
   if (*start != REGISTER_PREFIX)
     return NULL;
@@ -1145,7 +1236,7 @@ arm_reg_parse_multi (char **ccp)
 
 static int
 arm_reg_alt_syntax (char **ccp, char *start, struct reg_entry *reg,
-                    enum arm_reg_type type)
+                   enum arm_reg_type type)
 {
   /* Alternative syntaxes are accepted for a few register classes.  */
   switch (type)
@@ -1248,11 +1339,11 @@ parse_neon_type (struct neon_type *type, char **str)
        case 'p': thistype = NT_poly; break;
        case 's': thistype = NT_signed; break;
        case 'u': thistype = NT_unsigned; break;
-        case 'd':
-          thistype = NT_float;
-          thissize = 64;
-          ptr++;
-          goto done;
+       case 'd':
+         thistype = NT_float;
+         thissize = 64;
+         ptr++;
+         goto done;
        default:
          as_bad (_("unexpected character `%c' in type specifier"), *ptr);
          return FAIL;
@@ -1269,17 +1360,17 @@ parse_neon_type (struct neon_type *type, char **str)
          thissize = strtoul (ptr, &ptr, 10);
 
          if (thissize != 8 && thissize != 16 && thissize != 32
-              && thissize != 64)
-            {
-              as_bad (_("bad size %d in type specifier"), thissize);
+             && thissize != 64)
+           {
+             as_bad (_("bad size %d in type specifier"), thissize);
              return FAIL;
            }
        }
 
       done:
       if (type)
-        {
-          type->el[type->elems].type = thistype;
+       {
+         type->el[type->elems].type = thistype;
          type->el[type->elems].size = thissize;
          type->elems++;
        }
@@ -1316,20 +1407,20 @@ parse_neon_operand_type (struct neon_type_el *vectype, char **ccp)
   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;
-            }
-        }
+       {
+         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;
-        }
+       {
+         first_error (_("vector type expected"));
+         return FAIL;
+       }
     }
   else
     return FAIL;
@@ -1352,8 +1443,8 @@ parse_neon_operand_type (struct neon_type_el *vectype, char **ccp)
 
 static int
 parse_typed_reg_or_scalar (char **ccp, enum arm_reg_type type,
-                           enum arm_reg_type *rtype,
-                           struct neon_typed_alias *typeinfo)
+                          enum arm_reg_type *rtype,
+                          struct neon_typed_alias *typeinfo)
 {
   char *str = *ccp;
   struct reg_entry *reg = arm_reg_parse_multi (&str);
@@ -1371,9 +1462,9 @@ parse_typed_reg_or_scalar (char **ccp, enum arm_reg_type type,
     {
       int altreg = arm_reg_alt_syntax (&str, *ccp, reg, type);
       if (altreg != FAIL)
-        *ccp = str;
+       *ccp = str;
       if (typeinfo)
-        *typeinfo = atype;
+       *typeinfo = atype;
       return altreg;
     }
 
@@ -1381,10 +1472,10 @@ parse_typed_reg_or_scalar (char **ccp, enum arm_reg_type type,
   if ((type == REG_TYPE_NDQ
        && (reg->type == REG_TYPE_NQ || reg->type == REG_TYPE_VFD))
       || (type == REG_TYPE_VFSD
-          && (reg->type == REG_TYPE_VFS || reg->type == REG_TYPE_VFD))
+         && (reg->type == REG_TYPE_VFS || reg->type == REG_TYPE_VFD))
       || (type == REG_TYPE_NSDQ
-          && (reg->type == REG_TYPE_VFS || reg->type == REG_TYPE_VFD
-              || reg->type == REG_TYPE_NQ))
+         && (reg->type == REG_TYPE_VFS || reg->type == REG_TYPE_VFD
+             || reg->type == REG_TYPE_NQ))
       || (type == REG_TYPE_MMXWC
          && (reg->type == REG_TYPE_MMXWCG)))
     type = (enum arm_reg_type) reg->type;
@@ -1398,10 +1489,10 @@ parse_typed_reg_or_scalar (char **ccp, enum arm_reg_type type,
   if (parse_neon_operand_type (&parsetype, &str) == SUCCESS)
     {
       if ((atype.defined & NTA_HASTYPE) != 0)
-        {
-          first_error (_("can't redefine type for operand"));
-          return FAIL;
-        }
+       {
+         first_error (_("can't redefine type for operand"));
+         return FAIL;
+       }
       atype.defined |= NTA_HASTYPE;
       atype.eltype = parsetype;
     }
@@ -1409,38 +1500,38 @@ parse_typed_reg_or_scalar (char **ccp, enum arm_reg_type type,
   if (skip_past_char (&str, '[') == SUCCESS)
     {
       if (type != REG_TYPE_VFD)
-        {
-          first_error (_("only D registers may be indexed"));
-          return FAIL;
-        }
+       {
+         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;
-        }
+       {
+         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;
+       atype.index = NEON_ALL_LANES;
       else
-        {
-          expressionS exp;
+       {
+         expressionS exp;
 
-          my_get_expression (&exp, &str, GE_NO_PREFIX);
+         my_get_expression (&exp, &str, GE_NO_PREFIX);
 
-          if (exp.X_op != O_constant)
-            {
-              first_error (_("constant expression required"));
-              return FAIL;
-            }
+         if (exp.X_op != O_constant)
+           {
+             first_error (_("constant expression required"));
+             return FAIL;
+           }
 
-          if (skip_past_char (&str, ']') == FAIL)
-            return FAIL;
+         if (skip_past_char (&str, ']') == FAIL)
+           return FAIL;
 
-          atype.index = exp.X_add_number;
-        }
+         atype.index = exp.X_add_number;
+       }
     }
 
   if (typeinfo)
@@ -1463,7 +1554,7 @@ parse_typed_reg_or_scalar (char **ccp, enum arm_reg_type type,
 
 static int
 arm_typed_reg_parse (char **ccp, enum arm_reg_type type,
-                     enum arm_reg_type *rtype, struct neon_type_el *vectype)
+                    enum arm_reg_type *rtype, struct neon_type_el *vectype)
 {
   struct neon_typed_alias atype;
   char *str = *ccp;
@@ -1541,6 +1632,8 @@ parse_reg_list (char ** strp)
   /* We come back here if we get ranges concatenated by '+' or '|'.  */
   do
     {
+      skip_whitespace (str);
+
       another_range = 0;
 
       if (*str == '{')
@@ -1594,7 +1687,7 @@ parse_reg_list (char ** strp)
                 || (in_range = 1, *str++ == '-'));
          str--;
 
-         if (*str++ != '}')
+         if (skip_past_char (&str, '}') == FAIL)
            {
              first_error (_("missing `}'"));
              return FAIL;
@@ -1670,11 +1763,11 @@ enum reg_list_els
    If REGLIST_NEON_D is used, several syntax enhancements are enabled:
      - Q registers can be used to specify pairs of D registers
      - { } can be omitted from around a singleton register list
-         FIXME: This is not implemented, as it would require backtracking in
-         some cases, e.g.:
-           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.
+        FIXME: This is not implemented, as it would require backtracking in
+        some cases, e.g.:
+          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.  */
@@ -1692,14 +1785,12 @@ parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype)
   unsigned long mask = 0;
   int i;
 
-  if (*str != '{')
+  if (skip_past_char (&str, '{') == FAIL)
     {
       inst.error = _("expecting {");
       return FAIL;
     }
 
-  str++;
-
   switch (etype)
     {
     case REGLIST_VFP_S:
@@ -1720,17 +1811,17 @@ parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype)
     {
       /* VFPv3 allows 32 D registers, except for the VFPv3-D16 variant.  */
       if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_d32))
-        {
-          max_regs = 32;
-          if (thumb_mode)
-            ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
-                                    fpu_vfp_ext_d32);
-          else
-            ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used,
-                                    fpu_vfp_ext_d32);
-        }
+       {
+         max_regs = 32;
+         if (thumb_mode)
+           ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
+                                   fpu_vfp_ext_d32);
+         else
+           ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used,
+                                   fpu_vfp_ext_d32);
+       }
       else
-        max_regs = 16;
+       max_regs = 16;
     }
 
   base_reg = max_regs;
@@ -1748,17 +1839,17 @@ parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype)
        }
 
       if (new_base >= max_regs)
-        {
-          first_error (_("register out of range in list"));
-          return FAIL;
-        }
+       {
+         first_error (_("register out of range in list"));
+         return FAIL;
+       }
 
       /* Note: a value of 2 * n is returned for the register Q<n>.  */
       if (regtype == REG_TYPE_NQ)
-        {
-          setmask = 3;
-          addregs = 2;
-        }
+       {
+         setmask = 3;
+         addregs = 2;
+       }
 
       if (new_base < base_reg)
        base_reg = new_base;
@@ -1785,20 +1876,20 @@ parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype)
          str++;
 
          if ((high_range = arm_typed_reg_parse (&str, regtype, NULL, NULL))
-              == FAIL)
+             == FAIL)
            {
              inst.error = gettext (reg_expected_msgs[regtype]);
              return FAIL;
            }
 
-          if (high_range >= max_regs)
-            {
-              first_error (_("register out of range in list"));
-              return FAIL;
-            }
+         if (high_range >= max_regs)
+           {
+             first_error (_("register out of range in list"));
+             return FAIL;
+           }
 
-          if (regtype == REG_TYPE_NQ)
-            high_range = high_range + 1;
+         if (regtype == REG_TYPE_NQ)
+           high_range = high_range + 1;
 
          if (high_range <= new_base)
            {
@@ -1861,7 +1952,7 @@ neon_alias_types_same (struct neon_typed_alias *a, struct neon_typed_alias *b)
 
   if ((a->defined & NTA_HASTYPE) != 0
       && (a->eltype.type != b->eltype.type
-          || a->eltype.size != b->eltype.size))
+         || a->eltype.size != b->eltype.size))
     return FALSE;
 
   if ((a->defined & NTA_HASINDEX) != 0
@@ -1885,7 +1976,7 @@ neon_alias_types_same (struct neon_typed_alias *a, struct neon_typed_alias *b)
 
 static int
 parse_neon_el_struct_list (char **str, unsigned *pbase,
-                           struct neon_type_el *eltype)
+                          struct neon_type_el *eltype)
 {
   char *ptr = *str;
   int base_reg = -1;
@@ -1897,6 +1988,10 @@ parse_neon_el_struct_list (char **str, unsigned *pbase,
   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;
+  firsttype.defined = 0;
+  firsttype.eltype.type = NT_invtype;
+  firsttype.eltype.size = -1;
+  firsttype.index = -1;
 
   if (skip_past_char (&ptr, '{') == SUCCESS)
     leading_brace = 1;
@@ -1907,101 +2002,101 @@ parse_neon_el_struct_list (char **str, unsigned *pbase,
       int getreg = parse_typed_reg_or_scalar (&ptr, rtype, &rtype, &atype);
 
       if (getreg == FAIL)
-        {
-          first_error (_(reg_expected_msgs[rtype]));
-          return FAIL;
-        }
+       {
+         first_error (_(reg_expected_msgs[rtype]));
+         return FAIL;
+       }
 
       if (base_reg == -1)
-        {
-          base_reg = getreg;
-          if (rtype == REG_TYPE_NQ)
-            {
-              reg_incr = 1;
-            }
-          firsttype = atype;
-        }
+       {
+         base_reg = getreg;
+         if (rtype == REG_TYPE_NQ)
+           {
+             reg_incr = 1;
+           }
+         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;
-            }
-        }
+       {
+         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;
-        }
+       {
+         first_error (_(incr_error));
+         return FAIL;
+       }
 
       if (! neon_alias_types_same (&atype, &firsttype))
-        {
-          first_error (_(type_error));
-          return FAIL;
-        }
+       {
+         first_error (_(type_error));
+         return FAIL;
+       }
 
       /* Handle Dn-Dm or Qn-Qm syntax. Can only be used with non-indexed list
-         modes.  */
+        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;
-          continue;
-        }
+       {
+         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;
+         continue;
+       }
 
       /* If we're using Q registers, we can't use [] or [n] syntax.  */
       if (rtype == REG_TYPE_NQ)
-        {
-          count += 2;
-          continue;
-        }
+       {
+         count += 2;
+         continue;
+       }
 
       if ((atype.defined & NTA_HASINDEX) != 0)
-        {
-          if (lane == -1)
-            lane = atype.index;
-          else if (lane != atype.index)
-            {
-              first_error (_(type_error));
-              return FAIL;
-            }
-        }
+       {
+         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;
+       lane = NEON_INTERLEAVE_LANES;
       else if (lane != NEON_INTERLEAVE_LANES)
-        {
-          first_error (_(type_error));
-          return FAIL;
-        }
+       {
+         first_error (_(type_error));
+         return FAIL;
+       }
       count++;
     }
   while ((count != 1 || leading_brace) && skip_past_comma (&ptr) != FAIL);
@@ -2041,6 +2136,7 @@ parse_neon_el_struct_list (char **str, unsigned *pbase,
    arm_reloc_hsh contains no entries, so this function can only
    succeed if there is no () after the word.  Returns -1 on error,
    BFD_RELOC_UNUSED if there wasn't any suffix.         */
+
 static int
 parse_reloc (char **str)
 {
@@ -2088,7 +2184,7 @@ insert_reg_alias (char *str, unsigned number, int type)
     }
 
   name = xstrdup (str);
-  new_reg = (struct reg_entry *) xmalloc (sizeof (struct reg_entry));
+  new_reg = XNEW (struct reg_entry);
 
   new_reg->name = name;
   new_reg->number = number;
@@ -2104,7 +2200,7 @@ insert_reg_alias (char *str, unsigned number, int type)
 
 static void
 insert_neon_reg_alias (char *str, int number, int type,
-                       struct neon_typed_alias *atype)
+                      struct neon_typed_alias *atype)
 {
   struct reg_entry *reg = insert_reg_alias (str, number, type);
 
@@ -2116,8 +2212,7 @@ insert_neon_reg_alias (char *str, int number, int type,
 
   if (atype)
     {
-      reg->neon = (struct neon_typed_alias *)
-          xmalloc (sizeof (struct neon_typed_alias));
+      reg->neon = XNEW (struct neon_typed_alias);
       *reg->neon = *atype;
     }
 }
@@ -2163,7 +2258,7 @@ create_register_alias (char * newname, char *p)
   nlen = strlen (newname);
 #endif
 
-  nbuf = (char *) alloca (nlen + 1);
+  nbuf = xmalloc (nlen + 1);
   memcpy (nbuf, newname, nlen);
   nbuf[nlen] = '\0';
 
@@ -2187,7 +2282,10 @@ create_register_alias (char * newname, char *p)
             the artificial FOO alias because it has already been created by the
             first .req.  */
          if (insert_reg_alias (nbuf, old->number, old->type) == NULL)
-           return TRUE;
+           {
+             free (nbuf);
+             return TRUE;
+           }
        }
 
       for (p = nbuf; *p; p++)
@@ -2197,6 +2295,7 @@ create_register_alias (char * newname, char *p)
        insert_reg_alias (nbuf, old->number, old->type);
     }
 
+  free (nbuf);
   return TRUE;
 }
 
@@ -2254,13 +2353,13 @@ create_neon_reg_alias (char *newname, char *p)
       /* 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 FALSE;
-        }
+       {
+         as_bad (_("expression must be constant"));
+         return FALSE;
+       }
       basereg = &mybasereg;
       basereg->number = (basetype == REG_TYPE_NQ) ? exp.X_add_number * 2
-                                                  : exp.X_add_number;
+                                                 : exp.X_add_number;
       basereg->neon = 0;
     }
 
@@ -2271,17 +2370,17 @@ create_neon_reg_alias (char *newname, char *p)
     {
       /* We got a type.  */
       if (typeinfo.defined & NTA_HASTYPE)
-        {
-          as_bad (_("can't redefine the type of a register alias"));
-          return FALSE;
-        }
+       {
+         as_bad (_("can't redefine the type of a register alias"));
+         return FALSE;
+       }
 
       typeinfo.defined |= NTA_HASTYPE;
       if (ntype.elems != 1)
-        {
-          as_bad (_("you must specify a single type only"));
-          return FALSE;
-        }
+       {
+         as_bad (_("you must specify a single type only"));
+         return FALSE;
+       }
       typeinfo.eltype = ntype.el[0];
     }
 
@@ -2291,27 +2390,27 @@ create_neon_reg_alias (char *newname, char *p)
       /* We got a scalar index.  */
 
       if (typeinfo.defined & NTA_HASINDEX)
-        {
-          as_bad (_("can't redefine the index of a scalar alias"));
-          return FALSE;
-        }
+       {
+         as_bad (_("can't redefine the index of a scalar alias"));
+         return FALSE;
+       }
 
       my_get_expression (&exp, &p, GE_NO_PREFIX);
 
       if (exp.X_op != O_constant)
-        {
-          as_bad (_("scalar index must be constant"));
-          return FALSE;
-        }
+       {
+         as_bad (_("scalar index must be constant"));
+         return FALSE;
+       }
 
       typeinfo.defined |= NTA_HASINDEX;
       typeinfo.index = exp.X_add_number;
 
       if (skip_past_char (&p, ']') == FAIL)
-        {
-          as_bad (_("expecting ]"));
-          return FALSE;
-        }
+       {
+         as_bad (_("expecting ]"));
+         return FALSE;
+       }
     }
 
   /* If TC_CASE_SENSITIVE is defined, then newname already points to
@@ -2324,12 +2423,12 @@ create_neon_reg_alias (char *newname, char *p)
   namelen = strlen (newname);
 #endif
 
-  namebuf = (char *) alloca (namelen + 1);
+  namebuf = xmalloc (namelen + 1);
   strncpy (namebuf, newname, namelen);
   namebuf[namelen] = '\0';
 
   insert_neon_reg_alias (namebuf, basereg->number, basetype,
-                         typeinfo.defined != 0 ? &typeinfo : NULL);
+                        typeinfo.defined != 0 ? &typeinfo : NULL);
 
   /* Insert name in all uppercase.  */
   for (p = namebuf; *p; p++)
@@ -2337,7 +2436,7 @@ create_neon_reg_alias (char *newname, char *p)
 
   if (strncmp (namebuf, newname, namelen))
     insert_neon_reg_alias (namebuf, basereg->number, basetype,
-                           typeinfo.defined != 0 ? &typeinfo : NULL);
+                          typeinfo.defined != 0 ? &typeinfo : NULL);
 
   /* Insert name in all lowercase.  */
   for (p = namebuf; *p; p++)
@@ -2345,8 +2444,9 @@ create_neon_reg_alias (char *newname, char *p)
 
   if (strncmp (namebuf, newname, namelen))
     insert_neon_reg_alias (namebuf, basereg->number, basetype,
-                           typeinfo.defined != 0 ? &typeinfo : NULL);
+                          typeinfo.defined != 0 ? &typeinfo : NULL);
 
+  free (namebuf);
   return TRUE;
 }
 
@@ -2398,12 +2498,12 @@ s_unreq (int a ATTRIBUTE_UNUSED)
   else
     {
       struct reg_entry *reg = (struct reg_entry *) hash_find (arm_reg_hsh,
-                                                              name);
+                                                             name);
 
       if (!reg)
        as_bad (_("unknown register alias '%s'"), name);
       else if (reg->builtin)
-       as_warn (_("ignoring attempt to undefine built-in register '%s'"),
+       as_warn (_("ignoring attempt to use .unreq on fixed register name: '%s'"),
                 name);
       else
        {
@@ -2412,8 +2512,8 @@ s_unreq (int a ATTRIBUTE_UNUSED)
 
          hash_delete (arm_reg_hsh, name, FALSE);
          free ((char *) reg->name);
-          if (reg->neon)
-            free (reg->neon);
+         if (reg->neon)
+           free (reg->neon);
          free (reg);
 
          /* Also locate the all upper case and all lower case versions.
@@ -2569,36 +2669,38 @@ static void mapping_state_2 (enum mstate state, int max_chars);
 /* Set the mapping state to STATE.  Only call this when about to
    emit some STATE bytes to the file.  */
 
+#define TRANSITION(from, to) (mapstate == (from) && state == (to))
 void
 mapping_state (enum mstate state)
 {
   enum mstate mapstate = seg_info (now_seg)->tc_segment_info_data.mapstate;
 
-#define TRANSITION(from, to) (mapstate == (from) && state == (to))
-
   if (mapstate == state)
     /* The mapping symbol has already been emitted.
        There is nothing else to do.  */
     return;
-  else if (TRANSITION (MAP_UNDEFINED, MAP_DATA))
-    /* This case will be evaluated later in the next else.  */
-    return;
-  else if (TRANSITION (MAP_UNDEFINED, MAP_ARM)
-          || TRANSITION (MAP_UNDEFINED, MAP_THUMB))
-    {
-      /* Only add the symbol if the offset is > 0:
-         if we're at the first frag, check it's size > 0;
-         if we're not at the first frag, then for sure
-            the offset is > 0.  */
-      struct frag * const frag_first = seg_info (now_seg)->frchainP->frch_root;
-      const int add_symbol = (frag_now != frag_first) || (frag_now_fix () > 0);
 
-      if (add_symbol)
-        make_mapping_symbol (MAP_DATA, (valueT) 0, frag_first);
-    }
+  if (state == MAP_ARM || state == MAP_THUMB)
+    /*  PR gas/12931
+       All ARM instructions require 4-byte alignment.
+       (Almost) all Thumb instructions require 2-byte alignment.
+
+       When emitting instructions into any section, mark the section
+       appropriately.
+
+       Some Thumb instructions are alignment-sensitive modulo 4 bytes,
+       but themselves require 2-byte alignment; this applies to some
+       PC- relative forms.  However, these cases will invovle implicit
+       literal pool generation or an explicit .align >=2, both of
+       which will cause the section to me marked with sufficient
+       alignment.  Thus, we don't handle those cases here.  */
+    record_alignment (now_seg, state == MAP_ARM ? 2 : 1);
+
+  if (TRANSITION (MAP_UNDEFINED, MAP_DATA))
+    /* This case will be evaluated later.  */
+    return;
 
   mapping_state_2 (state, 0);
-#undef TRANSITION
 }
 
 /* Same as mapping_state, but MAX_CHARS bytes have already been
@@ -2617,9 +2719,20 @@ mapping_state_2 (enum mstate state, int max_chars)
        There is nothing else to do.  */
     return;
 
+  if (TRANSITION (MAP_UNDEFINED, MAP_ARM)
+         || TRANSITION (MAP_UNDEFINED, MAP_THUMB))
+    {
+      struct frag * const frag_first = seg_info (now_seg)->frchainP->frch_root;
+      const int add_symbol = (frag_now != frag_first) || (frag_now_fix () > 0);
+
+      if (add_symbol)
+       make_mapping_symbol (MAP_DATA, (valueT) 0, frag_first);
+    }
+
   seg_info (now_seg)->tc_segment_info_data.mapstate = state;
   make_mapping_symbol (state, (valueT) frag_now_fix () - max_chars, frag_now);
 }
+#undef TRANSITION
 #else
 #define mapping_state(x) ((void)0)
 #define mapping_state_2(x, y) ((void)0)
@@ -2649,8 +2762,9 @@ find_real_start (symbolS * symbolP)
   if (S_IS_LOCAL (symbolP) || name[0] == '.')
     return symbolP;
 
-  real_start = ACONCAT ((STUB_NAME, name, NULL));
+  real_start = concat (STUB_NAME, name, NULL);
   new_target = symbol_find (real_start);
+  free (real_start);
 
   if (new_target == NULL)
     {
@@ -2776,10 +2890,9 @@ s_thumb_set (int equiv)
   /* Especial apologies for the random logic:
      This just grew, and could be parsed much more simply!
      Dean - in haste.  */
-  name     = input_line_pointer;
-  delim            = get_symbol_end ();
+  delim            = get_symbol_name (& name);
   end_name  = input_line_pointer;
-  *end_name = delim;
+  (void) restore_line_pointer (delim);
 
   if (*input_line_pointer != ',')
     {
@@ -2859,8 +2972,7 @@ s_syntax (int unused ATTRIBUTE_UNUSED)
 {
   char *name, delim;
 
-  name = input_line_pointer;
-  delim = get_symbol_end ();
+  delim = get_symbol_name (& name);
 
   if (!strcasecmp (name, "unified"))
     unified_syntax = TRUE;
@@ -2871,59 +2983,12 @@ s_syntax (int unused ATTRIBUTE_UNUSED)
       as_bad (_("unrecognized syntax mode \"%s\""), name);
       return;
     }
-  *input_line_pointer = delim;
+  (void) restore_line_pointer (delim);
   demand_empty_rest_of_line ();
 }
 
 /* Directives: sectioning and alignment.  */
 
-/* Same as s_align_ptwo but align 0 => align 2.         */
-
-static void
-s_align (int unused ATTRIBUTE_UNUSED)
-{
-  int temp;
-  bfd_boolean fill_p;
-  long temp_fill;
-  long max_alignment = 15;
-
-  temp = get_absolute_expression ();
-  if (temp > max_alignment)
-    as_bad (_("alignment too large: %d assumed"), temp = max_alignment);
-  else if (temp < 0)
-    {
-      as_bad (_("alignment negative. 0 assumed."));
-      temp = 0;
-    }
-
-  if (*input_line_pointer == ',')
-    {
-      input_line_pointer++;
-      temp_fill = get_absolute_expression ();
-      fill_p = TRUE;
-    }
-  else
-    {
-      fill_p = FALSE;
-      temp_fill = 0;
-    }
-
-  if (!temp)
-    temp = 2;
-
-  /* Only make a frag if we HAVE to.  */
-  if (temp && !need_pass_2)
-    {
-      if (!fill_p && subseg_text_p (now_seg))
-       frag_align_code (temp, 0);
-      else
-       frag_align (temp, (int) temp_fill, 0);
-    }
-  demand_empty_rest_of_line ();
-
-  record_alignment (now_seg, temp);
-}
-
 static void
 s_bss (int ignore ATTRIBUTE_UNUSED)
 {
@@ -2949,6 +3014,104 @@ s_even (int ignore ATTRIBUTE_UNUSED)
   demand_empty_rest_of_line ();
 }
 
+/* Directives: CodeComposer Studio.  */
+
+/*  .ref  (for CodeComposer Studio syntax only).  */
+static void
+s_ccs_ref (int unused ATTRIBUTE_UNUSED)
+{
+  if (codecomposer_syntax)
+    ignore_rest_of_line ();
+  else
+    as_bad (_(".ref pseudo-op only available with -mccs flag."));
+}
+
+/*  If name is not NULL, then it is used for marking the beginning of a
+    function, wherease if it is NULL then it means the function end.  */
+static void
+asmfunc_debug (const char * name)
+{
+  static const char * last_name = NULL;
+
+  if (name != NULL)
+    {
+      gas_assert (last_name == NULL);
+      last_name = name;
+
+      if (debug_type == DEBUG_STABS)
+         stabs_generate_asm_func (name, name);
+    }
+  else
+    {
+      gas_assert (last_name != NULL);
+
+      if (debug_type == DEBUG_STABS)
+        stabs_generate_asm_endfunc (last_name, last_name);
+
+      last_name = NULL;
+    }
+}
+
+static void
+s_ccs_asmfunc (int unused ATTRIBUTE_UNUSED)
+{
+  if (codecomposer_syntax)
+    {
+      switch (asmfunc_state)
+       {
+       case OUTSIDE_ASMFUNC:
+         asmfunc_state = WAITING_ASMFUNC_NAME;
+         break;
+
+       case WAITING_ASMFUNC_NAME:
+         as_bad (_(".asmfunc repeated."));
+         break;
+
+       case WAITING_ENDASMFUNC:
+         as_bad (_(".asmfunc without function."));
+         break;
+       }
+      demand_empty_rest_of_line ();
+    }
+  else
+    as_bad (_(".asmfunc pseudo-op only available with -mccs flag."));
+}
+
+static void
+s_ccs_endasmfunc (int unused ATTRIBUTE_UNUSED)
+{
+  if (codecomposer_syntax)
+    {
+      switch (asmfunc_state)
+       {
+       case OUTSIDE_ASMFUNC:
+         as_bad (_(".endasmfunc without a .asmfunc."));
+         break;
+
+       case WAITING_ASMFUNC_NAME:
+         as_bad (_(".endasmfunc without function."));
+         break;
+
+       case WAITING_ENDASMFUNC:
+         asmfunc_state = OUTSIDE_ASMFUNC;
+         asmfunc_debug (NULL);
+         break;
+       }
+      demand_empty_rest_of_line ();
+    }
+  else
+    as_bad (_(".endasmfunc pseudo-op only available with -mccs flag."));
+}
+
+static void
+s_ccs_def (int name)
+{
+  if (codecomposer_syntax)
+    s_globl (name);
+  else
+    as_bad (_(".def pseudo-op only available with -mccs flag."));
+}
+
 /* Directives: Literal pools.  */
 
 static literal_pool *
@@ -2978,7 +3141,7 @@ find_or_make_literal_pool (void)
   if (pool == NULL)
     {
       /* Create a new pool.  */
-      pool = (literal_pool *) xmalloc (sizeof (* pool));
+      pool = XNEW (literal_pool);
       if (! pool)
        return NULL;
 
@@ -2987,6 +3150,7 @@ find_or_make_literal_pool (void)
       pool->sub_section            = now_subseg;
       pool->next           = list_of_pools;
       pool->symbol         = NULL;
+      pool->alignment      = 2;
 
       /* Add it to the list.  */
       list_of_pools = pool;
@@ -3008,33 +3172,74 @@ find_or_make_literal_pool (void)
    structure to the relevant literal pool.  */
 
 static int
-add_to_lit_pool (void)
+add_to_lit_pool (unsigned int nbytes)
 {
+#define PADDING_SLOT 0x1
+#define LIT_ENTRY_SIZE_MASK 0xFF
   literal_pool * pool;
-  unsigned int entry;
+  unsigned int entry, pool_size = 0;
+  bfd_boolean padding_slot_p = FALSE;
+  unsigned imm1 = 0;
+  unsigned imm2 = 0;
+
+  if (nbytes == 8)
+    {
+      imm1 = inst.operands[1].imm;
+      imm2 = (inst.operands[1].regisimm ? inst.operands[1].reg
+              : inst.reloc.exp.X_unsigned ? 0
+              : ((bfd_int64_t) inst.operands[1].imm) >> 32);
+      if (target_big_endian)
+       {
+         imm1 = imm2;
+         imm2 = inst.operands[1].imm;
+       }
+    }
 
   pool = find_or_make_literal_pool ();
 
   /* Check if this literal value is already in the pool.  */
   for (entry = 0; entry < pool->next_free_entry; entry ++)
     {
-      if ((pool->literals[entry].X_op == inst.reloc.exp.X_op)
-         && (inst.reloc.exp.X_op == O_constant)
-         && (pool->literals[entry].X_add_number
-             == inst.reloc.exp.X_add_number)
-         && (pool->literals[entry].X_unsigned
-             == inst.reloc.exp.X_unsigned))
+      if (nbytes == 4)
+       {
+         if ((pool->literals[entry].X_op == inst.reloc.exp.X_op)
+             && (inst.reloc.exp.X_op == O_constant)
+             && (pool->literals[entry].X_add_number
+                 == inst.reloc.exp.X_add_number)
+             && (pool->literals[entry].X_md == nbytes)
+             && (pool->literals[entry].X_unsigned
+                 == inst.reloc.exp.X_unsigned))
+           break;
+
+         if ((pool->literals[entry].X_op == inst.reloc.exp.X_op)
+             && (inst.reloc.exp.X_op == O_symbol)
+             && (pool->literals[entry].X_add_number
+                 == inst.reloc.exp.X_add_number)
+             && (pool->literals[entry].X_add_symbol
+                 == inst.reloc.exp.X_add_symbol)
+             && (pool->literals[entry].X_op_symbol
+                 == inst.reloc.exp.X_op_symbol)
+             && (pool->literals[entry].X_md == nbytes))
+           break;
+       }
+      else if ((nbytes == 8)
+              && !(pool_size & 0x7)
+              && ((entry + 1) != pool->next_free_entry)
+              && (pool->literals[entry].X_op == O_constant)
+              && (pool->literals[entry].X_add_number == (offsetT) imm1)
+              && (pool->literals[entry].X_unsigned
+                  == inst.reloc.exp.X_unsigned)
+              && (pool->literals[entry + 1].X_op == O_constant)
+              && (pool->literals[entry + 1].X_add_number == (offsetT) imm2)
+              && (pool->literals[entry + 1].X_unsigned
+                  == inst.reloc.exp.X_unsigned))
        break;
 
-      if ((pool->literals[entry].X_op == inst.reloc.exp.X_op)
-         && (inst.reloc.exp.X_op == O_symbol)
-         && (pool->literals[entry].X_add_number
-             == inst.reloc.exp.X_add_number)
-         && (pool->literals[entry].X_add_symbol
-             == inst.reloc.exp.X_add_symbol)
-         && (pool->literals[entry].X_op_symbol
-             == inst.reloc.exp.X_op_symbol))
+      padding_slot_p = ((pool->literals[entry].X_md >> 8) == PADDING_SLOT);
+      if (padding_slot_p && (nbytes == 4))
        break;
+
+      pool_size += 4;
     }
 
   /* Do we need to create a new entry? */
@@ -3046,17 +3251,113 @@ add_to_lit_pool (void)
          return FAIL;
        }
 
-      pool->literals[entry] = inst.reloc.exp;
-      pool->next_free_entry += 1;
-    }
+      if (nbytes == 8)
+       {
+         /* For 8-byte entries, we align to an 8-byte boundary,
+            and split it into two 4-byte entries, because on 32-bit
+            host, 8-byte constants are treated as big num, thus
+            saved in "generic_bignum" which will be overwritten
+            by later assignments.
+
+            We also need to make sure there is enough space for
+            the split.
+
+            We also check to make sure the literal operand is a
+            constant number.  */
+         if (!(inst.reloc.exp.X_op == O_constant
+               || inst.reloc.exp.X_op == O_big))
+           {
+             inst.error = _("invalid type for literal pool");
+             return FAIL;
+           }
+         else if (pool_size & 0x7)
+           {
+             if ((entry + 2) >= MAX_LITERAL_POOL_SIZE)
+               {
+                 inst.error = _("literal pool overflow");
+                 return FAIL;
+               }
 
-  inst.reloc.exp.X_op        = O_symbol;
-  inst.reloc.exp.X_add_number = ((int) entry) * 4;
-  inst.reloc.exp.X_add_symbol = pool->symbol;
+             pool->literals[entry] = inst.reloc.exp;
+             pool->literals[entry].X_add_number = 0;
+             pool->literals[entry++].X_md = (PADDING_SLOT << 8) | 4;
+             pool->next_free_entry += 1;
+             pool_size += 4;
+           }
+         else if ((entry + 1) >= MAX_LITERAL_POOL_SIZE)
+           {
+             inst.error = _("literal pool overflow");
+             return FAIL;
+           }
+
+         pool->literals[entry] = inst.reloc.exp;
+         pool->literals[entry].X_op = O_constant;
+         pool->literals[entry].X_add_number = imm1;
+         pool->literals[entry].X_unsigned = inst.reloc.exp.X_unsigned;
+         pool->literals[entry++].X_md = 4;
+         pool->literals[entry] = inst.reloc.exp;
+         pool->literals[entry].X_op = O_constant;
+         pool->literals[entry].X_add_number = imm2;
+         pool->literals[entry].X_unsigned = inst.reloc.exp.X_unsigned;
+         pool->literals[entry].X_md = 4;
+         pool->alignment = 3;
+         pool->next_free_entry += 1;
+       }
+      else
+       {
+         pool->literals[entry] = inst.reloc.exp;
+         pool->literals[entry].X_md = 4;
+       }
+
+#ifdef OBJ_ELF
+      /* PR ld/12974: Record the location of the first source line to reference
+        this entry in the literal pool.  If it turns out during linking that the
+        symbol does not exist we will be able to give an accurate line number for
+        the (first use of the) missing reference.  */
+      if (debug_type == DEBUG_DWARF2)
+       dwarf2_where (pool->locs + entry);
+#endif
+      pool->next_free_entry += 1;
+    }
+  else if (padding_slot_p)
+    {
+      pool->literals[entry] = inst.reloc.exp;
+      pool->literals[entry].X_md = nbytes;
+    }
+
+  inst.reloc.exp.X_op        = O_symbol;
+  inst.reloc.exp.X_add_number = pool_size;
+  inst.reloc.exp.X_add_symbol = pool->symbol;
 
   return SUCCESS;
 }
 
+bfd_boolean
+tc_start_label_without_colon (void)
+{
+  bfd_boolean ret = TRUE;
+
+  if (codecomposer_syntax && asmfunc_state == WAITING_ASMFUNC_NAME)
+    {
+      const char *label = input_line_pointer;
+
+      while (!is_end_of_line[(int) label[-1]])
+       --label;
+
+      if (*label == '.')
+       {
+         as_bad (_("Invalid label '%s'"), label);
+         ret = FALSE;
+       }
+
+      asmfunc_debug (label);
+
+      asmfunc_state = WAITING_ENDASMFUNC;
+    }
+
+  return ret;
+}
+
 /* Can't use symbol_new here, so have to create a symbol and then at
    a later date assign it a value. Thats what these functions do.  */
 
@@ -3067,7 +3368,7 @@ symbol_locate (symbolS *    symbolP,
               valueT       valu,       /* Symbol value.  */
               fragS *      frag)       /* Associated fragment.  */
 {
-  unsigned int name_length;
+  size_t name_length;
   char * preserved_copy_of_name;
 
   name_length = strlen (name) + 1;   /* +1 for \0.  */
@@ -3108,7 +3409,6 @@ symbol_locate (symbolS *    symbolP,
 #endif /* DEBUG_SYMS  */
 }
 
-
 static void
 s_ltorg (int ignored ATTRIBUTE_UNUSED)
 {
@@ -3122,15 +3422,17 @@ s_ltorg (int ignored ATTRIBUTE_UNUSED)
       || pool->next_free_entry == 0)
     return;
 
-  mapping_state (MAP_DATA);
-
   /* Align pool as you have word accesses.
      Only make a frag if we have to.  */
   if (!need_pass_2)
-    frag_align (2, 0, 0);
+    frag_align (pool->alignment, 0, 0);
 
   record_alignment (now_seg, 2);
 
+#ifdef OBJ_ELF
+  seg_info (now_seg)->tc_segment_info_data.mapstate = MAP_DATA;
+  make_mapping_symbol (MAP_DATA, (valueT) frag_now_fix (), frag_now);
+#endif
   sprintf (sym_name, "$$lit_\002%x", pool->id);
 
   symbol_locate (pool->symbol, sym_name, now_seg,
@@ -3144,8 +3446,15 @@ s_ltorg (int ignored ATTRIBUTE_UNUSED)
 #endif
 
   for (entry = 0; entry < pool->next_free_entry; entry ++)
-    /* First output the expression in the instruction to the pool.  */
-    emit_expr (&(pool->literals[entry]), 4); /* .word  */
+    {
+#ifdef OBJ_ELF
+      if (debug_type == DEBUG_DWARF2)
+       dwarf2_gen_line_info (frag_now_fix (), pool->locs + entry);
+#endif
+      /* First output the expression in the instruction to the pool.  */
+      emit_expr (&(pool->literals[entry]),
+                pool->literals[entry].X_md & LIT_ENTRY_SIZE_MASK);
+    }
 
   /* Mark the pool as empty.  */
   pool->next_free_entry = 0;
@@ -3207,8 +3516,8 @@ s_arm_elf_cons (int nbytes)
          else
            {
              reloc_howto_type *howto = (reloc_howto_type *)
-                  bfd_reloc_type_lookup (stdoutput,
-                                         (bfd_reloc_code_real_type) reloc);
+                 bfd_reloc_type_lookup (stdoutput,
+                                        (bfd_reloc_code_real_type) reloc);
              int size = bfd_get_reloc_size (howto);
 
              if (reloc == BFD_RELOC_ARM_PLT32)
@@ -3229,7 +3538,8 @@ s_arm_elf_cons (int nbytes)
                     XXX Surely there is a cleaner way to do this.  */
                  char *p = input_line_pointer;
                  int offset;
-                 char *save_buf = (char *) alloca (input_line_pointer - base);
+                 char *save_buf = XNEWVEC (char, input_line_pointer - base);
+
                  memcpy (save_buf, base, input_line_pointer - base);
                  memmove (base + (input_line_pointer - before_reloc),
                           base, before_reloc - base);
@@ -3239,9 +3549,11 @@ s_arm_elf_cons (int nbytes)
                  memcpy (base, save_buf, p - base);
 
                  offset = nbytes - size;
-                 p = frag_more ((int) nbytes);
+                 p = frag_more (nbytes);
+                 memset (p, 0, nbytes);
                  fix_new_exp (frag_now, p - frag_now->fr_literal + offset,
                               size, &exp, 0, (enum bfd_reloc_code_real) reloc);
+                 free (save_buf);
                }
            }
        }
@@ -3491,6 +3803,7 @@ s_arm_unwind_fnend (int ignored ATTRIBUTE_UNUSED)
   record_alignment (now_seg, 2);
 
   ptr = frag_more (8);
+  memset (ptr, 0, 8);
   where = frag_now_fix () - 8;
 
   /* Self relative offset of the function start.  */
@@ -3589,9 +3902,10 @@ s_arm_unwind_personality (int ignored ATTRIBUTE_UNUSED)
   if (unwind.personality_routine || unwind.personality_index != -1)
     as_bad (_("duplicate .personality directive"));
 
-  name = input_line_pointer;
-  c = get_symbol_end ();
+  c = get_symbol_name (& name);
   p = input_line_pointer;
+  if (c == '"')
+    ++ input_line_pointer;
   unwind.personality_routine = symbol_find_or_make (name);
   *p = c;
   demand_empty_rest_of_line ();
@@ -3857,8 +4171,7 @@ s_arm_unwind_save_mmxwr (void)
     }
   while (skip_past_comma (&input_line_pointer) != FAIL);
 
-  if (*input_line_pointer == '}')
-    input_line_pointer++;
+  skip_past_char (&input_line_pointer, '}');
 
   demand_empty_rest_of_line ();
 
@@ -3955,6 +4268,8 @@ s_arm_unwind_save_mmxwcg (void)
   if (*input_line_pointer == '{')
     input_line_pointer++;
 
+  skip_whitespace (input_line_pointer);
+
   do
     {
       reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWCG);
@@ -3990,8 +4305,7 @@ s_arm_unwind_save_mmxwcg (void)
     }
   while (skip_past_comma (&input_line_pointer) != FAIL);
 
-  if (*input_line_pointer == '}')
-    input_line_pointer++;
+  skip_past_char (&input_line_pointer, '}');
 
   demand_empty_rest_of_line ();
 
@@ -4056,15 +4370,24 @@ s_arm_unwind_save (int arch_v6)
       s_arm_unwind_save_fpa (reg->number);
       return;
 
-    case REG_TYPE_RN:    s_arm_unwind_save_core ();   return;
+    case REG_TYPE_RN:
+      s_arm_unwind_save_core ();
+      return;
+
     case REG_TYPE_VFD:
       if (arch_v6)
-        s_arm_unwind_save_vfp_armv6 ();
+       s_arm_unwind_save_vfp_armv6 ();
       else
-        s_arm_unwind_save_vfp ();
+       s_arm_unwind_save_vfp ();
+      return;
+
+    case REG_TYPE_MMXWR:
+      s_arm_unwind_save_mmxwr ();
+      return;
+
+    case REG_TYPE_MMXWCG:
+      s_arm_unwind_save_mmxwcg ();
       return;
-    case REG_TYPE_MMXWR:  s_arm_unwind_save_mmxwr ();  return;
-    case REG_TYPE_MMXWCG: s_arm_unwind_save_mmxwcg (); return;
 
     default:
       as_bad (_(".unwind_save does not support this kind of register"));
@@ -4270,7 +4593,7 @@ s_arm_unwind_raw (int ignored ATTRIBUTE_UNUSED)
 static void
 s_arm_eabi_attribute (int ignored ATTRIBUTE_UNUSED)
 {
-  int tag = s_vendor_attribute (OBJ_ATTR_PROC);
+  int tag = obj_elf_vendor_attribute (OBJ_ATTR_PROC);
 
   if (tag < NUM_KNOWN_OBJ_ATTRIBUTES)
     attributes_set_explicitly[tag] = 1;
@@ -4344,7 +4667,7 @@ const pseudo_typeS md_pseudo_table[] =
   { "qn",          s_qn,          0 },
   { "unreq",      s_unreq,       0 },
   { "bss",        s_bss,         0 },
-  { "align",      s_align,       0 },
+  { "align",      s_align_ptwo,  2 },
   { "arm",        s_arm,         0 },
   { "thumb",      s_thumb,       0 },
   { "code",       s_code,        0 },
@@ -4399,6 +4722,13 @@ const pseudo_typeS md_pseudo_table[] =
 #ifdef TE_PE
   {"secrel32", pe_directive_secrel, 0},
 #endif
+
+  /* These are for compatibility with CodeComposer Studio.  */
+  {"ref",          s_ccs_ref,        0},
+  {"def",          s_ccs_def,        0},
+  {"asmfunc",      s_ccs_asmfunc,    0},
+  {"endasmfunc",   s_ccs_endasmfunc, 0},
+
   { 0, 0, 0 }
 };
 \f
@@ -4437,41 +4767,44 @@ parse_immediate (char **str, int *val, int min, int max,
    instructions. Puts the result directly in inst.operands[i].  */
 
 static int
-parse_big_immediate (char **str, int i)
+parse_big_immediate (char **str, int i, expressionS *in_exp,
+                    bfd_boolean allow_symbol_p)
 {
   expressionS exp;
+  expressionS *exp_p = in_exp ? in_exp : &exp;
   char *ptr = *str;
 
-  my_get_expression (&exp, &ptr, GE_OPT_PREFIX_BIG);
+  my_get_expression (exp_p, &ptr, GE_OPT_PREFIX_BIG);
 
-  if (exp.X_op == O_constant)
+  if (exp_p->X_op == O_constant)
     {
-      inst.operands[i].imm = exp.X_add_number & 0xffffffff;
+      inst.operands[i].imm = exp_p->X_add_number & 0xffffffff;
       /* If we're on a 64-bit host, then a 64-bit number can be returned using
         O_constant.  We have to be careful not to break compilation for
         32-bit X_add_number, though.  */
-      if ((exp.X_add_number & ~0xffffffffl) != 0)
+      if ((exp_p->X_add_number & ~(offsetT)(0xffffffffU)) != 0)
        {
-          /* X >> 32 is illegal if sizeof (exp.X_add_number) == 4.  */
-         inst.operands[i].reg = ((exp.X_add_number >> 16) >> 16) & 0xffffffff;
+         /* X >> 32 is illegal if sizeof (exp_p->X_add_number) == 4.  */
+         inst.operands[i].reg = (((exp_p->X_add_number >> 16) >> 16)
+                                 & 0xffffffff);
          inst.operands[i].regisimm = 1;
        }
     }
-  else if (exp.X_op == O_big
-          && LITTLENUM_NUMBER_OF_BITS * exp.X_add_number > 32)
+  else if (exp_p->X_op == O_big
+          && LITTLENUM_NUMBER_OF_BITS * exp_p->X_add_number > 32)
     {
       unsigned parts = 32 / LITTLENUM_NUMBER_OF_BITS, j, idx = 0;
 
       /* Bignums have their least significant bits in
-         generic_bignum[0]. Make sure we put 32 bits in imm and
-         32 bits in reg,  in a (hopefully) portable way.  */
+        generic_bignum[0]. Make sure we put 32 bits in imm and
+        32 bits in reg,  in a (hopefully) portable way.  */
       gas_assert (parts != 0);
 
       /* Make sure that the number is not too big.
         PR 11972: Bignums can now be sign-extended to the
         size of a .octa so check that the out of range bits
         are all zero or all one.  */
-      if (LITTLENUM_NUMBER_OF_BITS * exp.X_add_number > 64)
+      if (LITTLENUM_NUMBER_OF_BITS * exp_p->X_add_number > 64)
        {
          LITTLENUM_TYPE m = -1;
 
@@ -4479,22 +4812,22 @@ parse_big_immediate (char **str, int i)
              && generic_bignum[parts * 2] != m)
            return FAIL;
 
-         for (j = parts * 2 + 1; j < (unsigned) exp.X_add_number; j++)
+         for (j = parts * 2 + 1; j < (unsigned) exp_p->X_add_number; j++)
            if (generic_bignum[j] != generic_bignum[j-1])
              return FAIL;
        }
 
       inst.operands[i].imm = 0;
       for (j = 0; j < parts; j++, idx++)
-        inst.operands[i].imm |= generic_bignum[idx]
-                                << (LITTLENUM_NUMBER_OF_BITS * j);
+       inst.operands[i].imm |= generic_bignum[idx]
+                               << (LITTLENUM_NUMBER_OF_BITS * j);
       inst.operands[i].reg = 0;
       for (j = 0; j < parts; j++, idx++)
-        inst.operands[i].reg |= generic_bignum[idx]
-                                << (LITTLENUM_NUMBER_OF_BITS * j);
+       inst.operands[i].reg |= generic_bignum[idx]
+                               << (LITTLENUM_NUMBER_OF_BITS * j);
       inst.operands[i].regisimm = 1;
     }
-  else
+  else if (!(exp_p->X_op == O_symbol && allow_symbol_p))
     return FAIL;
 
   *str = ptr;
@@ -4567,7 +4900,9 @@ parse_fpa_immediate (char ** str)
     {
       /* FIXME: 5 = X_PRECISION, should be #define'd where we can use it.
         Ditto for 15.  */
-      if (gen_to_words (words, 5, (long) 15) == 0)
+#define X_PRECISION 5
+#define E_PRECISION 15L
+      if (gen_to_words (words, X_PRECISION, E_PRECISION) == 0)
        {
          for (i = 0; i < NUM_FLOAT_VALS; i++)
            {
@@ -4603,6 +4938,41 @@ is_quarter_float (unsigned imm)
   return (imm & 0x7ffff) == 0 && ((imm & 0x7e000000) ^ bs) == 0;
 }
 
+
+/* Detect the presence of a floating point or integer zero constant,
+   i.e. #0.0 or #0.  */
+
+static bfd_boolean
+parse_ifimm_zero (char **in)
+{
+  int error_code;
+
+  if (!is_immediate_prefix (**in))
+    return FALSE;
+
+  ++*in;
+
+  /* Accept #0x0 as a synonym for #0.  */
+  if (strncmp (*in, "0x", 2) == 0)
+    {
+      int val;
+      if (parse_immediate (in, &val, 0, 0, TRUE) == FAIL)
+        return FALSE;
+      return TRUE;
+    }
+
+  error_code = atof_generic (in, ".", EXP_CHARS,
+                             &generic_floating_point_number);
+
+  if (!error_code
+      && generic_floating_point_number.sign == '+'
+      && (generic_floating_point_number.low
+          > generic_floating_point_number.leader))
+    return TRUE;
+
+  return FALSE;
+}
+
 /* Parse an 8-bit "quarter-precision" floating point number of the form:
    0baBbbbbbc defgh000 00000000 00000000.
    The zero and minus-zero cases need special handling, since they can't be
@@ -4632,14 +5002,14 @@ parse_qfloat_immediate (char **ccp, int *immed)
   else
     {
       for (; *fpnum != '\0' && *fpnum != ' ' && *fpnum != '\n'; fpnum++)
-        if (*fpnum == '.' || *fpnum == 'e' || *fpnum == 'E')
-          {
-            found_fpchar = 1;
-            break;
-          }
+       if (*fpnum == '.' || *fpnum == 'e' || *fpnum == 'E')
+         {
+           found_fpchar = 1;
+           break;
+         }
 
       if (!found_fpchar)
-        return FAIL;
+       return FAIL;
     }
 
   if ((str = atof_ieee (str, 's', words)) != NULL)
@@ -4649,15 +5019,15 @@ parse_qfloat_immediate (char **ccp, int *immed)
 
       /* Our FP word must be 32 bits (single-precision FP).  */
       for (i = 0; i < 32 / LITTLENUM_NUMBER_OF_BITS; i++)
-        {
-          fpword <<= LITTLENUM_NUMBER_OF_BITS;
-          fpword |= words[i];
-        }
+       {
+         fpword <<= LITTLENUM_NUMBER_OF_BITS;
+         fpword |= words[i];
+       }
 
       if (is_quarter_float (fpword) || (fpword & 0x7fffffff) == 0)
-        *immed = fpword;
+       *immed = fpword;
       else
-        return FAIL;
+       return FAIL;
 
       *ccp = str;
 
@@ -4718,7 +5088,7 @@ parse_shift (char **str, int i, enum parse_shift_mode mode)
     }
 
   shift_name = (const struct asm_shift_name *) hash_find_n (arm_shift_hsh, *str,
-                                                            p - *str);
+                                                           p - *str);
 
   if (shift_name == NULL)
     {
@@ -4840,10 +5210,9 @@ parse_shifter_operand (char **str, int i)
          return FAIL;
        }
 
-      /* Convert to decoded value.  md_apply_fix will put it back.  */
-      inst.reloc.exp.X_add_number
-       = (((inst.reloc.exp.X_add_number << (32 - value))
-           | (inst.reloc.exp.X_add_number >> value)) & 0xffffffff);
+      /* Encode as specified.  */
+      inst.operands[i].imm = inst.reloc.exp.X_add_number | value << 7;
+      return SUCCESS;
     }
 
   inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
@@ -4928,7 +5297,28 @@ static struct group_reloc_table_entry group_reloc_table[] =
       BFD_RELOC_ARM_ALU_SB_G2,         /* ALU */
       BFD_RELOC_ARM_LDR_SB_G2,         /* LDR */
       BFD_RELOC_ARM_LDRS_SB_G2,                /* LDRS */
-      BFD_RELOC_ARM_LDC_SB_G2 }        };      /* LDC */
+      BFD_RELOC_ARM_LDC_SB_G2 },       /* LDC */
+    /* Absolute thumb alu relocations.  */
+    { "lower0_7",
+      BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC,/* ALU.  */
+      0,                               /* LDR.  */
+      0,                               /* LDRS.  */
+      0 },                             /* LDC.  */
+    { "lower8_15",
+      BFD_RELOC_ARM_THUMB_ALU_ABS_G1_NC,/* ALU.  */
+      0,                               /* LDR.  */
+      0,                               /* LDRS.  */
+      0 },                             /* LDC.  */
+    { "upper0_7",
+      BFD_RELOC_ARM_THUMB_ALU_ABS_G2_NC,/* ALU.  */
+      0,                               /* LDR.  */
+      0,                               /* LDRS.  */
+      0 },                             /* LDC.  */
+    { "upper8_15",
+      BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC,/* ALU.  */
+      0,                               /* LDR.  */
+      0,                               /* LDRS.  */
+      0 } };                           /* LDC.  */
 
 /* Given the address of a pointer pointing to the textual name of a group
    relocation as may appear in assembler source, attempt to find its details
@@ -4947,11 +5337,11 @@ find_group_reloc_table_entry (char **str, struct group_reloc_table_entry **out)
 
       if (strncasecmp (group_reloc_table[i].name, *str, length) == 0
          && (*str)[length] == ':')
-        {
-          *out = &group_reloc_table[i];
-          *str += (length + 1);
-          return SUCCESS;
-        }
+       {
+         *out = &group_reloc_table[i];
+         *str += (length + 1);
+         return SUCCESS;
+       }
     }
 
   return FAIL;
@@ -4984,21 +5374,21 @@ parse_shifter_operand_group_reloc (char **str, int i)
       struct group_reloc_table_entry *entry;
 
       if ((*str)[0] == '#')
-        (*str) += 2;
+       (*str) += 2;
       else
-        (*str)++;
+       (*str)++;
 
       /* Try to parse a group relocation.  Anything else is an error.  */
       if (find_group_reloc_table_entry (str, &entry) == FAIL)
-        {
-          inst.error = _("unknown group relocation");
-          return PARSE_OPERAND_FAIL_NO_BACKTRACK;
-        }
+       {
+         inst.error = _("unknown group relocation");
+         return PARSE_OPERAND_FAIL_NO_BACKTRACK;
+       }
 
       /* We now have the group relocation table entry corresponding to
-         the name in the assembler source.  Next, we parse the expression.  */
+        the name in the assembler source.  Next, we parse the expression.  */
       if (my_get_expression (&inst.reloc.exp, str, GE_NO_PREFIX))
-        return PARSE_OPERAND_FAIL_NO_BACKTRACK;
+       return PARSE_OPERAND_FAIL_NO_BACKTRACK;
 
       /* Record the relocation type (always the ALU variant here).  */
       inst.reloc.type = (bfd_reloc_code_real_type) entry->alu_code;
@@ -5008,14 +5398,14 @@ parse_shifter_operand_group_reloc (char **str, int i)
     }
   else
     return parse_shifter_operand (str, i) == SUCCESS
-           ? PARSE_OPERAND_SUCCESS : PARSE_OPERAND_FAIL;
+          ? PARSE_OPERAND_SUCCESS : PARSE_OPERAND_FAIL;
 
   /* Never reached.  */
 }
 
 /* Parse a Neon alignment expression.  Information is written to
    inst.operands[i].  We assume the initial ':' has been skipped.
-   
+
    align       .imm = align << 8, .immisalign=1, .preind=0  */
 static parse_operand_result
 parse_neon_alignment (char **str, int i)
@@ -5074,7 +5464,7 @@ parse_neon_alignment (char **str, int i)
 
 static parse_operand_result
 parse_address_main (char **str, int i, int group_relocations,
-                    group_reloc_type group_type)
+                   group_reloc_type group_type)
 {
   char *p = *str;
   int reg;
@@ -5088,16 +5478,21 @@ parse_address_main (char **str, int i, int group_relocations,
          inst.operands[i].reg = REG_PC;
          inst.operands[i].isreg = 1;
          inst.operands[i].preind = 1;
-       }
-      /* Otherwise a load-constant pseudo op, no special treatment needed here.  */
 
-      if (my_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX))
+         if (my_get_expression (&inst.reloc.exp, &p, GE_OPT_PREFIX_BIG))
+           return PARSE_OPERAND_FAIL;
+       }
+      else if (parse_big_immediate (&p, i, &inst.reloc.exp,
+                                   /*allow_symbol_p=*/TRUE))
        return PARSE_OPERAND_FAIL;
 
       *str = p;
       return PARSE_OPERAND_SUCCESS;
     }
 
+  /* PR gas/14887: Allow for whitespace after the opening bracket.  */
+  skip_whitespace (p);
+
   if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) == FAIL)
     {
       inst.error = _(reg_expected_msgs[REG_TYPE_RN]);
@@ -5128,7 +5523,7 @@ parse_address_main (char **str, int i, int group_relocations,
             code before we get to see it here. This may be subject to
             change.  */
          parse_operand_result result = parse_neon_alignment (&p, i);
-         
+
          if (result != PARSE_OPERAND_SUCCESS)
            return result;
        }
@@ -5145,14 +5540,14 @@ parse_address_main (char **str, int i, int group_relocations,
            {
              struct group_reloc_table_entry *entry;
 
-              /* Skip over the #: or : sequence.  */
-              if (*p == '#')
-                p += 2;
-              else
-                p++;
+             /* Skip over the #: or : sequence.  */
+             if (*p == '#')
+               p += 2;
+             else
+               p++;
 
              /* Try to parse a group relocation.  Anything else is an
-                 error.  */
+                error.  */
              if (find_group_reloc_table_entry (&p, &entry) == FAIL)
                {
                  inst.error = _("unknown group relocation");
@@ -5161,38 +5556,54 @@ parse_address_main (char **str, int i, int group_relocations,
 
              /* We now have the group relocation table entry corresponding to
                 the name in the assembler source.  Next, we parse the
-                 expression.  */
+                expression.  */
              if (my_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX))
                return PARSE_OPERAND_FAIL_NO_BACKTRACK;
 
              /* Record the relocation type.  */
-              switch (group_type)
-                {
-                  case GROUP_LDR:
-                   inst.reloc.type = (bfd_reloc_code_real_type) entry->ldr_code;
-                    break;
+             switch (group_type)
+               {
+                 case GROUP_LDR:
+                   inst.reloc.type = (bfd_reloc_code_real_type) entry->ldr_code;
+                   break;
 
-                  case GROUP_LDRS:
-                   inst.reloc.type = (bfd_reloc_code_real_type) entry->ldrs_code;
-                    break;
+                 case GROUP_LDRS:
+                   inst.reloc.type = (bfd_reloc_code_real_type) entry->ldrs_code;
+                   break;
 
-                  case GROUP_LDC:
-                   inst.reloc.type = (bfd_reloc_code_real_type) entry->ldc_code;
-                    break;
+                 case GROUP_LDC:
+                   inst.reloc.type = (bfd_reloc_code_real_type) entry->ldc_code;
+                   break;
 
-                  default:
-                    gas_assert (0);
-                }
+                 default:
+                   gas_assert (0);
+               }
 
-              if (inst.reloc.type == 0)
+             if (inst.reloc.type == 0)
                {
                  inst.error = _("this group relocation is not allowed on this instruction");
                  return PARSE_OPERAND_FAIL_NO_BACKTRACK;
                }
-            }
-          else
-           if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX))
-             return PARSE_OPERAND_FAIL;
+           }
+         else
+           {
+             char *q = p;
+             if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX))
+               return PARSE_OPERAND_FAIL;
+             /* If the offset is 0, find out if it's a +0 or -0.  */
+             if (inst.reloc.exp.X_op == O_constant
+                 && inst.reloc.exp.X_add_number == 0)
+               {
+                 skip_whitespace (q);
+                 if (*q == '#')
+                   {
+                     q++;
+                     skip_whitespace (q);
+                   }
+                 if (*q == '-')
+                   inst.operands[i].negative = 1;
+               }
+           }
        }
     }
   else if (skip_past_char (&p, ':') == SUCCESS)
@@ -5200,7 +5611,7 @@ parse_address_main (char **str, int i, int group_relocations,
       /* FIXME: '@' should be used here, but it's filtered out by generic code
         before we get to see it here. This may be subject to change.  */
       parse_operand_result result = parse_neon_alignment (&p, i);
-      
+
       if (result != PARSE_OPERAND_SUCCESS)
        return result;
     }
@@ -5252,12 +5663,12 @@ parse_address_main (char **str, int i, int group_relocations,
 
          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.  */
-              if (inst.operands[i].immisalign)
-               inst.operands[i].imm |= reg;
-              else
-                inst.operands[i].imm = reg;
+             /* We might be using the immediate for alignment already. If we
+                are, OR the register number into the low-order bits.  */
+             if (inst.operands[i].immisalign)
+               inst.operands[i].imm |= reg;
+             else
+               inst.operands[i].imm = reg;
              inst.operands[i].immisreg = 1;
 
              if (skip_past_comma (&p) == SUCCESS)
@@ -5266,6 +5677,7 @@ parse_address_main (char **str, int i, int group_relocations,
            }
          else
            {
+             char *q = p;
              if (inst.operands[i].negative)
                {
                  inst.operands[i].negative = 0;
@@ -5273,6 +5685,19 @@ parse_address_main (char **str, int i, int group_relocations,
                }
              if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX))
                return PARSE_OPERAND_FAIL;
+             /* If the offset is 0, find out if it's a +0 or -0.  */
+             if (inst.reloc.exp.X_op == O_constant
+                 && inst.reloc.exp.X_add_number == 0)
+               {
+                 skip_whitespace (q);
+                 if (*q == '#')
+                   {
+                     q++;
+                     skip_whitespace (q);
+                   }
+                 if (*q == '-')
+                   inst.operands[i].negative = 1;
+               }
            }
        }
     }
@@ -5293,7 +5718,7 @@ static int
 parse_address (char **str, int i)
 {
   return parse_address_main (str, i, 0, GROUP_LDR) == PARSE_OPERAND_SUCCESS
-         ? SUCCESS : FAIL;
+        ? SUCCESS : FAIL;
 }
 
 static parse_operand_result
@@ -5356,6 +5781,12 @@ parse_psr (char **str, bfd_boolean lhs)
   bfd_boolean is_apsr = FALSE;
   bfd_boolean m_profile = ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_m);
 
+  /* PR gas/12698:  If the user has specified -march=all then m_profile will
+     be TRUE, but we want to ignore it in this case as we are building for any
+     CPU type, including non-m variants.  */
+  if (ARM_FEATURE_CORE_EQUAL (selected_cpu, arm_arch_any))
+    m_profile = FALSE;
+
   /* CPSR's and SPSR's can now be lowercase.  This is just a convenience
      feature for ease of use and backwards compatibility.  */
   p = *str;
@@ -5363,7 +5794,7 @@ parse_psr (char **str, bfd_boolean lhs)
     {
       if (m_profile)
        goto unsupported_psr;
-       
+
       psr_field = SPSR_BIT;
     }
   else if (strncasecmp (p, "CPSR", 4) == 0)
@@ -5394,7 +5825,7 @@ parse_psr (char **str, bfd_boolean lhs)
        p = start + strcspn (start, "rR") + 1;
 
       psr = (const struct asm_psr *) hash_find_n (arm_v7m_psr_hsh, start,
-                                                  p - start);
+                                                 p - start);
 
       if (!psr)
        return FAIL;
@@ -5436,11 +5867,11 @@ check_suffix:
          unsigned int nzcvq_bits = 0;
          unsigned int g_bit = 0;
          char *bit;
-         
+
          for (bit = start; bit != p; bit++)
            {
              switch (TOLOWER (*bit))
-               {
+               {
                case 'n':
                  nzcvq_bits |= (nzcvq_bits & 0x01) ? 0x20 : 0x01;
                  break;
@@ -5456,28 +5887,28 @@ check_suffix:
                case 'v':
                  nzcvq_bits |= (nzcvq_bits & 0x08) ? 0x20 : 0x08;
                  break;
-               
+
                case 'q':
                  nzcvq_bits |= (nzcvq_bits & 0x10) ? 0x20 : 0x10;
                  break;
-               
+
                case 'g':
                  g_bit |= (g_bit & 0x1) ? 0x2 : 0x1;
                  break;
-               
+
                default:
                  inst.error = _("unexpected bit specified after APSR");
                  return FAIL;
                }
            }
-         
+
          if (nzcvq_bits == 0x1f)
            psr_field |= PSR_f;
-         
+
          if (g_bit == 0x1)
            {
              if (!ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6_dsp))
-               {
+               {
                  inst.error = _("selected processor does not "
                                 "support DSP extension");
                  return FAIL;
@@ -5485,7 +5916,7 @@ check_suffix:
 
              psr_field |= PSR_s;
            }
-         
+
          if ((nzcvq_bits & 0x20) != 0
              || (nzcvq_bits != 0x1f && nzcvq_bits != 0)
              || (g_bit & 0x2) != 0)
@@ -5495,11 +5926,11 @@ check_suffix:
            }
        }
       else
-        {
+       {
          psr = (const struct asm_psr *) hash_find_n (arm_psr_hsh, start,
-                                                      p - start);
+                                                     p - start);
          if (!psr)
-            goto error;
+           goto error;
 
          psr_field |= psr->field;
        }
@@ -5510,7 +5941,7 @@ check_suffix:
        goto error;    /* Garbage after "[CS]PSR".  */
 
       /* Unadorned APSR is equivalent to APSR_nzcvq/CPSR_f (for writes).  This
-         is deprecated, but allow it anyway.  */
+        is deprecated, but allow it anyway.  */
       if (is_apsr && lhs)
        {
          psr_field |= PSR_f;
@@ -5666,6 +6097,32 @@ parse_cond (char **str)
   return c->value;
 }
 
+/* Record a use of the given feature.  */
+static void
+record_feature_use (const arm_feature_set *feature)
+{
+  if (thumb_mode)
+    ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used, *feature);
+  else
+    ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used, *feature);
+}
+
+/* If the given feature available in the selected CPU, mark it as used.
+   Returns TRUE iff feature is available.  */
+static bfd_boolean
+mark_feature_used (const arm_feature_set *feature)
+{
+  /* Ensure the option is valid on the current architecture.  */
+  if (!ARM_CPU_HAS_FEATURE (cpu_variant, *feature))
+    return FALSE;
+
+  /* Add the appropriate architecture feature for the barrier option used.
+     */
+  record_feature_use (feature);
+
+  return TRUE;
+}
+
 /* Parse an option for a barrier instruction.  Returns the encoding for the
    option, or FAIL.  */
 static int
@@ -5679,10 +6136,13 @@ parse_barrier (char **str)
     q++;
 
   o = (const struct asm_barrier_opt *) hash_find_n (arm_barrier_opt_hsh, p,
-                                                    q - p);
+                                                   q - p);
   if (!o)
     return FAIL;
 
+  if (!mark_feature_used (&o->arch))
+    return FAIL;
+
   *str = q;
   return o->value;
 }
@@ -5766,21 +6226,21 @@ parse_neon_mov (char **str, int *which_operand)
       inst.operands[i++].present = 1;
 
       if (skip_past_comma (&ptr) == FAIL)
-        goto wanted_comma;
+       goto wanted_comma;
 
       if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) == FAIL)
-        goto wanted_arm;
+       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_NSDQ, &rtype, &optype))
-           != FAIL)
+          != FAIL)
     {
       /* Cases 0, 1, 2, 3, 5 (D only).  */
       if (skip_past_comma (&ptr) == FAIL)
-        goto wanted_comma;
+       goto wanted_comma;
 
       inst.operands[i].reg = val;
       inst.operands[i].isreg = 1;
@@ -5791,84 +6251,85 @@ parse_neon_mov (char **str, int *which_operand)
       inst.operands[i++].present = 1;
 
       if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) != FAIL)
-        {
-          /* Case 5: VMOV<c><q> <Dm>, <Rd>, <Rn>.
-             Case 13: VMOV <Sd>, <Rm>  */
-          inst.operands[i].reg = val;
-          inst.operands[i].isreg = 1;
-          inst.operands[i].present = 1;
-
-          if (rtype == REG_TYPE_NQ)
-            {
-              first_error (_("can't use Neon quad register here"));
-              return FAIL;
-            }
-          else if (rtype != REG_TYPE_VFS)
-            {
-              i++;
-              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;
-            }
-        }
+       {
+         /* Case 5: VMOV<c><q> <Dm>, <Rd>, <Rn>.
+            Case 13: VMOV <Sd>, <Rm>  */
+         inst.operands[i].reg = val;
+         inst.operands[i].isreg = 1;
+         inst.operands[i].present = 1;
+
+         if (rtype == REG_TYPE_NQ)
+           {
+             first_error (_("can't use Neon quad register here"));
+             return FAIL;
+           }
+         else if (rtype != REG_TYPE_VFS)
+           {
+             i++;
+             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_NSDQ, &rtype,
-                                           &optype)) != FAIL)
-        {
-          /* Case 0: VMOV<c><q> <Qd>, <Qm>
-             Case 1: VMOV<c><q> <Dd>, <Dm>
-             Case 8: VMOV.F32 <Sd>, <Sm>
-             Case 15: VMOV <Sd>, <Se>, <Rn>, <Rm>  */
-
-          inst.operands[i].reg = val;
-          inst.operands[i].isreg = 1;
-          inst.operands[i].isquad = (rtype == REG_TYPE_NQ);
-          inst.operands[i].issingle = (rtype == REG_TYPE_VFS);
-          inst.operands[i].isvec = 1;
-          inst.operands[i].vectype = optype;
-          inst.operands[i].present = 1;
-
-          if (skip_past_comma (&ptr) == SUCCESS)
-            {
-              /* Case 15.  */
-              i++;
-
-              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;
-
-              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;
-            }
-        }
+                                          &optype)) != FAIL)
+       {
+         /* Case 0: VMOV<c><q> <Qd>, <Qm>
+            Case 1: VMOV<c><q> <Dd>, <Dm>
+            Case 8: VMOV.F32 <Sd>, <Sm>
+            Case 15: VMOV <Sd>, <Se>, <Rn>, <Rm>  */
+
+         inst.operands[i].reg = val;
+         inst.operands[i].isreg = 1;
+         inst.operands[i].isquad = (rtype == REG_TYPE_NQ);
+         inst.operands[i].issingle = (rtype == REG_TYPE_VFS);
+         inst.operands[i].isvec = 1;
+         inst.operands[i].vectype = optype;
+         inst.operands[i].present = 1;
+
+         if (skip_past_comma (&ptr) == SUCCESS)
+           {
+             /* Case 15.  */
+             i++;
+
+             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;
+
+             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 (parse_qfloat_immediate (&ptr, &inst.operands[i].imm) == SUCCESS)
-          /* Case 2: VMOV<c><q>.<dt> <Qd>, #<float-imm>
-             Case 3: VMOV<c><q>.<dt> <Dd>, #<float-imm>
-             Case 10: VMOV.F32 <Sd>, #<imm>
-             Case 11: VMOV.F64 <Dd>, #<imm>  */
-        inst.operands[i].immisfloat = 1;
-      else if (parse_big_immediate (&ptr, i) == SUCCESS)
-          /* Case 2: VMOV<c><q>.<dt> <Qd>, #<imm>
-             Case 3: VMOV<c><q>.<dt> <Dd>, #<imm>  */
-        ;
+         /* Case 2: VMOV<c><q>.<dt> <Qd>, #<float-imm>
+            Case 3: VMOV<c><q>.<dt> <Dd>, #<float-imm>
+            Case 10: VMOV.F32 <Sd>, #<imm>
+            Case 11: VMOV.F64 <Dd>, #<imm>  */
+       inst.operands[i].immisfloat = 1;
+      else if (parse_big_immediate (&ptr, i, NULL, /*allow_symbol_p=*/FALSE)
+              == SUCCESS)
+         /* Case 2: VMOV<c><q>.<dt> <Qd>, #<imm>
+            Case 3: VMOV<c><q>.<dt> <Dd>, #<imm>  */
+       ;
       else
-        {
-          first_error (_("expected <Rm> or <Dm> or <Qm> operand"));
-          return FAIL;
-        }
+       {
+         first_error (_("expected <Rm> or <Dm> or <Qm> operand"));
+         return FAIL;
+       }
     }
   else if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) != FAIL)
     {
@@ -5878,71 +6339,71 @@ parse_neon_mov (char **str, int *which_operand)
       inst.operands[i++].present = 1;
 
       if (skip_past_comma (&ptr) == FAIL)
-        goto wanted_comma;
+       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;
-        }
+       {
+         /* 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;
-          inst.operands[i].isreg = 1;
-          inst.operands[i++].present = 1;
-
-          if (skip_past_comma (&ptr) == FAIL)
-            goto wanted_comma;
-
-          if ((val = arm_typed_reg_parse (&ptr, REG_TYPE_VFSD, &rtype, &optype))
-              == FAIL)
-            {
-              first_error (_(reg_expected_msgs[REG_TYPE_VFSD]));
-              return FAIL;
-            }
-
-          inst.operands[i].reg = val;
-          inst.operands[i].isreg = 1;
-          inst.operands[i].isvec = 1;
-          inst.operands[i].issingle = (rtype == REG_TYPE_VFS);
-          inst.operands[i].vectype = optype;
-          inst.operands[i].present = 1;
-
-          if (rtype == REG_TYPE_VFS)
-            {
-              /* Case 14.  */
-              i++;
-              if (skip_past_comma (&ptr) == FAIL)
-                goto wanted_comma;
-              if ((val = arm_typed_reg_parse (&ptr, REG_TYPE_VFS, NULL,
-                                              &optype)) == FAIL)
-                {
-                  first_error (_(reg_expected_msgs[REG_TYPE_VFS]));
-                  return FAIL;
-                }
-              inst.operands[i].reg = val;
-              inst.operands[i].isreg = 1;
-              inst.operands[i].isvec = 1;
-              inst.operands[i].issingle = 1;
-              inst.operands[i].vectype = optype;
-              inst.operands[i].present = 1;
-            }
-        }
+       {
+         /* Case 7: VMOV<c><q> <Rd>, <Rn>, <Dm>  */
+         inst.operands[i].reg = val;
+         inst.operands[i].isreg = 1;
+         inst.operands[i++].present = 1;
+
+         if (skip_past_comma (&ptr) == FAIL)
+           goto wanted_comma;
+
+         if ((val = arm_typed_reg_parse (&ptr, REG_TYPE_VFSD, &rtype, &optype))
+             == FAIL)
+           {
+             first_error (_(reg_expected_msgs[REG_TYPE_VFSD]));
+             return FAIL;
+           }
+
+         inst.operands[i].reg = val;
+         inst.operands[i].isreg = 1;
+         inst.operands[i].isvec = 1;
+         inst.operands[i].issingle = (rtype == REG_TYPE_VFS);
+         inst.operands[i].vectype = optype;
+         inst.operands[i].present = 1;
+
+         if (rtype == REG_TYPE_VFS)
+           {
+             /* Case 14.  */
+             i++;
+             if (skip_past_comma (&ptr) == FAIL)
+               goto wanted_comma;
+             if ((val = arm_typed_reg_parse (&ptr, REG_TYPE_VFS, NULL,
+                                             &optype)) == FAIL)
+               {
+                 first_error (_(reg_expected_msgs[REG_TYPE_VFS]));
+                 return FAIL;
+               }
+             inst.operands[i].reg = val;
+             inst.operands[i].isreg = 1;
+             inst.operands[i].isvec = 1;
+             inst.operands[i].issingle = 1;
+             inst.operands[i].vectype = optype;
+             inst.operands[i].present = 1;
+           }
+       }
       else if ((val = arm_typed_reg_parse (&ptr, REG_TYPE_VFS, NULL, &optype))
-               != FAIL)
-        {
-          /* Case 13.  */
-          inst.operands[i].reg = val;
-          inst.operands[i].isreg = 1;
-          inst.operands[i].isvec = 1;
-          inst.operands[i].issingle = 1;
-          inst.operands[i].vectype = optype;
-          inst.operands[i++].present = 1;
-        }
+              != FAIL)
+       {
+         /* Case 13.  */
+         inst.operands[i].reg = val;
+         inst.operands[i].isreg = 1;
+         inst.operands[i].isvec = 1;
+         inst.operands[i].issingle = 1;
+         inst.operands[i].vectype = optype;
+         inst.operands[i].present = 1;
+       }
     }
   else
     {
@@ -5978,7 +6439,7 @@ enum operand_parse_code
   OP_RRnpc,    /* ARM register, not r15 */
   OP_RRnpcsp,  /* ARM register, neither r15 nor r13 (a.k.a. 'BadReg') */
   OP_RRnpcb,   /* ARM register, not r15, in square brackets */
-  OP_RRnpctw,  /* ARM register, not r15 in Thumb-state or with writeback, 
+  OP_RRnpctw,  /* ARM register, not r15 in Thumb-state or with writeback,
                   optional trailing ! */
   OP_RRw,      /* ARM register, not r15, optional trailing ! */
   OP_RCP,      /* Coprocessor number */
@@ -6013,6 +6474,7 @@ enum operand_parse_code
 
   OP_RNDQ_I0,   /* Neon D or Q reg, or immediate zero.  */
   OP_RVSD_I0,  /* VFP S or D reg, or immediate zero.  */
+  OP_RSVD_FI0, /* VFP S or D reg, or floating point immediate zero.  */
   OP_RR_RNSC,   /* ARM reg or Neon scalar.  */
   OP_RNSDQ_RNSC, /* Vector S, D or Q reg, or Neon scalar.  */
   OP_RNDQ_RNSC, /* Neon D or Q reg, or Neon scalar.  */
@@ -6073,6 +6535,7 @@ enum operand_parse_code
   OP_oI7b,      /* immediate, prefix optional, 0 .. 7 */
   OP_oI31b,     /*                             0 .. 31 */
   OP_oI32b,      /*                             1 .. 32 */
+  OP_oI32z,      /*                             0 .. 32 */
   OP_oIffffb,   /*                             0 .. 65535 */
   OP_oI255c,    /*       curly-brace enclosed, 0 .. 255 */
 
@@ -6108,7 +6571,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
   unsigned const int *upat = pattern;
   char *backtrack_pos = 0;
   const char *backtrack_error = 0;
-  int i, val, backtrack_index = 0;
+  int i, val = 0, backtrack_index = 0;
   enum arm_reg_type rtype;
   parse_operand_result result;
   unsigned int op_parse_code;
@@ -6117,7 +6580,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
   do                                           \
     {                                          \
       if (skip_past_char (&str, chr) == FAIL)  \
-        goto bad_args;                         \
+       goto bad_args;                          \
     }                                          \
   while (0)
 
@@ -6125,19 +6588,19 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
   do                                                           \
     {                                                          \
       val = arm_typed_reg_parse (& str, regtype, & rtype,      \
-                                & inst.operands[i].vectype);   \
+                                & inst.operands[i].vectype);   \
       if (val == FAIL)                                         \
-        {                                                      \
-          first_error (_(reg_expected_msgs[regtype]));         \
-          goto failure;                                                \
-        }                                                      \
+                                                             \
+         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);                \
       inst.operands[i].issingle = (rtype == REG_TYPE_VFS);     \
       inst.operands[i].isvec = (rtype == REG_TYPE_VFS          \
-                             || rtype == REG_TYPE_VFD          \
-                             || rtype == REG_TYPE_NQ);         \
+                            || rtype == REG_TYPE_VFD           \
+                            || rtype == REG_TYPE_NQ);          \
     }                                                          \
   while (0)
 
@@ -6154,7 +6617,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
       inst.operands[i].isquad = (rtype == REG_TYPE_NQ);                \
       inst.operands[i].issingle = (rtype == REG_TYPE_VFS);     \
       inst.operands[i].isvec = (rtype == REG_TYPE_VFS          \
-                             || rtype == REG_TYPE_VFD          \
+                            || rtype == REG_TYPE_VFD           \
                             || rtype == REG_TYPE_NQ);          \
     }                                                          \
   while (0)
@@ -6202,22 +6665,16 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
   do                                                      \
     {                                                     \
       val = parse_barrier (&str);                         \
-      if (val == FAIL)                                    \
+      if (val == FAIL && ! ISALPHA (*str))                \
+       goto immediate;                                    \
+      if (val == FAIL                                     \
+         /* ISB can only take SY as an option.  */        \
+         || ((inst.instruction & 0xf0) == 0x60            \
+              && val != 0xf))                             \
        {                                                  \
-         if (ISALPHA (*str))                              \
-             goto failure;                                \
-         else                                             \
-             goto immediate;                              \
-       }                                                  \
-      else                                                \
-       {                                                  \
-         if ((inst.instruction & 0xf0) == 0x60            \
-             && val != 0xf)                               \
-           {                                              \
-              /* ISB can only take SY as an option.  */   \
-              inst.error = _("invalid barrier type");     \
-              goto failure;                               \
-           }                                              \
+          inst.error = _("invalid barrier type");         \
+          backtrack_pos = 0;                              \
+          goto failure;                                   \
        }                                                  \
     }                                                     \
   while (0)
@@ -6257,7 +6714,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
        case OP_RF:    po_reg_or_fail (REG_TYPE_FN);      break;
        case OP_RVS:   po_reg_or_fail (REG_TYPE_VFS);     break;
        case OP_RVD:   po_reg_or_fail (REG_TYPE_VFD);     break;
-        case OP_oRND:
+       case OP_oRND:
        case OP_RND:   po_reg_or_fail (REG_TYPE_VFD);     break;
        case OP_RVC:
          po_reg_or_goto (REG_TYPE_VFC, coproc_reg);
@@ -6276,96 +6733,113 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
        case OP_RIWC:  po_reg_or_fail (REG_TYPE_MMXWC);   break;
        case OP_RIWG:  po_reg_or_fail (REG_TYPE_MMXWCG);  break;
        case OP_RXA:   po_reg_or_fail (REG_TYPE_XSCALE);  break;
-        case OP_oRNQ:
+       case OP_oRNQ:
        case OP_RNQ:   po_reg_or_fail (REG_TYPE_NQ);      break;
-        case OP_oRNDQ:
+       case OP_oRNDQ:
        case OP_RNDQ:  po_reg_or_fail (REG_TYPE_NDQ);     break;
-        case OP_RVSD:  po_reg_or_fail (REG_TYPE_VFSD);    break;
-        case OP_oRNSDQ:
-        case OP_RNSDQ: po_reg_or_fail (REG_TYPE_NSDQ);    break;
-
-        /* Neon scalar. Using an element size of 8 means that some invalid
-           scalars are accepted here, so deal with those in later code.  */
-        case OP_RNSC:  po_scalar_or_goto (8, failure);    break;
-
-        case OP_RNDQ_I0:
-          {
-            po_reg_or_goto (REG_TYPE_NDQ, try_imm0);
-            break;
-            try_imm0:
-            po_imm_or_fail (0, 0, TRUE);
-          }
-          break;
-
-        case OP_RVSD_I0:
-          po_reg_or_goto (REG_TYPE_VFSD, try_imm0);
-          break;
-
-        case OP_RR_RNSC:
-          {
-            po_scalar_or_goto (8, try_rr);
-            break;
-            try_rr:
-            po_reg_or_fail (REG_TYPE_RN);
-          }
-          break;
-
-        case OP_RNSDQ_RNSC:
-          {
-            po_scalar_or_goto (8, try_nsdq);
-            break;
-            try_nsdq:
-            po_reg_or_fail (REG_TYPE_NSDQ);
-          }
-          break;
-
-        case OP_RNDQ_RNSC:
-          {
-            po_scalar_or_goto (8, try_ndq);
-            break;
-            try_ndq:
-            po_reg_or_fail (REG_TYPE_NDQ);
-          }
-          break;
-
-        case OP_RND_RNSC:
-          {
-            po_scalar_or_goto (8, try_vfd);
-            break;
-            try_vfd:
-            po_reg_or_fail (REG_TYPE_VFD);
-          }
-          break;
-
-        case OP_VMOV:
-          /* WARNING: parse_neon_mov can move the operand counter, i. If we're
-             not careful then bad things might happen.  */
-          po_misc_or_fail (parse_neon_mov (&str, &i) == FAIL);
-          break;
-
-        case OP_RNDQ_Ibig:
-          {
-            po_reg_or_goto (REG_TYPE_NDQ, try_immbig);
-            break;
-            try_immbig:
-            /* There's a possibility of getting a 64-bit immediate here, so
-               we need special handling.  */
-            if (parse_big_immediate (&str, i) == FAIL)
-              {
-                inst.error = _("immediate value is out of range");
-                goto failure;
-              }
-          }
-          break;
-
-        case OP_RNDQ_I63b:
-          {
-            po_reg_or_goto (REG_TYPE_NDQ, try_shimm);
-            break;
-            try_shimm:
-            po_imm_or_fail (0, 63, TRUE);
-          }
-          break;
+       case OP_RVSD:  po_reg_or_fail (REG_TYPE_VFSD);    break;
+       case OP_oRNSDQ:
+       case OP_RNSDQ: po_reg_or_fail (REG_TYPE_NSDQ);    break;
+
+       /* Neon scalar. Using an element size of 8 means that some invalid
+          scalars are accepted here, so deal with those in later code.  */
+       case OP_RNSC:  po_scalar_or_goto (8, failure);    break;
+
+       case OP_RNDQ_I0:
+         {
+           po_reg_or_goto (REG_TYPE_NDQ, try_imm0);
+           break;
+           try_imm0:
+           po_imm_or_fail (0, 0, TRUE);
+         }
+         break;
+
+       case OP_RVSD_I0:
+         po_reg_or_goto (REG_TYPE_VFSD, try_imm0);
+         break;
+
+       case OP_RSVD_FI0:
+         {
+           po_reg_or_goto (REG_TYPE_VFSD, try_ifimm0);
+           break;
+           try_ifimm0:
+           if (parse_ifimm_zero (&str))
+             inst.operands[i].imm = 0;
+           else
+           {
+             inst.error
+               = _("only floating point zero is allowed as immediate value");
+             goto failure;
+           }
+         }
+         break;
+
+       case OP_RR_RNSC:
+         {
+           po_scalar_or_goto (8, try_rr);
+           break;
+           try_rr:
+           po_reg_or_fail (REG_TYPE_RN);
+         }
+         break;
+
+       case OP_RNSDQ_RNSC:
+         {
+           po_scalar_or_goto (8, try_nsdq);
+           break;
+           try_nsdq:
+           po_reg_or_fail (REG_TYPE_NSDQ);
+         }
+         break;
+
+       case OP_RNDQ_RNSC:
+         {
+           po_scalar_or_goto (8, try_ndq);
+           break;
+           try_ndq:
+           po_reg_or_fail (REG_TYPE_NDQ);
+         }
+         break;
+
+       case OP_RND_RNSC:
+         {
+           po_scalar_or_goto (8, try_vfd);
+           break;
+           try_vfd:
+           po_reg_or_fail (REG_TYPE_VFD);
+         }
+         break;
+
+       case OP_VMOV:
+         /* WARNING: parse_neon_mov can move the operand counter, i. If we're
+            not careful then bad things might happen.  */
+         po_misc_or_fail (parse_neon_mov (&str, &i) == FAIL);
+         break;
+
+       case OP_RNDQ_Ibig:
+         {
+           po_reg_or_goto (REG_TYPE_NDQ, try_immbig);
+           break;
+           try_immbig:
+           /* There's a possibility of getting a 64-bit immediate here, so
+              we need special handling.  */
+           if (parse_big_immediate (&str, i, NULL, /*allow_symbol_p=*/FALSE)
+               == FAIL)
+             {
+               inst.error = _("immediate value is out of range");
+               goto failure;
+             }
+         }
+         break;
+
+       case OP_RNDQ_I63b:
+         {
+           po_reg_or_goto (REG_TYPE_NDQ, try_shimm);
+           break;
+           try_shimm:
+           po_imm_or_fail (0, 63, TRUE);
+         }
+         break;
 
        case OP_RRnpcb:
          po_char_or_fail ('[');
@@ -6385,14 +6859,14 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
        case OP_I7:      po_imm_or_fail (  0,      7, FALSE);   break;
        case OP_I15:     po_imm_or_fail (  0,     15, FALSE);   break;
        case OP_I16:     po_imm_or_fail (  1,     16, FALSE);   break;
-        case OP_I16z:   po_imm_or_fail (  0,     16, FALSE);   break;
+       case OP_I16z:    po_imm_or_fail (  0,     16, FALSE);   break;
        case OP_I31:     po_imm_or_fail (  0,     31, FALSE);   break;
        case OP_I32:     po_imm_or_fail (  1,     32, FALSE);   break;
-        case OP_I32z:   po_imm_or_fail (  0,     32, FALSE);   break;
+       case OP_I32z:    po_imm_or_fail (  0,     32, FALSE);   break;
        case OP_I63s:    po_imm_or_fail (-64,     63, FALSE);   break;
-        case OP_I63:    po_imm_or_fail (  0,     63, FALSE);   break;
-        case OP_I64:    po_imm_or_fail (  1,     64, FALSE);   break;
-        case OP_I64z:   po_imm_or_fail (  0,     64, FALSE);   break;
+       case OP_I63:     po_imm_or_fail (  0,     63, FALSE);   break;
+       case OP_I64:     po_imm_or_fail (  1,     64, FALSE);   break;
+       case OP_I64z:    po_imm_or_fail (  0,     64, FALSE);   break;
        case OP_I255:    po_imm_or_fail (  0,    255, FALSE);   break;
 
        case OP_I4b:     po_imm_or_fail (  1,      4, TRUE);    break;
@@ -6401,7 +6875,8 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
        case OP_I15b:    po_imm_or_fail (  0,     15, TRUE);    break;
        case OP_oI31b:
        case OP_I31b:    po_imm_or_fail (  0,     31, TRUE);    break;
-        case OP_oI32b:   po_imm_or_fail (  1,     32, TRUE);    break;
+       case OP_oI32b:   po_imm_or_fail (  1,     32, TRUE);    break;
+       case OP_oI32z:   po_imm_or_fail (  0,     32, TRUE);    break;
        case OP_oIffffb: po_imm_or_fail (  0, 0xffff, TRUE);    break;
 
          /* Immediate variants */
@@ -6530,10 +7005,10 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
          po_barrier_or_imm (str); break;
          immediate:
          if (parse_immediate (&str, &val, 0, 15, TRUE) == FAIL)
-            goto failure;
+           goto failure;
          break;
 
-       case OP_wPSR:    
+       case OP_wPSR:
        case OP_rPSR:
          po_reg_or_goto (REG_TYPE_RNB, try_psr);
          if (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_virt))
@@ -6547,35 +7022,35 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
          val = parse_psr (&str, op_parse_code == OP_wPSR);
          break;
 
-        case OP_APSR_RR:
-          po_reg_or_goto (REG_TYPE_RN, try_apsr);
-          break;
-          try_apsr:
-          /* Parse "APSR_nvzc" operand (for FMSTAT-equivalent MRS
-             instruction).  */
-          if (strncasecmp (str, "APSR_", 5) == 0)
-            {
-              unsigned found = 0;
-              str += 5;
-              while (found < 15)
-                switch (*str++)
-                  {
-                  case 'c': found = (found & 1) ? 16 : found | 1; break;
-                  case 'n': found = (found & 2) ? 16 : found | 2; break;
-                  case 'z': found = (found & 4) ? 16 : found | 4; break;
-                  case 'v': found = (found & 8) ? 16 : found | 8; break;
-                  default: found = 16;
-                  }
-              if (found != 15)
-                goto failure;
-              inst.operands[i].isvec = 1;
+       case OP_APSR_RR:
+         po_reg_or_goto (REG_TYPE_RN, try_apsr);
+         break;
+         try_apsr:
+         /* Parse "APSR_nvzc" operand (for FMSTAT-equivalent MRS
+            instruction).  */
+         if (strncasecmp (str, "APSR_", 5) == 0)
+           {
+             unsigned found = 0;
+             str += 5;
+             while (found < 15)
+               switch (*str++)
+                 {
+                 case 'c': found = (found & 1) ? 16 : found | 1; break;
+                 case 'n': found = (found & 2) ? 16 : found | 2; break;
+                 case 'z': found = (found & 4) ? 16 : found | 4; break;
+                 case 'v': found = (found & 8) ? 16 : found | 8; break;
+                 default: found = 16;
+                 }
+             if (found != 15)
+               goto failure;
+             inst.operands[i].isvec = 1;
              /* APSR_nzcv is encoded in instructions as if it were the REG_PC.  */
              inst.operands[i].reg = REG_PC;
-            }
-          else
-            goto failure;
-          break;
-
+           }
+         else
+           goto failure;
+         break;
+
        case OP_TB:
          po_misc_or_fail (parse_tb (&str));
          break;
@@ -6585,7 +7060,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
          val = parse_reg_list (&str);
          if (*str == '^')
            {
-             inst.operands[1].writeback = 1;
+             inst.operands[i].writeback = 1;
              str++;
            }
          break;
@@ -6598,28 +7073,28 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
          val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_D);
          break;
 
-        case OP_VRSDLST:
-          /* Allow Q registers too.  */
-          val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
-                                    REGLIST_NEON_D);
-          if (val == FAIL)
-            {
-              inst.error = NULL;
-              val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
-                                        REGLIST_VFP_S);
-              inst.operands[i].issingle = 1;
-            }
-          break;
-
-        case OP_NRDLST:
-          val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
-                                    REGLIST_NEON_D);
-          break;
+       case OP_VRSDLST:
+         /* Allow Q registers too.  */
+         val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
+                                   REGLIST_NEON_D);
+         if (val == FAIL)
+           {
+             inst.error = NULL;
+             val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
+                                       REGLIST_VFP_S);
+             inst.operands[i].issingle = 1;
+           }
+         break;
+
+       case OP_NRDLST:
+         val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
+                                   REGLIST_NEON_D);
+         break;
 
        case OP_NSTRLST:
-          val = parse_neon_el_struct_list (&str, &inst.operands[i].reg,
-                                           &inst.operands[i].vectype);
-          break;
+         val = parse_neon_el_struct_list (&str, &inst.operands[i].reg,
+                                          &inst.operands[i].vectype);
+         break;
 
          /* Addressing modes */
        case OP_ADDR:
@@ -6628,17 +7103,17 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
 
        case OP_ADDRGLDR:
          po_misc_or_fail_no_backtrack (
-            parse_address_group_reloc (&str, i, GROUP_LDR));
+           parse_address_group_reloc (&str, i, GROUP_LDR));
          break;
 
        case OP_ADDRGLDRS:
          po_misc_or_fail_no_backtrack (
-            parse_address_group_reloc (&str, i, GROUP_LDRS));
+           parse_address_group_reloc (&str, i, GROUP_LDRS));
          break;
 
        case OP_ADDRGLDC:
          po_misc_or_fail_no_backtrack (
-            parse_address_group_reloc (&str, i, GROUP_LDC));
+           parse_address_group_reloc (&str, i, GROUP_LDC));
          break;
 
        case OP_SH:
@@ -6647,7 +7122,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
 
        case OP_SHG:
          po_misc_or_fail_no_backtrack (
-            parse_shifter_operand_group_reloc (&str, i));
+           parse_shifter_operand_group_reloc (&str, i));
          break;
 
        case OP_oSHll:
@@ -6693,8 +7168,8 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
          break;
 
        case OP_RRnpctw:
-         if (inst.operands[i].isreg 
-             && inst.operands[i].reg == REG_PC 
+         if (inst.operands[i].isreg
+             && inst.operands[i].reg == REG_PC
              && (inst.operands[i].writeback || thumb))
            inst.error = BAD_PC;
          break;
@@ -6709,9 +7184,9 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
        case OP_REGLST:
        case OP_VRSLST:
        case OP_VRDLST:
-        case OP_VRSDLST:
-        case OP_NRDLST:
-        case OP_NSTRLST:
+       case OP_VRSDLST:
+       case OP_NRDLST:
+       case OP_NSTRLST:
          if (val == FAIL)
            goto failure;
          inst.operands[i].imm = val;
@@ -6801,12 +7276,32 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
 #define warn_deprecated_sp(reg)                        \
   do                                           \
     if (warn_on_deprecated && reg == REG_SP)   \
-       as_warn (_("use of r13 is deprecated"));        \
+       as_tsktsk (_("use of r13 is deprecated"));      \
   while (0)
 
 /* Functions for operand encoding.  ARM, then Thumb.  */
 
-#define rotate_left(v, n) (v << n | v >> (32 - n))
+#define rotate_left(v, n) (v << (n & 31) | v >> ((32 - n) & 31))
+
+/* If the current inst is scalar ARMv8.2 fp16 instruction, do special encoding.
+
+   The only binary encoding difference is the Coprocessor number.  Coprocessor
+   9 is used for half-precision calculations or conversions.  The format of the
+   instruction is the same as the equivalent Coprocessor 10 instuction that
+   exists for Single-Precision operation.  */
+
+static void
+do_scalar_fp16_v82_encode (void)
+{
+  if (inst.cond != COND_ALWAYS)
+    as_warn (_("ARMv8.2 scalar fp16 instruction cannot be conditional,"
+              " the behaviour is UNPREDICTABLE"));
+  constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_fp16),
+             _(BAD_FP16));
+
+  inst.instruction = (inst.instruction & 0xfffff0ff) | 0x900;
+  mark_feature_used (&arm_ext_fp16);
+}
 
 /* If VAL can be encoded in the immediate field of an ARM instruction,
    return the encoded form.  Otherwise, return FAIL.  */
@@ -6816,7 +7311,10 @@ encode_arm_immediate (unsigned int val)
 {
   unsigned int a, i;
 
-  for (i = 0; i < 32; i += 2)
+  if (val <= 0xff)
+    return val;
+
+  for (i = 2; i < 32; i += 2)
     if ((a = rotate_left (val, i)) <= 0xff)
       return a | (i << 7); /* 12-bit pack: [shift-cnt,const].  */
 
@@ -6861,19 +7359,19 @@ encode_arm_vfp_reg (int reg, enum vfp_reg_pos pos)
       && reg > 15)
     {
       if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_d32))
-        {
-          if (thumb_mode)
-            ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
-                                    fpu_vfp_ext_d32);
-          else
-            ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used,
-                                    fpu_vfp_ext_d32);
-        }
+       {
+         if (thumb_mode)
+           ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
+                                   fpu_vfp_ext_d32);
+         else
+           ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used,
+                                   fpu_vfp_ext_d32);
+       }
       else
-        {
-          first_error (_("D register out of range for selected VFP version"));
-          return;
-        }
+       {
+         first_error (_("D register out of range for selected VFP version"));
+         return;
+       }
     }
 
   switch (pos)
@@ -6936,14 +7434,22 @@ encode_arm_shifter_operand (int i)
       encode_arm_shift (i);
     }
   else
-    inst.instruction |= INST_IMMEDIATE;
+    {
+      inst.instruction |= INST_IMMEDIATE;
+      if (inst.reloc.type != BFD_RELOC_ARM_IMMEDIATE)
+       inst.instruction |= inst.operands[i].imm;
+    }
 }
 
 /* Subroutine of encode_arm_addr_mode_2 and encode_arm_addr_mode_3.  */
 static void
 encode_arm_addr_mode_common (int i, bfd_boolean is_t)
 {
-  gas_assert (inst.operands[i].isreg);
+  /* PR 14260:
+     Generate an error if the operand is not a register.  */
+  constraint (!inst.operands[i].isreg,
+             _("Instruction does not support =N addresses"));
+
   inst.instruction |= inst.operands[i].reg << 16;
 
   if (inst.operands[i].preind)
@@ -7025,11 +7531,16 @@ encode_arm_addr_mode_2 (int i, bfd_boolean is_t)
          if (warn_on_deprecated
              && !is_load
              && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v7))
-           as_warn (_("use of PC in this instruction is deprecated"));
+           as_tsktsk (_("use of PC in this instruction is deprecated"));
        }
 
       if (inst.reloc.type == BFD_RELOC_UNUSED)
-       inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM;
+       {
+         /* Prefer + for zero encoded value.  */
+         if (!inst.operands[i].negative)
+           inst.instruction |= INDEX_UP;
+         inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM;
+       }
     }
 }
 
@@ -7052,8 +7563,10 @@ encode_arm_addr_mode_3 (int i, bfd_boolean is_t)
   if (inst.operands[i].immisreg)
     {
       constraint ((inst.operands[i].imm == REG_PC
-                  || inst.operands[i].reg == REG_PC),
+                  || (is_t && inst.operands[i].reg == REG_PC)),
                  BAD_PC_ADDRESSING);
+      constraint (inst.operands[i].reg == REG_PC && inst.operands[i].writeback,
+                 BAD_PC_WRITEBACK);
       inst.instruction |= inst.operands[i].imm;
       if (!inst.operands[i].negative)
        inst.instruction |= INDEX_UP;
@@ -7065,8328 +7578,9807 @@ encode_arm_addr_mode_3 (int i, bfd_boolean is_t)
                  BAD_PC_WRITEBACK);
       inst.instruction |= HWOFFSET_IMM;
       if (inst.reloc.type == BFD_RELOC_UNUSED)
-       inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8;
+       {
+         /* Prefer + for zero encoded value.  */
+         if (!inst.operands[i].negative)
+           inst.instruction |= INDEX_UP;
+
+         inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8;
+       }
     }
 }
 
-/* inst.operands[i] was set up by parse_address.  Encode it into an
-   ARM-format instruction.  Reject all forms which cannot be encoded
-   into a coprocessor load/store instruction.  If wb_ok is false,
-   reject use of writeback; if unind_ok is false, reject use of
-   unindexed addressing.  If reloc_override is not 0, use it instead
-   of BFD_ARM_CP_OFF_IMM, unless the initial relocation is a group one
-   (in which case it is preserved).  */
+/* Write immediate bits [7:0] to the following locations:
 
-static int
-encode_arm_cp_address (int i, int wb_ok, int unind_ok, int reloc_override)
-{
-  inst.instruction |= inst.operands[i].reg << 16;
+  |28/24|23     19|18 16|15                    4|3     0|
+  |  a  |x x x x x|b c d|x x x x x x x x x x x x|e f g h|
 
-  gas_assert (!(inst.operands[i].preind && inst.operands[i].postind));
+  This function is used by VMOV/VMVN/VORR/VBIC.  */
 
-  if (!inst.operands[i].preind && !inst.operands[i].postind) /* unindexed */
-    {
-      gas_assert (!inst.operands[i].writeback);
-      if (!unind_ok)
-       {
-         inst.error = _("instruction does not support unindexed addressing");
-         return FAIL;
-       }
-      inst.instruction |= inst.operands[i].imm;
-      inst.instruction |= INDEX_UP;
-      return SUCCESS;
-    }
+static void
+neon_write_immbits (unsigned immbits)
+{
+  inst.instruction |= immbits & 0xf;
+  inst.instruction |= ((immbits >> 4) & 0x7) << 16;
+  inst.instruction |= ((immbits >> 7) & 0x1) << (thumb_mode ? 28 : 24);
+}
 
-  if (inst.operands[i].preind)
-    inst.instruction |= PRE_INDEX;
+/* Invert low-order SIZE bits of XHI:XLO.  */
 
-  if (inst.operands[i].writeback)
-    {
-      if (inst.operands[i].reg == REG_PC)
-       {
-         inst.error = _("pc may not be used with write-back");
-         return FAIL;
-       }
-      if (!wb_ok)
-       {
-         inst.error = _("instruction does not support writeback");
-         return FAIL;
-       }
-      inst.instruction |= WRITE_BACK;
-    }
+static void
+neon_invert_size (unsigned *xlo, unsigned *xhi, int size)
+{
+  unsigned immlo = xlo ? *xlo : 0;
+  unsigned immhi = xhi ? *xhi : 0;
 
-  if (reloc_override)
-    inst.reloc.type = (bfd_reloc_code_real_type) reloc_override;
-  else if ((inst.reloc.type < BFD_RELOC_ARM_ALU_PC_G0_NC
-            || inst.reloc.type > BFD_RELOC_ARM_LDC_SB_G2)
-           && inst.reloc.type != BFD_RELOC_ARM_LDR_PC_G0)
+  switch (size)
     {
-      if (thumb_mode)
-        inst.reloc.type = BFD_RELOC_ARM_T32_CP_OFF_IMM;
-      else
-        inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM;
-    }
-
-  return SUCCESS;
-}
-
-/* inst.reloc.exp describes an "=expr" load pseudo-operation.
-   Determine whether it can be performed with a move instruction; if
-   it can, convert inst.instruction to that move instruction and
-   return TRUE; if it can't, convert inst.instruction to a literal-pool
-   load and return FALSE.  If this is not a valid thing to do in the
-   current context, set inst.error and return TRUE.
+    case 8:
+      immlo = (~immlo) & 0xff;
+      break;
 
-   inst.operands[i] describes the destination register.         */
+    case 16:
+      immlo = (~immlo) & 0xffff;
+      break;
 
-static bfd_boolean
-move_or_literal_pool (int i, bfd_boolean thumb_p, bfd_boolean mode_3)
-{
-  unsigned long tbit;
+    case 64:
+      immhi = (~immhi) & 0xffffffff;
+      /* fall through.  */
 
-  if (thumb_p)
-    tbit = (inst.instruction > 0xffff) ? THUMB2_LOAD_BIT : THUMB_LOAD_BIT;
-  else
-    tbit = LOAD_BIT;
+    case 32:
+      immlo = (~immlo) & 0xffffffff;
+      break;
 
-  if ((inst.instruction & tbit) == 0)
-    {
-      inst.error = _("invalid pseudo operation");
-      return TRUE;
-    }
-  if (inst.reloc.exp.X_op != O_constant && inst.reloc.exp.X_op != O_symbol)
-    {
-      inst.error = _("constant expression expected");
-      return TRUE;
+    default:
+      abort ();
     }
-  if (inst.reloc.exp.X_op == O_constant)
-    {
-      if (thumb_p)
-       {
-         if (!unified_syntax && (inst.reloc.exp.X_add_number & ~0xFF) == 0)
-           {
-             /* This can be done with a mov(1) instruction.  */
-             inst.instruction  = T_OPCODE_MOV_I8 | (inst.operands[i].reg << 8);
-             inst.instruction |= inst.reloc.exp.X_add_number;
-             return TRUE;
-           }
-       }
-      else
-       {
-         int value = encode_arm_immediate (inst.reloc.exp.X_add_number);
-         if (value != FAIL)
-           {
-             /* This can be done with a mov instruction.  */
-             inst.instruction &= LITERAL_MASK;
-             inst.instruction |= INST_IMMEDIATE | (OPCODE_MOV << DATA_OP_SHIFT);
-             inst.instruction |= value & 0xfff;
-             return TRUE;
-           }
 
-         value = encode_arm_immediate (~inst.reloc.exp.X_add_number);
-         if (value != FAIL)
-           {
-             /* This can be done with a mvn instruction.  */
-             inst.instruction &= LITERAL_MASK;
-             inst.instruction |= INST_IMMEDIATE | (OPCODE_MVN << DATA_OP_SHIFT);
-             inst.instruction |= value & 0xfff;
-             return TRUE;
-           }
-       }
-    }
+  if (xlo)
+    *xlo = immlo;
 
-  if (add_to_lit_pool () == FAIL)
-    {
-      inst.error = _("literal pool insertion failed");
-      return TRUE;
-    }
-  inst.operands[1].reg = REG_PC;
-  inst.operands[1].isreg = 1;
-  inst.operands[1].preind = 1;
-  inst.reloc.pc_rel = 1;
-  inst.reloc.type = (thumb_p
-                    ? BFD_RELOC_ARM_THUMB_OFFSET
-                    : (mode_3
-                       ? BFD_RELOC_ARM_HWLITERAL
-                       : BFD_RELOC_ARM_LITERAL));
-  return FALSE;
+  if (xhi)
+    *xhi = immhi;
 }
 
-/* Functions for instruction encoding, sorted by sub-architecture.
-   First some generics; their names are taken from the conventional
-   bit positions for register arguments in ARM format instructions.  */
+/* True if IMM has form 0bAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD for bits
+   A, B, C, D.  */
 
-static void
-do_noargs (void)
+static int
+neon_bits_same_in_bytes (unsigned imm)
 {
+  return ((imm & 0x000000ff) == 0 || (imm & 0x000000ff) == 0x000000ff)
+        && ((imm & 0x0000ff00) == 0 || (imm & 0x0000ff00) == 0x0000ff00)
+        && ((imm & 0x00ff0000) == 0 || (imm & 0x00ff0000) == 0x00ff0000)
+        && ((imm & 0xff000000) == 0 || (imm & 0xff000000) == 0xff000000);
 }
 
-static void
-do_rd (void)
-{
-  inst.instruction |= inst.operands[0].reg << 12;
-}
+/* For immediate of above form, return 0bABCD.  */
 
-static void
-do_rd_rm (void)
+static unsigned
+neon_squash_bits (unsigned imm)
 {
-  inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= inst.operands[1].reg;
+  return (imm & 0x01) | ((imm & 0x0100) >> 7) | ((imm & 0x010000) >> 14)
+        | ((imm & 0x01000000) >> 21);
 }
 
-static void
-do_rd_rn (void)
-{
-  inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= inst.operands[1].reg << 16;
-}
+/* Compress quarter-float representation to 0b...000 abcdefgh.  */
 
-static void
-do_rn_rd (void)
+static unsigned
+neon_qfloat_bits (unsigned imm)
 {
-  inst.instruction |= inst.operands[0].reg << 16;
-  inst.instruction |= inst.operands[1].reg << 12;
+  return ((imm >> 19) & 0x7f) | ((imm >> 24) & 0x80);
 }
 
-static void
-do_rd_rm_rn (void)
-{
-  unsigned Rn = inst.operands[2].reg;
-  /* Enforce restrictions on SWP instruction.  */
-  if ((inst.instruction & 0x0fbfffff) == 0x01000090)
-    {
-      constraint (Rn == inst.operands[0].reg || Rn == inst.operands[1].reg,
-                 _("Rn must not overlap other operands"));
+/* Returns CMODE. IMMBITS [7:0] is set to bits suitable for inserting into
+   the instruction. *OP is passed as the initial value of the op field, and
+   may be set to a different value depending on the constant (i.e.
+   "MOV I64, 0bAAAAAAAABBBB..." which uses OP = 1 despite being MOV not
+   MVN).  If the immediate looks like a repeated pattern then also
+   try smaller element sizes.  */
 
-      /* SWP{b} is deprecated for ARMv6* and ARMv7.  */
-      if (warn_on_deprecated
-         && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6))
-       as_warn (_("swp{b} use is deprecated for this architecture"));
+static int
+neon_cmode_for_move_imm (unsigned immlo, unsigned immhi, int float_p,
+                        unsigned *immbits, int *op, int size,
+                        enum neon_el_type type)
+{
+  /* Only permit float immediates (including 0.0/-0.0) if the operand type is
+     float.  */
+  if (type == NT_float && !float_p)
+    return FAIL;
 
+  if (type == NT_float && is_quarter_float (immlo) && immhi == 0)
+    {
+      if (size != 32 || *op == 1)
+       return FAIL;
+      *immbits = neon_qfloat_bits (immlo);
+      return 0xf;
     }
-  inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= inst.operands[1].reg;
-  inst.instruction |= Rn << 16;
-}
 
-static void
-do_rd_rn_rm (void)
-{
-  inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= inst.operands[1].reg << 16;
-  inst.instruction |= inst.operands[2].reg;
-}
+  if (size == 64)
+    {
+      if (neon_bits_same_in_bytes (immhi)
+         && neon_bits_same_in_bytes (immlo))
+       {
+         if (*op == 1)
+           return FAIL;
+         *immbits = (neon_squash_bits (immhi) << 4)
+                    | neon_squash_bits (immlo);
+         *op = 1;
+         return 0xe;
+       }
 
-static void
-do_rm_rd_rn (void)
-{
-  constraint ((inst.operands[2].reg == REG_PC), BAD_PC);
-  constraint (((inst.reloc.exp.X_op != O_constant
-               && inst.reloc.exp.X_op != O_illegal)
-              || inst.reloc.exp.X_add_number != 0),
-             BAD_ADDR_MODE);
-  inst.instruction |= inst.operands[0].reg;
-  inst.instruction |= inst.operands[1].reg << 12;
-  inst.instruction |= inst.operands[2].reg << 16;
-}
+      if (immhi != immlo)
+       return FAIL;
+    }
 
-static void
-do_imm0 (void)
-{
-  inst.instruction |= inst.operands[0].imm;
-}
+  if (size >= 32)
+    {
+      if (immlo == (immlo & 0x000000ff))
+       {
+         *immbits = immlo;
+         return 0x0;
+       }
+      else if (immlo == (immlo & 0x0000ff00))
+       {
+         *immbits = immlo >> 8;
+         return 0x2;
+       }
+      else if (immlo == (immlo & 0x00ff0000))
+       {
+         *immbits = immlo >> 16;
+         return 0x4;
+       }
+      else if (immlo == (immlo & 0xff000000))
+       {
+         *immbits = immlo >> 24;
+         return 0x6;
+       }
+      else if (immlo == ((immlo & 0x0000ff00) | 0x000000ff))
+       {
+         *immbits = (immlo >> 8) & 0xff;
+         return 0xc;
+       }
+      else if (immlo == ((immlo & 0x00ff0000) | 0x0000ffff))
+       {
+         *immbits = (immlo >> 16) & 0xff;
+         return 0xd;
+       }
 
-static void
-do_rd_cpaddr (void)
-{
-  inst.instruction |= inst.operands[0].reg << 12;
-  encode_arm_cp_address (1, TRUE, TRUE, 0);
-}
+      if ((immlo & 0xffff) != (immlo >> 16))
+       return FAIL;
+      immlo &= 0xffff;
+    }
 
-/* ARM instructions, in alphabetical order by function name (except
-   that wrapper functions appear immediately after the function they
-   wrap).  */
+  if (size >= 16)
+    {
+      if (immlo == (immlo & 0x000000ff))
+       {
+         *immbits = immlo;
+         return 0x8;
+       }
+      else if (immlo == (immlo & 0x0000ff00))
+       {
+         *immbits = immlo >> 8;
+         return 0xa;
+       }
 
-/* This is a pseudo-op of the form "adr rd, label" to be converted
-   into a relative address of the form "add rd, pc, #label-.-8".  */
+      if ((immlo & 0xff) != (immlo >> 8))
+       return FAIL;
+      immlo &= 0xff;
+    }
 
-static void
-do_adr (void)
-{
-  inst.instruction |= (inst.operands[0].reg << 12);  /* Rd */
+  if (immlo == (immlo & 0x000000ff))
+    {
+      /* Don't allow MVN with 8-bit immediate.  */
+      if (*op == 1)
+       return FAIL;
+      *immbits = immlo;
+      return 0xe;
+    }
 
-  /* Frag hacking will turn this into a sub instruction if the offset turns
-     out to be negative.  */
-  inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
-  inst.reloc.pc_rel = 1;
-  inst.reloc.exp.X_add_number -= 8;
+  return FAIL;
 }
 
-/* This is a pseudo-op of the form "adrl rd, label" to be converted
-   into a relative address of the form:
-   add rd, pc, #low(label-.-8)"
-   add rd, rd, #high(label-.-8)"  */
+#if defined BFD_HOST_64_BIT
+/* Returns TRUE if double precision value V may be cast
+   to single precision without loss of accuracy.  */
 
-static void
-do_adrl (void)
+static bfd_boolean
+is_double_a_single (bfd_int64_t v)
 {
-  inst.instruction |= (inst.operands[0].reg << 12);  /* Rd */
+  int exp = (int)((v >> 52) & 0x7FF);
+  bfd_int64_t mantissa = (v & (bfd_int64_t)0xFFFFFFFFFFFFFULL);
 
-  /* Frag hacking will turn this into a sub instruction if the offset turns
-     out to be negative.  */
-  inst.reloc.type             = BFD_RELOC_ARM_ADRL_IMMEDIATE;
-  inst.reloc.pc_rel           = 1;
-  inst.size                   = INSN_SIZE * 2;
-  inst.reloc.exp.X_add_number -= 8;
+  return (exp == 0 || exp == 0x7FF
+         || (exp >= 1023 - 126 && exp <= 1023 + 127))
+    && (mantissa & 0x1FFFFFFFl) == 0;
 }
 
-static void
-do_arit (void)
-{
-  if (!inst.operands[1].present)
-    inst.operands[1].reg = inst.operands[0].reg;
-  inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= inst.operands[1].reg << 16;
-  encode_arm_shifter_operand (2);
-}
+/* Returns a double precision value casted to single precision
+   (ignoring the least significant bits in exponent and mantissa).  */
 
-static void
-do_barrier (void)
+static int
+double_to_single (bfd_int64_t v)
 {
-  if (inst.operands[0].present)
+  int sign = (int) ((v >> 63) & 1l);
+  int exp = (int) ((v >> 52) & 0x7FF);
+  bfd_int64_t mantissa = (v & (bfd_int64_t)0xFFFFFFFFFFFFFULL);
+
+  if (exp == 0x7FF)
+    exp = 0xFF;
+  else
     {
-      constraint ((inst.instruction & 0xf0) != 0x40
-                 && inst.operands[0].imm > 0xf
-                 && inst.operands[0].imm < 0x0,
-                 _("bad barrier type"));
-      inst.instruction |= inst.operands[0].imm;
+      exp = exp - 1023 + 127;
+      if (exp >= 0xFF)
+       {
+         /* Infinity.  */
+         exp = 0x7F;
+         mantissa = 0;
+       }
+      else if (exp < 0)
+       {
+         /* No denormalized numbers.  */
+         exp = 0;
+         mantissa = 0;
+       }
     }
-  else
-    inst.instruction |= 0xf;
+  mantissa >>= 29;
+  return (sign << 31) | (exp << 23) | mantissa;
 }
+#endif /* BFD_HOST_64_BIT */
 
-static void
-do_bfc (void)
+enum lit_type
 {
-  unsigned int msb = inst.operands[1].imm + inst.operands[2].imm;
-  constraint (msb > 32, _("bit-field extends past end of register"));
-  /* The instruction encoding stores the LSB and MSB,
-     not the LSB and width.  */
-  inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= inst.operands[1].imm << 7;
-  inst.instruction |= (msb - 1) << 16;
-}
+  CONST_THUMB,
+  CONST_ARM,
+  CONST_VEC
+};
 
-static void
-do_bfi (void)
-{
-  unsigned int msb;
+static void do_vfp_nsyn_opcode (const char *);
 
-  /* #0 in second position is alternative syntax for bfc, which is
-     the same instruction but with REG_PC in the Rm field.  */
-  if (!inst.operands[1].isreg)
-    inst.operands[1].reg = REG_PC;
+/* inst.reloc.exp describes an "=expr" load pseudo-operation.
+   Determine whether it can be performed with a move instruction; if
+   it can, convert inst.instruction to that move instruction and
+   return TRUE; if it can't, convert inst.instruction to a literal-pool
+   load and return FALSE.  If this is not a valid thing to do in the
+   current context, set inst.error and return TRUE.
 
-  msb = inst.operands[2].imm + inst.operands[3].imm;
-  constraint (msb > 32, _("bit-field extends past end of register"));
-  /* The instruction encoding stores the LSB and MSB,
-     not the LSB and width.  */
-  inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= inst.operands[1].reg;
-  inst.instruction |= inst.operands[2].imm << 7;
-  inst.instruction |= (msb - 1) << 16;
-}
+   inst.operands[i] describes the destination register.         */
 
-static void
-do_bfx (void)
+static bfd_boolean
+move_or_literal_pool (int i, enum lit_type t, bfd_boolean mode_3)
 {
-  constraint (inst.operands[2].imm + inst.operands[3].imm > 32,
-             _("bit-field extends past end of register"));
-  inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= inst.operands[1].reg;
-  inst.instruction |= inst.operands[2].imm << 7;
-  inst.instruction |= (inst.operands[3].imm - 1) << 16;
-}
-
-/* ARM V5 breakpoint instruction (argument parse)
-     BKPT <16 bit unsigned immediate>
-     Instruction is not conditional.
-       The bit pattern given in insns[] has the COND_ALWAYS condition,
-       and it is an error if the caller tried to override that.  */
+  unsigned long tbit;
+  bfd_boolean thumb_p = (t == CONST_THUMB);
+  bfd_boolean arm_p   = (t == CONST_ARM);
 
-static void
-do_bkpt (void)
-{
-  /* Top 12 of 16 bits to bits 19:8.  */
-  inst.instruction |= (inst.operands[0].imm & 0xfff0) << 4;
+  if (thumb_p)
+    tbit = (inst.instruction > 0xffff) ? THUMB2_LOAD_BIT : THUMB_LOAD_BIT;
+  else
+    tbit = LOAD_BIT;
 
-  /* Bottom 4 of 16 bits to bits 3:0.  */
-  inst.instruction |= inst.operands[0].imm & 0xf;
-}
+  if ((inst.instruction & tbit) == 0)
+    {
+      inst.error = _("invalid pseudo operation");
+      return TRUE;
+    }
 
-static void
-encode_branch (int default_reloc)
-{
-  if (inst.operands[0].hasreloc)
+  if (inst.reloc.exp.X_op != O_constant
+      && inst.reloc.exp.X_op != O_symbol
+      && inst.reloc.exp.X_op != O_big)
     {
-      constraint (inst.operands[0].imm != BFD_RELOC_ARM_PLT32
-                 && inst.operands[0].imm != BFD_RELOC_ARM_TLS_CALL,
-                 _("the only valid suffixes here are '(plt)' and '(tlscall)'"));
-      inst.reloc.type = inst.operands[0].imm == BFD_RELOC_ARM_PLT32
-       ? BFD_RELOC_ARM_PLT32
-       : thumb_mode ? BFD_RELOC_ARM_THM_TLS_CALL : BFD_RELOC_ARM_TLS_CALL;
+      inst.error = _("constant expression expected");
+      return TRUE;
     }
-  else
-    inst.reloc.type = (bfd_reloc_code_real_type) default_reloc;
-  inst.reloc.pc_rel = 1;
-}
 
-static void
-do_branch (void)
-{
-#ifdef OBJ_ELF
-  if (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4)
-    encode_branch (BFD_RELOC_ARM_PCREL_JUMP);
-  else
+  if (inst.reloc.exp.X_op == O_constant
+      || inst.reloc.exp.X_op == O_big)
+    {
+#if defined BFD_HOST_64_BIT
+      bfd_int64_t v;
+#else
+      offsetT v;
 #endif
-    encode_branch (BFD_RELOC_ARM_PCREL_BRANCH);
-}
+      if (inst.reloc.exp.X_op == O_big)
+       {
+         LITTLENUM_TYPE w[X_PRECISION];
+         LITTLENUM_TYPE * l;
 
-static void
-do_bl (void)
-{
-#ifdef OBJ_ELF
-  if (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4)
-    {
-      if (inst.cond == COND_ALWAYS)
-       encode_branch (BFD_RELOC_ARM_PCREL_CALL);
+         if (inst.reloc.exp.X_add_number == -1)
+           {
+             gen_to_words (w, X_PRECISION, E_PRECISION);
+             l = w;
+             /* FIXME: Should we check words w[2..5] ?  */
+           }
+         else
+           l = generic_bignum;
+
+#if defined BFD_HOST_64_BIT
+         v =
+           ((((((((bfd_int64_t) l[3] & LITTLENUM_MASK)
+                 << LITTLENUM_NUMBER_OF_BITS)
+                | ((bfd_int64_t) l[2] & LITTLENUM_MASK))
+               << LITTLENUM_NUMBER_OF_BITS)
+              | ((bfd_int64_t) l[1] & LITTLENUM_MASK))
+             << LITTLENUM_NUMBER_OF_BITS)
+            | ((bfd_int64_t) l[0] & LITTLENUM_MASK));
+#else
+         v = ((l[1] & LITTLENUM_MASK) << LITTLENUM_NUMBER_OF_BITS)
+           |  (l[0] & LITTLENUM_MASK);
+#endif
+       }
       else
-       encode_branch (BFD_RELOC_ARM_PCREL_JUMP);
-    }
-  else
+       v = inst.reloc.exp.X_add_number;
+
+      if (!inst.operands[i].issingle)
+       {
+         if (thumb_p)
+           {
+             /* This can be encoded only for a low register.  */
+             if ((v & ~0xFF) == 0 && (inst.operands[i].reg < 8))
+               {
+                 /* This can be done with a mov(1) instruction.  */
+                 inst.instruction = T_OPCODE_MOV_I8 | (inst.operands[i].reg << 8);
+                 inst.instruction |= v;
+                 return TRUE;
+               }
+
+             if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6t2)
+                 || ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6t2_v8m))
+               {
+                 /* Check if on thumb2 it can be done with a mov.w, mvn or
+                    movw instruction.  */
+                 unsigned int newimm;
+                 bfd_boolean isNegated;
+
+                 newimm = encode_thumb32_immediate (v);
+                 if (newimm != (unsigned int) FAIL)
+                   isNegated = FALSE;
+                 else
+                   {
+                     newimm = encode_thumb32_immediate (~v);
+                     if (newimm != (unsigned int) FAIL)
+                       isNegated = TRUE;
+                   }
+
+                 /* The number can be loaded with a mov.w or mvn
+                    instruction.  */
+                 if (newimm != (unsigned int) FAIL
+                     && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6t2))
+                   {
+                     inst.instruction = (0xf04f0000  /*  MOV.W.  */
+                                         | (inst.operands[i].reg << 8));
+                     /* Change to MOVN.  */
+                     inst.instruction |= (isNegated ? 0x200000 : 0);
+                     inst.instruction |= (newimm & 0x800) << 15;
+                     inst.instruction |= (newimm & 0x700) << 4;
+                     inst.instruction |= (newimm & 0x0ff);
+                     return TRUE;
+                   }
+                 /* The number can be loaded with a movw instruction.  */
+                 else if ((v & ~0xFFFF) == 0
+                          && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6t2_v8m))
+                   {
+                     int imm = v & 0xFFFF;
+
+                     inst.instruction = 0xf2400000;  /* MOVW.  */
+                     inst.instruction |= (inst.operands[i].reg << 8);
+                     inst.instruction |= (imm & 0xf000) << 4;
+                     inst.instruction |= (imm & 0x0800) << 15;
+                     inst.instruction |= (imm & 0x0700) << 4;
+                     inst.instruction |= (imm & 0x00ff);
+                     return TRUE;
+                   }
+               }
+           }
+         else if (arm_p)
+           {
+             int value = encode_arm_immediate (v);
+
+             if (value != FAIL)
+               {
+                 /* This can be done with a mov instruction.  */
+                 inst.instruction &= LITERAL_MASK;
+                 inst.instruction |= INST_IMMEDIATE | (OPCODE_MOV << DATA_OP_SHIFT);
+                 inst.instruction |= value & 0xfff;
+                 return TRUE;
+               }
+
+             value = encode_arm_immediate (~ v);
+             if (value != FAIL)
+               {
+                 /* This can be done with a mvn instruction.  */
+                 inst.instruction &= LITERAL_MASK;
+                 inst.instruction |= INST_IMMEDIATE | (OPCODE_MVN << DATA_OP_SHIFT);
+                 inst.instruction |= value & 0xfff;
+                 return TRUE;
+               }
+           }
+         else if (t == CONST_VEC)
+           {
+             int op = 0;
+             unsigned immbits = 0;
+             unsigned immlo = inst.operands[1].imm;
+             unsigned immhi = inst.operands[1].regisimm
+               ? inst.operands[1].reg
+               : inst.reloc.exp.X_unsigned
+               ? 0
+               : ((bfd_int64_t)((int) immlo)) >> 32;
+             int cmode = neon_cmode_for_move_imm (immlo, immhi, FALSE, &immbits,
+                                                  &op, 64, NT_invtype);
+
+             if (cmode == FAIL)
+               {
+                 neon_invert_size (&immlo, &immhi, 64);
+                 op = !op;
+                 cmode = neon_cmode_for_move_imm (immlo, immhi, FALSE, &immbits,
+                                                  &op, 64, NT_invtype);
+               }
+
+             if (cmode != FAIL)
+               {
+                 inst.instruction = (inst.instruction & VLDR_VMOV_SAME)
+                   | (1 << 23)
+                   | (cmode << 8)
+                   | (op << 5)
+                   | (1 << 4);
+
+                 /* Fill other bits in vmov encoding for both thumb and arm.  */
+                 if (thumb_mode)
+                   inst.instruction |= (0x7U << 29) | (0xF << 24);
+                 else
+                   inst.instruction |= (0xFU << 28) | (0x1 << 25);
+                 neon_write_immbits (immbits);
+                 return TRUE;
+               }
+           }
+       }
+
+      if (t == CONST_VEC)
+       {
+         /* Check if vldr Rx, =constant could be optimized to vmov Rx, #constant.  */
+         if (inst.operands[i].issingle
+             && is_quarter_float (inst.operands[1].imm)
+             && ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v3xd))
+           {
+             inst.operands[1].imm =
+               neon_qfloat_bits (v);
+             do_vfp_nsyn_opcode ("fconsts");
+             return TRUE;
+           }
+
+         /* If our host does not support a 64-bit type then we cannot perform
+            the following optimization.  This mean that there will be a
+            discrepancy between the output produced by an assembler built for
+            a 32-bit-only host and the output produced from a 64-bit host, but
+            this cannot be helped.  */
+#if defined BFD_HOST_64_BIT
+         else if (!inst.operands[1].issingle
+                  && ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v3))
+           {
+             if (is_double_a_single (v)
+                 && is_quarter_float (double_to_single (v)))
+               {
+                 inst.operands[1].imm =
+                   neon_qfloat_bits (double_to_single (v));
+                 do_vfp_nsyn_opcode ("fconstd");
+                 return TRUE;
+               }
+           }
 #endif
-    encode_branch (BFD_RELOC_ARM_PCREL_BRANCH);
+       }
+    }
+
+  if (add_to_lit_pool ((!inst.operands[i].isvec
+                       || inst.operands[i].issingle) ? 4 : 8) == FAIL)
+    return TRUE;
+
+  inst.operands[1].reg = REG_PC;
+  inst.operands[1].isreg = 1;
+  inst.operands[1].preind = 1;
+  inst.reloc.pc_rel = 1;
+  inst.reloc.type = (thumb_p
+                    ? BFD_RELOC_ARM_THUMB_OFFSET
+                    : (mode_3
+                       ? BFD_RELOC_ARM_HWLITERAL
+                       : BFD_RELOC_ARM_LITERAL));
+  return FALSE;
 }
 
-/* ARM V5 branch-link-exchange instruction (argument parse)
-     BLX <target_addr>         ie BLX(1)
-     BLX{<condition>} <Rm>     ie BLX(2)
-   Unfortunately, there are two different opcodes for this mnemonic.
-   So, the insns[].value is not used, and the code here zaps values
-       into inst.instruction.
-   Also, the <target_addr> can be 25 bits, hence has its own reloc.  */
+/* inst.operands[i] was set up by parse_address.  Encode it into an
+   ARM-format instruction.  Reject all forms which cannot be encoded
+   into a coprocessor load/store instruction.  If wb_ok is false,
+   reject use of writeback; if unind_ok is false, reject use of
+   unindexed addressing.  If reloc_override is not 0, use it instead
+   of BFD_ARM_CP_OFF_IMM, unless the initial relocation is a group one
+   (in which case it is preserved).  */
 
-static void
-do_blx (void)
+static int
+encode_arm_cp_address (int i, int wb_ok, int unind_ok, int reloc_override)
 {
-  if (inst.operands[0].isreg)
+  if (!inst.operands[i].isreg)
     {
-      /* Arg is a register; the opcode provided by insns[] is correct.
-        It is not illegal to do "blx pc", just useless.  */
-      if (inst.operands[0].reg == REG_PC)
-       as_tsktsk (_("use of r15 in blx in ARM mode is not really useful"));
-
-      inst.instruction |= inst.operands[0].reg;
+      /* PR 18256 */
+      if (! inst.operands[0].isvec)
+       {
+         inst.error = _("invalid co-processor operand");
+         return FAIL;
+       }
+      if (move_or_literal_pool (0, CONST_VEC, /*mode_3=*/FALSE))
+       return SUCCESS;
     }
-  else
+
+  inst.instruction |= inst.operands[i].reg << 16;
+
+  gas_assert (!(inst.operands[i].preind && inst.operands[i].postind));
+
+  if (!inst.operands[i].preind && !inst.operands[i].postind) /* unindexed */
     {
-      /* Arg is an address; this instruction cannot be executed
-        conditionally, and the opcode must be adjusted.
-        We retain the BFD_RELOC_ARM_PCREL_BLX till the very end
-        where we generate out a BFD_RELOC_ARM_PCREL_CALL instead.  */
-      constraint (inst.cond != COND_ALWAYS, BAD_COND);
-      inst.instruction = 0xfa000000;
-      encode_branch (BFD_RELOC_ARM_PCREL_BLX);
+      gas_assert (!inst.operands[i].writeback);
+      if (!unind_ok)
+       {
+         inst.error = _("instruction does not support unindexed addressing");
+         return FAIL;
+       }
+      inst.instruction |= inst.operands[i].imm;
+      inst.instruction |= INDEX_UP;
+      return SUCCESS;
     }
-}
 
-static void
-do_bx (void)
-{
-  bfd_boolean want_reloc;
+  if (inst.operands[i].preind)
+    inst.instruction |= PRE_INDEX;
 
-  if (inst.operands[0].reg == REG_PC)
-    as_tsktsk (_("use of r15 in bx in ARM mode is not really useful"));
+  if (inst.operands[i].writeback)
+    {
+      if (inst.operands[i].reg == REG_PC)
+       {
+         inst.error = _("pc may not be used with write-back");
+         return FAIL;
+       }
+      if (!wb_ok)
+       {
+         inst.error = _("instruction does not support writeback");
+         return FAIL;
+       }
+      inst.instruction |= WRITE_BACK;
+    }
 
-  inst.instruction |= inst.operands[0].reg;
-  /* Output R_ARM_V4BX relocations if is an EABI object that looks like
-     it is for ARMv4t or earlier.  */
-  want_reloc = !ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v5);
-  if (object_arch && !ARM_CPU_HAS_FEATURE (*object_arch, arm_ext_v5))
-      want_reloc = TRUE;
+  if (reloc_override)
+    inst.reloc.type = (bfd_reloc_code_real_type) reloc_override;
+  else if ((inst.reloc.type < BFD_RELOC_ARM_ALU_PC_G0_NC
+           || inst.reloc.type > BFD_RELOC_ARM_LDC_SB_G2)
+          && inst.reloc.type != BFD_RELOC_ARM_LDR_PC_G0)
+    {
+      if (thumb_mode)
+       inst.reloc.type = BFD_RELOC_ARM_T32_CP_OFF_IMM;
+      else
+       inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM;
+    }
 
-#ifdef OBJ_ELF
-  if (EF_ARM_EABI_VERSION (meabi_flags) < EF_ARM_EABI_VER4)
-#endif
-    want_reloc = FALSE;
+  /* Prefer + for zero encoded value.  */
+  if (!inst.operands[i].negative)
+    inst.instruction |= INDEX_UP;
 
-  if (want_reloc)
-    inst.reloc.type = BFD_RELOC_ARM_V4BX;
+  return SUCCESS;
 }
 
+/* Functions for instruction encoding, sorted by sub-architecture.
+   First some generics; their names are taken from the conventional
+   bit positions for register arguments in ARM format instructions.  */
 
-/* ARM v5TEJ.  Jump to Jazelle code.  */
+static void
+do_noargs (void)
+{
+}
 
 static void
-do_bxj (void)
+do_rd (void)
 {
-  if (inst.operands[0].reg == REG_PC)
-    as_tsktsk (_("use of r15 in bxj is not really useful"));
+  inst.instruction |= inst.operands[0].reg << 12;
+}
+
+static void
+do_rd_rm (void)
+{
+  inst.instruction |= inst.operands[0].reg << 12;
+  inst.instruction |= inst.operands[1].reg;
+}
 
+static void
+do_rm_rn (void)
+{
   inst.instruction |= inst.operands[0].reg;
+  inst.instruction |= inst.operands[1].reg << 16;
 }
 
-/* Co-processor data operation:
-      CDP{cond} <coproc>, <opcode_1>, <CRd>, <CRn>, <CRm>{, <opcode_2>}
-      CDP2     <coproc>, <opcode_1>, <CRd>, <CRn>, <CRm>{, <opcode_2>}  */
 static void
-do_cdp (void)
+do_rd_rn (void)
 {
-  inst.instruction |= inst.operands[0].reg << 8;
-  inst.instruction |= inst.operands[1].imm << 20;
-  inst.instruction |= inst.operands[2].reg << 12;
-  inst.instruction |= inst.operands[3].reg << 16;
-  inst.instruction |= inst.operands[4].reg;
-  inst.instruction |= inst.operands[5].imm << 5;
+  inst.instruction |= inst.operands[0].reg << 12;
+  inst.instruction |= inst.operands[1].reg << 16;
 }
 
 static void
-do_cmp (void)
+do_rn_rd (void)
 {
   inst.instruction |= inst.operands[0].reg << 16;
-  encode_arm_shifter_operand (1);
+  inst.instruction |= inst.operands[1].reg << 12;
 }
 
-/* Transfer between coprocessor and ARM registers.
-   MRC{cond} <coproc>, <opcode_1>, <Rd>, <CRn>, <CRm>{, <opcode_2>}
-   MRC2
-   MCR{cond}
-   MCR2
-
-   No special properties.  */
-
 static void
-do_co_reg (void)
+do_tt (void)
 {
-  unsigned Rd;
+  inst.instruction |= inst.operands[0].reg << 8;
+  inst.instruction |= inst.operands[1].reg << 16;
+}
 
-  Rd = inst.operands[2].reg;
-  if (thumb_mode)
+static bfd_boolean
+check_obsolete (const arm_feature_set *feature, const char *msg)
+{
+  if (ARM_CPU_IS_ANY (cpu_variant))
     {
-      if (inst.instruction == 0xee000010
-         || inst.instruction == 0xfe000010)
-       /* MCR, MCR2  */
-       reject_bad_reg (Rd);
-      else
-       /* MRC, MRC2  */
-       constraint (Rd == REG_SP, BAD_SP);
+      as_tsktsk ("%s", msg);
+      return TRUE;
     }
-  else
+  else if (ARM_CPU_HAS_FEATURE (cpu_variant, *feature))
     {
-      /* MCR */
-      if (inst.instruction == 0xe000010)
-       constraint (Rd == REG_PC, BAD_PC);
+      as_bad ("%s", msg);
+      return TRUE;
     }
 
-
-  inst.instruction |= inst.operands[0].reg << 8;
-  inst.instruction |= inst.operands[1].imm << 21;
-  inst.instruction |= Rd << 12;
-  inst.instruction |= inst.operands[3].reg << 16;
-  inst.instruction |= inst.operands[4].reg;
-  inst.instruction |= inst.operands[5].imm << 5;
+  return FALSE;
 }
 
-/* Transfer between coprocessor register and pair of ARM registers.
-   MCRR{cond} <coproc>, <opcode>, <Rd>, <Rn>, <CRm>.
-   MCRR2
-   MRRC{cond}
-   MRRC2
-
-   Two XScale instructions are special cases of these:
-
-     MAR{cond} acc0, <RdLo>, <RdHi> == MCRR{cond} p0, #0, <RdLo>, <RdHi>, c0
-     MRA{cond} acc0, <RdLo>, <RdHi> == MRRC{cond} p0, #0, <RdLo>, <RdHi>, c0
-
-   Result unpredictable if Rd or Rn is R15.  */
-
 static void
-do_co_reg2c (void)
+do_rd_rm_rn (void)
 {
-  unsigned Rd, Rn;
-
-  Rd = inst.operands[2].reg;
-  Rn = inst.operands[3].reg;
-
-  if (thumb_mode)
-    {
-      reject_bad_reg (Rd);
-      reject_bad_reg (Rn);
-    }
-  else
+  unsigned Rn = inst.operands[2].reg;
+  /* Enforce restrictions on SWP instruction.  */
+  if ((inst.instruction & 0x0fbfffff) == 0x01000090)
     {
-      constraint (Rd == REG_PC, BAD_PC);
-      constraint (Rn == REG_PC, BAD_PC);
+      constraint (Rn == inst.operands[0].reg || Rn == inst.operands[1].reg,
+                 _("Rn must not overlap other operands"));
+
+      /* SWP{b} is obsolete for ARMv8-A, and deprecated for ARMv6* and ARMv7.
+       */
+      if (!check_obsolete (&arm_ext_v8,
+                          _("swp{b} use is obsoleted for ARMv8 and later"))
+         && warn_on_deprecated
+         && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6))
+       as_tsktsk (_("swp{b} use is deprecated for ARMv6 and ARMv7"));
     }
 
-  inst.instruction |= inst.operands[0].reg << 8;
-  inst.instruction |= inst.operands[1].imm << 4;
-  inst.instruction |= Rd << 12;
+  inst.instruction |= inst.operands[0].reg << 12;
+  inst.instruction |= inst.operands[1].reg;
   inst.instruction |= Rn << 16;
-  inst.instruction |= inst.operands[4].reg;
 }
 
 static void
-do_cpsi (void)
+do_rd_rn_rm (void)
 {
-  inst.instruction |= inst.operands[0].imm << 6;
-  if (inst.operands[1].present)
-    {
-      inst.instruction |= CPSI_MMOD;
-      inst.instruction |= inst.operands[1].imm;
-    }
+  inst.instruction |= inst.operands[0].reg << 12;
+  inst.instruction |= inst.operands[1].reg << 16;
+  inst.instruction |= inst.operands[2].reg;
 }
 
 static void
-do_dbg (void)
+do_rm_rd_rn (void)
 {
-  inst.instruction |= inst.operands[0].imm;
+  constraint ((inst.operands[2].reg == REG_PC), BAD_PC);
+  constraint (((inst.reloc.exp.X_op != O_constant
+               && inst.reloc.exp.X_op != O_illegal)
+              || inst.reloc.exp.X_add_number != 0),
+             BAD_ADDR_MODE);
+  inst.instruction |= inst.operands[0].reg;
+  inst.instruction |= inst.operands[1].reg << 12;
+  inst.instruction |= inst.operands[2].reg << 16;
 }
 
 static void
-do_div (void)
+do_imm0 (void)
 {
-  unsigned Rd, Rn, Rm;
-
-  Rd = inst.operands[0].reg;
-  Rn = (inst.operands[1].present
-       ? inst.operands[1].reg : Rd);
-  Rm = inst.operands[2].reg;
-
-  constraint ((Rd == REG_PC), BAD_PC);
-  constraint ((Rn == REG_PC), BAD_PC);
-  constraint ((Rm == REG_PC), BAD_PC);
-
-  inst.instruction |= Rd << 16;
-  inst.instruction |= Rn << 0;
-  inst.instruction |= Rm << 8;
+  inst.instruction |= inst.operands[0].imm;
 }
 
 static void
-do_it (void)
+do_rd_cpaddr (void)
 {
-  /* There is no IT instruction in ARM mode.  We
-     process it to do the validation as if in
-     thumb mode, just in case the code gets
-     assembled for thumb using the unified syntax.  */
-
-  inst.size = 0;
-  if (unified_syntax)
-    {
-      set_it_insn_type (IT_INSN);
-      now_it.mask = (inst.instruction & 0xf) | 0x10;
-      now_it.cc = inst.operands[0].imm;
-    }
+  inst.instruction |= inst.operands[0].reg << 12;
+  encode_arm_cp_address (1, TRUE, TRUE, 0);
 }
 
-static void
-do_ldmstm (void)
-{
-  int base_reg = inst.operands[0].reg;
-  int range = inst.operands[1].imm;
+/* ARM instructions, in alphabetical order by function name (except
+   that wrapper functions appear immediately after the function they
+   wrap).  */
 
-  inst.instruction |= base_reg << 16;
-  inst.instruction |= range;
+/* This is a pseudo-op of the form "adr rd, label" to be converted
+   into a relative address of the form "add rd, pc, #label-.-8".  */
 
-  if (inst.operands[1].writeback)
-    inst.instruction |= LDM_TYPE_2_OR_3;
+static void
+do_adr (void)
+{
+  inst.instruction |= (inst.operands[0].reg << 12);  /* Rd */
 
-  if (inst.operands[0].writeback)
-    {
-      inst.instruction |= WRITE_BACK;
-      /* Check for unpredictable uses of writeback.  */
-      if (inst.instruction & LOAD_BIT)
-       {
-         /* Not allowed in LDM type 2.  */
-         if ((inst.instruction & LDM_TYPE_2_OR_3)
-             && ((range & (1 << REG_PC)) == 0))
-           as_warn (_("writeback of base register is UNPREDICTABLE"));
-         /* Only allowed if base reg not in list for other types.  */
-         else if (range & (1 << base_reg))
-           as_warn (_("writeback of base register when in register list is UNPREDICTABLE"));
-       }
-      else /* STM.  */
-       {
-         /* Not allowed for type 2.  */
-         if (inst.instruction & LDM_TYPE_2_OR_3)
-           as_warn (_("writeback of base register is UNPREDICTABLE"));
-         /* Only allowed if base reg not in list, or first in list.  */
-         else if ((range & (1 << base_reg))
-                  && (range & ((1 << base_reg) - 1)))
-           as_warn (_("if writeback register is in list, it must be the lowest reg in the list"));
-       }
-    }
+  /* Frag hacking will turn this into a sub instruction if the offset turns
+     out to be negative.  */
+  inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
+  inst.reloc.pc_rel = 1;
+  inst.reloc.exp.X_add_number -= 8;
 }
 
-/* ARMv5TE load-consecutive (argument parse)
-   Mode is like LDRH.
-
-     LDRccD R, mode
-     STRccD R, mode.  */
+/* This is a pseudo-op of the form "adrl rd, label" to be converted
+   into a relative address of the form:
+   add rd, pc, #low(label-.-8)"
+   add rd, rd, #high(label-.-8)"  */
 
 static void
-do_ldrd (void)
+do_adrl (void)
 {
-  constraint (inst.operands[0].reg % 2 != 0,
-             _("first destination register must be even"));
-  constraint (inst.operands[1].present
-             && inst.operands[1].reg != inst.operands[0].reg + 1,
-             _("can only load two consecutive registers"));
-  constraint (inst.operands[0].reg == REG_LR, _("r14 not allowed here"));
-  constraint (!inst.operands[2].isreg, _("'[' expected"));
-
-  if (!inst.operands[1].present)
-    inst.operands[1].reg = inst.operands[0].reg + 1;
-
-  if (inst.instruction & LOAD_BIT)
-    {
-      /* encode_arm_addr_mode_3 will diagnose overlap between the base
-        register and the first register written; we have to diagnose
-        overlap between the base and the second register written here.  */
-
-      if (inst.operands[2].reg == inst.operands[1].reg
-         && (inst.operands[2].writeback || inst.operands[2].postind))
-       as_warn (_("base register written back, and overlaps "
-                  "second destination register"));
-
-      /* For an index-register load, the index register must not overlap the
-        destination (even if not write-back).  */
-      else if (inst.operands[2].immisreg
-              && ((unsigned) inst.operands[2].imm == inst.operands[0].reg
-                  || (unsigned) inst.operands[2].imm == inst.operands[1].reg))
-       as_warn (_("index register overlaps destination register"));
-    }
+  inst.instruction |= (inst.operands[0].reg << 12);  /* Rd */
 
-  inst.instruction |= inst.operands[0].reg << 12;
-  encode_arm_addr_mode_3 (2, /*is_t=*/FALSE);
+  /* Frag hacking will turn this into a sub instruction if the offset turns
+     out to be negative.  */
+  inst.reloc.type             = BFD_RELOC_ARM_ADRL_IMMEDIATE;
+  inst.reloc.pc_rel           = 1;
+  inst.size                   = INSN_SIZE * 2;
+  inst.reloc.exp.X_add_number -= 8;
 }
 
 static void
-do_ldrex (void)
+do_arit (void)
 {
-  constraint (!inst.operands[1].isreg || !inst.operands[1].preind
-             || inst.operands[1].postind || inst.operands[1].writeback
-             || inst.operands[1].immisreg || inst.operands[1].shifted
-             || inst.operands[1].negative
-             /* This can arise if the programmer has written
-                  strex rN, rM, foo
-                or if they have mistakenly used a register name as the last
-                operand,  eg:
-                  strex rN, rM, rX
-                It is very difficult to distinguish between these two cases
-                because "rX" might actually be a label. ie the register
-                name has been occluded by a symbol of the same name. So we
-                just generate a general 'bad addressing mode' type error
-                message and leave it up to the programmer to discover the
-                true cause and fix their mistake.  */
-             || (inst.operands[1].reg == REG_PC),
-             BAD_ADDR_MODE);
-
-  constraint (inst.reloc.exp.X_op != O_constant
-             || inst.reloc.exp.X_add_number != 0,
-             _("offset must be zero in ARM encoding"));
-
-  constraint ((inst.operands[1].reg == REG_PC), BAD_PC);
-
+  constraint (inst.reloc.type >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
+             && inst.reloc.type <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC ,
+             THUMB1_RELOC_ONLY);
+  if (!inst.operands[1].present)
+    inst.operands[1].reg = inst.operands[0].reg;
   inst.instruction |= inst.operands[0].reg << 12;
   inst.instruction |= inst.operands[1].reg << 16;
-  inst.reloc.type = BFD_RELOC_UNUSED;
+  encode_arm_shifter_operand (2);
 }
 
 static void
-do_ldrexd (void)
+do_barrier (void)
 {
-  constraint (inst.operands[0].reg % 2 != 0,
-             _("even register required"));
-  constraint (inst.operands[1].present
-             && inst.operands[1].reg != inst.operands[0].reg + 1,
-             _("can only load two consecutive registers"));
-  /* If op 1 were present and equal to PC, this function wouldn't
-     have been called in the first place.  */
-  constraint (inst.operands[0].reg == REG_LR, _("r14 not allowed here"));
-
-  inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= inst.operands[2].reg << 16;
+  if (inst.operands[0].present)
+    inst.instruction |= inst.operands[0].imm;
+  else
+    inst.instruction |= 0xf;
 }
 
 static void
-do_ldst (void)
+do_bfc (void)
 {
+  unsigned int msb = inst.operands[1].imm + inst.operands[2].imm;
+  constraint (msb > 32, _("bit-field extends past end of register"));
+  /* The instruction encoding stores the LSB and MSB,
+     not the LSB and width.  */
   inst.instruction |= inst.operands[0].reg << 12;
-  if (!inst.operands[1].isreg)
-    if (move_or_literal_pool (0, /*thumb_p=*/FALSE, /*mode_3=*/FALSE))
-      return;
-  encode_arm_addr_mode_2 (1, /*is_t=*/FALSE);
+  inst.instruction |= inst.operands[1].imm << 7;
+  inst.instruction |= (msb - 1) << 16;
 }
 
 static void
-do_ldstt (void)
+do_bfi (void)
 {
-  /* ldrt/strt always use post-indexed addressing.  Turn [Rn] into [Rn]! and
-     reject [Rn,...].  */
-  if (inst.operands[1].preind)
-    {
-      constraint (inst.reloc.exp.X_op != O_constant
-                 || inst.reloc.exp.X_add_number != 0,
-                 _("this instruction requires a post-indexed address"));
+  unsigned int msb;
 
-      inst.operands[1].preind = 0;
-      inst.operands[1].postind = 1;
-      inst.operands[1].writeback = 1;
-    }
+  /* #0 in second position is alternative syntax for bfc, which is
+     the same instruction but with REG_PC in the Rm field.  */
+  if (!inst.operands[1].isreg)
+    inst.operands[1].reg = REG_PC;
+
+  msb = inst.operands[2].imm + inst.operands[3].imm;
+  constraint (msb > 32, _("bit-field extends past end of register"));
+  /* The instruction encoding stores the LSB and MSB,
+     not the LSB and width.  */
   inst.instruction |= inst.operands[0].reg << 12;
-  encode_arm_addr_mode_2 (1, /*is_t=*/TRUE);
+  inst.instruction |= inst.operands[1].reg;
+  inst.instruction |= inst.operands[2].imm << 7;
+  inst.instruction |= (msb - 1) << 16;
 }
 
-/* Halfword and signed-byte load/store operations.  */
-
 static void
-do_ldstv4 (void)
+do_bfx (void)
 {
-  constraint (inst.operands[0].reg == REG_PC, BAD_PC);
-  inst.instruction |= inst.operands[0].reg << 12;
-  if (!inst.operands[1].isreg)
-    if (move_or_literal_pool (0, /*thumb_p=*/FALSE, /*mode_3=*/TRUE))
-      return;
-  encode_arm_addr_mode_3 (1, /*is_t=*/FALSE);
-}
-
-static void
-do_ldsttv4 (void)
-{
-  /* ldrt/strt always use post-indexed addressing.  Turn [Rn] into [Rn]! and
-     reject [Rn,...].  */
-  if (inst.operands[1].preind)
-    {
-      constraint (inst.reloc.exp.X_op != O_constant
-                 || inst.reloc.exp.X_add_number != 0,
-                 _("this instruction requires a post-indexed address"));
-
-      inst.operands[1].preind = 0;
-      inst.operands[1].postind = 1;
-      inst.operands[1].writeback = 1;
-    }
+  constraint (inst.operands[2].imm + inst.operands[3].imm > 32,
+             _("bit-field extends past end of register"));
   inst.instruction |= inst.operands[0].reg << 12;
-  encode_arm_addr_mode_3 (1, /*is_t=*/TRUE);
+  inst.instruction |= inst.operands[1].reg;
+  inst.instruction |= inst.operands[2].imm << 7;
+  inst.instruction |= (inst.operands[3].imm - 1) << 16;
 }
 
-/* Co-processor register load/store.
-   Format: <LDC|STC>{cond}[L] CP#,CRd,<address>         */
+/* ARM V5 breakpoint instruction (argument parse)
+     BKPT <16 bit unsigned immediate>
+     Instruction is not conditional.
+       The bit pattern given in insns[] has the COND_ALWAYS condition,
+       and it is an error if the caller tried to override that.  */
+
 static void
-do_lstc (void)
+do_bkpt (void)
 {
-  inst.instruction |= inst.operands[0].reg << 8;
-  inst.instruction |= inst.operands[1].reg << 12;
-  encode_arm_cp_address (2, TRUE, TRUE, 0);
+  /* Top 12 of 16 bits to bits 19:8.  */
+  inst.instruction |= (inst.operands[0].imm & 0xfff0) << 4;
+
+  /* Bottom 4 of 16 bits to bits 3:0.  */
+  inst.instruction |= inst.operands[0].imm & 0xf;
 }
 
 static void
-do_mlas (void)
+encode_branch (int default_reloc)
 {
-  /* This restriction does not apply to mls (nor to mla in v6 or later).  */
-  if (inst.operands[0].reg == inst.operands[1].reg
-      && !ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6)
-      && !(inst.instruction & 0x00400000))
-    as_tsktsk (_("Rd and Rm should be different in mla"));
-
-  inst.instruction |= inst.operands[0].reg << 16;
-  inst.instruction |= inst.operands[1].reg;
-  inst.instruction |= inst.operands[2].reg << 8;
-  inst.instruction |= inst.operands[3].reg << 12;
+  if (inst.operands[0].hasreloc)
+    {
+      constraint (inst.operands[0].imm != BFD_RELOC_ARM_PLT32
+                 && inst.operands[0].imm != BFD_RELOC_ARM_TLS_CALL,
+                 _("the only valid suffixes here are '(plt)' and '(tlscall)'"));
+      inst.reloc.type = inst.operands[0].imm == BFD_RELOC_ARM_PLT32
+       ? BFD_RELOC_ARM_PLT32
+       : thumb_mode ? BFD_RELOC_ARM_THM_TLS_CALL : BFD_RELOC_ARM_TLS_CALL;
+    }
+  else
+    inst.reloc.type = (bfd_reloc_code_real_type) default_reloc;
+  inst.reloc.pc_rel = 1;
 }
 
 static void
-do_mov (void)
+do_branch (void)
 {
-  inst.instruction |= inst.operands[0].reg << 12;
-  encode_arm_shifter_operand (1);
+#ifdef OBJ_ELF
+  if (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4)
+    encode_branch (BFD_RELOC_ARM_PCREL_JUMP);
+  else
+#endif
+    encode_branch (BFD_RELOC_ARM_PCREL_BRANCH);
 }
 
-/* ARM V6T2 16-bit immediate register load: MOV[WT]{cond} Rd, #<imm16>.         */
 static void
-do_mov16 (void)
+do_bl (void)
 {
-  bfd_vma imm;
-  bfd_boolean top;
-
-  top = (inst.instruction & 0x00400000) != 0;
-  constraint (top && inst.reloc.type == BFD_RELOC_ARM_MOVW,
-             _(":lower16: not allowed this instruction"));
-  constraint (!top && inst.reloc.type == BFD_RELOC_ARM_MOVT,
-             _(":upper16: not allowed instruction"));
-  inst.instruction |= inst.operands[0].reg << 12;
-  if (inst.reloc.type == BFD_RELOC_UNUSED)
+#ifdef OBJ_ELF
+  if (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4)
     {
-      imm = inst.reloc.exp.X_add_number;
-      /* The value is in two pieces: 0:11, 16:19.  */
-      inst.instruction |= (imm & 0x00000fff);
-      inst.instruction |= (imm & 0x0000f000) << 4;
+      if (inst.cond == COND_ALWAYS)
+       encode_branch (BFD_RELOC_ARM_PCREL_CALL);
+      else
+       encode_branch (BFD_RELOC_ARM_PCREL_JUMP);
     }
+  else
+#endif
+    encode_branch (BFD_RELOC_ARM_PCREL_BRANCH);
 }
 
-static void do_vfp_nsyn_opcode (const char *);
+/* ARM V5 branch-link-exchange instruction (argument parse)
+     BLX <target_addr>         ie BLX(1)
+     BLX{<condition>} <Rm>     ie BLX(2)
+   Unfortunately, there are two different opcodes for this mnemonic.
+   So, the insns[].value is not used, and the code here zaps values
+       into inst.instruction.
+   Also, the <target_addr> can be 25 bits, hence has its own reloc.  */
 
-static int
-do_vfp_nsyn_mrs (void)
+static void
+do_blx (void)
 {
-  if (inst.operands[0].isvec)
+  if (inst.operands[0].isreg)
     {
-      if (inst.operands[1].reg != 1)
-        first_error (_("operand 1 must be FPSCR"));
-      memset (&inst.operands[0], '\0', sizeof (inst.operands[0]));
-      memset (&inst.operands[1], '\0', sizeof (inst.operands[1]));
-      do_vfp_nsyn_opcode ("fmstat");
-    }
-  else if (inst.operands[1].isvec)
-    do_vfp_nsyn_opcode ("fmrx");
-  else
-    return FAIL;
-
-  return SUCCESS;
-}
+      /* Arg is a register; the opcode provided by insns[] is correct.
+        It is not illegal to do "blx pc", just useless.  */
+      if (inst.operands[0].reg == REG_PC)
+       as_tsktsk (_("use of r15 in blx in ARM mode is not really useful"));
 
-static int
-do_vfp_nsyn_msr (void)
-{
-  if (inst.operands[0].isvec)
-    do_vfp_nsyn_opcode ("fmxr");
+      inst.instruction |= inst.operands[0].reg;
+    }
   else
-    return FAIL;
-
-  return SUCCESS;
+    {
+      /* Arg is an address; this instruction cannot be executed
+        conditionally, and the opcode must be adjusted.
+        We retain the BFD_RELOC_ARM_PCREL_BLX till the very end
+        where we generate out a BFD_RELOC_ARM_PCREL_CALL instead.  */
+      constraint (inst.cond != COND_ALWAYS, BAD_COND);
+      inst.instruction = 0xfa000000;
+      encode_branch (BFD_RELOC_ARM_PCREL_BLX);
+    }
 }
 
 static void
-do_vmrs (void)
+do_bx (void)
 {
-  unsigned Rt = inst.operands[0].reg;
-  
-  if (thumb_mode && inst.operands[0].reg == REG_SP)
-    {
-      inst.error = BAD_SP;
-      return;
-    }
+  bfd_boolean want_reloc;
 
-  /* APSR_ sets isvec. All other refs to PC are illegal.  */
-  if (!inst.operands[0].isvec && inst.operands[0].reg == REG_PC)
-    {
-      inst.error = BAD_PC;
-      return;
-    }
+  if (inst.operands[0].reg == REG_PC)
+    as_tsktsk (_("use of r15 in bx in ARM mode is not really useful"));
 
-  if (inst.operands[1].reg != 1)
-    first_error (_("operand 1 must be FPSCR"));
+  inst.instruction |= inst.operands[0].reg;
+  /* Output R_ARM_V4BX relocations if is an EABI object that looks like
+     it is for ARMv4t or earlier.  */
+  want_reloc = !ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v5);
+  if (object_arch && !ARM_CPU_HAS_FEATURE (*object_arch, arm_ext_v5))
+      want_reloc = TRUE;
 
-  inst.instruction |= (Rt << 12);
+#ifdef OBJ_ELF
+  if (EF_ARM_EABI_VERSION (meabi_flags) < EF_ARM_EABI_VER4)
+#endif
+    want_reloc = FALSE;
+
+  if (want_reloc)
+    inst.reloc.type = BFD_RELOC_ARM_V4BX;
 }
 
+
+/* ARM v5TEJ.  Jump to Jazelle code.  */
+
 static void
-do_vmsr (void)
+do_bxj (void)
 {
-  unsigned Rt = inst.operands[1].reg;
-  
-  if (thumb_mode)
-    reject_bad_reg (Rt);
-  else if (Rt == REG_PC)
-    {
-      inst.error = BAD_PC;
-      return;
-    }
+  if (inst.operands[0].reg == REG_PC)
+    as_tsktsk (_("use of r15 in bxj is not really useful"));
 
-  if (inst.operands[0].reg != 1)
-    first_error (_("operand 0 must be FPSCR"));
+  inst.instruction |= inst.operands[0].reg;
+}
 
-  inst.instruction |= (Rt << 12);
+/* Co-processor data operation:
+      CDP{cond} <coproc>, <opcode_1>, <CRd>, <CRn>, <CRm>{, <opcode_2>}
+      CDP2     <coproc>, <opcode_1>, <CRd>, <CRn>, <CRm>{, <opcode_2>}  */
+static void
+do_cdp (void)
+{
+  inst.instruction |= inst.operands[0].reg << 8;
+  inst.instruction |= inst.operands[1].imm << 20;
+  inst.instruction |= inst.operands[2].reg << 12;
+  inst.instruction |= inst.operands[3].reg << 16;
+  inst.instruction |= inst.operands[4].reg;
+  inst.instruction |= inst.operands[5].imm << 5;
 }
 
 static void
-do_mrs (void)
+do_cmp (void)
 {
-  unsigned br;
+  inst.instruction |= inst.operands[0].reg << 16;
+  encode_arm_shifter_operand (1);
+}
 
-  if (do_vfp_nsyn_mrs () == SUCCESS)
-    return;
+/* Transfer between coprocessor and ARM registers.
+   MRC{cond} <coproc>, <opcode_1>, <Rd>, <CRn>, <CRm>{, <opcode_2>}
+   MRC2
+   MCR{cond}
+   MCR2
 
-  constraint (inst.operands[0].reg == REG_PC, BAD_PC);
-  inst.instruction |= inst.operands[0].reg << 12;
+   No special properties.  */
 
-  if (inst.operands[1].isreg)
-    {
-      br = inst.operands[1].reg;
-      if (((br & 0x200) == 0) && ((br & 0xf0000) != 0xf000))
-       as_bad (_("bad register for mrs"));
-    }
-  else
-    {
-      /* mrs only accepts CPSR/SPSR/CPSR_all/SPSR_all.  */
-      constraint ((inst.operands[1].imm & (PSR_c|PSR_x|PSR_s|PSR_f))
-                 != (PSR_c|PSR_f),
-                 _("'APSR', 'CPSR' or 'SPSR' expected"));
-      br = (15<<16) | (inst.operands[1].imm & SPSR_BIT);
-    }
+struct deprecated_coproc_regs_s
+{
+  unsigned cp;
+  int opc1;
+  unsigned crn;
+  unsigned crm;
+  int opc2;
+  arm_feature_set deprecated;
+  arm_feature_set obsoleted;
+  const char *dep_msg;
+  const char *obs_msg;
+};
 
-  inst.instruction |= br;
-}
+#define DEPR_ACCESS_V8 \
+  N_("This coprocessor register access is deprecated in ARMv8")
+
+/* Table of all deprecated coprocessor registers.  */
+static struct deprecated_coproc_regs_s deprecated_coproc_regs[] =
+{
+    {15, 0, 7, 10, 5,                                  /* CP15DMB.  */
+     ARM_FEATURE_CORE_LOW (ARM_EXT_V8), ARM_ARCH_NONE,
+     DEPR_ACCESS_V8, NULL},
+    {15, 0, 7, 10, 4,                                  /* CP15DSB.  */
+     ARM_FEATURE_CORE_LOW (ARM_EXT_V8), ARM_ARCH_NONE,
+     DEPR_ACCESS_V8, NULL},
+    {15, 0, 7,  5, 4,                                  /* CP15ISB.  */
+     ARM_FEATURE_CORE_LOW (ARM_EXT_V8), ARM_ARCH_NONE,
+     DEPR_ACCESS_V8, NULL},
+    {14, 6, 1,  0, 0,                                  /* TEEHBR.  */
+     ARM_FEATURE_CORE_LOW (ARM_EXT_V8), ARM_ARCH_NONE,
+     DEPR_ACCESS_V8, NULL},
+    {14, 6, 0,  0, 0,                                  /* TEECR.  */
+     ARM_FEATURE_CORE_LOW (ARM_EXT_V8), ARM_ARCH_NONE,
+     DEPR_ACCESS_V8, NULL},
+};
 
-/* Two possible forms:
-      "{C|S}PSR_<field>, Rm",
-      "{C|S}PSR_f, #expression".  */
+#undef DEPR_ACCESS_V8
+
+static const size_t deprecated_coproc_reg_count =
+  sizeof (deprecated_coproc_regs) / sizeof (deprecated_coproc_regs[0]);
 
 static void
-do_msr (void)
+do_co_reg (void)
 {
-  if (do_vfp_nsyn_msr () == SUCCESS)
-    return;
+  unsigned Rd;
+  size_t i;
 
-  inst.instruction |= inst.operands[0].imm;
-  if (inst.operands[1].isreg)
-    inst.instruction |= inst.operands[1].reg;
+  Rd = inst.operands[2].reg;
+  if (thumb_mode)
+    {
+      if (inst.instruction == 0xee000010
+         || inst.instruction == 0xfe000010)
+       /* MCR, MCR2  */
+       reject_bad_reg (Rd);
+      else
+       /* MRC, MRC2  */
+       constraint (Rd == REG_SP, BAD_SP);
+    }
   else
     {
-      inst.instruction |= INST_IMMEDIATE;
-      inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
-      inst.reloc.pc_rel = 0;
+      /* MCR */
+      if (inst.instruction == 0xe000010)
+       constraint (Rd == REG_PC, BAD_PC);
     }
-}
-
-static void
-do_mul (void)
-{
-  constraint (inst.operands[2].reg == REG_PC, BAD_PC);
 
-  if (!inst.operands[2].present)
-    inst.operands[2].reg = inst.operands[0].reg;
-  inst.instruction |= inst.operands[0].reg << 16;
-  inst.instruction |= inst.operands[1].reg;
-  inst.instruction |= inst.operands[2].reg << 8;
+    for (i = 0; i < deprecated_coproc_reg_count; ++i)
+      {
+       const struct deprecated_coproc_regs_s *r =
+         deprecated_coproc_regs + i;
+
+       if (inst.operands[0].reg == r->cp
+           && inst.operands[1].imm == r->opc1
+           && inst.operands[3].reg == r->crn
+           && inst.operands[4].reg == r->crm
+           && inst.operands[5].imm == r->opc2)
+         {
+           if (! ARM_CPU_IS_ANY (cpu_variant)
+               && warn_on_deprecated
+               && ARM_CPU_HAS_FEATURE (cpu_variant, r->deprecated))
+             as_tsktsk ("%s", r->dep_msg);
+         }
+      }
 
-  if (inst.operands[0].reg == inst.operands[1].reg
-      && !ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6))
-    as_tsktsk (_("Rd and Rm should be different in mul"));
+  inst.instruction |= inst.operands[0].reg << 8;
+  inst.instruction |= inst.operands[1].imm << 21;
+  inst.instruction |= Rd << 12;
+  inst.instruction |= inst.operands[3].reg << 16;
+  inst.instruction |= inst.operands[4].reg;
+  inst.instruction |= inst.operands[5].imm << 5;
 }
 
-/* Long Multiply Parser
-   UMULL RdLo, RdHi, Rm, Rs
-   SMULL RdLo, RdHi, Rm, Rs
-   UMLAL RdLo, RdHi, Rm, Rs
-   SMLAL RdLo, RdHi, Rm, Rs.  */
-
-static void
-do_mull (void)
-{
-  inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= inst.operands[1].reg << 16;
-  inst.instruction |= inst.operands[2].reg;
-  inst.instruction |= inst.operands[3].reg << 8;
-
-  /* rdhi and rdlo must be different.  */
-  if (inst.operands[0].reg == inst.operands[1].reg)
-    as_tsktsk (_("rdhi and rdlo must be different"));
+/* Transfer between coprocessor register and pair of ARM registers.
+   MCRR{cond} <coproc>, <opcode>, <Rd>, <Rn>, <CRm>.
+   MCRR2
+   MRRC{cond}
+   MRRC2
 
-  /* rdhi, rdlo and rm must all be different before armv6.  */
-  if ((inst.operands[0].reg == inst.operands[2].reg
-      || inst.operands[1].reg == inst.operands[2].reg)
-      && !ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6))
-    as_tsktsk (_("rdhi, rdlo and rm must all be different"));
-}
+   Two XScale instructions are special cases of these:
 
-static void
-do_nop (void)
-{
-  if (inst.operands[0].present
-      || ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6k))
-    {
-      /* Architectural NOP hints are CPSR sets with no bits selected.  */
-      inst.instruction &= 0xf0000000;
-      inst.instruction |= 0x0320f000;
-      if (inst.operands[0].present)
-       inst.instruction |= inst.operands[0].imm;
-    }
-}
+     MAR{cond} acc0, <RdLo>, <RdHi> == MCRR{cond} p0, #0, <RdLo>, <RdHi>, c0
+     MRA{cond} acc0, <RdLo>, <RdHi> == MRRC{cond} p0, #0, <RdLo>, <RdHi>, c0
 
-/* ARM V6 Pack Halfword Bottom Top instruction (argument parse).
-   PKHBT {<cond>} <Rd>, <Rn>, <Rm> {, LSL #<shift_imm>}
-   Condition defaults to COND_ALWAYS.
-   Error if Rd, Rn or Rm are R15.  */
+   Result unpredictable if Rd or Rn is R15.  */
 
 static void
-do_pkhbt (void)
+do_co_reg2c (void)
 {
-  inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= inst.operands[1].reg << 16;
-  inst.instruction |= inst.operands[2].reg;
-  if (inst.operands[3].present)
-    encode_arm_shift (3);
-}
+  unsigned Rd, Rn;
 
-/* ARM V6 PKHTB (Argument Parse).  */
+  Rd = inst.operands[2].reg;
+  Rn = inst.operands[3].reg;
 
-static void
-do_pkhtb (void)
-{
-  if (!inst.operands[3].present)
+  if (thumb_mode)
     {
-      /* If the shift specifier is omitted, turn the instruction
-        into pkhbt rd, rm, rn. */
-      inst.instruction &= 0xfff00010;
-      inst.instruction |= inst.operands[0].reg << 12;
-      inst.instruction |= inst.operands[1].reg;
-      inst.instruction |= inst.operands[2].reg << 16;
+      reject_bad_reg (Rd);
+      reject_bad_reg (Rn);
     }
   else
     {
-      inst.instruction |= inst.operands[0].reg << 12;
-      inst.instruction |= inst.operands[1].reg << 16;
-      inst.instruction |= inst.operands[2].reg;
-      encode_arm_shift (3);
+      constraint (Rd == REG_PC, BAD_PC);
+      constraint (Rn == REG_PC, BAD_PC);
     }
-}
-
-/* ARMv5TE: Preload-Cache
-   MP Extensions: Preload for write
-
-    PLD(W) <addr_mode>
-
-  Syntactically, like LDR with B=1, W=0, L=1.  */
 
-static void
-do_pld (void)
-{
-  constraint (!inst.operands[0].isreg,
-             _("'[' expected after PLD mnemonic"));
-  constraint (inst.operands[0].postind,
-             _("post-indexed expression used in preload instruction"));
-  constraint (inst.operands[0].writeback,
-             _("writeback used in preload instruction"));
-  constraint (!inst.operands[0].preind,
-             _("unindexed addressing used in preload instruction"));
-  encode_arm_addr_mode_2 (0, /*is_t=*/FALSE);
+  inst.instruction |= inst.operands[0].reg << 8;
+  inst.instruction |= inst.operands[1].imm << 4;
+  inst.instruction |= Rd << 12;
+  inst.instruction |= Rn << 16;
+  inst.instruction |= inst.operands[4].reg;
 }
 
-/* ARMv7: PLI <addr_mode>  */
 static void
-do_pli (void)
+do_cpsi (void)
 {
-  constraint (!inst.operands[0].isreg,
-             _("'[' expected after PLI mnemonic"));
-  constraint (inst.operands[0].postind,
-             _("post-indexed expression used in preload instruction"));
-  constraint (inst.operands[0].writeback,
-             _("writeback used in preload instruction"));
-  constraint (!inst.operands[0].preind,
-             _("unindexed addressing used in preload instruction"));
-  encode_arm_addr_mode_2 (0, /*is_t=*/FALSE);
-  inst.instruction &= ~PRE_INDEX;
+  inst.instruction |= inst.operands[0].imm << 6;
+  if (inst.operands[1].present)
+    {
+      inst.instruction |= CPSI_MMOD;
+      inst.instruction |= inst.operands[1].imm;
+    }
 }
 
 static void
-do_push_pop (void)
+do_dbg (void)
 {
-  inst.operands[1] = inst.operands[0];
-  memset (&inst.operands[0], 0, sizeof inst.operands[0]);
-  inst.operands[0].isreg = 1;
-  inst.operands[0].writeback = 1;
-  inst.operands[0].reg = REG_SP;
-  do_ldmstm ();
+  inst.instruction |= inst.operands[0].imm;
 }
 
-/* ARM V6 RFE (Return from Exception) loads the PC and CPSR from the
-   word at the specified address and the following word
-   respectively.
-   Unconditionally executed.
-   Error if Rn is R15. */
-
 static void
-do_rfe (void)
+do_div (void)
 {
-  inst.instruction |= inst.operands[0].reg << 16;
-  if (inst.operands[0].writeback)
-    inst.instruction |= WRITE_BACK;
-}
+  unsigned Rd, Rn, Rm;
 
-/* ARM V6 ssat (argument parse).  */
+  Rd = inst.operands[0].reg;
+  Rn = (inst.operands[1].present
+       ? inst.operands[1].reg : Rd);
+  Rm = inst.operands[2].reg;
 
-static void
-do_ssat (void)
-{
-  inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= (inst.operands[1].imm - 1) << 16;
-  inst.instruction |= inst.operands[2].reg;
+  constraint ((Rd == REG_PC), BAD_PC);
+  constraint ((Rn == REG_PC), BAD_PC);
+  constraint ((Rm == REG_PC), BAD_PC);
 
-  if (inst.operands[3].present)
-    encode_arm_shift (3);
+  inst.instruction |= Rd << 16;
+  inst.instruction |= Rn << 0;
+  inst.instruction |= Rm << 8;
 }
 
-/* ARM V6 usat (argument parse).  */
-
 static void
-do_usat (void)
+do_it (void)
 {
-  inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= inst.operands[1].imm << 16;
-  inst.instruction |= inst.operands[2].reg;
+  /* There is no IT instruction in ARM mode.  We
+     process it to do the validation as if in
+     thumb mode, just in case the code gets
+     assembled for thumb using the unified syntax.  */
 
-  if (inst.operands[3].present)
-    encode_arm_shift (3);
+  inst.size = 0;
+  if (unified_syntax)
+    {
+      set_it_insn_type (IT_INSN);
+      now_it.mask = (inst.instruction & 0xf) | 0x10;
+      now_it.cc = inst.operands[0].imm;
+    }
 }
 
-/* ARM V6 ssat16 (argument parse).  */
-
-static void
-do_ssat16 (void)
+/* If there is only one register in the register list,
+   then return its register number.  Otherwise return -1.  */
+static int
+only_one_reg_in_list (int range)
 {
-  inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= ((inst.operands[1].imm - 1) << 16);
-  inst.instruction |= inst.operands[2].reg;
+  int i = ffs (range) - 1;
+  return (i > 15 || range != (1 << i)) ? -1 : i;
 }
 
 static void
-do_usat16 (void)
+encode_ldmstm(int from_push_pop_mnem)
 {
-  inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= inst.operands[1].imm << 16;
-  inst.instruction |= inst.operands[2].reg;
-}
+  int base_reg = inst.operands[0].reg;
+  int range = inst.operands[1].imm;
+  int one_reg;
 
-/* ARM V6 SETEND (argument parse).  Sets the E bit in the CPSR while
-   preserving the other bits.
+  inst.instruction |= base_reg << 16;
+  inst.instruction |= range;
 
-   setend <endian_specifier>, where <endian_specifier> is either
-   BE or LE.  */
+  if (inst.operands[1].writeback)
+    inst.instruction |= LDM_TYPE_2_OR_3;
 
-static void
-do_setend (void)
-{
-  if (inst.operands[0].imm)
-    inst.instruction |= 0x200;
-}
-
-static void
-do_shift (void)
-{
-  unsigned int Rm = (inst.operands[1].present
-                    ? inst.operands[1].reg
-                    : inst.operands[0].reg);
-
-  inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= Rm;
-  if (inst.operands[2].isreg)  /* Rd, {Rm,} Rs */
+  if (inst.operands[0].writeback)
     {
-      inst.instruction |= inst.operands[2].reg << 8;
-      inst.instruction |= SHIFT_BY_REG;
+      inst.instruction |= WRITE_BACK;
+      /* Check for unpredictable uses of writeback.  */
+      if (inst.instruction & LOAD_BIT)
+       {
+         /* Not allowed in LDM type 2.  */
+         if ((inst.instruction & LDM_TYPE_2_OR_3)
+             && ((range & (1 << REG_PC)) == 0))
+           as_warn (_("writeback of base register is UNPREDICTABLE"));
+         /* Only allowed if base reg not in list for other types.  */
+         else if (range & (1 << base_reg))
+           as_warn (_("writeback of base register when in register list is UNPREDICTABLE"));
+       }
+      else /* STM.  */
+       {
+         /* Not allowed for type 2.  */
+         if (inst.instruction & LDM_TYPE_2_OR_3)
+           as_warn (_("writeback of base register is UNPREDICTABLE"));
+         /* Only allowed if base reg not in list, or first in list.  */
+         else if ((range & (1 << base_reg))
+                  && (range & ((1 << base_reg) - 1)))
+           as_warn (_("if writeback register is in list, it must be the lowest reg in the list"));
+       }
     }
-  else
-    inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM;
-}
 
-static void
-do_smc (void)
-{
-  inst.reloc.type = BFD_RELOC_ARM_SMC;
-  inst.reloc.pc_rel = 0;
-}
+  /* If PUSH/POP has only one register, then use the A2 encoding.  */
+  one_reg = only_one_reg_in_list (range);
+  if (from_push_pop_mnem && one_reg >= 0)
+    {
+      int is_push = (inst.instruction & A_PUSH_POP_OP_MASK) == A1_OPCODE_PUSH;
 
-static void
-do_hvc (void)
-{
-  inst.reloc.type = BFD_RELOC_ARM_HVC;
-  inst.reloc.pc_rel = 0;
+      inst.instruction &= A_COND_MASK;
+      inst.instruction |= is_push ? A2_OPCODE_PUSH : A2_OPCODE_POP;
+      inst.instruction |= one_reg << 12;
+    }
 }
 
 static void
-do_swi (void)
+do_ldmstm (void)
 {
-  inst.reloc.type = BFD_RELOC_ARM_SWI;
-  inst.reloc.pc_rel = 0;
+  encode_ldmstm (/*from_push_pop_mnem=*/FALSE);
 }
 
-/* ARM V5E (El Segundo) signed-multiply-accumulate (argument parse)
-   SMLAxy{cond} Rd,Rm,Rs,Rn
-   SMLAWy{cond} Rd,Rm,Rs,Rn
-   Error if any register is R15.  */
-
-static void
-do_smla (void)
-{
-  inst.instruction |= inst.operands[0].reg << 16;
-  inst.instruction |= inst.operands[1].reg;
-  inst.instruction |= inst.operands[2].reg << 8;
-  inst.instruction |= inst.operands[3].reg << 12;
-}
+/* ARMv5TE load-consecutive (argument parse)
+   Mode is like LDRH.
 
-/* ARM V5E (El Segundo) signed-multiply-accumulate-long (argument parse)
-   SMLALxy{cond} Rdlo,Rdhi,Rm,Rs
-   Error if any register is R15.
-   Warning if Rdlo == Rdhi.  */
+     LDRccD R, mode
+     STRccD R, mode.  */
 
 static void
-do_smlal (void)
+do_ldrd (void)
 {
-  inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= inst.operands[1].reg << 16;
-  inst.instruction |= inst.operands[2].reg;
-  inst.instruction |= inst.operands[3].reg << 8;
-
-  if (inst.operands[0].reg == inst.operands[1].reg)
-    as_tsktsk (_("rdhi and rdlo must be different"));
-}
-
-/* ARM V5E (El Segundo) signed-multiply (argument parse)
-   SMULxy{cond} Rd,Rm,Rs
-   Error if any register is R15.  */
+  constraint (inst.operands[0].reg % 2 != 0,
+             _("first transfer register must be even"));
+  constraint (inst.operands[1].present
+             && inst.operands[1].reg != inst.operands[0].reg + 1,
+             _("can only transfer two consecutive registers"));
+  constraint (inst.operands[0].reg == REG_LR, _("r14 not allowed here"));
+  constraint (!inst.operands[2].isreg, _("'[' expected"));
 
-static void
-do_smul (void)
-{
-  inst.instruction |= inst.operands[0].reg << 16;
-  inst.instruction |= inst.operands[1].reg;
-  inst.instruction |= inst.operands[2].reg << 8;
-}
+  if (!inst.operands[1].present)
+    inst.operands[1].reg = inst.operands[0].reg + 1;
 
-/* ARM V6 srs (argument parse).  The variable fields in the encoding are
-   the same for both ARM and Thumb-2.  */
+  /* encode_arm_addr_mode_3 will diagnose overlap between the base
+     register and the first register written; we have to diagnose
+     overlap between the base and the second register written here.  */
 
-static void
-do_srs (void)
-{
-  int reg;
+  if (inst.operands[2].reg == inst.operands[1].reg
+      && (inst.operands[2].writeback || inst.operands[2].postind))
+    as_warn (_("base register written back, and overlaps "
+              "second transfer register"));
 
-  if (inst.operands[0].present)
+  if (!(inst.instruction & V4_STR_BIT))
     {
-      reg = inst.operands[0].reg;
-      constraint (reg != REG_SP, _("SRS base register must be r13"));
+      /* For an index-register load, the index register must not overlap the
+       destination (even if not write-back).  */
+      if (inst.operands[2].immisreg
+             && ((unsigned) inst.operands[2].imm == inst.operands[0].reg
+             || (unsigned) inst.operands[2].imm == inst.operands[1].reg))
+       as_warn (_("index register overlaps transfer register"));
     }
-  else
-    reg = REG_SP;
-
-  inst.instruction |= reg << 16;
-  inst.instruction |= inst.operands[1].imm;
-  if (inst.operands[0].writeback || inst.operands[1].writeback)
-    inst.instruction |= WRITE_BACK;
+  inst.instruction |= inst.operands[0].reg << 12;
+  encode_arm_addr_mode_3 (2, /*is_t=*/FALSE);
 }
 
-/* ARM V6 strex (argument parse).  */
-
 static void
-do_strex (void)
+do_ldrex (void)
 {
-  constraint (!inst.operands[2].isreg || !inst.operands[2].preind
-             || inst.operands[2].postind || inst.operands[2].writeback
-             || inst.operands[2].immisreg || inst.operands[2].shifted
-             || inst.operands[2].negative
-             /* See comment in do_ldrex().  */
-             || (inst.operands[2].reg == REG_PC),
+  constraint (!inst.operands[1].isreg || !inst.operands[1].preind
+             || inst.operands[1].postind || inst.operands[1].writeback
+             || inst.operands[1].immisreg || inst.operands[1].shifted
+             || inst.operands[1].negative
+             /* This can arise if the programmer has written
+                  strex rN, rM, foo
+                or if they have mistakenly used a register name as the last
+                operand,  eg:
+                  strex rN, rM, rX
+                It is very difficult to distinguish between these two cases
+                because "rX" might actually be a label. ie the register
+                name has been occluded by a symbol of the same name. So we
+                just generate a general 'bad addressing mode' type error
+                message and leave it up to the programmer to discover the
+                true cause and fix their mistake.  */
+             || (inst.operands[1].reg == REG_PC),
              BAD_ADDR_MODE);
 
-  constraint (inst.operands[0].reg == inst.operands[1].reg
-             || inst.operands[0].reg == inst.operands[2].reg, BAD_OVERLAP);
-
   constraint (inst.reloc.exp.X_op != O_constant
              || inst.reloc.exp.X_add_number != 0,
              _("offset must be zero in ARM encoding"));
 
+  constraint ((inst.operands[1].reg == REG_PC), BAD_PC);
+
   inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= inst.operands[1].reg;
-  inst.instruction |= inst.operands[2].reg << 16;
+  inst.instruction |= inst.operands[1].reg << 16;
   inst.reloc.type = BFD_RELOC_UNUSED;
 }
 
 static void
-do_strexd (void)
+do_ldrexd (void)
 {
-  constraint (inst.operands[1].reg % 2 != 0,
+  constraint (inst.operands[0].reg % 2 != 0,
              _("even register required"));
-  constraint (inst.operands[2].present
-             && inst.operands[2].reg != inst.operands[1].reg + 1,
-             _("can only store two consecutive registers"));
-  /* If op 2 were present and equal to PC, this function wouldn't
+  constraint (inst.operands[1].present
+             && inst.operands[1].reg != inst.operands[0].reg + 1,
+             _("can only load two consecutive registers"));
+  /* If op 1 were present and equal to PC, this function wouldn't
      have been called in the first place.  */
-  constraint (inst.operands[1].reg == REG_LR, _("r14 not allowed here"));
-
-  constraint (inst.operands[0].reg == inst.operands[1].reg
-             || inst.operands[0].reg == inst.operands[1].reg + 1
-             || inst.operands[0].reg == inst.operands[3].reg,
-             BAD_OVERLAP);
+  constraint (inst.operands[0].reg == REG_LR, _("r14 not allowed here"));
 
   inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= inst.operands[1].reg;
-  inst.instruction |= inst.operands[3].reg << 16;
+  inst.instruction |= inst.operands[2].reg << 16;
 }
 
-/* ARM V6 SXTAH extracts a 16-bit value from a register, sign
-   extends it to 32-bits, and adds the result to a value in another
-   register.  You can specify a rotation by 0, 8, 16, or 24 bits
-   before extracting the 16-bit value.
-   SXTAH{<cond>} <Rd>, <Rn>, <Rm>{, <rotation>}
-   Condition defaults to COND_ALWAYS.
-   Error if any register uses R15.  */
-
+/* In both ARM and thumb state 'ldr pc, #imm'  with an immediate
+   which is not a multiple of four is UNPREDICTABLE.  */
 static void
-do_sxtah (void)
+check_ldr_r15_aligned (void)
 {
-  inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= inst.operands[1].reg << 16;
-  inst.instruction |= inst.operands[2].reg;
-  inst.instruction |= inst.operands[3].imm << 10;
+  constraint (!(inst.operands[1].immisreg)
+             && (inst.operands[0].reg == REG_PC
+             && inst.operands[1].reg == REG_PC
+             && (inst.reloc.exp.X_add_number & 0x3)),
+             _("ldr to register 15 must be 4-byte alligned"));
 }
 
-/* ARM V6 SXTH.
-
-   SXTH {<cond>} <Rd>, <Rm>{, <rotation>}
-   Condition defaults to COND_ALWAYS.
-   Error if any register uses R15.  */
-
 static void
-do_sxth (void)
+do_ldst (void)
 {
   inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= inst.operands[1].reg;
-  inst.instruction |= inst.operands[2].imm << 10;
+  if (!inst.operands[1].isreg)
+    if (move_or_literal_pool (0, CONST_ARM, /*mode_3=*/FALSE))
+      return;
+  encode_arm_addr_mode_2 (1, /*is_t=*/FALSE);
+  check_ldr_r15_aligned ();
 }
-\f
-/* VFP instructions.  In a logical order: SP variant first, monad
-   before dyad, arithmetic then move then load/store.  */
 
 static void
-do_vfp_sp_monadic (void)
+do_ldstt (void)
 {
-  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
-  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Sm);
-}
+  /* ldrt/strt always use post-indexed addressing.  Turn [Rn] into [Rn]! and
+     reject [Rn,...].  */
+  if (inst.operands[1].preind)
+    {
+      constraint (inst.reloc.exp.X_op != O_constant
+                 || inst.reloc.exp.X_add_number != 0,
+                 _("this instruction requires a post-indexed address"));
 
-static void
-do_vfp_sp_dyadic (void)
-{
-  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
-  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Sn);
-  encode_arm_vfp_reg (inst.operands[2].reg, VFP_REG_Sm);
+      inst.operands[1].preind = 0;
+      inst.operands[1].postind = 1;
+      inst.operands[1].writeback = 1;
+    }
+  inst.instruction |= inst.operands[0].reg << 12;
+  encode_arm_addr_mode_2 (1, /*is_t=*/TRUE);
 }
 
-static void
-do_vfp_sp_compare_z (void)
-{
-  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
-}
+/* Halfword and signed-byte load/store operations.  */
 
 static void
-do_vfp_dp_sp_cvt (void)
+do_ldstv4 (void)
 {
-  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
-  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Sm);
+  constraint (inst.operands[0].reg == REG_PC, BAD_PC);
+  inst.instruction |= inst.operands[0].reg << 12;
+  if (!inst.operands[1].isreg)
+    if (move_or_literal_pool (0, CONST_ARM, /*mode_3=*/TRUE))
+      return;
+  encode_arm_addr_mode_3 (1, /*is_t=*/FALSE);
 }
 
 static void
-do_vfp_sp_dp_cvt (void)
+do_ldsttv4 (void)
 {
-  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
-  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dm);
-}
-
-static void
-do_vfp_reg_from_sp (void)
-{
-  inst.instruction |= inst.operands[0].reg << 12;
-  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Sn);
-}
+  /* ldrt/strt always use post-indexed addressing.  Turn [Rn] into [Rn]! and
+     reject [Rn,...].  */
+  if (inst.operands[1].preind)
+    {
+      constraint (inst.reloc.exp.X_op != O_constant
+                 || inst.reloc.exp.X_add_number != 0,
+                 _("this instruction requires a post-indexed address"));
 
-static void
-do_vfp_reg2_from_sp2 (void)
-{
-  constraint (inst.operands[2].imm != 2,
-             _("only two consecutive VFP SP registers allowed here"));
+      inst.operands[1].preind = 0;
+      inst.operands[1].postind = 1;
+      inst.operands[1].writeback = 1;
+    }
   inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= inst.operands[1].reg << 16;
-  encode_arm_vfp_reg (inst.operands[2].reg, VFP_REG_Sm);
+  encode_arm_addr_mode_3 (1, /*is_t=*/TRUE);
 }
 
+/* Co-processor register load/store.
+   Format: <LDC|STC>{cond}[L] CP#,CRd,<address>         */
 static void
-do_vfp_sp_from_reg (void)
+do_lstc (void)
 {
-  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sn);
+  inst.instruction |= inst.operands[0].reg << 8;
   inst.instruction |= inst.operands[1].reg << 12;
+  encode_arm_cp_address (2, TRUE, TRUE, 0);
 }
 
 static void
-do_vfp_sp2_from_reg2 (void)
+do_mlas (void)
 {
-  constraint (inst.operands[0].imm != 2,
-             _("only two consecutive VFP SP registers allowed here"));
-  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sm);
-  inst.instruction |= inst.operands[1].reg << 12;
-  inst.instruction |= inst.operands[2].reg << 16;
+  /* This restriction does not apply to mls (nor to mla in v6 or later).  */
+  if (inst.operands[0].reg == inst.operands[1].reg
+      && !ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6)
+      && !(inst.instruction & 0x00400000))
+    as_tsktsk (_("Rd and Rm should be different in mla"));
+
+  inst.instruction |= inst.operands[0].reg << 16;
+  inst.instruction |= inst.operands[1].reg;
+  inst.instruction |= inst.operands[2].reg << 8;
+  inst.instruction |= inst.operands[3].reg << 12;
 }
 
 static void
-do_vfp_sp_ldst (void)
+do_mov (void)
 {
-  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
-  encode_arm_cp_address (1, FALSE, TRUE, 0);
+  constraint (inst.reloc.type >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
+             && inst.reloc.type <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC ,
+             THUMB1_RELOC_ONLY);
+  inst.instruction |= inst.operands[0].reg << 12;
+  encode_arm_shifter_operand (1);
 }
 
+/* ARM V6T2 16-bit immediate register load: MOV[WT]{cond} Rd, #<imm16>.         */
 static void
-do_vfp_dp_ldst (void)
+do_mov16 (void)
 {
-  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
-  encode_arm_cp_address (1, FALSE, TRUE, 0);
+  bfd_vma imm;
+  bfd_boolean top;
+
+  top = (inst.instruction & 0x00400000) != 0;
+  constraint (top && inst.reloc.type == BFD_RELOC_ARM_MOVW,
+             _(":lower16: not allowed this instruction"));
+  constraint (!top && inst.reloc.type == BFD_RELOC_ARM_MOVT,
+             _(":upper16: not allowed instruction"));
+  inst.instruction |= inst.operands[0].reg << 12;
+  if (inst.reloc.type == BFD_RELOC_UNUSED)
+    {
+      imm = inst.reloc.exp.X_add_number;
+      /* The value is in two pieces: 0:11, 16:19.  */
+      inst.instruction |= (imm & 0x00000fff);
+      inst.instruction |= (imm & 0x0000f000) << 4;
+    }
 }
 
+static int
+do_vfp_nsyn_mrs (void)
+{
+  if (inst.operands[0].isvec)
+    {
+      if (inst.operands[1].reg != 1)
+       first_error (_("operand 1 must be FPSCR"));
+      memset (&inst.operands[0], '\0', sizeof (inst.operands[0]));
+      memset (&inst.operands[1], '\0', sizeof (inst.operands[1]));
+      do_vfp_nsyn_opcode ("fmstat");
+    }
+  else if (inst.operands[1].isvec)
+    do_vfp_nsyn_opcode ("fmrx");
+  else
+    return FAIL;
+
+  return SUCCESS;
+}
 
-static void
-vfp_sp_ldstm (enum vfp_ldstm_type ldstm_type)
+static int
+do_vfp_nsyn_msr (void)
 {
-  if (inst.operands[0].writeback)
-    inst.instruction |= WRITE_BACK;
+  if (inst.operands[0].isvec)
+    do_vfp_nsyn_opcode ("fmxr");
   else
-    constraint (ldstm_type != VFP_LDSTMIA,
-               _("this addressing mode requires base-register writeback"));
-  inst.instruction |= inst.operands[0].reg << 16;
-  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Sd);
-  inst.instruction |= inst.operands[1].imm;
+    return FAIL;
+
+  return SUCCESS;
 }
 
 static void
-vfp_dp_ldstm (enum vfp_ldstm_type ldstm_type)
+do_vmrs (void)
 {
-  int count;
-
-  if (inst.operands[0].writeback)
-    inst.instruction |= WRITE_BACK;
-  else
-    constraint (ldstm_type != VFP_LDSTMIA && ldstm_type != VFP_LDSTMIAX,
-               _("this addressing mode requires base-register writeback"));
+  unsigned Rt = inst.operands[0].reg;
 
-  inst.instruction |= inst.operands[0].reg << 16;
-  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dd);
+  if (thumb_mode && Rt == REG_SP)
+    {
+      inst.error = BAD_SP;
+      return;
+    }
 
-  count = inst.operands[1].imm << 1;
-  if (ldstm_type == VFP_LDSTMIAX || ldstm_type == VFP_LDSTMDBX)
-    count += 1;
+  /* APSR_ sets isvec. All other refs to PC are illegal.  */
+  if (!inst.operands[0].isvec && Rt == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
 
-  inst.instruction |= count;
+  /* If we get through parsing the register name, we just insert the number
+     generated into the instruction without further validation.  */
+  inst.instruction |= (inst.operands[1].reg << 16);
+  inst.instruction |= (Rt << 12);
 }
 
 static void
-do_vfp_sp_ldstmia (void)
+do_vmsr (void)
 {
-  vfp_sp_ldstm (VFP_LDSTMIA);
+  unsigned Rt = inst.operands[1].reg;
+
+  if (thumb_mode)
+    reject_bad_reg (Rt);
+  else if (Rt == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
+
+  /* If we get through parsing the register name, we just insert the number
+     generated into the instruction without further validation.  */
+  inst.instruction |= (inst.operands[0].reg << 16);
+  inst.instruction |= (Rt << 12);
 }
 
 static void
-do_vfp_sp_ldstmdb (void)
+do_mrs (void)
 {
-  vfp_sp_ldstm (VFP_LDSTMDB);
+  unsigned br;
+
+  if (do_vfp_nsyn_mrs () == SUCCESS)
+    return;
+
+  constraint (inst.operands[0].reg == REG_PC, BAD_PC);
+  inst.instruction |= inst.operands[0].reg << 12;
+
+  if (inst.operands[1].isreg)
+    {
+      br = inst.operands[1].reg;
+      if (((br & 0x200) == 0) && ((br & 0xf0000) != 0xf000))
+       as_bad (_("bad register for mrs"));
+    }
+  else
+    {
+      /* mrs only accepts CPSR/SPSR/CPSR_all/SPSR_all.  */
+      constraint ((inst.operands[1].imm & (PSR_c|PSR_x|PSR_s|PSR_f))
+                 != (PSR_c|PSR_f),
+                 _("'APSR', 'CPSR' or 'SPSR' expected"));
+      br = (15<<16) | (inst.operands[1].imm & SPSR_BIT);
+    }
+
+  inst.instruction |= br;
 }
 
+/* Two possible forms:
+      "{C|S}PSR_<field>, Rm",
+      "{C|S}PSR_f, #expression".  */
+
 static void
-do_vfp_dp_ldstmia (void)
+do_msr (void)
 {
-  vfp_dp_ldstm (VFP_LDSTMIA);
+  if (do_vfp_nsyn_msr () == SUCCESS)
+    return;
+
+  inst.instruction |= inst.operands[0].imm;
+  if (inst.operands[1].isreg)
+    inst.instruction |= inst.operands[1].reg;
+  else
+    {
+      inst.instruction |= INST_IMMEDIATE;
+      inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
+      inst.reloc.pc_rel = 0;
+    }
 }
 
 static void
-do_vfp_dp_ldstmdb (void)
+do_mul (void)
 {
-  vfp_dp_ldstm (VFP_LDSTMDB);
+  constraint (inst.operands[2].reg == REG_PC, BAD_PC);
+
+  if (!inst.operands[2].present)
+    inst.operands[2].reg = inst.operands[0].reg;
+  inst.instruction |= inst.operands[0].reg << 16;
+  inst.instruction |= inst.operands[1].reg;
+  inst.instruction |= inst.operands[2].reg << 8;
+
+  if (inst.operands[0].reg == inst.operands[1].reg
+      && !ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6))
+    as_tsktsk (_("Rd and Rm should be different in mul"));
 }
 
+/* Long Multiply Parser
+   UMULL RdLo, RdHi, Rm, Rs
+   SMULL RdLo, RdHi, Rm, Rs
+   UMLAL RdLo, RdHi, Rm, Rs
+   SMLAL RdLo, RdHi, Rm, Rs.  */
+
 static void
-do_vfp_xp_ldstmia (void)
+do_mull (void)
 {
-  vfp_dp_ldstm (VFP_LDSTMIAX);
+  inst.instruction |= inst.operands[0].reg << 12;
+  inst.instruction |= inst.operands[1].reg << 16;
+  inst.instruction |= inst.operands[2].reg;
+  inst.instruction |= inst.operands[3].reg << 8;
+
+  /* rdhi and rdlo must be different.  */
+  if (inst.operands[0].reg == inst.operands[1].reg)
+    as_tsktsk (_("rdhi and rdlo must be different"));
+
+  /* rdhi, rdlo and rm must all be different before armv6.  */
+  if ((inst.operands[0].reg == inst.operands[2].reg
+      || inst.operands[1].reg == inst.operands[2].reg)
+      && !ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6))
+    as_tsktsk (_("rdhi, rdlo and rm must all be different"));
 }
 
 static void
-do_vfp_xp_ldstmdb (void)
+do_nop (void)
 {
-  vfp_dp_ldstm (VFP_LDSTMDBX);
+  if (inst.operands[0].present
+      || ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6k))
+    {
+      /* Architectural NOP hints are CPSR sets with no bits selected.  */
+      inst.instruction &= 0xf0000000;
+      inst.instruction |= 0x0320f000;
+      if (inst.operands[0].present)
+       inst.instruction |= inst.operands[0].imm;
+    }
 }
 
+/* ARM V6 Pack Halfword Bottom Top instruction (argument parse).
+   PKHBT {<cond>} <Rd>, <Rn>, <Rm> {, LSL #<shift_imm>}
+   Condition defaults to COND_ALWAYS.
+   Error if Rd, Rn or Rm are R15.  */
+
 static void
-do_vfp_dp_rd_rm (void)
+do_pkhbt (void)
 {
-  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
-  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dm);
+  inst.instruction |= inst.operands[0].reg << 12;
+  inst.instruction |= inst.operands[1].reg << 16;
+  inst.instruction |= inst.operands[2].reg;
+  if (inst.operands[3].present)
+    encode_arm_shift (3);
 }
 
-static void
-do_vfp_dp_rn_rd (void)
-{
-  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dn);
-  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dd);
-}
+/* ARM V6 PKHTB (Argument Parse).  */
 
 static void
-do_vfp_dp_rd_rn (void)
+do_pkhtb (void)
 {
-  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
-  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dn);
+  if (!inst.operands[3].present)
+    {
+      /* If the shift specifier is omitted, turn the instruction
+        into pkhbt rd, rm, rn. */
+      inst.instruction &= 0xfff00010;
+      inst.instruction |= inst.operands[0].reg << 12;
+      inst.instruction |= inst.operands[1].reg;
+      inst.instruction |= inst.operands[2].reg << 16;
+    }
+  else
+    {
+      inst.instruction |= inst.operands[0].reg << 12;
+      inst.instruction |= inst.operands[1].reg << 16;
+      inst.instruction |= inst.operands[2].reg;
+      encode_arm_shift (3);
+    }
 }
 
-static void
-do_vfp_dp_rd_rn_rm (void)
-{
-  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
-  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dn);
-  encode_arm_vfp_reg (inst.operands[2].reg, VFP_REG_Dm);
-}
+/* ARMv5TE: Preload-Cache
+   MP Extensions: Preload for write
 
-static void
-do_vfp_dp_rd (void)
-{
-  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
-}
+    PLD(W) <addr_mode>
+
+  Syntactically, like LDR with B=1, W=0, L=1.  */
 
 static void
-do_vfp_dp_rm_rd_rn (void)
+do_pld (void)
 {
-  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dm);
-  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dd);
-  encode_arm_vfp_reg (inst.operands[2].reg, VFP_REG_Dn);
+  constraint (!inst.operands[0].isreg,
+             _("'[' expected after PLD mnemonic"));
+  constraint (inst.operands[0].postind,
+             _("post-indexed expression used in preload instruction"));
+  constraint (inst.operands[0].writeback,
+             _("writeback used in preload instruction"));
+  constraint (!inst.operands[0].preind,
+             _("unindexed addressing used in preload instruction"));
+  encode_arm_addr_mode_2 (0, /*is_t=*/FALSE);
 }
 
-/* VFPv3 instructions.  */
+/* ARMv7: PLI <addr_mode>  */
 static void
-do_vfp_sp_const (void)
+do_pli (void)
 {
-  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
-  inst.instruction |= (inst.operands[1].imm & 0xf0) << 12;
-  inst.instruction |= (inst.operands[1].imm & 0x0f);
+  constraint (!inst.operands[0].isreg,
+             _("'[' expected after PLI mnemonic"));
+  constraint (inst.operands[0].postind,
+             _("post-indexed expression used in preload instruction"));
+  constraint (inst.operands[0].writeback,
+             _("writeback used in preload instruction"));
+  constraint (!inst.operands[0].preind,
+             _("unindexed addressing used in preload instruction"));
+  encode_arm_addr_mode_2 (0, /*is_t=*/FALSE);
+  inst.instruction &= ~PRE_INDEX;
 }
 
 static void
-do_vfp_dp_const (void)
+do_push_pop (void)
 {
-  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
-  inst.instruction |= (inst.operands[1].imm & 0xf0) << 12;
-  inst.instruction |= (inst.operands[1].imm & 0x0f);
+  constraint (inst.operands[0].writeback,
+             _("push/pop do not support {reglist}^"));
+  inst.operands[1] = inst.operands[0];
+  memset (&inst.operands[0], 0, sizeof inst.operands[0]);
+  inst.operands[0].isreg = 1;
+  inst.operands[0].writeback = 1;
+  inst.operands[0].reg = REG_SP;
+  encode_ldmstm (/*from_push_pop_mnem=*/TRUE);
 }
 
+/* ARM V6 RFE (Return from Exception) loads the PC and CPSR from the
+   word at the specified address and the following word
+   respectively.
+   Unconditionally executed.
+   Error if Rn is R15. */
+
 static void
-vfp_conv (int srcsize)
+do_rfe (void)
 {
-  unsigned immbits = srcsize - inst.operands[1].imm;
-  inst.instruction |= (immbits & 1) << 5;
-  inst.instruction |= (immbits >> 1);
+  inst.instruction |= inst.operands[0].reg << 16;
+  if (inst.operands[0].writeback)
+    inst.instruction |= WRITE_BACK;
 }
 
+/* ARM V6 ssat (argument parse).  */
+
 static void
-do_vfp_sp_conv_16 (void)
+do_ssat (void)
 {
-  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
-  vfp_conv (16);
+  inst.instruction |= inst.operands[0].reg << 12;
+  inst.instruction |= (inst.operands[1].imm - 1) << 16;
+  inst.instruction |= inst.operands[2].reg;
+
+  if (inst.operands[3].present)
+    encode_arm_shift (3);
 }
 
+/* ARM V6 usat (argument parse).  */
+
 static void
-do_vfp_dp_conv_16 (void)
+do_usat (void)
 {
-  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
-  vfp_conv (16);
+  inst.instruction |= inst.operands[0].reg << 12;
+  inst.instruction |= inst.operands[1].imm << 16;
+  inst.instruction |= inst.operands[2].reg;
+
+  if (inst.operands[3].present)
+    encode_arm_shift (3);
 }
 
+/* ARM V6 ssat16 (argument parse).  */
+
 static void
-do_vfp_sp_conv_32 (void)
+do_ssat16 (void)
 {
-  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
-  vfp_conv (32);
+  inst.instruction |= inst.operands[0].reg << 12;
+  inst.instruction |= ((inst.operands[1].imm - 1) << 16);
+  inst.instruction |= inst.operands[2].reg;
 }
 
 static void
-do_vfp_dp_conv_32 (void)
+do_usat16 (void)
 {
-  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
-  vfp_conv (32);
+  inst.instruction |= inst.operands[0].reg << 12;
+  inst.instruction |= inst.operands[1].imm << 16;
+  inst.instruction |= inst.operands[2].reg;
 }
-\f
-/* FPA instructions.  Also in a logical order. */
+
+/* ARM V6 SETEND (argument parse).  Sets the E bit in the CPSR while
+   preserving the other bits.
+
+   setend <endian_specifier>, where <endian_specifier> is either
+   BE or LE.  */
 
 static void
-do_fpa_cmp (void)
+do_setend (void)
 {
-  inst.instruction |= inst.operands[0].reg << 16;
-  inst.instruction |= inst.operands[1].reg;
+  if (warn_on_deprecated
+      && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v8))
+      as_tsktsk (_("setend use is deprecated for ARMv8"));
+
+  if (inst.operands[0].imm)
+    inst.instruction |= 0x200;
 }
 
 static void
-do_fpa_ldmstm (void)
+do_shift (void)
 {
-  inst.instruction |= inst.operands[0].reg << 12;
-  switch (inst.operands[1].imm)
-    {
-    case 1: inst.instruction |= CP_T_X;                 break;
-    case 2: inst.instruction |= CP_T_Y;                 break;
-    case 3: inst.instruction |= CP_T_Y | CP_T_X; break;
-    case 4:                                     break;
-    default: abort ();
-    }
+  unsigned int Rm = (inst.operands[1].present
+                    ? inst.operands[1].reg
+                    : inst.operands[0].reg);
 
-  if (inst.instruction & (PRE_INDEX | INDEX_UP))
+  inst.instruction |= inst.operands[0].reg << 12;
+  inst.instruction |= Rm;
+  if (inst.operands[2].isreg)  /* Rd, {Rm,} Rs */
     {
-      /* The instruction specified "ea" or "fd", so we can only accept
-        [Rn]{!}.  The instruction does not really support stacking or
-        unstacking, so we have to emulate these by setting appropriate
-        bits and offsets.  */
-      constraint (inst.reloc.exp.X_op != O_constant
-                 || inst.reloc.exp.X_add_number != 0,
-                 _("this instruction does not support indexing"));
-
-      if ((inst.instruction & PRE_INDEX) || inst.operands[2].writeback)
-       inst.reloc.exp.X_add_number = 12 * inst.operands[1].imm;
-
-      if (!(inst.instruction & INDEX_UP))
-       inst.reloc.exp.X_add_number = -inst.reloc.exp.X_add_number;
-
-      if (!(inst.instruction & PRE_INDEX) && inst.operands[2].writeback)
-       {
-         inst.operands[2].preind = 0;
-         inst.operands[2].postind = 1;
-       }
+      inst.instruction |= inst.operands[2].reg << 8;
+      inst.instruction |= SHIFT_BY_REG;
+      /* PR 12854: Error on extraneous shifts.  */
+      constraint (inst.operands[2].shifted,
+                 _("extraneous shift as part of operand to shift insn"));
     }
-
-  encode_arm_cp_address (2, TRUE, TRUE, 0);
+  else
+    inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM;
 }
-\f
-/* iWMMXt instructions: strictly in alphabetical order.         */
 
 static void
-do_iwmmxt_tandorc (void)
+do_smc (void)
 {
-  constraint (inst.operands[0].reg != REG_PC, _("only r15 allowed here"));
+  inst.reloc.type = BFD_RELOC_ARM_SMC;
+  inst.reloc.pc_rel = 0;
 }
 
 static void
-do_iwmmxt_textrc (void)
+do_hvc (void)
 {
-  inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= inst.operands[1].imm;
+  inst.reloc.type = BFD_RELOC_ARM_HVC;
+  inst.reloc.pc_rel = 0;
 }
 
 static void
-do_iwmmxt_textrm (void)
+do_swi (void)
 {
-  inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= inst.operands[1].reg << 16;
-  inst.instruction |= inst.operands[2].imm;
+  inst.reloc.type = BFD_RELOC_ARM_SWI;
+  inst.reloc.pc_rel = 0;
 }
 
 static void
-do_iwmmxt_tinsr (void)
+do_setpan (void)
 {
-  inst.instruction |= inst.operands[0].reg << 16;
-  inst.instruction |= inst.operands[1].reg << 12;
-  inst.instruction |= inst.operands[2].imm;
+  constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_pan),
+             _("selected processor does not support SETPAN instruction"));
+
+  inst.instruction |= ((inst.operands[0].imm & 1) << 9);
 }
 
 static void
-do_iwmmxt_tmia (void)
+do_t_setpan (void)
 {
-  inst.instruction |= inst.operands[0].reg << 5;
-  inst.instruction |= inst.operands[1].reg;
-  inst.instruction |= inst.operands[2].reg << 12;
+  constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_pan),
+             _("selected processor does not support SETPAN instruction"));
+
+  inst.instruction |= (inst.operands[0].imm << 3);
 }
 
+/* ARM V5E (El Segundo) signed-multiply-accumulate (argument parse)
+   SMLAxy{cond} Rd,Rm,Rs,Rn
+   SMLAWy{cond} Rd,Rm,Rs,Rn
+   Error if any register is R15.  */
+
 static void
-do_iwmmxt_waligni (void)
+do_smla (void)
 {
-  inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= inst.operands[1].reg << 16;
-  inst.instruction |= inst.operands[2].reg;
-  inst.instruction |= inst.operands[3].imm << 20;
+  inst.instruction |= inst.operands[0].reg << 16;
+  inst.instruction |= inst.operands[1].reg;
+  inst.instruction |= inst.operands[2].reg << 8;
+  inst.instruction |= inst.operands[3].reg << 12;
 }
 
+/* ARM V5E (El Segundo) signed-multiply-accumulate-long (argument parse)
+   SMLALxy{cond} Rdlo,Rdhi,Rm,Rs
+   Error if any register is R15.
+   Warning if Rdlo == Rdhi.  */
+
 static void
-do_iwmmxt_wmerge (void)
+do_smlal (void)
 {
   inst.instruction |= inst.operands[0].reg << 12;
   inst.instruction |= inst.operands[1].reg << 16;
   inst.instruction |= inst.operands[2].reg;
-  inst.instruction |= inst.operands[3].imm << 21;
+  inst.instruction |= inst.operands[3].reg << 8;
+
+  if (inst.operands[0].reg == inst.operands[1].reg)
+    as_tsktsk (_("rdhi and rdlo must be different"));
 }
 
-static void
-do_iwmmxt_wmov (void)
-{
-  /* WMOV rD, rN is an alias for WOR rD, rN, rN.  */
-  inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= inst.operands[1].reg << 16;
-  inst.instruction |= inst.operands[1].reg;
-}
+/* ARM V5E (El Segundo) signed-multiply (argument parse)
+   SMULxy{cond} Rd,Rm,Rs
+   Error if any register is R15.  */
 
 static void
-do_iwmmxt_wldstbh (void)
+do_smul (void)
 {
-  int reloc;
-  inst.instruction |= inst.operands[0].reg << 12;
-  if (thumb_mode)
-    reloc = BFD_RELOC_ARM_T32_CP_OFF_IMM_S2;
-  else
-    reloc = BFD_RELOC_ARM_CP_OFF_IMM_S2;
-  encode_arm_cp_address (1, TRUE, FALSE, reloc);
+  inst.instruction |= inst.operands[0].reg << 16;
+  inst.instruction |= inst.operands[1].reg;
+  inst.instruction |= inst.operands[2].reg << 8;
 }
 
-static void
-do_iwmmxt_wldstw (void)
-{
-  /* RIWR_RIWC clears .isreg for a control register.  */
-  if (!inst.operands[0].isreg)
-    {
-      constraint (inst.cond != COND_ALWAYS, BAD_COND);
-      inst.instruction |= 0xf0000000;
-    }
-
-  inst.instruction |= inst.operands[0].reg << 12;
-  encode_arm_cp_address (1, TRUE, TRUE, 0);
-}
+/* ARM V6 srs (argument parse).  The variable fields in the encoding are
+   the same for both ARM and Thumb-2.  */
 
 static void
-do_iwmmxt_wldstd (void)
+do_srs (void)
 {
-  inst.instruction |= inst.operands[0].reg << 12;
-  if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt2)
-      && inst.operands[1].immisreg)
+  int reg;
+
+  if (inst.operands[0].present)
     {
-      inst.instruction &= ~0x1a000ff;
-      inst.instruction |= (0xf << 28);
-      if (inst.operands[1].preind)
-       inst.instruction |= PRE_INDEX;
-      if (!inst.operands[1].negative)
-       inst.instruction |= INDEX_UP;
-      if (inst.operands[1].writeback)
-       inst.instruction |= WRITE_BACK;
-      inst.instruction |= inst.operands[1].reg << 16;
-      inst.instruction |= inst.reloc.exp.X_add_number << 4;
-      inst.instruction |= inst.operands[1].imm;
+      reg = inst.operands[0].reg;
+      constraint (reg != REG_SP, _("SRS base register must be r13"));
     }
   else
-    encode_arm_cp_address (1, TRUE, FALSE, 0);
+    reg = REG_SP;
+
+  inst.instruction |= reg << 16;
+  inst.instruction |= inst.operands[1].imm;
+  if (inst.operands[0].writeback || inst.operands[1].writeback)
+    inst.instruction |= WRITE_BACK;
 }
 
+/* ARM V6 strex (argument parse).  */
+
 static void
-do_iwmmxt_wshufh (void)
+do_strex (void)
 {
+  constraint (!inst.operands[2].isreg || !inst.operands[2].preind
+             || inst.operands[2].postind || inst.operands[2].writeback
+             || inst.operands[2].immisreg || inst.operands[2].shifted
+             || inst.operands[2].negative
+             /* See comment in do_ldrex().  */
+             || (inst.operands[2].reg == REG_PC),
+             BAD_ADDR_MODE);
+
+  constraint (inst.operands[0].reg == inst.operands[1].reg
+             || inst.operands[0].reg == inst.operands[2].reg, BAD_OVERLAP);
+
+  constraint (inst.reloc.exp.X_op != O_constant
+             || inst.reloc.exp.X_add_number != 0,
+             _("offset must be zero in ARM encoding"));
+
   inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= inst.operands[1].reg << 16;
-  inst.instruction |= ((inst.operands[2].imm & 0xf0) << 16);
-  inst.instruction |= (inst.operands[2].imm & 0x0f);
+  inst.instruction |= inst.operands[1].reg;
+  inst.instruction |= inst.operands[2].reg << 16;
+  inst.reloc.type = BFD_RELOC_UNUSED;
 }
 
 static void
-do_iwmmxt_wzero (void)
+do_t_strexbh (void)
 {
-  /* WZERO reg is an alias for WANDN reg, reg, reg.  */
-  inst.instruction |= inst.operands[0].reg;
-  inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= inst.operands[0].reg << 16;
+  constraint (!inst.operands[2].isreg || !inst.operands[2].preind
+             || inst.operands[2].postind || inst.operands[2].writeback
+             || inst.operands[2].immisreg || inst.operands[2].shifted
+             || inst.operands[2].negative,
+             BAD_ADDR_MODE);
+
+  constraint (inst.operands[0].reg == inst.operands[1].reg
+             || inst.operands[0].reg == inst.operands[2].reg, BAD_OVERLAP);
+
+  do_rm_rd_rn ();
 }
 
 static void
-do_iwmmxt_wrwrwr_or_imm5 (void)
+do_strexd (void)
 {
-  if (inst.operands[2].isreg)
-    do_rd_rn_rm ();
-  else {
-    constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt2),
-               _("immediate operand requires iWMMXt2"));
-    do_rd_rn ();
-    if (inst.operands[2].imm == 0)
-      {
-       switch ((inst.instruction >> 20) & 0xf)
-         {
-         case 4:
-         case 5:
-         case 6:
-         case 7:
-           /* w...h wrd, wrn, #0 -> wrorh wrd, wrn, #16.  */
-           inst.operands[2].imm = 16;
-           inst.instruction = (inst.instruction & 0xff0fffff) | (0x7 << 20);
-           break;
-         case 8:
-         case 9:
-         case 10:
-         case 11:
-           /* w...w wrd, wrn, #0 -> wrorw wrd, wrn, #32.  */
-           inst.operands[2].imm = 32;
-           inst.instruction = (inst.instruction & 0xff0fffff) | (0xb << 20);
-           break;
-         case 12:
-         case 13:
-         case 14:
-         case 15:
-           {
-             /* w...d wrd, wrn, #0 -> wor wrd, wrn, wrn.  */
-             unsigned long wrn;
-             wrn = (inst.instruction >> 16) & 0xf;
-             inst.instruction &= 0xff0fff0f;
-             inst.instruction |= wrn;
-             /* Bail out here; the instruction is now assembled.  */
-             return;
-           }
-         }
-      }
-    /* Map 32 -> 0, etc.  */
-    inst.operands[2].imm &= 0x1f;
-    inst.instruction |= (0xf << 28) | ((inst.operands[2].imm & 0x10) << 4) | (inst.operands[2].imm & 0xf);
-  }
-}
-\f
-/* Cirrus Maverick instructions.  Simple 2-, 3-, and 4-register
-   operations first, then control, shift, and load/store.  */
+  constraint (inst.operands[1].reg % 2 != 0,
+             _("even register required"));
+  constraint (inst.operands[2].present
+             && inst.operands[2].reg != inst.operands[1].reg + 1,
+             _("can only store two consecutive registers"));
+  /* If op 2 were present and equal to PC, this function wouldn't
+     have been called in the first place.  */
+  constraint (inst.operands[1].reg == REG_LR, _("r14 not allowed here"));
 
-/* Insns like "foo X,Y,Z".  */
+  constraint (inst.operands[0].reg == inst.operands[1].reg
+             || inst.operands[0].reg == inst.operands[1].reg + 1
+             || inst.operands[0].reg == inst.operands[3].reg,
+             BAD_OVERLAP);
 
-static void
-do_mav_triple (void)
-{
-  inst.instruction |= inst.operands[0].reg << 16;
+  inst.instruction |= inst.operands[0].reg << 12;
   inst.instruction |= inst.operands[1].reg;
-  inst.instruction |= inst.operands[2].reg << 12;
+  inst.instruction |= inst.operands[3].reg << 16;
 }
 
-/* Insns like "foo W,X,Y,Z".
-    where W=MVAX[0:3] and X,Y,Z=MVFX[0:15].  */
-
+/* ARM V8 STRL.  */
 static void
-do_mav_quad (void)
+do_stlex (void)
 {
-  inst.instruction |= inst.operands[0].reg << 5;
-  inst.instruction |= inst.operands[1].reg << 12;
-  inst.instruction |= inst.operands[2].reg << 16;
-  inst.instruction |= inst.operands[3].reg;
+  constraint (inst.operands[0].reg == inst.operands[1].reg
+             || inst.operands[0].reg == inst.operands[2].reg, BAD_OVERLAP);
+
+  do_rd_rm_rn ();
 }
 
-/* cfmvsc32<cond> DSPSC,MVDX[15:0].  */
 static void
-do_mav_dspsc (void)
+do_t_stlex (void)
 {
-  inst.instruction |= inst.operands[1].reg << 12;
+  constraint (inst.operands[0].reg == inst.operands[1].reg
+             || inst.operands[0].reg == inst.operands[2].reg, BAD_OVERLAP);
+
+  do_rm_rd_rn ();
 }
 
-/* Maverick shift immediate instructions.
-   cfsh32<cond> MVFX[15:0],MVFX[15:0],Shift[6:0].
-   cfsh64<cond> MVDX[15:0],MVDX[15:0],Shift[6:0].  */
+/* ARM V6 SXTAH extracts a 16-bit value from a register, sign
+   extends it to 32-bits, and adds the result to a value in another
+   register.  You can specify a rotation by 0, 8, 16, or 24 bits
+   before extracting the 16-bit value.
+   SXTAH{<cond>} <Rd>, <Rn>, <Rm>{, <rotation>}
+   Condition defaults to COND_ALWAYS.
+   Error if any register uses R15.  */
 
 static void
-do_mav_shift (void)
+do_sxtah (void)
 {
-  int imm = inst.operands[2].imm;
-
   inst.instruction |= inst.operands[0].reg << 12;
   inst.instruction |= inst.operands[1].reg << 16;
-
-  /* Bits 0-3 of the insn should have bits 0-3 of the immediate.
-     Bits 5-7 of the insn should have bits 4-6 of the immediate.
-     Bit 4 should be 0.         */
-  imm = (imm & 0xf) | ((imm & 0x70) << 1);
-
-  inst.instruction |= imm;
+  inst.instruction |= inst.operands[2].reg;
+  inst.instruction |= inst.operands[3].imm << 10;
 }
-\f
-/* XScale instructions.         Also sorted arithmetic before move.  */
 
-/* Xscale multiply-accumulate (argument parse)
-     MIAcc   acc0,Rm,Rs
-     MIAPHcc acc0,Rm,Rs
-     MIAxycc acc0,Rm,Rs.  */
+/* ARM V6 SXTH.
+
+   SXTH {<cond>} <Rd>, <Rm>{, <rotation>}
+   Condition defaults to COND_ALWAYS.
+   Error if any register uses R15.  */
 
 static void
-do_xsc_mia (void)
+do_sxth (void)
 {
+  inst.instruction |= inst.operands[0].reg << 12;
   inst.instruction |= inst.operands[1].reg;
-  inst.instruction |= inst.operands[2].reg << 12;
+  inst.instruction |= inst.operands[2].imm << 10;
 }
-
-/* Xscale move-accumulator-register (argument parse)
-
-     MARcc   acc0,RdLo,RdHi.  */
+\f
+/* VFP instructions.  In a logical order: SP variant first, monad
+   before dyad, arithmetic then move then load/store.  */
 
 static void
-do_xsc_mar (void)
+do_vfp_sp_monadic (void)
 {
-  inst.instruction |= inst.operands[1].reg << 12;
-  inst.instruction |= inst.operands[2].reg << 16;
+  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
+  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Sm);
 }
 
-/* Xscale move-register-accumulator (argument parse)
-
-     MRAcc   RdLo,RdHi,acc0.  */
-
 static void
-do_xsc_mra (void)
+do_vfp_sp_dyadic (void)
 {
-  constraint (inst.operands[0].reg == inst.operands[1].reg, BAD_OVERLAP);
-  inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= inst.operands[1].reg << 16;
+  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
+  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Sn);
+  encode_arm_vfp_reg (inst.operands[2].reg, VFP_REG_Sm);
 }
-\f
-/* Encoding functions relevant only to Thumb.  */
 
-/* inst.operands[i] is a shifted-register operand; encode
-   it into inst.instruction in the format used by Thumb32.  */
+static void
+do_vfp_sp_compare_z (void)
+{
+  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
+}
 
 static void
-encode_thumb32_shifted_operand (int i)
+do_vfp_dp_sp_cvt (void)
 {
-  unsigned int value = inst.reloc.exp.X_add_number;
-  unsigned int shift = inst.operands[i].shift_kind;
+  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
+  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Sm);
+}
 
-  constraint (inst.operands[i].immisreg,
-             _("shift by register not allowed in thumb mode"));
-  inst.instruction |= inst.operands[i].reg;
-  if (shift == SHIFT_RRX)
-    inst.instruction |= SHIFT_ROR << 4;
+static void
+do_vfp_sp_dp_cvt (void)
+{
+  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
+  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dm);
+}
+
+static void
+do_vfp_reg_from_sp (void)
+{
+  inst.instruction |= inst.operands[0].reg << 12;
+  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Sn);
+}
+
+static void
+do_vfp_reg2_from_sp2 (void)
+{
+  constraint (inst.operands[2].imm != 2,
+             _("only two consecutive VFP SP registers allowed here"));
+  inst.instruction |= inst.operands[0].reg << 12;
+  inst.instruction |= inst.operands[1].reg << 16;
+  encode_arm_vfp_reg (inst.operands[2].reg, VFP_REG_Sm);
+}
+
+static void
+do_vfp_sp_from_reg (void)
+{
+  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sn);
+  inst.instruction |= inst.operands[1].reg << 12;
+}
+
+static void
+do_vfp_sp2_from_reg2 (void)
+{
+  constraint (inst.operands[0].imm != 2,
+             _("only two consecutive VFP SP registers allowed here"));
+  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sm);
+  inst.instruction |= inst.operands[1].reg << 12;
+  inst.instruction |= inst.operands[2].reg << 16;
+}
+
+static void
+do_vfp_sp_ldst (void)
+{
+  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
+  encode_arm_cp_address (1, FALSE, TRUE, 0);
+}
+
+static void
+do_vfp_dp_ldst (void)
+{
+  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
+  encode_arm_cp_address (1, FALSE, TRUE, 0);
+}
+
+
+static void
+vfp_sp_ldstm (enum vfp_ldstm_type ldstm_type)
+{
+  if (inst.operands[0].writeback)
+    inst.instruction |= WRITE_BACK;
   else
-    {
-      constraint (inst.reloc.exp.X_op != O_constant,
-                 _("expression too complex"));
+    constraint (ldstm_type != VFP_LDSTMIA,
+               _("this addressing mode requires base-register writeback"));
+  inst.instruction |= inst.operands[0].reg << 16;
+  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Sd);
+  inst.instruction |= inst.operands[1].imm;
+}
 
-      constraint (value > 32
-                 || (value == 32 && (shift == SHIFT_LSL
-                                     || shift == SHIFT_ROR)),
-                 _("shift expression is too large"));
+static void
+vfp_dp_ldstm (enum vfp_ldstm_type ldstm_type)
+{
+  int count;
 
-      if (value == 0)
-       shift = SHIFT_LSL;
-      else if (value == 32)
-       value = 0;
+  if (inst.operands[0].writeback)
+    inst.instruction |= WRITE_BACK;
+  else
+    constraint (ldstm_type != VFP_LDSTMIA && ldstm_type != VFP_LDSTMIAX,
+               _("this addressing mode requires base-register writeback"));
 
-      inst.instruction |= shift << 4;
-      inst.instruction |= (value & 0x1c) << 10;
-      inst.instruction |= (value & 0x03) << 6;
-    }
+  inst.instruction |= inst.operands[0].reg << 16;
+  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dd);
+
+  count = inst.operands[1].imm << 1;
+  if (ldstm_type == VFP_LDSTMIAX || ldstm_type == VFP_LDSTMDBX)
+    count += 1;
+
+  inst.instruction |= count;
 }
 
+static void
+do_vfp_sp_ldstmia (void)
+{
+  vfp_sp_ldstm (VFP_LDSTMIA);
+}
 
-/* inst.operands[i] was set up by parse_address.  Encode it into a
-   Thumb32 format load or store instruction.  Reject forms that cannot
-   be used with such instructions.  If is_t is true, reject forms that
-   cannot be used with a T instruction; if is_d is true, reject forms
-   that cannot be used with a D instruction.  If it is a store insn,
-   reject PC in Rn.  */
+static void
+do_vfp_sp_ldstmdb (void)
+{
+  vfp_sp_ldstm (VFP_LDSTMDB);
+}
 
 static void
-encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d)
+do_vfp_dp_ldstmia (void)
 {
-  const bfd_boolean is_pc = (inst.operands[i].reg == REG_PC);
+  vfp_dp_ldstm (VFP_LDSTMIA);
+}
 
-  constraint (!inst.operands[i].isreg,
-             _("Instruction does not support =N addresses"));
+static void
+do_vfp_dp_ldstmdb (void)
+{
+  vfp_dp_ldstm (VFP_LDSTMDB);
+}
 
-  inst.instruction |= inst.operands[i].reg << 16;
-  if (inst.operands[i].immisreg)
-    {
-      constraint (is_pc, BAD_PC_ADDRESSING);
-      constraint (is_t || is_d, _("cannot use register index with this instruction"));
-      constraint (inst.operands[i].negative,
-                 _("Thumb does not support negative register indexing"));
-      constraint (inst.operands[i].postind,
-                 _("Thumb does not support register post-indexing"));
-      constraint (inst.operands[i].writeback,
-                 _("Thumb does not support register indexing with writeback"));
-      constraint (inst.operands[i].shifted && inst.operands[i].shift_kind != SHIFT_LSL,
-                 _("Thumb supports only LSL in shifted register indexing"));
+static void
+do_vfp_xp_ldstmia (void)
+{
+  vfp_dp_ldstm (VFP_LDSTMIAX);
+}
 
-      inst.instruction |= inst.operands[i].imm;
-      if (inst.operands[i].shifted)
-       {
-         constraint (inst.reloc.exp.X_op != O_constant,
-                     _("expression too complex"));
-         constraint (inst.reloc.exp.X_add_number < 0
-                     || inst.reloc.exp.X_add_number > 3,
-                     _("shift out of range"));
-         inst.instruction |= inst.reloc.exp.X_add_number << 4;
-       }
-      inst.reloc.type = BFD_RELOC_UNUSED;
-    }
-  else if (inst.operands[i].preind)
-    {
-      constraint (is_pc && inst.operands[i].writeback, BAD_PC_WRITEBACK);
-      constraint (is_t && inst.operands[i].writeback,
-                 _("cannot use writeback with this instruction"));
-      constraint (is_pc && ((inst.instruction & THUMB2_LOAD_BIT) == 0)
-                 && !inst.reloc.pc_rel, BAD_PC_ADDRESSING);
+static void
+do_vfp_xp_ldstmdb (void)
+{
+  vfp_dp_ldstm (VFP_LDSTMDBX);
+}
 
-      if (is_d)
-       {
-         inst.instruction |= 0x01000000;
-         if (inst.operands[i].writeback)
-           inst.instruction |= 0x00200000;
-       }
-      else
-       {
-         inst.instruction |= 0x00000c00;
-         if (inst.operands[i].writeback)
-           inst.instruction |= 0x00000100;
-       }
-      inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_IMM;
-    }
-  else if (inst.operands[i].postind)
-    {
-      gas_assert (inst.operands[i].writeback);
-      constraint (is_pc, _("cannot use post-indexing with PC-relative addressing"));
-      constraint (is_t, _("cannot use post-indexing with this instruction"));
+static void
+do_vfp_dp_rd_rm (void)
+{
+  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
+  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dm);
+}
 
-      if (is_d)
-       inst.instruction |= 0x00200000;
-      else
-       inst.instruction |= 0x00000900;
-      inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_IMM;
-    }
-  else /* unindexed - only for coprocessor */
-    inst.error = _("instruction does not accept unindexed addressing");
+static void
+do_vfp_dp_rn_rd (void)
+{
+  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dn);
+  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dd);
 }
 
-/* Table of Thumb instructions which exist in both 16- and 32-bit
-   encodings (the latter only in post-V6T2 cores).  The index is the
-   value used in the insns table below.  When there is more than one
-   possible 16-bit encoding for the instruction, this table always
-   holds variant (1).
-   Also contains several pseudo-instructions used during relaxation.  */
-#define T16_32_TAB                             \
-  X(_adc,   4140, eb400000),                   \
-  X(_adcs,  4140, eb500000),                   \
-  X(_add,   1c00, eb000000),                   \
-  X(_adds,  1c00, eb100000),                   \
-  X(_addi,  0000, f1000000),                   \
-  X(_addis, 0000, f1100000),                   \
-  X(_add_pc,000f, f20f0000),                   \
-  X(_add_sp,000d, f10d0000),                   \
-  X(_adr,   000f, f20f0000),                   \
-  X(_and,   4000, ea000000),                   \
-  X(_ands,  4000, ea100000),                   \
-  X(_asr,   1000, fa40f000),                   \
-  X(_asrs,  1000, fa50f000),                   \
-  X(_b,     e000, f000b000),                   \
-  X(_bcond, d000, f0008000),                   \
-  X(_bic,   4380, ea200000),                   \
-  X(_bics,  4380, ea300000),                   \
-  X(_cmn,   42c0, eb100f00),                   \
-  X(_cmp,   2800, ebb00f00),                   \
-  X(_cpsie, b660, f3af8400),                   \
-  X(_cpsid, b670, f3af8600),                   \
-  X(_cpy,   4600, ea4f0000),                   \
-  X(_dec_sp,80dd, f1ad0d00),                   \
-  X(_eor,   4040, ea800000),                   \
-  X(_eors,  4040, ea900000),                   \
-  X(_inc_sp,00dd, f10d0d00),                   \
-  X(_ldmia, c800, e8900000),                   \
-  X(_ldr,   6800, f8500000),                   \
-  X(_ldrb,  7800, f8100000),                   \
-  X(_ldrh,  8800, f8300000),                   \
-  X(_ldrsb, 5600, f9100000),                   \
-  X(_ldrsh, 5e00, f9300000),                   \
-  X(_ldr_pc,4800, f85f0000),                   \
-  X(_ldr_pc2,4800, f85f0000),                  \
-  X(_ldr_sp,9800, f85d0000),                   \
-  X(_lsl,   0000, fa00f000),                   \
-  X(_lsls,  0000, fa10f000),                   \
-  X(_lsr,   0800, fa20f000),                   \
-  X(_lsrs,  0800, fa30f000),                   \
-  X(_mov,   2000, ea4f0000),                   \
-  X(_movs,  2000, ea5f0000),                   \
-  X(_mul,   4340, fb00f000),                     \
-  X(_muls,  4340, ffffffff), /* no 32b muls */ \
-  X(_mvn,   43c0, ea6f0000),                   \
-  X(_mvns,  43c0, ea7f0000),                   \
-  X(_neg,   4240, f1c00000), /* rsb #0 */      \
-  X(_negs,  4240, f1d00000), /* rsbs #0 */     \
-  X(_orr,   4300, ea400000),                   \
-  X(_orrs,  4300, ea500000),                   \
-  X(_pop,   bc00, e8bd0000), /* ldmia sp!,... */       \
-  X(_push,  b400, e92d0000), /* stmdb sp!,... */       \
-  X(_rev,   ba00, fa90f080),                   \
-  X(_rev16, ba40, fa90f090),                   \
-  X(_revsh, bac0, fa90f0b0),                   \
-  X(_ror,   41c0, fa60f000),                   \
-  X(_rors,  41c0, fa70f000),                   \
-  X(_sbc,   4180, eb600000),                   \
-  X(_sbcs,  4180, eb700000),                   \
-  X(_stmia, c000, e8800000),                   \
-  X(_str,   6000, f8400000),                   \
-  X(_strb,  7000, f8000000),                   \
-  X(_strh,  8000, f8200000),                   \
-  X(_str_sp,9000, f84d0000),                   \
-  X(_sub,   1e00, eba00000),                   \
-  X(_subs,  1e00, ebb00000),                   \
-  X(_subi,  8000, f1a00000),                   \
-  X(_subis, 8000, f1b00000),                   \
-  X(_sxtb,  b240, fa4ff080),                   \
-  X(_sxth,  b200, fa0ff080),                   \
-  X(_tst,   4200, ea100f00),                   \
-  X(_uxtb,  b2c0, fa5ff080),                   \
-  X(_uxth,  b280, fa1ff080),                   \
-  X(_nop,   bf00, f3af8000),                   \
-  X(_yield, bf10, f3af8001),                   \
-  X(_wfe,   bf20, f3af8002),                   \
-  X(_wfi,   bf30, f3af8003),                   \
-  X(_sev,   bf40, f3af8004),
+static void
+do_vfp_dp_rd_rn (void)
+{
+  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
+  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dn);
+}
 
-/* To catch errors in encoding functions, the codes are all offset by
-   0xF800, putting them in one of the 32-bit prefix ranges, ergo undefined
-   as 16-bit instructions.  */
-#define X(a,b,c) T_MNEM##a
-enum t16_32_codes { T16_32_OFFSET = 0xF7FF, T16_32_TAB };
-#undef X
+static void
+do_vfp_dp_rd_rn_rm (void)
+{
+  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
+  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dn);
+  encode_arm_vfp_reg (inst.operands[2].reg, VFP_REG_Dm);
+}
 
-#define X(a,b,c) 0x##b
-static const unsigned short thumb_op16[] = { T16_32_TAB };
-#define THUMB_OP16(n) (thumb_op16[(n) - (T16_32_OFFSET + 1)])
-#undef X
+static void
+do_vfp_dp_rd (void)
+{
+  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
+}
 
-#define X(a,b,c) 0x##c
-static const unsigned int thumb_op32[] = { T16_32_TAB };
-#define THUMB_OP32(n)        (thumb_op32[(n) - (T16_32_OFFSET + 1)])
-#define THUMB_SETS_FLAGS(n)  (THUMB_OP32 (n) & 0x00100000)
-#undef X
-#undef T16_32_TAB
+static void
+do_vfp_dp_rm_rd_rn (void)
+{
+  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dm);
+  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dd);
+  encode_arm_vfp_reg (inst.operands[2].reg, VFP_REG_Dn);
+}
 
-/* Thumb instruction encoders, in alphabetical order.  */
+/* VFPv3 instructions.  */
+static void
+do_vfp_sp_const (void)
+{
+  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
+  inst.instruction |= (inst.operands[1].imm & 0xf0) << 12;
+  inst.instruction |= (inst.operands[1].imm & 0x0f);
+}
 
-/* ADDW or SUBW.  */
+static void
+do_vfp_dp_const (void)
+{
+  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
+  inst.instruction |= (inst.operands[1].imm & 0xf0) << 12;
+  inst.instruction |= (inst.operands[1].imm & 0x0f);
+}
 
 static void
-do_t_add_sub_w (void)
+vfp_conv (int srcsize)
 {
-  int Rd, Rn;
+  int immbits = srcsize - inst.operands[1].imm;
 
-  Rd = inst.operands[0].reg;
-  Rn = inst.operands[1].reg;
+  if (srcsize == 16 && !(immbits >= 0 && immbits <= srcsize))
+    {
+      /* If srcsize is 16, inst.operands[1].imm must be in the range 0-16.
+        i.e. immbits must be in range 0 - 16.  */
+      inst.error = _("immediate value out of range, expected range [0, 16]");
+      return;
+    }
+  else if (srcsize == 32 && !(immbits >= 0 && immbits < srcsize))
+    {
+      /* If srcsize is 32, inst.operands[1].imm must be in the range 1-32.
+        i.e. immbits must be in range 0 - 31.  */
+      inst.error = _("immediate value out of range, expected range [1, 32]");
+      return;
+    }
 
-  /* If Rn is REG_PC, this is ADR; if Rn is REG_SP, then this
-     is the SP-{plus,minus}-immediate form of the instruction.  */
-  if (Rn == REG_SP)
-    constraint (Rd == REG_PC, BAD_PC);
-  else
-    reject_bad_reg (Rd);
+  inst.instruction |= (immbits & 1) << 5;
+  inst.instruction |= (immbits >> 1);
+}
 
-  inst.instruction |= (Rn << 16) | (Rd << 8);
-  inst.reloc.type = BFD_RELOC_ARM_T32_IMM12;
+static void
+do_vfp_sp_conv_16 (void)
+{
+  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
+  vfp_conv (16);
 }
 
-/* Parse an add or subtract instruction.  We get here with inst.instruction
-   equalling any of THUMB_OPCODE_add, adds, sub, or subs.  */
+static void
+do_vfp_dp_conv_16 (void)
+{
+  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
+  vfp_conv (16);
+}
 
 static void
-do_t_add_sub (void)
+do_vfp_sp_conv_32 (void)
 {
-  int Rd, Rs, Rn;
+  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
+  vfp_conv (32);
+}
 
-  Rd = inst.operands[0].reg;
-  Rs = (inst.operands[1].present
-       ? inst.operands[1].reg    /* Rd, Rs, foo */
-       : inst.operands[0].reg);  /* Rd, foo -> Rd, Rd, foo */
+static void
+do_vfp_dp_conv_32 (void)
+{
+  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
+  vfp_conv (32);
+}
+\f
+/* FPA instructions.  Also in a logical order. */
 
-  if (Rd == REG_PC)
-    set_it_insn_type_last ();
+static void
+do_fpa_cmp (void)
+{
+  inst.instruction |= inst.operands[0].reg << 16;
+  inst.instruction |= inst.operands[1].reg;
+}
 
-  if (unified_syntax)
+static void
+do_fpa_ldmstm (void)
+{
+  inst.instruction |= inst.operands[0].reg << 12;
+  switch (inst.operands[1].imm)
     {
-      bfd_boolean flags;
-      bfd_boolean narrow;
-      int opcode;
+    case 1: inst.instruction |= CP_T_X;                 break;
+    case 2: inst.instruction |= CP_T_Y;                 break;
+    case 3: inst.instruction |= CP_T_Y | CP_T_X; break;
+    case 4:                                     break;
+    default: abort ();
+    }
 
-      flags = (inst.instruction == T_MNEM_adds
-              || inst.instruction == T_MNEM_subs);
-      if (flags)
-       narrow = !in_it_block ();
-      else
-       narrow = in_it_block ();
-      if (!inst.operands[2].isreg)
+  if (inst.instruction & (PRE_INDEX | INDEX_UP))
+    {
+      /* The instruction specified "ea" or "fd", so we can only accept
+        [Rn]{!}.  The instruction does not really support stacking or
+        unstacking, so we have to emulate these by setting appropriate
+        bits and offsets.  */
+      constraint (inst.reloc.exp.X_op != O_constant
+                 || inst.reloc.exp.X_add_number != 0,
+                 _("this instruction does not support indexing"));
+
+      if ((inst.instruction & PRE_INDEX) || inst.operands[2].writeback)
+       inst.reloc.exp.X_add_number = 12 * inst.operands[1].imm;
+
+      if (!(inst.instruction & INDEX_UP))
+       inst.reloc.exp.X_add_number = -inst.reloc.exp.X_add_number;
+
+      if (!(inst.instruction & PRE_INDEX) && inst.operands[2].writeback)
        {
-         int add;
+         inst.operands[2].preind = 0;
+         inst.operands[2].postind = 1;
+       }
+    }
 
-         constraint (Rd == REG_SP && Rs != REG_SP, BAD_SP);
+  encode_arm_cp_address (2, TRUE, TRUE, 0);
+}
+\f
+/* iWMMXt instructions: strictly in alphabetical order.         */
 
-         add = (inst.instruction == T_MNEM_add
-                || inst.instruction == T_MNEM_adds);
-         opcode = 0;
-         if (inst.size_req != 4)
-           {
-             /* Attempt to use a narrow opcode, with relaxation if
-                appropriate.  */
-             if (Rd == REG_SP && Rs == REG_SP && !flags)
-               opcode = add ? T_MNEM_inc_sp : T_MNEM_dec_sp;
-             else if (Rd <= 7 && Rs == REG_SP && add && !flags)
-               opcode = T_MNEM_add_sp;
-             else if (Rd <= 7 && Rs == REG_PC && add && !flags)
-               opcode = T_MNEM_add_pc;
-             else if (Rd <= 7 && Rs <= 7 && narrow)
-               {
-                 if (flags)
-                   opcode = add ? T_MNEM_addis : T_MNEM_subis;
-                 else
-                   opcode = add ? T_MNEM_addi : T_MNEM_subi;
-               }
-             if (opcode)
-               {
-                 inst.instruction = THUMB_OP16(opcode);
-                 inst.instruction |= (Rd << 4) | Rs;
-                 inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
-                 if (inst.size_req != 2)
-                   inst.relax = opcode;
-               }
-             else
-               constraint (inst.size_req == 2, BAD_HIREG);
-           }
-         if (inst.size_req == 4
-             || (inst.size_req != 2 && !opcode))
-           {
-             if (Rd == REG_PC)
-               {
-                 constraint (add, BAD_PC);
-                 constraint (Rs != REG_LR || inst.instruction != T_MNEM_subs,
-                            _("only SUBS PC, LR, #const allowed"));
-                 constraint (inst.reloc.exp.X_op != O_constant,
-                             _("expression too complex"));
-                 constraint (inst.reloc.exp.X_add_number < 0
-                             || inst.reloc.exp.X_add_number > 0xff,
-                            _("immediate value out of range"));
-                 inst.instruction = T2_SUBS_PC_LR
-                                    | inst.reloc.exp.X_add_number;
-                 inst.reloc.type = BFD_RELOC_UNUSED;
-                 return;
-               }
-             else if (Rs == REG_PC)
-               {
-                 /* Always use addw/subw.  */
-                 inst.instruction = add ? 0xf20f0000 : 0xf2af0000;
-                 inst.reloc.type = BFD_RELOC_ARM_T32_IMM12;
-               }
-             else
-               {
-                 inst.instruction = THUMB_OP32 (inst.instruction);
-                 inst.instruction = (inst.instruction & 0xe1ffffff)
-                                    | 0x10000000;
-                 if (flags)
-                   inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
-                 else
-                   inst.reloc.type = BFD_RELOC_ARM_T32_ADD_IMM;
-               }
-             inst.instruction |= Rd << 8;
-             inst.instruction |= Rs << 16;
-           }
-       }
-      else
-       {
-         Rn = inst.operands[2].reg;
-         /* See if we can do this with a 16-bit instruction.  */
-         if (!inst.operands[2].shifted && inst.size_req != 4)
-           {
-             if (Rd > 7 || Rs > 7 || Rn > 7)
-               narrow = FALSE;
-
-             if (narrow)
-               {
-                 inst.instruction = ((inst.instruction == T_MNEM_adds
-                                      || inst.instruction == T_MNEM_add)
-                                     ? T_OPCODE_ADD_R3
-                                     : T_OPCODE_SUB_R3);
-                 inst.instruction |= Rd | (Rs << 3) | (Rn << 6);
-                 return;
-               }
-
-             if (inst.instruction == T_MNEM_add && (Rd == Rs || Rd == Rn))
-               {
-                 /* Thumb-1 cores (except v6-M) require at least one high
-                    register in a narrow non flag setting add.  */
-                 if (Rd > 7 || Rn > 7
-                     || ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6t2)
-                     || ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_msr))
-                   {
-                     if (Rd == Rn)
-                       {
-                         Rn = Rs;
-                         Rs = Rd;
-                       }
-                     inst.instruction = T_OPCODE_ADD_HI;
-                     inst.instruction |= (Rd & 8) << 4;
-                     inst.instruction |= (Rd & 7);
-                     inst.instruction |= Rn << 3;
-                     return;
-                   }
-               }
-           }
+static void
+do_iwmmxt_tandorc (void)
+{
+  constraint (inst.operands[0].reg != REG_PC, _("only r15 allowed here"));
+}
 
-         constraint (Rd == REG_PC, BAD_PC);
-         constraint (Rd == REG_SP && Rs != REG_SP, BAD_SP);
-         constraint (Rs == REG_PC, BAD_PC);
-         reject_bad_reg (Rn);
+static void
+do_iwmmxt_textrc (void)
+{
+  inst.instruction |= inst.operands[0].reg << 12;
+  inst.instruction |= inst.operands[1].imm;
+}
 
-         /* If we get here, it can't be done in 16 bits.  */
-         constraint (inst.operands[2].shifted && inst.operands[2].immisreg,
-                     _("shift must be constant"));
-         inst.instruction = THUMB_OP32 (inst.instruction);
-         inst.instruction |= Rd << 8;
-         inst.instruction |= Rs << 16;
-         encode_thumb32_shifted_operand (2);
-       }
-    }
-  else
-    {
-      constraint (inst.instruction == T_MNEM_adds
-                 || inst.instruction == T_MNEM_subs,
-                 BAD_THUMB32);
+static void
+do_iwmmxt_textrm (void)
+{
+  inst.instruction |= inst.operands[0].reg << 12;
+  inst.instruction |= inst.operands[1].reg << 16;
+  inst.instruction |= inst.operands[2].imm;
+}
 
-      if (!inst.operands[2].isreg) /* Rd, Rs, #imm */
-       {
-         constraint ((Rd > 7 && (Rd != REG_SP || Rs != REG_SP))
-                     || (Rs > 7 && Rs != REG_SP && Rs != REG_PC),
-                     BAD_HIREG);
+static void
+do_iwmmxt_tinsr (void)
+{
+  inst.instruction |= inst.operands[0].reg << 16;
+  inst.instruction |= inst.operands[1].reg << 12;
+  inst.instruction |= inst.operands[2].imm;
+}
 
-         inst.instruction = (inst.instruction == T_MNEM_add
-                             ? 0x0000 : 0x8000);
-         inst.instruction |= (Rd << 4) | Rs;
-         inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
-         return;
-       }
+static void
+do_iwmmxt_tmia (void)
+{
+  inst.instruction |= inst.operands[0].reg << 5;
+  inst.instruction |= inst.operands[1].reg;
+  inst.instruction |= inst.operands[2].reg << 12;
+}
 
-      Rn = inst.operands[2].reg;
-      constraint (inst.operands[2].shifted, _("unshifted register required"));
+static void
+do_iwmmxt_waligni (void)
+{
+  inst.instruction |= inst.operands[0].reg << 12;
+  inst.instruction |= inst.operands[1].reg << 16;
+  inst.instruction |= inst.operands[2].reg;
+  inst.instruction |= inst.operands[3].imm << 20;
+}
 
-      /* We now have Rd, Rs, and Rn set to registers.  */
-      if (Rd > 7 || Rs > 7 || Rn > 7)
-       {
-         /* Can't do this for SUB.      */
-         constraint (inst.instruction == T_MNEM_sub, BAD_HIREG);
-         inst.instruction = T_OPCODE_ADD_HI;
-         inst.instruction |= (Rd & 8) << 4;
-         inst.instruction |= (Rd & 7);
-         if (Rs == Rd)
-           inst.instruction |= Rn << 3;
-         else if (Rn == Rd)
-           inst.instruction |= Rs << 3;
-         else
-           constraint (1, _("dest must overlap one source register"));
-       }
-      else
-       {
-         inst.instruction = (inst.instruction == T_MNEM_add
-                             ? T_OPCODE_ADD_R3 : T_OPCODE_SUB_R3);
-         inst.instruction |= Rd | (Rs << 3) | (Rn << 6);
-       }
-    }
+static void
+do_iwmmxt_wmerge (void)
+{
+  inst.instruction |= inst.operands[0].reg << 12;
+  inst.instruction |= inst.operands[1].reg << 16;
+  inst.instruction |= inst.operands[2].reg;
+  inst.instruction |= inst.operands[3].imm << 21;
 }
 
 static void
-do_t_adr (void)
+do_iwmmxt_wmov (void)
 {
-  unsigned Rd;
+  /* WMOV rD, rN is an alias for WOR rD, rN, rN.  */
+  inst.instruction |= inst.operands[0].reg << 12;
+  inst.instruction |= inst.operands[1].reg << 16;
+  inst.instruction |= inst.operands[1].reg;
+}
 
-  Rd = inst.operands[0].reg;
-  reject_bad_reg (Rd);
+static void
+do_iwmmxt_wldstbh (void)
+{
+  int reloc;
+  inst.instruction |= inst.operands[0].reg << 12;
+  if (thumb_mode)
+    reloc = BFD_RELOC_ARM_T32_CP_OFF_IMM_S2;
+  else
+    reloc = BFD_RELOC_ARM_CP_OFF_IMM_S2;
+  encode_arm_cp_address (1, TRUE, FALSE, reloc);
+}
 
-  if (unified_syntax && inst.size_req == 0 && Rd <= 7)
+static void
+do_iwmmxt_wldstw (void)
+{
+  /* RIWR_RIWC clears .isreg for a control register.  */
+  if (!inst.operands[0].isreg)
     {
-      /* Defer to section relaxation.  */
-      inst.relax = inst.instruction;
-      inst.instruction = THUMB_OP16 (inst.instruction);
-      inst.instruction |= Rd << 4;
+      constraint (inst.cond != COND_ALWAYS, BAD_COND);
+      inst.instruction |= 0xf0000000;
     }
-  else if (unified_syntax && inst.size_req != 2)
+
+  inst.instruction |= inst.operands[0].reg << 12;
+  encode_arm_cp_address (1, TRUE, TRUE, 0);
+}
+
+static void
+do_iwmmxt_wldstd (void)
+{
+  inst.instruction |= inst.operands[0].reg << 12;
+  if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt2)
+      && inst.operands[1].immisreg)
     {
-      /* Generate a 32-bit opcode.  */
-      inst.instruction = THUMB_OP32 (inst.instruction);
-      inst.instruction |= Rd << 8;
-      inst.reloc.type = BFD_RELOC_ARM_T32_ADD_PC12;
-      inst.reloc.pc_rel = 1;
+      inst.instruction &= ~0x1a000ff;
+      inst.instruction |= (0xfU << 28);
+      if (inst.operands[1].preind)
+       inst.instruction |= PRE_INDEX;
+      if (!inst.operands[1].negative)
+       inst.instruction |= INDEX_UP;
+      if (inst.operands[1].writeback)
+       inst.instruction |= WRITE_BACK;
+      inst.instruction |= inst.operands[1].reg << 16;
+      inst.instruction |= inst.reloc.exp.X_add_number << 4;
+      inst.instruction |= inst.operands[1].imm;
     }
   else
-    {
-      /* Generate a 16-bit opcode.  */
-      inst.instruction = THUMB_OP16 (inst.instruction);
-      inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
-      inst.reloc.exp.X_add_number -= 4; /* PC relative adjust.  */
-      inst.reloc.pc_rel = 1;
-
-      inst.instruction |= Rd << 4;
-    }
+    encode_arm_cp_address (1, TRUE, FALSE, 0);
 }
 
-/* Arithmetic instructions for which there is just one 16-bit
-   instruction encoding, and it allows only two low registers.
-   For maximal compatibility with ARM syntax, we allow three register
-   operands even when Thumb-32 instructions are not available, as long
-   as the first two are identical.  For instance, both "sbc r0,r1" and
-   "sbc r0,r0,r1" are allowed.  */
 static void
-do_t_arit3 (void)
+do_iwmmxt_wshufh (void)
 {
-  int Rd, Rs, Rn;
+  inst.instruction |= inst.operands[0].reg << 12;
+  inst.instruction |= inst.operands[1].reg << 16;
+  inst.instruction |= ((inst.operands[2].imm & 0xf0) << 16);
+  inst.instruction |= (inst.operands[2].imm & 0x0f);
+}
 
-  Rd = inst.operands[0].reg;
-  Rs = (inst.operands[1].present
-       ? inst.operands[1].reg    /* Rd, Rs, foo */
-       : inst.operands[0].reg);  /* Rd, foo -> Rd, Rd, foo */
-  Rn = inst.operands[2].reg;
+static void
+do_iwmmxt_wzero (void)
+{
+  /* WZERO reg is an alias for WANDN reg, reg, reg.  */
+  inst.instruction |= inst.operands[0].reg;
+  inst.instruction |= inst.operands[0].reg << 12;
+  inst.instruction |= inst.operands[0].reg << 16;
+}
 
-  reject_bad_reg (Rd);
-  reject_bad_reg (Rs);
+static void
+do_iwmmxt_wrwrwr_or_imm5 (void)
+{
   if (inst.operands[2].isreg)
-    reject_bad_reg (Rn);
-
-  if (unified_syntax)
-    {
-      if (!inst.operands[2].isreg)
-       {
-         /* For an immediate, we always generate a 32-bit opcode;
-            section relaxation will shrink it later if possible.  */
-         inst.instruction = THUMB_OP32 (inst.instruction);
-         inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
-         inst.instruction |= Rd << 8;
-         inst.instruction |= Rs << 16;
-         inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
-       }
-      else
-       {
-         bfd_boolean narrow;
-
-         /* See if we can do this with a 16-bit instruction.  */
-         if (THUMB_SETS_FLAGS (inst.instruction))
-           narrow = !in_it_block ();
-         else
-           narrow = in_it_block ();
-
-         if (Rd > 7 || Rn > 7 || Rs > 7)
-           narrow = FALSE;
-         if (inst.operands[2].shifted)
-           narrow = FALSE;
-         if (inst.size_req == 4)
-           narrow = FALSE;
-
-         if (narrow
-             && Rd == Rs)
+    do_rd_rn_rm ();
+  else {
+    constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt2),
+               _("immediate operand requires iWMMXt2"));
+    do_rd_rn ();
+    if (inst.operands[2].imm == 0)
+      {
+       switch ((inst.instruction >> 20) & 0xf)
+         {
+         case 4:
+         case 5:
+         case 6:
+         case 7:
+           /* w...h wrd, wrn, #0 -> wrorh wrd, wrn, #16.  */
+           inst.operands[2].imm = 16;
+           inst.instruction = (inst.instruction & 0xff0fffff) | (0x7 << 20);
+           break;
+         case 8:
+         case 9:
+         case 10:
+         case 11:
+           /* w...w wrd, wrn, #0 -> wrorw wrd, wrn, #32.  */
+           inst.operands[2].imm = 32;
+           inst.instruction = (inst.instruction & 0xff0fffff) | (0xb << 20);
+           break;
+         case 12:
+         case 13:
+         case 14:
+         case 15:
            {
-             inst.instruction = THUMB_OP16 (inst.instruction);
-             inst.instruction |= Rd;
-             inst.instruction |= Rn << 3;
+             /* w...d wrd, wrn, #0 -> wor wrd, wrn, wrn.  */
+             unsigned long wrn;
+             wrn = (inst.instruction >> 16) & 0xf;
+             inst.instruction &= 0xff0fff0f;
+             inst.instruction |= wrn;
+             /* Bail out here; the instruction is now assembled.  */
              return;
            }
+         }
+      }
+    /* Map 32 -> 0, etc.  */
+    inst.operands[2].imm &= 0x1f;
+    inst.instruction |= (0xfU << 28) | ((inst.operands[2].imm & 0x10) << 4) | (inst.operands[2].imm & 0xf);
+  }
+}
+\f
+/* Cirrus Maverick instructions.  Simple 2-, 3-, and 4-register
+   operations first, then control, shift, and load/store.  */
 
-         /* If we get here, it can't be done in 16 bits.  */
-         constraint (inst.operands[2].shifted
-                     && inst.operands[2].immisreg,
-                     _("shift must be constant"));
-         inst.instruction = THUMB_OP32 (inst.instruction);
-         inst.instruction |= Rd << 8;
-         inst.instruction |= Rs << 16;
-         encode_thumb32_shifted_operand (2);
-       }
-    }
-  else
-    {
-      /* On its face this is a lie - the instruction does set the
-        flags.  However, the only supported mnemonic in this mode
-        says it doesn't.  */
-      constraint (THUMB_SETS_FLAGS (inst.instruction), BAD_THUMB32);
+/* Insns like "foo X,Y,Z".  */
 
-      constraint (!inst.operands[2].isreg || inst.operands[2].shifted,
-                 _("unshifted register required"));
-      constraint (Rd > 7 || Rs > 7 || Rn > 7, BAD_HIREG);
-      constraint (Rd != Rs,
-                 _("dest and source1 must be the same register"));
+static void
+do_mav_triple (void)
+{
+  inst.instruction |= inst.operands[0].reg << 16;
+  inst.instruction |= inst.operands[1].reg;
+  inst.instruction |= inst.operands[2].reg << 12;
+}
 
-      inst.instruction = THUMB_OP16 (inst.instruction);
-      inst.instruction |= Rd;
-      inst.instruction |= Rn << 3;
-    }
+/* Insns like "foo W,X,Y,Z".
+    where W=MVAX[0:3] and X,Y,Z=MVFX[0:15].  */
+
+static void
+do_mav_quad (void)
+{
+  inst.instruction |= inst.operands[0].reg << 5;
+  inst.instruction |= inst.operands[1].reg << 12;
+  inst.instruction |= inst.operands[2].reg << 16;
+  inst.instruction |= inst.operands[3].reg;
 }
 
-/* Similarly, but for instructions where the arithmetic operation is
-   commutative, so we can allow either of them to be different from
-   the destination operand in a 16-bit instruction.  For instance, all
-   three of "adc r0,r1", "adc r0,r0,r1", and "adc r0,r1,r0" are
-   accepted.  */
+/* cfmvsc32<cond> DSPSC,MVDX[15:0].  */
 static void
-do_t_arit3c (void)
+do_mav_dspsc (void)
 {
-  int Rd, Rs, Rn;
+  inst.instruction |= inst.operands[1].reg << 12;
+}
 
-  Rd = inst.operands[0].reg;
-  Rs = (inst.operands[1].present
-       ? inst.operands[1].reg    /* Rd, Rs, foo */
-       : inst.operands[0].reg);  /* Rd, foo -> Rd, Rd, foo */
-  Rn = inst.operands[2].reg;
+/* Maverick shift immediate instructions.
+   cfsh32<cond> MVFX[15:0],MVFX[15:0],Shift[6:0].
+   cfsh64<cond> MVDX[15:0],MVDX[15:0],Shift[6:0].  */
 
-  reject_bad_reg (Rd);
-  reject_bad_reg (Rs);
-  if (inst.operands[2].isreg)
-    reject_bad_reg (Rn);
+static void
+do_mav_shift (void)
+{
+  int imm = inst.operands[2].imm;
 
-  if (unified_syntax)
-    {
-      if (!inst.operands[2].isreg)
-       {
-         /* For an immediate, we always generate a 32-bit opcode;
-            section relaxation will shrink it later if possible.  */
-         inst.instruction = THUMB_OP32 (inst.instruction);
-         inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
-         inst.instruction |= Rd << 8;
-         inst.instruction |= Rs << 16;
-         inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
-       }
-      else
-       {
-         bfd_boolean narrow;
+  inst.instruction |= inst.operands[0].reg << 12;
+  inst.instruction |= inst.operands[1].reg << 16;
 
-         /* See if we can do this with a 16-bit instruction.  */
-         if (THUMB_SETS_FLAGS (inst.instruction))
-           narrow = !in_it_block ();
-         else
-           narrow = in_it_block ();
+  /* Bits 0-3 of the insn should have bits 0-3 of the immediate.
+     Bits 5-7 of the insn should have bits 4-6 of the immediate.
+     Bit 4 should be 0.         */
+  imm = (imm & 0xf) | ((imm & 0x70) << 1);
 
-         if (Rd > 7 || Rn > 7 || Rs > 7)
-           narrow = FALSE;
-         if (inst.operands[2].shifted)
-           narrow = FALSE;
-         if (inst.size_req == 4)
-           narrow = FALSE;
+  inst.instruction |= imm;
+}
+\f
+/* XScale instructions.         Also sorted arithmetic before move.  */
 
-         if (narrow)
-           {
-             if (Rd == Rs)
-               {
-                 inst.instruction = THUMB_OP16 (inst.instruction);
-                 inst.instruction |= Rd;
-                 inst.instruction |= Rn << 3;
-                 return;
-               }
-             if (Rd == Rn)
-               {
-                 inst.instruction = THUMB_OP16 (inst.instruction);
-                 inst.instruction |= Rd;
-                 inst.instruction |= Rs << 3;
-                 return;
-               }
-           }
+/* Xscale multiply-accumulate (argument parse)
+     MIAcc   acc0,Rm,Rs
+     MIAPHcc acc0,Rm,Rs
+     MIAxycc acc0,Rm,Rs.  */
 
-         /* If we get here, it can't be done in 16 bits.  */
-         constraint (inst.operands[2].shifted
-                     && inst.operands[2].immisreg,
-                     _("shift must be constant"));
-         inst.instruction = THUMB_OP32 (inst.instruction);
-         inst.instruction |= Rd << 8;
-         inst.instruction |= Rs << 16;
-         encode_thumb32_shifted_operand (2);
-       }
-    }
-  else
-    {
-      /* On its face this is a lie - the instruction does set the
-        flags.  However, the only supported mnemonic in this mode
-        says it doesn't.  */
-      constraint (THUMB_SETS_FLAGS (inst.instruction), BAD_THUMB32);
+static void
+do_xsc_mia (void)
+{
+  inst.instruction |= inst.operands[1].reg;
+  inst.instruction |= inst.operands[2].reg << 12;
+}
 
-      constraint (!inst.operands[2].isreg || inst.operands[2].shifted,
-                 _("unshifted register required"));
-      constraint (Rd > 7 || Rs > 7 || Rn > 7, BAD_HIREG);
+/* Xscale move-accumulator-register (argument parse)
 
-      inst.instruction = THUMB_OP16 (inst.instruction);
-      inst.instruction |= Rd;
-
-      if (Rd == Rs)
-       inst.instruction |= Rn << 3;
-      else if (Rd == Rn)
-       inst.instruction |= Rs << 3;
-      else
-       constraint (1, _("dest must overlap one source register"));
-    }
-}
+     MARcc   acc0,RdLo,RdHi.  */
 
 static void
-do_t_barrier (void)
+do_xsc_mar (void)
 {
-  if (inst.operands[0].present)
-    {
-      constraint ((inst.instruction & 0xf0) != 0x40
-                 && inst.operands[0].imm > 0xf
-                 && inst.operands[0].imm < 0x0,
-                 _("bad barrier type"));
-      inst.instruction |= inst.operands[0].imm;
-    }
-  else
-    inst.instruction |= 0xf;
+  inst.instruction |= inst.operands[1].reg << 12;
+  inst.instruction |= inst.operands[2].reg << 16;
 }
 
+/* Xscale move-register-accumulator (argument parse)
+
+     MRAcc   RdLo,RdHi,acc0.  */
+
 static void
-do_t_bfc (void)
+do_xsc_mra (void)
 {
-  unsigned Rd;
-  unsigned int msb = inst.operands[1].imm + inst.operands[2].imm;
-  constraint (msb > 32, _("bit-field extends past end of register"));
-  /* The instruction encoding stores the LSB and MSB,
-     not the LSB and width.  */
-  Rd = inst.operands[0].reg;
-  reject_bad_reg (Rd);
-  inst.instruction |= Rd << 8;
-  inst.instruction |= (inst.operands[1].imm & 0x1c) << 10;
-  inst.instruction |= (inst.operands[1].imm & 0x03) << 6;
-  inst.instruction |= msb - 1;
+  constraint (inst.operands[0].reg == inst.operands[1].reg, BAD_OVERLAP);
+  inst.instruction |= inst.operands[0].reg << 12;
+  inst.instruction |= inst.operands[1].reg << 16;
 }
+\f
+/* Encoding functions relevant only to Thumb.  */
+
+/* inst.operands[i] is a shifted-register operand; encode
+   it into inst.instruction in the format used by Thumb32.  */
 
 static void
-do_t_bfi (void)
+encode_thumb32_shifted_operand (int i)
 {
-  int Rd, Rn;
-  unsigned int msb;
-
-  Rd = inst.operands[0].reg;
-  reject_bad_reg (Rd);
+  unsigned int value = inst.reloc.exp.X_add_number;
+  unsigned int shift = inst.operands[i].shift_kind;
 
-  /* #0 in second position is alternative syntax for bfc, which is
-     the same instruction but with REG_PC in the Rm field.  */
-  if (!inst.operands[1].isreg)
-    Rn = REG_PC;
+  constraint (inst.operands[i].immisreg,
+             _("shift by register not allowed in thumb mode"));
+  inst.instruction |= inst.operands[i].reg;
+  if (shift == SHIFT_RRX)
+    inst.instruction |= SHIFT_ROR << 4;
   else
     {
-      Rn = inst.operands[1].reg;
-      reject_bad_reg (Rn);
-    }
-
-  msb = inst.operands[2].imm + inst.operands[3].imm;
-  constraint (msb > 32, _("bit-field extends past end of register"));
-  /* The instruction encoding stores the LSB and MSB,
-     not the LSB and width.  */
-  inst.instruction |= Rd << 8;
-  inst.instruction |= Rn << 16;
-  inst.instruction |= (inst.operands[2].imm & 0x1c) << 10;
-  inst.instruction |= (inst.operands[2].imm & 0x03) << 6;
-  inst.instruction |= msb - 1;
-}
-
-static void
-do_t_bfx (void)
-{
-  unsigned Rd, Rn;
+      constraint (inst.reloc.exp.X_op != O_constant,
+                 _("expression too complex"));
 
-  Rd = inst.operands[0].reg;
-  Rn = inst.operands[1].reg;
+      constraint (value > 32
+                 || (value == 32 && (shift == SHIFT_LSL
+                                     || shift == SHIFT_ROR)),
+                 _("shift expression is too large"));
 
-  reject_bad_reg (Rd);
-  reject_bad_reg (Rn);
+      if (value == 0)
+       shift = SHIFT_LSL;
+      else if (value == 32)
+       value = 0;
 
-  constraint (inst.operands[2].imm + inst.operands[3].imm > 32,
-             _("bit-field extends past end of register"));
-  inst.instruction |= Rd << 8;
-  inst.instruction |= Rn << 16;
-  inst.instruction |= (inst.operands[2].imm & 0x1c) << 10;
-  inst.instruction |= (inst.operands[2].imm & 0x03) << 6;
-  inst.instruction |= inst.operands[3].imm - 1;
+      inst.instruction |= shift << 4;
+      inst.instruction |= (value & 0x1c) << 10;
+      inst.instruction |= (value & 0x03) << 6;
+    }
 }
 
-/* ARM V5 Thumb BLX (argument parse)
-       BLX <target_addr>       which is BLX(1)
-       BLX <Rm>                which is BLX(2)
-   Unfortunately, there are two different opcodes for this mnemonic.
-   So, the insns[].value is not used, and the code here zaps values
-       into inst.instruction.
-
-   ??? How to take advantage of the additional two bits of displacement
-   available in Thumb32 mode?  Need new relocation?  */
-
-static void
-do_t_blx (void)
-{
-  set_it_insn_type_last ();
 
-  if (inst.operands[0].isreg)
-    {
-      constraint (inst.operands[0].reg == REG_PC, BAD_PC);
-      /* We have a register, so this is BLX(2).  */
-      inst.instruction |= inst.operands[0].reg << 3;
-    }
-  else
-    {
-      /* No register.  This must be BLX(1).  */
-      inst.instruction = 0xf000e800;
-      encode_branch (BFD_RELOC_THUMB_PCREL_BLX);
-    }
-}
+/* inst.operands[i] was set up by parse_address.  Encode it into a
+   Thumb32 format load or store instruction.  Reject forms that cannot
+   be used with such instructions.  If is_t is true, reject forms that
+   cannot be used with a T instruction; if is_d is true, reject forms
+   that cannot be used with a D instruction.  If it is a store insn,
+   reject PC in Rn.  */
 
 static void
-do_t_branch (void)
+encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d)
 {
-  int opcode;
-  int cond;
-  int reloc;
+  const bfd_boolean is_pc = (inst.operands[i].reg == REG_PC);
 
-  cond = inst.cond;
-  set_it_insn_type (IF_INSIDE_IT_LAST_INSN);
+  constraint (!inst.operands[i].isreg,
+             _("Instruction does not support =N addresses"));
 
-  if (in_it_block ())
+  inst.instruction |= inst.operands[i].reg << 16;
+  if (inst.operands[i].immisreg)
     {
-      /* Conditional branches inside IT blocks are encoded as unconditional
-         branches.  */
-      cond = COND_ALWAYS;
-    }
-  else
-    cond = inst.cond;
-
-  if (cond != COND_ALWAYS)
-    opcode = T_MNEM_bcond;
-  else
-    opcode = inst.instruction;
+      constraint (is_pc, BAD_PC_ADDRESSING);
+      constraint (is_t || is_d, _("cannot use register index with this instruction"));
+      constraint (inst.operands[i].negative,
+                 _("Thumb does not support negative register indexing"));
+      constraint (inst.operands[i].postind,
+                 _("Thumb does not support register post-indexing"));
+      constraint (inst.operands[i].writeback,
+                 _("Thumb does not support register indexing with writeback"));
+      constraint (inst.operands[i].shifted && inst.operands[i].shift_kind != SHIFT_LSL,
+                 _("Thumb supports only LSL in shifted register indexing"));
 
-  if (unified_syntax
-      && (inst.size_req == 4
-         || (inst.size_req != 2 && inst.operands[0].hasreloc)))
-    {
-      inst.instruction = THUMB_OP32(opcode);
-      if (cond == COND_ALWAYS)
-       reloc = BFD_RELOC_THUMB_PCREL_BRANCH25;
-      else
+      inst.instruction |= inst.operands[i].imm;
+      if (inst.operands[i].shifted)
        {
-         gas_assert (cond != 0xF);
-         inst.instruction |= cond << 22;
-         reloc = BFD_RELOC_THUMB_PCREL_BRANCH20;
+         constraint (inst.reloc.exp.X_op != O_constant,
+                     _("expression too complex"));
+         constraint (inst.reloc.exp.X_add_number < 0
+                     || inst.reloc.exp.X_add_number > 3,
+                     _("shift out of range"));
+         inst.instruction |= inst.reloc.exp.X_add_number << 4;
        }
+      inst.reloc.type = BFD_RELOC_UNUSED;
     }
-  else
+  else if (inst.operands[i].preind)
     {
-      inst.instruction = THUMB_OP16(opcode);
-      if (cond == COND_ALWAYS)
-       reloc = BFD_RELOC_THUMB_PCREL_BRANCH12;
+      constraint (is_pc && inst.operands[i].writeback, BAD_PC_WRITEBACK);
+      constraint (is_t && inst.operands[i].writeback,
+                 _("cannot use writeback with this instruction"));
+      constraint (is_pc && ((inst.instruction & THUMB2_LOAD_BIT) == 0),
+                 BAD_PC_ADDRESSING);
+
+      if (is_d)
+       {
+         inst.instruction |= 0x01000000;
+         if (inst.operands[i].writeback)
+           inst.instruction |= 0x00200000;
+       }
       else
        {
-         inst.instruction |= cond << 8;
-         reloc = BFD_RELOC_THUMB_PCREL_BRANCH9;
+         inst.instruction |= 0x00000c00;
+         if (inst.operands[i].writeback)
+           inst.instruction |= 0x00000100;
        }
-      /* Allow section relaxation.  */
-      if (unified_syntax && inst.size_req != 2)
-       inst.relax = opcode;
+      inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_IMM;
     }
-  inst.reloc.type = reloc;
-  inst.reloc.pc_rel = 1;
-}
-
-static void
-do_t_bkpt (void)
-{
-  constraint (inst.cond != COND_ALWAYS,
-             _("instruction is always unconditional"));
-  if (inst.operands[0].present)
+  else if (inst.operands[i].postind)
     {
-      constraint (inst.operands[0].imm > 255,
-                 _("immediate value out of range"));
-      inst.instruction |= inst.operands[0].imm;
-      set_it_insn_type (NEUTRAL_IT_INSN);
+      gas_assert (inst.operands[i].writeback);
+      constraint (is_pc, _("cannot use post-indexing with PC-relative addressing"));
+      constraint (is_t, _("cannot use post-indexing with this instruction"));
+
+      if (is_d)
+       inst.instruction |= 0x00200000;
+      else
+       inst.instruction |= 0x00000900;
+      inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_IMM;
     }
+  else /* unindexed - only for coprocessor */
+    inst.error = _("instruction does not accept unindexed addressing");
 }
 
-static void
-do_t_branch23 (void)
-{
-  set_it_insn_type_last ();
-  encode_branch (BFD_RELOC_THUMB_PCREL_BRANCH23);
-  
-  /* md_apply_fix blows up with 'bl foo(PLT)' where foo is defined in
-     this file.  We used to simply ignore the PLT reloc type here --
-     the branch encoding is now needed to deal with TLSCALL relocs.
-     So if we see a PLT reloc now, put it back to how it used to be to
-     keep the preexisting behaviour.  */
-  if (inst.reloc.type == BFD_RELOC_ARM_PLT32)
-    inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH23;
-
-#if defined(OBJ_COFF)
-  /* If the destination of the branch is a defined symbol which does not have
-     the THUMB_FUNC attribute, then we must be calling a function which has
-     the (interfacearm) attribute.  We look for the Thumb entry point to that
-     function and change the branch to refer to that function instead. */
-  if (  inst.reloc.exp.X_op == O_symbol
-      && inst.reloc.exp.X_add_symbol != NULL
-      && S_IS_DEFINED (inst.reloc.exp.X_add_symbol)
-      && ! THUMB_IS_FUNC (inst.reloc.exp.X_add_symbol))
-    inst.reloc.exp.X_add_symbol =
-      find_real_start (inst.reloc.exp.X_add_symbol);
-#endif
-}
-
-static void
-do_t_bx (void)
-{
-  set_it_insn_type_last ();
-  inst.instruction |= inst.operands[0].reg << 3;
-  /* ??? FIXME: Should add a hacky reloc here if reg is REG_PC.         The reloc
-     should cause the alignment to be checked once it is known.         This is
-     because BX PC only works if the instruction is word aligned.  */
-}
-
-static void
-do_t_bxj (void)
-{
-  int Rm;
-
-  set_it_insn_type_last ();
-  Rm = inst.operands[0].reg;
-  reject_bad_reg (Rm);
-  inst.instruction |= Rm << 16;
-}
+/* Table of Thumb instructions which exist in both 16- and 32-bit
+   encodings (the latter only in post-V6T2 cores).  The index is the
+   value used in the insns table below.  When there is more than one
+   possible 16-bit encoding for the instruction, this table always
+   holds variant (1).
+   Also contains several pseudo-instructions used during relaxation.  */
+#define T16_32_TAB                             \
+  X(_adc,   4140, eb400000),                   \
+  X(_adcs,  4140, eb500000),                   \
+  X(_add,   1c00, eb000000),                   \
+  X(_adds,  1c00, eb100000),                   \
+  X(_addi,  0000, f1000000),                   \
+  X(_addis, 0000, f1100000),                   \
+  X(_add_pc,000f, f20f0000),                   \
+  X(_add_sp,000d, f10d0000),                   \
+  X(_adr,   000f, f20f0000),                   \
+  X(_and,   4000, ea000000),                   \
+  X(_ands,  4000, ea100000),                   \
+  X(_asr,   1000, fa40f000),                   \
+  X(_asrs,  1000, fa50f000),                   \
+  X(_b,     e000, f000b000),                   \
+  X(_bcond, d000, f0008000),                   \
+  X(_bic,   4380, ea200000),                   \
+  X(_bics,  4380, ea300000),                   \
+  X(_cmn,   42c0, eb100f00),                   \
+  X(_cmp,   2800, ebb00f00),                   \
+  X(_cpsie, b660, f3af8400),                   \
+  X(_cpsid, b670, f3af8600),                   \
+  X(_cpy,   4600, ea4f0000),                   \
+  X(_dec_sp,80dd, f1ad0d00),                   \
+  X(_eor,   4040, ea800000),                   \
+  X(_eors,  4040, ea900000),                   \
+  X(_inc_sp,00dd, f10d0d00),                   \
+  X(_ldmia, c800, e8900000),                   \
+  X(_ldr,   6800, f8500000),                   \
+  X(_ldrb,  7800, f8100000),                   \
+  X(_ldrh,  8800, f8300000),                   \
+  X(_ldrsb, 5600, f9100000),                   \
+  X(_ldrsh, 5e00, f9300000),                   \
+  X(_ldr_pc,4800, f85f0000),                   \
+  X(_ldr_pc2,4800, f85f0000),                  \
+  X(_ldr_sp,9800, f85d0000),                   \
+  X(_lsl,   0000, fa00f000),                   \
+  X(_lsls,  0000, fa10f000),                   \
+  X(_lsr,   0800, fa20f000),                   \
+  X(_lsrs,  0800, fa30f000),                   \
+  X(_mov,   2000, ea4f0000),                   \
+  X(_movs,  2000, ea5f0000),                   \
+  X(_mul,   4340, fb00f000),                     \
+  X(_muls,  4340, ffffffff), /* no 32b muls */ \
+  X(_mvn,   43c0, ea6f0000),                   \
+  X(_mvns,  43c0, ea7f0000),                   \
+  X(_neg,   4240, f1c00000), /* rsb #0 */      \
+  X(_negs,  4240, f1d00000), /* rsbs #0 */     \
+  X(_orr,   4300, ea400000),                   \
+  X(_orrs,  4300, ea500000),                   \
+  X(_pop,   bc00, e8bd0000), /* ldmia sp!,... */       \
+  X(_push,  b400, e92d0000), /* stmdb sp!,... */       \
+  X(_rev,   ba00, fa90f080),                   \
+  X(_rev16, ba40, fa90f090),                   \
+  X(_revsh, bac0, fa90f0b0),                   \
+  X(_ror,   41c0, fa60f000),                   \
+  X(_rors,  41c0, fa70f000),                   \
+  X(_sbc,   4180, eb600000),                   \
+  X(_sbcs,  4180, eb700000),                   \
+  X(_stmia, c000, e8800000),                   \
+  X(_str,   6000, f8400000),                   \
+  X(_strb,  7000, f8000000),                   \
+  X(_strh,  8000, f8200000),                   \
+  X(_str_sp,9000, f84d0000),                   \
+  X(_sub,   1e00, eba00000),                   \
+  X(_subs,  1e00, ebb00000),                   \
+  X(_subi,  8000, f1a00000),                   \
+  X(_subis, 8000, f1b00000),                   \
+  X(_sxtb,  b240, fa4ff080),                   \
+  X(_sxth,  b200, fa0ff080),                   \
+  X(_tst,   4200, ea100f00),                   \
+  X(_uxtb,  b2c0, fa5ff080),                   \
+  X(_uxth,  b280, fa1ff080),                   \
+  X(_nop,   bf00, f3af8000),                   \
+  X(_yield, bf10, f3af8001),                   \
+  X(_wfe,   bf20, f3af8002),                   \
+  X(_wfi,   bf30, f3af8003),                   \
+  X(_sev,   bf40, f3af8004),                    \
+  X(_sevl,  bf50, f3af8005),                   \
+  X(_udf,   de00, f7f0a000)
 
-static void
-do_t_clz (void)
-{
-  unsigned Rd;
-  unsigned Rm;
+/* To catch errors in encoding functions, the codes are all offset by
+   0xF800, putting them in one of the 32-bit prefix ranges, ergo undefined
+   as 16-bit instructions.  */
+#define X(a,b,c) T_MNEM##a
+enum t16_32_codes { T16_32_OFFSET = 0xF7FF, T16_32_TAB };
+#undef X
 
-  Rd = inst.operands[0].reg;
-  Rm = inst.operands[1].reg;
+#define X(a,b,c) 0x##b
+static const unsigned short thumb_op16[] = { T16_32_TAB };
+#define THUMB_OP16(n) (thumb_op16[(n) - (T16_32_OFFSET + 1)])
+#undef X
 
-  reject_bad_reg (Rd);
-  reject_bad_reg (Rm);
+#define X(a,b,c) 0x##c
+static const unsigned int thumb_op32[] = { T16_32_TAB };
+#define THUMB_OP32(n)        (thumb_op32[(n) - (T16_32_OFFSET + 1)])
+#define THUMB_SETS_FLAGS(n)  (THUMB_OP32 (n) & 0x00100000)
+#undef X
+#undef T16_32_TAB
 
-  inst.instruction |= Rd << 8;
-  inst.instruction |= Rm << 16;
-  inst.instruction |= Rm;
-}
+/* Thumb instruction encoders, in alphabetical order.  */
 
-static void
-do_t_cps (void)
-{
-  set_it_insn_type (OUTSIDE_IT_INSN);
-  inst.instruction |= inst.operands[0].imm;
-}
+/* ADDW or SUBW.  */
 
 static void
-do_t_cpsi (void)
+do_t_add_sub_w (void)
 {
-  set_it_insn_type (OUTSIDE_IT_INSN);
-  if (unified_syntax
-      && (inst.operands[1].present || inst.size_req == 4)
-      && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6_notm))
-    {
-      unsigned int imod = (inst.instruction & 0x0030) >> 4;
-      inst.instruction = 0xf3af8000;
-      inst.instruction |= imod << 9;
-      inst.instruction |= inst.operands[0].imm << 5;
-      if (inst.operands[1].present)
-       inst.instruction |= 0x100 | inst.operands[1].imm;
-    }
-  else
-    {
-      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1)
-                 && (inst.operands[0].imm & 4),
-                 _("selected processor does not support 'A' form "
-                   "of this instruction"));
-      constraint (inst.operands[1].present || inst.size_req == 4,
-                 _("Thumb does not support the 2-argument "
-                   "form of this instruction"));
-      inst.instruction |= inst.operands[0].imm;
-    }
-}
+  int Rd, Rn;
 
-/* THUMB CPY instruction (argument parse).  */
+  Rd = inst.operands[0].reg;
+  Rn = inst.operands[1].reg;
 
-static void
-do_t_cpy (void)
-{
-  if (inst.size_req == 4)
-    {
-      inst.instruction = THUMB_OP32 (T_MNEM_mov);
-      inst.instruction |= inst.operands[0].reg << 8;
-      inst.instruction |= inst.operands[1].reg;
-    }
+  /* If Rn is REG_PC, this is ADR; if Rn is REG_SP, then this
+     is the SP-{plus,minus}-immediate form of the instruction.  */
+  if (Rn == REG_SP)
+    constraint (Rd == REG_PC, BAD_PC);
   else
-    {
-      inst.instruction |= (inst.operands[0].reg & 0x8) << 4;
-      inst.instruction |= (inst.operands[0].reg & 0x7);
-      inst.instruction |= inst.operands[1].reg << 3;
-    }
-}
+    reject_bad_reg (Rd);
 
-static void
-do_t_cbz (void)
-{
-  set_it_insn_type (OUTSIDE_IT_INSN);
-  constraint (inst.operands[0].reg > 7, BAD_HIREG);
-  inst.instruction |= inst.operands[0].reg;
-  inst.reloc.pc_rel = 1;
-  inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH7;
+  inst.instruction |= (Rn << 16) | (Rd << 8);
+  inst.reloc.type = BFD_RELOC_ARM_T32_IMM12;
 }
 
-static void
-do_t_dbg (void)
-{
-  inst.instruction |= inst.operands[0].imm;
-}
+/* Parse an add or subtract instruction.  We get here with inst.instruction
+   equalling any of THUMB_OPCODE_add, adds, sub, or subs.  */
 
 static void
-do_t_div (void)
+do_t_add_sub (void)
 {
-  unsigned Rd, Rn, Rm;
+  int Rd, Rs, Rn;
 
   Rd = inst.operands[0].reg;
-  Rn = (inst.operands[1].present
-       ? inst.operands[1].reg : Rd);
-  Rm = inst.operands[2].reg;
+  Rs = (inst.operands[1].present
+       ? inst.operands[1].reg    /* Rd, Rs, foo */
+       : inst.operands[0].reg);  /* Rd, foo -> Rd, Rd, foo */
 
-  reject_bad_reg (Rd);
-  reject_bad_reg (Rn);
-  reject_bad_reg (Rm);
+  if (Rd == REG_PC)
+    set_it_insn_type_last ();
 
-  inst.instruction |= Rd << 8;
-  inst.instruction |= Rn << 16;
-  inst.instruction |= Rm;
-}
+  if (unified_syntax)
+    {
+      bfd_boolean flags;
+      bfd_boolean narrow;
+      int opcode;
 
-static void
-do_t_hint (void)
-{
-  if (unified_syntax && inst.size_req == 4)
-    inst.instruction = THUMB_OP32 (inst.instruction);
-  else
-    inst.instruction = THUMB_OP16 (inst.instruction);
-}
+      flags = (inst.instruction == T_MNEM_adds
+              || inst.instruction == T_MNEM_subs);
+      if (flags)
+       narrow = !in_it_block ();
+      else
+       narrow = in_it_block ();
+      if (!inst.operands[2].isreg)
+       {
+         int add;
 
-static void
-do_t_it (void)
-{
-  unsigned int cond = inst.operands[0].imm;
-
-  set_it_insn_type (IT_INSN);
-  now_it.mask = (inst.instruction & 0xf) | 0x10;
-  now_it.cc = cond;
-
-  /* If the condition is a negative condition, invert the mask.  */
-  if ((cond & 0x1) == 0x0)
-    {
-      unsigned int mask = inst.instruction & 0x000f;
+         constraint (Rd == REG_SP && Rs != REG_SP, BAD_SP);
 
-      if ((mask & 0x7) == 0)
-       /* no conversion needed */;
-      else if ((mask & 0x3) == 0)
-       mask ^= 0x8;
-      else if ((mask & 0x1) == 0)
-       mask ^= 0xC;
+         add = (inst.instruction == T_MNEM_add
+                || inst.instruction == T_MNEM_adds);
+         opcode = 0;
+         if (inst.size_req != 4)
+           {
+             /* Attempt to use a narrow opcode, with relaxation if
+                appropriate.  */
+             if (Rd == REG_SP && Rs == REG_SP && !flags)
+               opcode = add ? T_MNEM_inc_sp : T_MNEM_dec_sp;
+             else if (Rd <= 7 && Rs == REG_SP && add && !flags)
+               opcode = T_MNEM_add_sp;
+             else if (Rd <= 7 && Rs == REG_PC && add && !flags)
+               opcode = T_MNEM_add_pc;
+             else if (Rd <= 7 && Rs <= 7 && narrow)
+               {
+                 if (flags)
+                   opcode = add ? T_MNEM_addis : T_MNEM_subis;
+                 else
+                   opcode = add ? T_MNEM_addi : T_MNEM_subi;
+               }
+             if (opcode)
+               {
+                 inst.instruction = THUMB_OP16(opcode);
+                 inst.instruction |= (Rd << 4) | Rs;
+                 if (inst.reloc.type < BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
+                     || inst.reloc.type > BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC)
+                 {
+                   if (inst.size_req == 2)
+                     inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
+                   else
+                     inst.relax = opcode;
+                 }
+               }
+             else
+               constraint (inst.size_req == 2, BAD_HIREG);
+           }
+         if (inst.size_req == 4
+             || (inst.size_req != 2 && !opcode))
+           {
+             constraint (inst.reloc.type >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
+                         && inst.reloc.type <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC ,
+                         THUMB1_RELOC_ONLY);
+             if (Rd == REG_PC)
+               {
+                 constraint (add, BAD_PC);
+                 constraint (Rs != REG_LR || inst.instruction != T_MNEM_subs,
+                            _("only SUBS PC, LR, #const allowed"));
+                 constraint (inst.reloc.exp.X_op != O_constant,
+                             _("expression too complex"));
+                 constraint (inst.reloc.exp.X_add_number < 0
+                             || inst.reloc.exp.X_add_number > 0xff,
+                            _("immediate value out of range"));
+                 inst.instruction = T2_SUBS_PC_LR
+                                    | inst.reloc.exp.X_add_number;
+                 inst.reloc.type = BFD_RELOC_UNUSED;
+                 return;
+               }
+             else if (Rs == REG_PC)
+               {
+                 /* Always use addw/subw.  */
+                 inst.instruction = add ? 0xf20f0000 : 0xf2af0000;
+                 inst.reloc.type = BFD_RELOC_ARM_T32_IMM12;
+               }
+             else
+               {
+                 inst.instruction = THUMB_OP32 (inst.instruction);
+                 inst.instruction = (inst.instruction & 0xe1ffffff)
+                                    | 0x10000000;
+                 if (flags)
+                   inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
+                 else
+                   inst.reloc.type = BFD_RELOC_ARM_T32_ADD_IMM;
+               }
+             inst.instruction |= Rd << 8;
+             inst.instruction |= Rs << 16;
+           }
+       }
       else
-       mask ^= 0xE;
-
-      inst.instruction &= 0xfff0;
-      inst.instruction |= mask;
-    }
-
-  inst.instruction |= cond << 4;
-}
+       {
+         unsigned int value = inst.reloc.exp.X_add_number;
+         unsigned int shift = inst.operands[2].shift_kind;
 
-/* Helper function used for both push/pop and ldm/stm.  */
-static void
-encode_thumb2_ldmstm (int base, unsigned mask, bfd_boolean writeback)
-{
-  bfd_boolean load;
+         Rn = inst.operands[2].reg;
+         /* See if we can do this with a 16-bit instruction.  */
+         if (!inst.operands[2].shifted && inst.size_req != 4)
+           {
+             if (Rd > 7 || Rs > 7 || Rn > 7)
+               narrow = FALSE;
 
-  load = (inst.instruction & (1 << 20)) != 0;
+             if (narrow)
+               {
+                 inst.instruction = ((inst.instruction == T_MNEM_adds
+                                      || inst.instruction == T_MNEM_add)
+                                     ? T_OPCODE_ADD_R3
+                                     : T_OPCODE_SUB_R3);
+                 inst.instruction |= Rd | (Rs << 3) | (Rn << 6);
+                 return;
+               }
 
-  if (mask & (1 << 13))
-    inst.error =  _("SP not allowed in register list");
+             if (inst.instruction == T_MNEM_add && (Rd == Rs || Rd == Rn))
+               {
+                 /* Thumb-1 cores (except v6-M) require at least one high
+                    register in a narrow non flag setting add.  */
+                 if (Rd > 7 || Rn > 7
+                     || ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6t2)
+                     || ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_msr))
+                   {
+                     if (Rd == Rn)
+                       {
+                         Rn = Rs;
+                         Rs = Rd;
+                       }
+                     inst.instruction = T_OPCODE_ADD_HI;
+                     inst.instruction |= (Rd & 8) << 4;
+                     inst.instruction |= (Rd & 7);
+                     inst.instruction |= Rn << 3;
+                     return;
+                   }
+               }
+           }
 
-  if ((mask & (1 << base)) != 0
-      && writeback)
-    inst.error = _("having the base register in the register list when "
-                  "using write back is UNPREDICTABLE");
+         constraint (Rd == REG_PC, BAD_PC);
+         constraint (Rd == REG_SP && Rs != REG_SP, BAD_SP);
+         constraint (Rs == REG_PC, BAD_PC);
+         reject_bad_reg (Rn);
 
-  if (load)
-    {
-      if (mask & (1 << 15))
-        {
-          if (mask & (1 << 14))
-            inst.error = _("LR and PC should not both be in register list");
-          else
-            set_it_insn_type_last ();
-        }
+         /* If we get here, it can't be done in 16 bits.  */
+         constraint (inst.operands[2].shifted && inst.operands[2].immisreg,
+                     _("shift must be constant"));
+         inst.instruction = THUMB_OP32 (inst.instruction);
+         inst.instruction |= Rd << 8;
+         inst.instruction |= Rs << 16;
+         constraint (Rd == REG_SP && Rs == REG_SP && value > 3,
+                     _("shift value over 3 not allowed in thumb mode"));
+         constraint (Rd == REG_SP && Rs == REG_SP && shift != SHIFT_LSL,
+                     _("only LSL shift allowed in thumb mode"));
+         encode_thumb32_shifted_operand (2);
+       }
     }
   else
     {
-      if (mask & (1 << 15))
-       inst.error = _("PC not allowed in register list");
-    }
+      constraint (inst.instruction == T_MNEM_adds
+                 || inst.instruction == T_MNEM_subs,
+                 BAD_THUMB32);
 
-  if ((mask & (mask - 1)) == 0)
-    {
-      /* Single register transfers implemented as str/ldr.  */
-      if (writeback)
+      if (!inst.operands[2].isreg) /* Rd, Rs, #imm */
        {
-         if (inst.instruction & (1 << 23))
-           inst.instruction = 0x00000b04; /* ia! -> [base], #4 */
+         constraint ((Rd > 7 && (Rd != REG_SP || Rs != REG_SP))
+                     || (Rs > 7 && Rs != REG_SP && Rs != REG_PC),
+                     BAD_HIREG);
+
+         inst.instruction = (inst.instruction == T_MNEM_add
+                             ? 0x0000 : 0x8000);
+         inst.instruction |= (Rd << 4) | Rs;
+         inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
+         return;
+       }
+
+      Rn = inst.operands[2].reg;
+      constraint (inst.operands[2].shifted, _("unshifted register required"));
+
+      /* We now have Rd, Rs, and Rn set to registers.  */
+      if (Rd > 7 || Rs > 7 || Rn > 7)
+       {
+         /* Can't do this for SUB.      */
+         constraint (inst.instruction == T_MNEM_sub, BAD_HIREG);
+         inst.instruction = T_OPCODE_ADD_HI;
+         inst.instruction |= (Rd & 8) << 4;
+         inst.instruction |= (Rd & 7);
+         if (Rs == Rd)
+           inst.instruction |= Rn << 3;
+         else if (Rn == Rd)
+           inst.instruction |= Rs << 3;
          else
-           inst.instruction = 0x00000d04; /* db! -> [base, #-4]! */
+           constraint (1, _("dest must overlap one source register"));
        }
       else
        {
-         if (inst.instruction & (1 << 23))
-           inst.instruction = 0x00800000; /* ia -> [base] */
-         else
-           inst.instruction = 0x00000c04; /* db -> [base, #-4] */
+         inst.instruction = (inst.instruction == T_MNEM_add
+                             ? T_OPCODE_ADD_R3 : T_OPCODE_SUB_R3);
+         inst.instruction |= Rd | (Rs << 3) | (Rn << 6);
        }
-
-      inst.instruction |= 0xf8400000;
-      if (load)
-       inst.instruction |= 0x00100000;
-
-      mask = ffs (mask) - 1;
-      mask <<= 12;
     }
-  else if (writeback)
-    inst.instruction |= WRITE_BACK;
-
-  inst.instruction |= mask;
-  inst.instruction |= base << 16;
 }
 
 static void
-do_t_ldmstm (void)
+do_t_adr (void)
 {
-  /* This really doesn't seem worth it.  */
-  constraint (inst.reloc.type != BFD_RELOC_UNUSED,
-             _("expression too complex"));
-  constraint (inst.operands[1].writeback,
-             _("Thumb load/store multiple does not support {reglist}^"));
+  unsigned Rd;
 
-  if (unified_syntax)
+  Rd = inst.operands[0].reg;
+  reject_bad_reg (Rd);
+
+  if (unified_syntax && inst.size_req == 0 && Rd <= 7)
     {
-      bfd_boolean narrow;
-      unsigned mask;
+      /* Defer to section relaxation.  */
+      inst.relax = inst.instruction;
+      inst.instruction = THUMB_OP16 (inst.instruction);
+      inst.instruction |= Rd << 4;
+    }
+  else if (unified_syntax && inst.size_req != 2)
+    {
+      /* Generate a 32-bit opcode.  */
+      inst.instruction = THUMB_OP32 (inst.instruction);
+      inst.instruction |= Rd << 8;
+      inst.reloc.type = BFD_RELOC_ARM_T32_ADD_PC12;
+      inst.reloc.pc_rel = 1;
+    }
+  else
+    {
+      /* Generate a 16-bit opcode.  */
+      inst.instruction = THUMB_OP16 (inst.instruction);
+      inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
+      inst.reloc.exp.X_add_number -= 4; /* PC relative adjust.  */
+      inst.reloc.pc_rel = 1;
 
-      narrow = FALSE;
-      /* See if we can use a 16-bit instruction.  */
-      if (inst.instruction < 0xffff /* not ldmdb/stmdb */
-         && inst.size_req != 4
-         && !(inst.operands[1].imm & ~0xff))
-       {
-         mask = 1 << inst.operands[0].reg;
+      inst.instruction |= Rd << 4;
+    }
+}
 
-         if (inst.operands[0].reg <= 7)
-           {
-             if (inst.instruction == T_MNEM_stmia
-                 ? inst.operands[0].writeback
-                 : (inst.operands[0].writeback
-                    == !(inst.operands[1].imm & mask)))
-               {
-                 if (inst.instruction == T_MNEM_stmia
-                     && (inst.operands[1].imm & mask)
-                     && (inst.operands[1].imm & (mask - 1)))
-                   as_warn (_("value stored for r%d is UNKNOWN"),
-                            inst.operands[0].reg);
+/* Arithmetic instructions for which there is just one 16-bit
+   instruction encoding, and it allows only two low registers.
+   For maximal compatibility with ARM syntax, we allow three register
+   operands even when Thumb-32 instructions are not available, as long
+   as the first two are identical.  For instance, both "sbc r0,r1" and
+   "sbc r0,r0,r1" are allowed.  */
+static void
+do_t_arit3 (void)
+{
+  int Rd, Rs, Rn;
 
-                 inst.instruction = THUMB_OP16 (inst.instruction);
-                 inst.instruction |= inst.operands[0].reg << 8;
-                 inst.instruction |= inst.operands[1].imm;
-                 narrow = TRUE;
-               }
-             else if ((inst.operands[1].imm & (inst.operands[1].imm-1)) == 0)
-               {
-                 /* This means 1 register in reg list one of 3 situations:
-                    1. Instruction is stmia, but without writeback.
-                    2. lmdia without writeback, but with Rn not in
-                       reglist.
-                    3. ldmia with writeback, but with Rn in reglist.
-                    Case 3 is UNPREDICTABLE behaviour, so we handle
-                    case 1 and 2 which can be converted into a 16-bit
-                    str or ldr. The SP cases are handled below.  */
-                 unsigned long opcode;
-                 /* First, record an error for Case 3.  */
-                 if (inst.operands[1].imm & mask
-                     && inst.operands[0].writeback)
-                   inst.error = 
-                       _("having the base register in the register list when "
-                         "using write back is UNPREDICTABLE");
-                   
-                 opcode = (inst.instruction == T_MNEM_stmia ? T_MNEM_str 
-                                                            : T_MNEM_ldr);
-                 inst.instruction = THUMB_OP16 (opcode);
-                 inst.instruction |= inst.operands[0].reg << 3;
-                 inst.instruction |= (ffs (inst.operands[1].imm)-1);
-                 narrow = TRUE;
-               }
-           }
-         else if (inst.operands[0] .reg == REG_SP)
-           {
-             if (inst.operands[0].writeback)
-               {
-                 inst.instruction = 
-                       THUMB_OP16 (inst.instruction == T_MNEM_stmia
-                                   ? T_MNEM_push : T_MNEM_pop);
-                 inst.instruction |= inst.operands[1].imm;
-                 narrow = TRUE;
-               }
-             else if ((inst.operands[1].imm & (inst.operands[1].imm-1)) == 0)
-               {
-                 inst.instruction = 
-                       THUMB_OP16 (inst.instruction == T_MNEM_stmia
-                                   ? T_MNEM_str_sp : T_MNEM_ldr_sp);
-                 inst.instruction |= ((ffs (inst.operands[1].imm)-1) << 8);
-                 narrow = TRUE;
-               }
-           }
-       }
+  Rd = inst.operands[0].reg;
+  Rs = (inst.operands[1].present
+       ? inst.operands[1].reg    /* Rd, Rs, foo */
+       : inst.operands[0].reg);  /* Rd, foo -> Rd, Rd, foo */
+  Rn = inst.operands[2].reg;
 
-      if (!narrow)
-       {
-         if (inst.instruction < 0xffff)
-           inst.instruction = THUMB_OP32 (inst.instruction);
+  reject_bad_reg (Rd);
+  reject_bad_reg (Rs);
+  if (inst.operands[2].isreg)
+    reject_bad_reg (Rn);
 
-         encode_thumb2_ldmstm (inst.operands[0].reg, inst.operands[1].imm,
-                               inst.operands[0].writeback);
-       }
-    }
-  else
+  if (unified_syntax)
     {
-      constraint (inst.operands[0].reg > 7
-                 || (inst.operands[1].imm & ~0xff), BAD_HIREG);
-      constraint (inst.instruction != T_MNEM_ldmia
-                 && inst.instruction != T_MNEM_stmia,
-                 _("Thumb-2 instruction only valid in unified syntax"));
-      if (inst.instruction == T_MNEM_stmia)
+      if (!inst.operands[2].isreg)
        {
-         if (!inst.operands[0].writeback)
-           as_warn (_("this instruction will write back the base register"));
-         if ((inst.operands[1].imm & (1 << inst.operands[0].reg))
-             && (inst.operands[1].imm & ((1 << inst.operands[0].reg) - 1)))
-           as_warn (_("value stored for r%d is UNKNOWN"),
-                    inst.operands[0].reg);
+         /* For an immediate, we always generate a 32-bit opcode;
+            section relaxation will shrink it later if possible.  */
+         inst.instruction = THUMB_OP32 (inst.instruction);
+         inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
+         inst.instruction |= Rd << 8;
+         inst.instruction |= Rs << 16;
+         inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
        }
       else
        {
-         if (!inst.operands[0].writeback
-             && !(inst.operands[1].imm & (1 << inst.operands[0].reg)))
-           as_warn (_("this instruction will write back the base register"));
-         else if (inst.operands[0].writeback
-                  && (inst.operands[1].imm & (1 << inst.operands[0].reg)))
-           as_warn (_("this instruction will not write back the base register"));
-       }
-
-      inst.instruction = THUMB_OP16 (inst.instruction);
-      inst.instruction |= inst.operands[0].reg << 8;
-      inst.instruction |= inst.operands[1].imm;
-    }
-}
+         bfd_boolean narrow;
 
-static void
-do_t_ldrex (void)
-{
-  constraint (!inst.operands[1].isreg || !inst.operands[1].preind
-             || inst.operands[1].postind || inst.operands[1].writeback
-             || inst.operands[1].immisreg || inst.operands[1].shifted
-             || inst.operands[1].negative,
-             BAD_ADDR_MODE);
+         /* See if we can do this with a 16-bit instruction.  */
+         if (THUMB_SETS_FLAGS (inst.instruction))
+           narrow = !in_it_block ();
+         else
+           narrow = in_it_block ();
 
-  constraint ((inst.operands[1].reg == REG_PC), BAD_PC);
+         if (Rd > 7 || Rn > 7 || Rs > 7)
+           narrow = FALSE;
+         if (inst.operands[2].shifted)
+           narrow = FALSE;
+         if (inst.size_req == 4)
+           narrow = FALSE;
 
-  inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= inst.operands[1].reg << 16;
-  inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_U8;
-}
+         if (narrow
+             && Rd == Rs)
+           {
+             inst.instruction = THUMB_OP16 (inst.instruction);
+             inst.instruction |= Rd;
+             inst.instruction |= Rn << 3;
+             return;
+           }
 
-static void
-do_t_ldrexd (void)
-{
-  if (!inst.operands[1].present)
-    {
-      constraint (inst.operands[0].reg == REG_LR,
-                 _("r14 not allowed as first register "
-                   "when second register is omitted"));
-      inst.operands[1].reg = inst.operands[0].reg + 1;
+         /* If we get here, it can't be done in 16 bits.  */
+         constraint (inst.operands[2].shifted
+                     && inst.operands[2].immisreg,
+                     _("shift must be constant"));
+         inst.instruction = THUMB_OP32 (inst.instruction);
+         inst.instruction |= Rd << 8;
+         inst.instruction |= Rs << 16;
+         encode_thumb32_shifted_operand (2);
+       }
     }
-  constraint (inst.operands[0].reg == inst.operands[1].reg,
-             BAD_OVERLAP);
+  else
+    {
+      /* On its face this is a lie - the instruction does set the
+        flags.  However, the only supported mnemonic in this mode
+        says it doesn't.  */
+      constraint (THUMB_SETS_FLAGS (inst.instruction), BAD_THUMB32);
 
-  inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= inst.operands[1].reg << 8;
-  inst.instruction |= inst.operands[2].reg << 16;
+      constraint (!inst.operands[2].isreg || inst.operands[2].shifted,
+                 _("unshifted register required"));
+      constraint (Rd > 7 || Rs > 7 || Rn > 7, BAD_HIREG);
+      constraint (Rd != Rs,
+                 _("dest and source1 must be the same register"));
+
+      inst.instruction = THUMB_OP16 (inst.instruction);
+      inst.instruction |= Rd;
+      inst.instruction |= Rn << 3;
+    }
 }
 
+/* Similarly, but for instructions where the arithmetic operation is
+   commutative, so we can allow either of them to be different from
+   the destination operand in a 16-bit instruction.  For instance, all
+   three of "adc r0,r1", "adc r0,r0,r1", and "adc r0,r1,r0" are
+   accepted.  */
 static void
-do_t_ldst (void)
+do_t_arit3c (void)
 {
-  unsigned long opcode;
-  int Rn;
+  int Rd, Rs, Rn;
 
-  if (inst.operands[0].isreg
-      && !inst.operands[0].preind
-      && inst.operands[0].reg == REG_PC)
-    set_it_insn_type_last ();
+  Rd = inst.operands[0].reg;
+  Rs = (inst.operands[1].present
+       ? inst.operands[1].reg    /* Rd, Rs, foo */
+       : inst.operands[0].reg);  /* Rd, foo -> Rd, Rd, foo */
+  Rn = inst.operands[2].reg;
+
+  reject_bad_reg (Rd);
+  reject_bad_reg (Rs);
+  if (inst.operands[2].isreg)
+    reject_bad_reg (Rn);
 
-  opcode = inst.instruction;
   if (unified_syntax)
     {
-      if (!inst.operands[1].isreg)
+      if (!inst.operands[2].isreg)
        {
-         if (opcode <= 0xffff)
-           inst.instruction = THUMB_OP32 (opcode);
-         if (move_or_literal_pool (0, /*thumb_p=*/TRUE, /*mode_3=*/FALSE))
-           return;
+         /* For an immediate, we always generate a 32-bit opcode;
+            section relaxation will shrink it later if possible.  */
+         inst.instruction = THUMB_OP32 (inst.instruction);
+         inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
+         inst.instruction |= Rd << 8;
+         inst.instruction |= Rs << 16;
+         inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
        }
-      if (inst.operands[1].isreg
-         && !inst.operands[1].writeback
-         && !inst.operands[1].shifted && !inst.operands[1].postind
-         && !inst.operands[1].negative && inst.operands[0].reg <= 7
-         && opcode <= 0xffff
-         && inst.size_req != 4)
+      else
        {
-         /* Insn may have a 16-bit form.  */
-         Rn = inst.operands[1].reg;
-         if (inst.operands[1].immisreg)
+         bfd_boolean narrow;
+
+         /* See if we can do this with a 16-bit instruction.  */
+         if (THUMB_SETS_FLAGS (inst.instruction))
+           narrow = !in_it_block ();
+         else
+           narrow = in_it_block ();
+
+         if (Rd > 7 || Rn > 7 || Rs > 7)
+           narrow = FALSE;
+         if (inst.operands[2].shifted)
+           narrow = FALSE;
+         if (inst.size_req == 4)
+           narrow = FALSE;
+
+         if (narrow)
            {
-             inst.instruction = THUMB_OP16 (opcode);
-             /* [Rn, Rik] */
-             if (Rn <= 7 && inst.operands[1].imm <= 7)
-               goto op16;
-             else if (opcode != T_MNEM_ldr && opcode != T_MNEM_str)
-               reject_bad_reg (inst.operands[1].imm);
-           }
-         else if ((Rn <= 7 && opcode != T_MNEM_ldrsh
-                   && opcode != T_MNEM_ldrsb)
-                  || ((Rn == REG_PC || Rn == REG_SP) && opcode == T_MNEM_ldr)
-                  || (Rn == REG_SP && opcode == T_MNEM_str))
-           {
-             /* [Rn, #const] */
-             if (Rn > 7)
+             if (Rd == Rs)
                {
-                 if (Rn == REG_PC)
-                   {
-                     if (inst.reloc.pc_rel)
-                       opcode = T_MNEM_ldr_pc2;
-                     else
-                       opcode = T_MNEM_ldr_pc;
-                   }
-                 else
-                   {
-                     if (opcode == T_MNEM_ldr)
-                       opcode = T_MNEM_ldr_sp;
-                     else
-                       opcode = T_MNEM_str_sp;
-                   }
-                 inst.instruction = inst.operands[0].reg << 8;
+                 inst.instruction = THUMB_OP16 (inst.instruction);
+                 inst.instruction |= Rd;
+                 inst.instruction |= Rn << 3;
+                 return;
                }
-             else
+             if (Rd == Rn)
                {
-                 inst.instruction = inst.operands[0].reg;
-                 inst.instruction |= inst.operands[1].reg << 3;
+                 inst.instruction = THUMB_OP16 (inst.instruction);
+                 inst.instruction |= Rd;
+                 inst.instruction |= Rs << 3;
+                 return;
                }
-             inst.instruction |= THUMB_OP16 (opcode);
-             if (inst.size_req == 2)
-               inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
-             else
-               inst.relax = opcode;
-             return;
            }
-       }
-      /* Definitely a 32-bit variant.  */
-
-      /* Do some validations regarding addressing modes.  */
-      if (inst.operands[1].immisreg && opcode != T_MNEM_ldr
-         && opcode != T_MNEM_str)
-       reject_bad_reg (inst.operands[1].imm);
 
-      inst.instruction = THUMB_OP32 (opcode);
-      inst.instruction |= inst.operands[0].reg << 12;
-      encode_thumb32_addr_mode (1, /*is_t=*/FALSE, /*is_d=*/FALSE);
-      return;
+         /* If we get here, it can't be done in 16 bits.  */
+         constraint (inst.operands[2].shifted
+                     && inst.operands[2].immisreg,
+                     _("shift must be constant"));
+         inst.instruction = THUMB_OP32 (inst.instruction);
+         inst.instruction |= Rd << 8;
+         inst.instruction |= Rs << 16;
+         encode_thumb32_shifted_operand (2);
+       }
     }
-
-  constraint (inst.operands[0].reg > 7, BAD_HIREG);
-
-  if (inst.instruction == T_MNEM_ldrsh || inst.instruction == T_MNEM_ldrsb)
+  else
     {
-      /* Only [Rn,Rm] is acceptable.  */
-      constraint (inst.operands[1].reg > 7 || inst.operands[1].imm > 7, BAD_HIREG);
-      constraint (!inst.operands[1].isreg || !inst.operands[1].immisreg
-                 || inst.operands[1].postind || inst.operands[1].shifted
-                 || inst.operands[1].negative,
-                 _("Thumb does not support this addressing mode"));
-      inst.instruction = THUMB_OP16 (inst.instruction);
-      goto op16;
-    }
+      /* On its face this is a lie - the instruction does set the
+        flags.  However, the only supported mnemonic in this mode
+        says it doesn't.  */
+      constraint (THUMB_SETS_FLAGS (inst.instruction), BAD_THUMB32);
 
-  inst.instruction = THUMB_OP16 (inst.instruction);
-  if (!inst.operands[1].isreg)
-    if (move_or_literal_pool (0, /*thumb_p=*/TRUE, /*mode_3=*/FALSE))
-      return;
+      constraint (!inst.operands[2].isreg || inst.operands[2].shifted,
+                 _("unshifted register required"));
+      constraint (Rd > 7 || Rs > 7 || Rn > 7, BAD_HIREG);
 
-  constraint (!inst.operands[1].preind
-             || inst.operands[1].shifted
-             || inst.operands[1].writeback,
-             _("Thumb does not support this addressing mode"));
-  if (inst.operands[1].reg == REG_PC || inst.operands[1].reg == REG_SP)
-    {
-      constraint (inst.instruction & 0x0600,
-                 _("byte or halfword not valid for base register"));
-      constraint (inst.operands[1].reg == REG_PC
-                 && !(inst.instruction & THUMB_LOAD_BIT),
-                 _("r15 based store not allowed"));
-      constraint (inst.operands[1].immisreg,
-                 _("invalid base register for register offset"));
+      inst.instruction = THUMB_OP16 (inst.instruction);
+      inst.instruction |= Rd;
 
-      if (inst.operands[1].reg == REG_PC)
-       inst.instruction = T_OPCODE_LDR_PC;
-      else if (inst.instruction & THUMB_LOAD_BIT)
-       inst.instruction = T_OPCODE_LDR_SP;
+      if (Rd == Rs)
+       inst.instruction |= Rn << 3;
+      else if (Rd == Rn)
+       inst.instruction |= Rs << 3;
       else
-       inst.instruction = T_OPCODE_STR_SP;
-
-      inst.instruction |= inst.operands[0].reg << 8;
-      inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
-      return;
-    }
-
-  constraint (inst.operands[1].reg > 7, BAD_HIREG);
-  if (!inst.operands[1].immisreg)
-    {
-      /* Immediate offset.  */
-      inst.instruction |= inst.operands[0].reg;
-      inst.instruction |= inst.operands[1].reg << 3;
-      inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
-      return;
-    }
-
-  /* Register offset.  */
-  constraint (inst.operands[1].imm > 7, BAD_HIREG);
-  constraint (inst.operands[1].negative,
-             _("Thumb does not support this addressing mode"));
-
- op16:
-  switch (inst.instruction)
-    {
-    case T_OPCODE_STR_IW: inst.instruction = T_OPCODE_STR_RW; break;
-    case T_OPCODE_STR_IH: inst.instruction = T_OPCODE_STR_RH; break;
-    case T_OPCODE_STR_IB: inst.instruction = T_OPCODE_STR_RB; break;
-    case T_OPCODE_LDR_IW: inst.instruction = T_OPCODE_LDR_RW; break;
-    case T_OPCODE_LDR_IH: inst.instruction = T_OPCODE_LDR_RH; break;
-    case T_OPCODE_LDR_IB: inst.instruction = T_OPCODE_LDR_RB; break;
-    case 0x5600 /* ldrsb */:
-    case 0x5e00 /* ldrsh */: break;
-    default: abort ();
+       constraint (1, _("dest must overlap one source register"));
     }
-
-  inst.instruction |= inst.operands[0].reg;
-  inst.instruction |= inst.operands[1].reg << 3;
-  inst.instruction |= inst.operands[1].imm << 6;
 }
 
 static void
-do_t_ldstd (void)
+do_t_bfc (void)
 {
-  if (!inst.operands[1].present)
-    {
-      inst.operands[1].reg = inst.operands[0].reg + 1;
-      constraint (inst.operands[0].reg == REG_LR,
-                 _("r14 not allowed here"));
-    }
-  inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= inst.operands[1].reg << 8;
-  encode_thumb32_addr_mode (2, /*is_t=*/FALSE, /*is_d=*/TRUE);
+  unsigned Rd;
+  unsigned int msb = inst.operands[1].imm + inst.operands[2].imm;
+  constraint (msb > 32, _("bit-field extends past end of register"));
+  /* The instruction encoding stores the LSB and MSB,
+     not the LSB and width.  */
+  Rd = inst.operands[0].reg;
+  reject_bad_reg (Rd);
+  inst.instruction |= Rd << 8;
+  inst.instruction |= (inst.operands[1].imm & 0x1c) << 10;
+  inst.instruction |= (inst.operands[1].imm & 0x03) << 6;
+  inst.instruction |= msb - 1;
 }
 
 static void
-do_t_ldstt (void)
+do_t_bfi (void)
 {
-  inst.instruction |= inst.operands[0].reg << 12;
-  encode_thumb32_addr_mode (1, /*is_t=*/TRUE, /*is_d=*/FALSE);
+  int Rd, Rn;
+  unsigned int msb;
+
+  Rd = inst.operands[0].reg;
+  reject_bad_reg (Rd);
+
+  /* #0 in second position is alternative syntax for bfc, which is
+     the same instruction but with REG_PC in the Rm field.  */
+  if (!inst.operands[1].isreg)
+    Rn = REG_PC;
+  else
+    {
+      Rn = inst.operands[1].reg;
+      reject_bad_reg (Rn);
+    }
+
+  msb = inst.operands[2].imm + inst.operands[3].imm;
+  constraint (msb > 32, _("bit-field extends past end of register"));
+  /* The instruction encoding stores the LSB and MSB,
+     not the LSB and width.  */
+  inst.instruction |= Rd << 8;
+  inst.instruction |= Rn << 16;
+  inst.instruction |= (inst.operands[2].imm & 0x1c) << 10;
+  inst.instruction |= (inst.operands[2].imm & 0x03) << 6;
+  inst.instruction |= msb - 1;
 }
 
 static void
-do_t_mla (void)
+do_t_bfx (void)
 {
-  unsigned Rd, Rn, Rm, Ra;
+  unsigned Rd, Rn;
 
   Rd = inst.operands[0].reg;
   Rn = inst.operands[1].reg;
-  Rm = inst.operands[2].reg;
-  Ra = inst.operands[3].reg;
 
   reject_bad_reg (Rd);
   reject_bad_reg (Rn);
-  reject_bad_reg (Rm);
-  reject_bad_reg (Ra);
 
+  constraint (inst.operands[2].imm + inst.operands[3].imm > 32,
+             _("bit-field extends past end of register"));
   inst.instruction |= Rd << 8;
   inst.instruction |= Rn << 16;
-  inst.instruction |= Rm;
-  inst.instruction |= Ra << 12;
+  inst.instruction |= (inst.operands[2].imm & 0x1c) << 10;
+  inst.instruction |= (inst.operands[2].imm & 0x03) << 6;
+  inst.instruction |= inst.operands[3].imm - 1;
 }
 
-static void
-do_t_mlal (void)
-{
-  unsigned RdLo, RdHi, Rn, Rm;
+/* ARM V5 Thumb BLX (argument parse)
+       BLX <target_addr>       which is BLX(1)
+       BLX <Rm>                which is BLX(2)
+   Unfortunately, there are two different opcodes for this mnemonic.
+   So, the insns[].value is not used, and the code here zaps values
+       into inst.instruction.
 
-  RdLo = inst.operands[0].reg;
-  RdHi = inst.operands[1].reg;
-  Rn = inst.operands[2].reg;
-  Rm = inst.operands[3].reg;
+   ??? How to take advantage of the additional two bits of displacement
+   available in Thumb32 mode?  Need new relocation?  */
 
-  reject_bad_reg (RdLo);
-  reject_bad_reg (RdHi);
-  reject_bad_reg (Rn);
-  reject_bad_reg (Rm);
+static void
+do_t_blx (void)
+{
+  set_it_insn_type_last ();
 
-  inst.instruction |= RdLo << 12;
-  inst.instruction |= RdHi << 8;
-  inst.instruction |= Rn << 16;
-  inst.instruction |= Rm;
+  if (inst.operands[0].isreg)
+    {
+      constraint (inst.operands[0].reg == REG_PC, BAD_PC);
+      /* We have a register, so this is BLX(2).  */
+      inst.instruction |= inst.operands[0].reg << 3;
+    }
+  else
+    {
+      /* No register.  This must be BLX(1).  */
+      inst.instruction = 0xf000e800;
+      encode_branch (BFD_RELOC_THUMB_PCREL_BLX);
+    }
 }
 
 static void
-do_t_mov_cmp (void)
+do_t_branch (void)
 {
-  unsigned Rn, Rm;
+  int opcode;
+  int cond;
+  bfd_reloc_code_real_type reloc;
 
-  Rn = inst.operands[0].reg;
+  cond = inst.cond;
+  set_it_insn_type (IF_INSIDE_IT_LAST_INSN);
+
+  if (in_it_block ())
+    {
+      /* Conditional branches inside IT blocks are encoded as unconditional
+        branches.  */
+      cond = COND_ALWAYS;
+    }
+  else
+    cond = inst.cond;
+
+  if (cond != COND_ALWAYS)
+    opcode = T_MNEM_bcond;
+  else
+    opcode = inst.instruction;
+
+  if (unified_syntax
+      && (inst.size_req == 4
+         || (inst.size_req != 2
+             && (inst.operands[0].hasreloc
+                 || inst.reloc.exp.X_op == O_constant))))
+    {
+      inst.instruction = THUMB_OP32(opcode);
+      if (cond == COND_ALWAYS)
+       reloc = BFD_RELOC_THUMB_PCREL_BRANCH25;
+      else
+       {
+         constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6t2),
+                     _("selected architecture does not support "
+                       "wide conditional branch instruction"));
+
+         gas_assert (cond != 0xF);
+         inst.instruction |= cond << 22;
+         reloc = BFD_RELOC_THUMB_PCREL_BRANCH20;
+       }
+    }
+  else
+    {
+      inst.instruction = THUMB_OP16(opcode);
+      if (cond == COND_ALWAYS)
+       reloc = BFD_RELOC_THUMB_PCREL_BRANCH12;
+      else
+       {
+         inst.instruction |= cond << 8;
+         reloc = BFD_RELOC_THUMB_PCREL_BRANCH9;
+       }
+      /* Allow section relaxation.  */
+      if (unified_syntax && inst.size_req != 2)
+       inst.relax = opcode;
+    }
+  inst.reloc.type = reloc;
+  inst.reloc.pc_rel = 1;
+}
+
+/* Actually do the work for Thumb state bkpt and hlt.  The only difference
+   between the two is the maximum immediate allowed - which is passed in
+   RANGE.  */
+static void
+do_t_bkpt_hlt1 (int range)
+{
+  constraint (inst.cond != COND_ALWAYS,
+             _("instruction is always unconditional"));
+  if (inst.operands[0].present)
+    {
+      constraint (inst.operands[0].imm > range,
+                 _("immediate value out of range"));
+      inst.instruction |= inst.operands[0].imm;
+    }
+
+  set_it_insn_type (NEUTRAL_IT_INSN);
+}
+
+static void
+do_t_hlt (void)
+{
+  do_t_bkpt_hlt1 (63);
+}
+
+static void
+do_t_bkpt (void)
+{
+  do_t_bkpt_hlt1 (255);
+}
+
+static void
+do_t_branch23 (void)
+{
+  set_it_insn_type_last ();
+  encode_branch (BFD_RELOC_THUMB_PCREL_BRANCH23);
+
+  /* md_apply_fix blows up with 'bl foo(PLT)' where foo is defined in
+     this file.  We used to simply ignore the PLT reloc type here --
+     the branch encoding is now needed to deal with TLSCALL relocs.
+     So if we see a PLT reloc now, put it back to how it used to be to
+     keep the preexisting behaviour.  */
+  if (inst.reloc.type == BFD_RELOC_ARM_PLT32)
+    inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH23;
+
+#if defined(OBJ_COFF)
+  /* If the destination of the branch is a defined symbol which does not have
+     the THUMB_FUNC attribute, then we must be calling a function which has
+     the (interfacearm) attribute.  We look for the Thumb entry point to that
+     function and change the branch to refer to that function instead. */
+  if (  inst.reloc.exp.X_op == O_symbol
+      && inst.reloc.exp.X_add_symbol != NULL
+      && S_IS_DEFINED (inst.reloc.exp.X_add_symbol)
+      && ! THUMB_IS_FUNC (inst.reloc.exp.X_add_symbol))
+    inst.reloc.exp.X_add_symbol =
+      find_real_start (inst.reloc.exp.X_add_symbol);
+#endif
+}
+
+static void
+do_t_bx (void)
+{
+  set_it_insn_type_last ();
+  inst.instruction |= inst.operands[0].reg << 3;
+  /* ??? FIXME: Should add a hacky reloc here if reg is REG_PC.         The reloc
+     should cause the alignment to be checked once it is known.         This is
+     because BX PC only works if the instruction is word aligned.  */
+}
+
+static void
+do_t_bxj (void)
+{
+  int Rm;
+
+  set_it_insn_type_last ();
+  Rm = inst.operands[0].reg;
+  reject_bad_reg (Rm);
+  inst.instruction |= Rm << 16;
+}
+
+static void
+do_t_clz (void)
+{
+  unsigned Rd;
+  unsigned Rm;
+
+  Rd = inst.operands[0].reg;
   Rm = inst.operands[1].reg;
 
-  if (Rn == REG_PC)
-    set_it_insn_type_last ();
+  reject_bad_reg (Rd);
+  reject_bad_reg (Rm);
+
+  inst.instruction |= Rd << 8;
+  inst.instruction |= Rm << 16;
+  inst.instruction |= Rm;
+}
+
+static void
+do_t_cps (void)
+{
+  set_it_insn_type (OUTSIDE_IT_INSN);
+  inst.instruction |= inst.operands[0].imm;
+}
+
+static void
+do_t_cpsi (void)
+{
+  set_it_insn_type (OUTSIDE_IT_INSN);
+  if (unified_syntax
+      && (inst.operands[1].present || inst.size_req == 4)
+      && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6_notm))
+    {
+      unsigned int imod = (inst.instruction & 0x0030) >> 4;
+      inst.instruction = 0xf3af8000;
+      inst.instruction |= imod << 9;
+      inst.instruction |= inst.operands[0].imm << 5;
+      if (inst.operands[1].present)
+       inst.instruction |= 0x100 | inst.operands[1].imm;
+    }
+  else
+    {
+      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1)
+                 && (inst.operands[0].imm & 4),
+                 _("selected processor does not support 'A' form "
+                   "of this instruction"));
+      constraint (inst.operands[1].present || inst.size_req == 4,
+                 _("Thumb does not support the 2-argument "
+                   "form of this instruction"));
+      inst.instruction |= inst.operands[0].imm;
+    }
+}
+
+/* THUMB CPY instruction (argument parse).  */
+
+static void
+do_t_cpy (void)
+{
+  if (inst.size_req == 4)
+    {
+      inst.instruction = THUMB_OP32 (T_MNEM_mov);
+      inst.instruction |= inst.operands[0].reg << 8;
+      inst.instruction |= inst.operands[1].reg;
+    }
+  else
+    {
+      inst.instruction |= (inst.operands[0].reg & 0x8) << 4;
+      inst.instruction |= (inst.operands[0].reg & 0x7);
+      inst.instruction |= inst.operands[1].reg << 3;
+    }
+}
+
+static void
+do_t_cbz (void)
+{
+  set_it_insn_type (OUTSIDE_IT_INSN);
+  constraint (inst.operands[0].reg > 7, BAD_HIREG);
+  inst.instruction |= inst.operands[0].reg;
+  inst.reloc.pc_rel = 1;
+  inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH7;
+}
+
+static void
+do_t_dbg (void)
+{
+  inst.instruction |= inst.operands[0].imm;
+}
+
+static void
+do_t_div (void)
+{
+  unsigned Rd, Rn, Rm;
+
+  Rd = inst.operands[0].reg;
+  Rn = (inst.operands[1].present
+       ? inst.operands[1].reg : Rd);
+  Rm = inst.operands[2].reg;
+
+  reject_bad_reg (Rd);
+  reject_bad_reg (Rn);
+  reject_bad_reg (Rm);
+
+  inst.instruction |= Rd << 8;
+  inst.instruction |= Rn << 16;
+  inst.instruction |= Rm;
+}
+
+static void
+do_t_hint (void)
+{
+  if (unified_syntax && inst.size_req == 4)
+    inst.instruction = THUMB_OP32 (inst.instruction);
+  else
+    inst.instruction = THUMB_OP16 (inst.instruction);
+}
+
+static void
+do_t_it (void)
+{
+  unsigned int cond = inst.operands[0].imm;
+
+  set_it_insn_type (IT_INSN);
+  now_it.mask = (inst.instruction & 0xf) | 0x10;
+  now_it.cc = cond;
+  now_it.warn_deprecated = FALSE;
+
+  /* If the condition is a negative condition, invert the mask.  */
+  if ((cond & 0x1) == 0x0)
+    {
+      unsigned int mask = inst.instruction & 0x000f;
+
+      if ((mask & 0x7) == 0)
+       {
+         /* No conversion needed.  */
+         now_it.block_length = 1;
+       }
+      else if ((mask & 0x3) == 0)
+       {
+         mask ^= 0x8;
+         now_it.block_length = 2;
+       }
+      else if ((mask & 0x1) == 0)
+       {
+         mask ^= 0xC;
+         now_it.block_length = 3;
+       }
+      else
+       {
+         mask ^= 0xE;
+         now_it.block_length = 4;
+       }
+
+      inst.instruction &= 0xfff0;
+      inst.instruction |= mask;
+    }
+
+  inst.instruction |= cond << 4;
+}
+
+/* Helper function used for both push/pop and ldm/stm.  */
+static void
+encode_thumb2_ldmstm (int base, unsigned mask, bfd_boolean writeback)
+{
+  bfd_boolean load;
+
+  load = (inst.instruction & (1 << 20)) != 0;
+
+  if (mask & (1 << 13))
+    inst.error =  _("SP not allowed in register list");
+
+  if ((mask & (1 << base)) != 0
+      && writeback)
+    inst.error = _("having the base register in the register list when "
+                  "using write back is UNPREDICTABLE");
+
+  if (load)
+    {
+      if (mask & (1 << 15))
+       {
+         if (mask & (1 << 14))
+           inst.error = _("LR and PC should not both be in register list");
+         else
+           set_it_insn_type_last ();
+       }
+    }
+  else
+    {
+      if (mask & (1 << 15))
+       inst.error = _("PC not allowed in register list");
+    }
+
+  if ((mask & (mask - 1)) == 0)
+    {
+      /* Single register transfers implemented as str/ldr.  */
+      if (writeback)
+       {
+         if (inst.instruction & (1 << 23))
+           inst.instruction = 0x00000b04; /* ia! -> [base], #4 */
+         else
+           inst.instruction = 0x00000d04; /* db! -> [base, #-4]! */
+       }
+      else
+       {
+         if (inst.instruction & (1 << 23))
+           inst.instruction = 0x00800000; /* ia -> [base] */
+         else
+           inst.instruction = 0x00000c04; /* db -> [base, #-4] */
+       }
+
+      inst.instruction |= 0xf8400000;
+      if (load)
+       inst.instruction |= 0x00100000;
+
+      mask = ffs (mask) - 1;
+      mask <<= 12;
+    }
+  else if (writeback)
+    inst.instruction |= WRITE_BACK;
+
+  inst.instruction |= mask;
+  inst.instruction |= base << 16;
+}
+
+static void
+do_t_ldmstm (void)
+{
+  /* This really doesn't seem worth it.  */
+  constraint (inst.reloc.type != BFD_RELOC_UNUSED,
+             _("expression too complex"));
+  constraint (inst.operands[1].writeback,
+             _("Thumb load/store multiple does not support {reglist}^"));
+
+  if (unified_syntax)
+    {
+      bfd_boolean narrow;
+      unsigned mask;
+
+      narrow = FALSE;
+      /* See if we can use a 16-bit instruction.  */
+      if (inst.instruction < 0xffff /* not ldmdb/stmdb */
+         && inst.size_req != 4
+         && !(inst.operands[1].imm & ~0xff))
+       {
+         mask = 1 << inst.operands[0].reg;
+
+         if (inst.operands[0].reg <= 7)
+           {
+             if (inst.instruction == T_MNEM_stmia
+                 ? inst.operands[0].writeback
+                 : (inst.operands[0].writeback
+                    == !(inst.operands[1].imm & mask)))
+               {
+                 if (inst.instruction == T_MNEM_stmia
+                     && (inst.operands[1].imm & mask)
+                     && (inst.operands[1].imm & (mask - 1)))
+                   as_warn (_("value stored for r%d is UNKNOWN"),
+                            inst.operands[0].reg);
+
+                 inst.instruction = THUMB_OP16 (inst.instruction);
+                 inst.instruction |= inst.operands[0].reg << 8;
+                 inst.instruction |= inst.operands[1].imm;
+                 narrow = TRUE;
+               }
+             else if ((inst.operands[1].imm & (inst.operands[1].imm-1)) == 0)
+               {
+                 /* This means 1 register in reg list one of 3 situations:
+                    1. Instruction is stmia, but without writeback.
+                    2. lmdia without writeback, but with Rn not in
+                       reglist.
+                    3. ldmia with writeback, but with Rn in reglist.
+                    Case 3 is UNPREDICTABLE behaviour, so we handle
+                    case 1 and 2 which can be converted into a 16-bit
+                    str or ldr. The SP cases are handled below.  */
+                 unsigned long opcode;
+                 /* First, record an error for Case 3.  */
+                 if (inst.operands[1].imm & mask
+                     && inst.operands[0].writeback)
+                   inst.error =
+                       _("having the base register in the register list when "
+                         "using write back is UNPREDICTABLE");
+
+                 opcode = (inst.instruction == T_MNEM_stmia ? T_MNEM_str
+                                                            : T_MNEM_ldr);
+                 inst.instruction = THUMB_OP16 (opcode);
+                 inst.instruction |= inst.operands[0].reg << 3;
+                 inst.instruction |= (ffs (inst.operands[1].imm)-1);
+                 narrow = TRUE;
+               }
+           }
+         else if (inst.operands[0] .reg == REG_SP)
+           {
+             if (inst.operands[0].writeback)
+               {
+                 inst.instruction =
+                       THUMB_OP16 (inst.instruction == T_MNEM_stmia
+                                   ? T_MNEM_push : T_MNEM_pop);
+                 inst.instruction |= inst.operands[1].imm;
+                 narrow = TRUE;
+               }
+             else if ((inst.operands[1].imm & (inst.operands[1].imm-1)) == 0)
+               {
+                 inst.instruction =
+                       THUMB_OP16 (inst.instruction == T_MNEM_stmia
+                                   ? T_MNEM_str_sp : T_MNEM_ldr_sp);
+                 inst.instruction |= ((ffs (inst.operands[1].imm)-1) << 8);
+                 narrow = TRUE;
+               }
+           }
+       }
+
+      if (!narrow)
+       {
+         if (inst.instruction < 0xffff)
+           inst.instruction = THUMB_OP32 (inst.instruction);
+
+         encode_thumb2_ldmstm (inst.operands[0].reg, inst.operands[1].imm,
+                               inst.operands[0].writeback);
+       }
+    }
+  else
+    {
+      constraint (inst.operands[0].reg > 7
+                 || (inst.operands[1].imm & ~0xff), BAD_HIREG);
+      constraint (inst.instruction != T_MNEM_ldmia
+                 && inst.instruction != T_MNEM_stmia,
+                 _("Thumb-2 instruction only valid in unified syntax"));
+      if (inst.instruction == T_MNEM_stmia)
+       {
+         if (!inst.operands[0].writeback)
+           as_warn (_("this instruction will write back the base register"));
+         if ((inst.operands[1].imm & (1 << inst.operands[0].reg))
+             && (inst.operands[1].imm & ((1 << inst.operands[0].reg) - 1)))
+           as_warn (_("value stored for r%d is UNKNOWN"),
+                    inst.operands[0].reg);
+       }
+      else
+       {
+         if (!inst.operands[0].writeback
+             && !(inst.operands[1].imm & (1 << inst.operands[0].reg)))
+           as_warn (_("this instruction will write back the base register"));
+         else if (inst.operands[0].writeback
+                  && (inst.operands[1].imm & (1 << inst.operands[0].reg)))
+           as_warn (_("this instruction will not write back the base register"));
+       }
+
+      inst.instruction = THUMB_OP16 (inst.instruction);
+      inst.instruction |= inst.operands[0].reg << 8;
+      inst.instruction |= inst.operands[1].imm;
+    }
+}
+
+static void
+do_t_ldrex (void)
+{
+  constraint (!inst.operands[1].isreg || !inst.operands[1].preind
+             || inst.operands[1].postind || inst.operands[1].writeback
+             || inst.operands[1].immisreg || inst.operands[1].shifted
+             || inst.operands[1].negative,
+             BAD_ADDR_MODE);
+
+  constraint ((inst.operands[1].reg == REG_PC), BAD_PC);
+
+  inst.instruction |= inst.operands[0].reg << 12;
+  inst.instruction |= inst.operands[1].reg << 16;
+  inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_U8;
+}
+
+static void
+do_t_ldrexd (void)
+{
+  if (!inst.operands[1].present)
+    {
+      constraint (inst.operands[0].reg == REG_LR,
+                 _("r14 not allowed as first register "
+                   "when second register is omitted"));
+      inst.operands[1].reg = inst.operands[0].reg + 1;
+    }
+  constraint (inst.operands[0].reg == inst.operands[1].reg,
+             BAD_OVERLAP);
+
+  inst.instruction |= inst.operands[0].reg << 12;
+  inst.instruction |= inst.operands[1].reg << 8;
+  inst.instruction |= inst.operands[2].reg << 16;
+}
+
+static void
+do_t_ldst (void)
+{
+  unsigned long opcode;
+  int Rn;
+
+  if (inst.operands[0].isreg
+      && !inst.operands[0].preind
+      && inst.operands[0].reg == REG_PC)
+    set_it_insn_type_last ();
+
+  opcode = inst.instruction;
+  if (unified_syntax)
+    {
+      if (!inst.operands[1].isreg)
+       {
+         if (opcode <= 0xffff)
+           inst.instruction = THUMB_OP32 (opcode);
+         if (move_or_literal_pool (0, CONST_THUMB, /*mode_3=*/FALSE))
+           return;
+       }
+      if (inst.operands[1].isreg
+         && !inst.operands[1].writeback
+         && !inst.operands[1].shifted && !inst.operands[1].postind
+         && !inst.operands[1].negative && inst.operands[0].reg <= 7
+         && opcode <= 0xffff
+         && inst.size_req != 4)
+       {
+         /* Insn may have a 16-bit form.  */
+         Rn = inst.operands[1].reg;
+         if (inst.operands[1].immisreg)
+           {
+             inst.instruction = THUMB_OP16 (opcode);
+             /* [Rn, Rik] */
+             if (Rn <= 7 && inst.operands[1].imm <= 7)
+               goto op16;
+             else if (opcode != T_MNEM_ldr && opcode != T_MNEM_str)
+               reject_bad_reg (inst.operands[1].imm);
+           }
+         else if ((Rn <= 7 && opcode != T_MNEM_ldrsh
+                   && opcode != T_MNEM_ldrsb)
+                  || ((Rn == REG_PC || Rn == REG_SP) && opcode == T_MNEM_ldr)
+                  || (Rn == REG_SP && opcode == T_MNEM_str))
+           {
+             /* [Rn, #const] */
+             if (Rn > 7)
+               {
+                 if (Rn == REG_PC)
+                   {
+                     if (inst.reloc.pc_rel)
+                       opcode = T_MNEM_ldr_pc2;
+                     else
+                       opcode = T_MNEM_ldr_pc;
+                   }
+                 else
+                   {
+                     if (opcode == T_MNEM_ldr)
+                       opcode = T_MNEM_ldr_sp;
+                     else
+                       opcode = T_MNEM_str_sp;
+                   }
+                 inst.instruction = inst.operands[0].reg << 8;
+               }
+             else
+               {
+                 inst.instruction = inst.operands[0].reg;
+                 inst.instruction |= inst.operands[1].reg << 3;
+               }
+             inst.instruction |= THUMB_OP16 (opcode);
+             if (inst.size_req == 2)
+               inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
+             else
+               inst.relax = opcode;
+             return;
+           }
+       }
+      /* Definitely a 32-bit variant.  */
+
+      /* Warning for Erratum 752419.  */
+      if (opcode == T_MNEM_ldr
+         && inst.operands[0].reg == REG_SP
+         && inst.operands[1].writeback == 1
+         && !inst.operands[1].immisreg)
+       {
+         if (no_cpu_selected ()
+             || (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v7)
+                 && !ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v7a)
+                 && !ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v7r)))
+           as_warn (_("This instruction may be unpredictable "
+                      "if executed on M-profile cores "
+                      "with interrupts enabled."));
+       }
+
+      /* Do some validations regarding addressing modes.  */
+      if (inst.operands[1].immisreg)
+       reject_bad_reg (inst.operands[1].imm);
+
+      constraint (inst.operands[1].writeback == 1
+                 && inst.operands[0].reg == inst.operands[1].reg,
+                 BAD_OVERLAP);
+
+      inst.instruction = THUMB_OP32 (opcode);
+      inst.instruction |= inst.operands[0].reg << 12;
+      encode_thumb32_addr_mode (1, /*is_t=*/FALSE, /*is_d=*/FALSE);
+      check_ldr_r15_aligned ();
+      return;
+    }
+
+  constraint (inst.operands[0].reg > 7, BAD_HIREG);
+
+  if (inst.instruction == T_MNEM_ldrsh || inst.instruction == T_MNEM_ldrsb)
+    {
+      /* Only [Rn,Rm] is acceptable.  */
+      constraint (inst.operands[1].reg > 7 || inst.operands[1].imm > 7, BAD_HIREG);
+      constraint (!inst.operands[1].isreg || !inst.operands[1].immisreg
+                 || inst.operands[1].postind || inst.operands[1].shifted
+                 || inst.operands[1].negative,
+                 _("Thumb does not support this addressing mode"));
+      inst.instruction = THUMB_OP16 (inst.instruction);
+      goto op16;
+    }
+
+  inst.instruction = THUMB_OP16 (inst.instruction);
+  if (!inst.operands[1].isreg)
+    if (move_or_literal_pool (0, CONST_THUMB, /*mode_3=*/FALSE))
+      return;
+
+  constraint (!inst.operands[1].preind
+             || inst.operands[1].shifted
+             || inst.operands[1].writeback,
+             _("Thumb does not support this addressing mode"));
+  if (inst.operands[1].reg == REG_PC || inst.operands[1].reg == REG_SP)
+    {
+      constraint (inst.instruction & 0x0600,
+                 _("byte or halfword not valid for base register"));
+      constraint (inst.operands[1].reg == REG_PC
+                 && !(inst.instruction & THUMB_LOAD_BIT),
+                 _("r15 based store not allowed"));
+      constraint (inst.operands[1].immisreg,
+                 _("invalid base register for register offset"));
+
+      if (inst.operands[1].reg == REG_PC)
+       inst.instruction = T_OPCODE_LDR_PC;
+      else if (inst.instruction & THUMB_LOAD_BIT)
+       inst.instruction = T_OPCODE_LDR_SP;
+      else
+       inst.instruction = T_OPCODE_STR_SP;
+
+      inst.instruction |= inst.operands[0].reg << 8;
+      inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
+      return;
+    }
+
+  constraint (inst.operands[1].reg > 7, BAD_HIREG);
+  if (!inst.operands[1].immisreg)
+    {
+      /* Immediate offset.  */
+      inst.instruction |= inst.operands[0].reg;
+      inst.instruction |= inst.operands[1].reg << 3;
+      inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
+      return;
+    }
+
+  /* Register offset.  */
+  constraint (inst.operands[1].imm > 7, BAD_HIREG);
+  constraint (inst.operands[1].negative,
+             _("Thumb does not support this addressing mode"));
+
+ op16:
+  switch (inst.instruction)
+    {
+    case T_OPCODE_STR_IW: inst.instruction = T_OPCODE_STR_RW; break;
+    case T_OPCODE_STR_IH: inst.instruction = T_OPCODE_STR_RH; break;
+    case T_OPCODE_STR_IB: inst.instruction = T_OPCODE_STR_RB; break;
+    case T_OPCODE_LDR_IW: inst.instruction = T_OPCODE_LDR_RW; break;
+    case T_OPCODE_LDR_IH: inst.instruction = T_OPCODE_LDR_RH; break;
+    case T_OPCODE_LDR_IB: inst.instruction = T_OPCODE_LDR_RB; break;
+    case 0x5600 /* ldrsb */:
+    case 0x5e00 /* ldrsh */: break;
+    default: abort ();
+    }
+
+  inst.instruction |= inst.operands[0].reg;
+  inst.instruction |= inst.operands[1].reg << 3;
+  inst.instruction |= inst.operands[1].imm << 6;
+}
+
+static void
+do_t_ldstd (void)
+{
+  if (!inst.operands[1].present)
+    {
+      inst.operands[1].reg = inst.operands[0].reg + 1;
+      constraint (inst.operands[0].reg == REG_LR,
+                 _("r14 not allowed here"));
+      constraint (inst.operands[0].reg == REG_R12,
+                 _("r12 not allowed here"));
+    }
+
+  if (inst.operands[2].writeback
+      && (inst.operands[0].reg == inst.operands[2].reg
+      || inst.operands[1].reg == inst.operands[2].reg))
+    as_warn (_("base register written back, and overlaps "
+              "one of transfer registers"));
+
+  inst.instruction |= inst.operands[0].reg << 12;
+  inst.instruction |= inst.operands[1].reg << 8;
+  encode_thumb32_addr_mode (2, /*is_t=*/FALSE, /*is_d=*/TRUE);
+}
+
+static void
+do_t_ldstt (void)
+{
+  inst.instruction |= inst.operands[0].reg << 12;
+  encode_thumb32_addr_mode (1, /*is_t=*/TRUE, /*is_d=*/FALSE);
+}
+
+static void
+do_t_mla (void)
+{
+  unsigned Rd, Rn, Rm, Ra;
+
+  Rd = inst.operands[0].reg;
+  Rn = inst.operands[1].reg;
+  Rm = inst.operands[2].reg;
+  Ra = inst.operands[3].reg;
+
+  reject_bad_reg (Rd);
+  reject_bad_reg (Rn);
+  reject_bad_reg (Rm);
+  reject_bad_reg (Ra);
+
+  inst.instruction |= Rd << 8;
+  inst.instruction |= Rn << 16;
+  inst.instruction |= Rm;
+  inst.instruction |= Ra << 12;
+}
+
+static void
+do_t_mlal (void)
+{
+  unsigned RdLo, RdHi, Rn, Rm;
+
+  RdLo = inst.operands[0].reg;
+  RdHi = inst.operands[1].reg;
+  Rn = inst.operands[2].reg;
+  Rm = inst.operands[3].reg;
+
+  reject_bad_reg (RdLo);
+  reject_bad_reg (RdHi);
+  reject_bad_reg (Rn);
+  reject_bad_reg (Rm);
+
+  inst.instruction |= RdLo << 12;
+  inst.instruction |= RdHi << 8;
+  inst.instruction |= Rn << 16;
+  inst.instruction |= Rm;
+}
+
+static void
+do_t_mov_cmp (void)
+{
+  unsigned Rn, Rm;
+
+  Rn = inst.operands[0].reg;
+  Rm = inst.operands[1].reg;
+
+  if (Rn == REG_PC)
+    set_it_insn_type_last ();
+
+  if (unified_syntax)
+    {
+      int r0off = (inst.instruction == T_MNEM_mov
+                  || inst.instruction == T_MNEM_movs) ? 8 : 16;
+      unsigned long opcode;
+      bfd_boolean narrow;
+      bfd_boolean low_regs;
+
+      low_regs = (Rn <= 7 && Rm <= 7);
+      opcode = inst.instruction;
+      if (in_it_block ())
+       narrow = opcode != T_MNEM_movs;
+      else
+       narrow = opcode != T_MNEM_movs || low_regs;
+      if (inst.size_req == 4
+         || inst.operands[1].shifted)
+       narrow = FALSE;
+
+      /* MOVS PC, LR is encoded as SUBS PC, LR, #0.  */
+      if (opcode == T_MNEM_movs && inst.operands[1].isreg
+         && !inst.operands[1].shifted
+         && Rn == REG_PC
+         && Rm == REG_LR)
+       {
+         inst.instruction = T2_SUBS_PC_LR;
+         return;
+       }
+
+      if (opcode == T_MNEM_cmp)
+       {
+         constraint (Rn == REG_PC, BAD_PC);
+         if (narrow)
+           {
+             /* In the Thumb-2 ISA, use of R13 as Rm is deprecated,
+                but valid.  */
+             warn_deprecated_sp (Rm);
+             /* R15 was documented as a valid choice for Rm in ARMv6,
+                but as UNPREDICTABLE in ARMv7.  ARM's proprietary
+                tools reject R15, so we do too.  */
+             constraint (Rm == REG_PC, BAD_PC);
+           }
+         else
+           reject_bad_reg (Rm);
+       }
+      else if (opcode == T_MNEM_mov
+              || opcode == T_MNEM_movs)
+       {
+         if (inst.operands[1].isreg)
+           {
+             if (opcode == T_MNEM_movs)
+               {
+                 reject_bad_reg (Rn);
+                 reject_bad_reg (Rm);
+               }
+             else if (narrow)
+               {
+                 /* This is mov.n.  */
+                 if ((Rn == REG_SP || Rn == REG_PC)
+                     && (Rm == REG_SP || Rm == REG_PC))
+                   {
+                     as_tsktsk (_("Use of r%u as a source register is "
+                                "deprecated when r%u is the destination "
+                                "register."), Rm, Rn);
+                   }
+               }
+             else
+               {
+                 /* This is mov.w.  */
+                 constraint (Rn == REG_PC, BAD_PC);
+                 constraint (Rm == REG_PC, BAD_PC);
+                 constraint (Rn == REG_SP && Rm == REG_SP, BAD_SP);
+               }
+           }
+         else
+           reject_bad_reg (Rn);
+       }
+
+      if (!inst.operands[1].isreg)
+       {
+         /* Immediate operand.  */
+         if (!in_it_block () && opcode == T_MNEM_mov)
+           narrow = 0;
+         if (low_regs && narrow)
+           {
+             inst.instruction = THUMB_OP16 (opcode);
+             inst.instruction |= Rn << 8;
+             if (inst.reloc.type < BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
+                 || inst.reloc.type > BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC)
+               {
+                 if (inst.size_req == 2)
+                   inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM;
+                 else
+                   inst.relax = opcode;
+               }
+           }
+         else
+           {
+             constraint (inst.reloc.type >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
+                         && inst.reloc.type <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC ,
+                         THUMB1_RELOC_ONLY);
+
+             inst.instruction = THUMB_OP32 (inst.instruction);
+             inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
+             inst.instruction |= Rn << r0off;
+             inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
+           }
+       }
+      else if (inst.operands[1].shifted && inst.operands[1].immisreg
+              && (inst.instruction == T_MNEM_mov
+                  || inst.instruction == T_MNEM_movs))
+       {
+         /* Register shifts are encoded as separate shift instructions.  */
+         bfd_boolean flags = (inst.instruction == T_MNEM_movs);
+
+         if (in_it_block ())
+           narrow = !flags;
+         else
+           narrow = flags;
+
+         if (inst.size_req == 4)
+           narrow = FALSE;
+
+         if (!low_regs || inst.operands[1].imm > 7)
+           narrow = FALSE;
+
+         if (Rn != Rm)
+           narrow = FALSE;
+
+         switch (inst.operands[1].shift_kind)
+           {
+           case SHIFT_LSL:
+             opcode = narrow ? T_OPCODE_LSL_R : THUMB_OP32 (T_MNEM_lsl);
+             break;
+           case SHIFT_ASR:
+             opcode = narrow ? T_OPCODE_ASR_R : THUMB_OP32 (T_MNEM_asr);
+             break;
+           case SHIFT_LSR:
+             opcode = narrow ? T_OPCODE_LSR_R : THUMB_OP32 (T_MNEM_lsr);
+             break;
+           case SHIFT_ROR:
+             opcode = narrow ? T_OPCODE_ROR_R : THUMB_OP32 (T_MNEM_ror);
+             break;
+           default:
+             abort ();
+           }
+
+         inst.instruction = opcode;
+         if (narrow)
+           {
+             inst.instruction |= Rn;
+             inst.instruction |= inst.operands[1].imm << 3;
+           }
+         else
+           {
+             if (flags)
+               inst.instruction |= CONDS_BIT;
+
+             inst.instruction |= Rn << 8;
+             inst.instruction |= Rm << 16;
+             inst.instruction |= inst.operands[1].imm;
+           }
+       }
+      else if (!narrow)
+       {
+         /* Some mov with immediate shift have narrow variants.
+            Register shifts are handled above.  */
+         if (low_regs && inst.operands[1].shifted
+             && (inst.instruction == T_MNEM_mov
+                 || inst.instruction == T_MNEM_movs))
+           {
+             if (in_it_block ())
+               narrow = (inst.instruction == T_MNEM_mov);
+             else
+               narrow = (inst.instruction == T_MNEM_movs);
+           }
+
+         if (narrow)
+           {
+             switch (inst.operands[1].shift_kind)
+               {
+               case SHIFT_LSL: inst.instruction = T_OPCODE_LSL_I; break;
+               case SHIFT_LSR: inst.instruction = T_OPCODE_LSR_I; break;
+               case SHIFT_ASR: inst.instruction = T_OPCODE_ASR_I; break;
+               default: narrow = FALSE; break;
+               }
+           }
+
+         if (narrow)
+           {
+             inst.instruction |= Rn;
+             inst.instruction |= Rm << 3;
+             inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
+           }
+         else
+           {
+             inst.instruction = THUMB_OP32 (inst.instruction);
+             inst.instruction |= Rn << r0off;
+             encode_thumb32_shifted_operand (1);
+           }
+       }
+      else
+       switch (inst.instruction)
+         {
+         case T_MNEM_mov:
+           /* In v4t or v5t a move of two lowregs produces unpredictable
+              results. Don't allow this.  */
+           if (low_regs)
+             {
+               constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6),
+                           "MOV Rd, Rs with two low registers is not "
+                           "permitted on this architecture");
+               ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
+                                       arm_ext_v6);
+             }
+
+           inst.instruction = T_OPCODE_MOV_HR;
+           inst.instruction |= (Rn & 0x8) << 4;
+           inst.instruction |= (Rn & 0x7);
+           inst.instruction |= Rm << 3;
+           break;
+
+         case T_MNEM_movs:
+           /* We know we have low registers at this point.
+              Generate LSLS Rd, Rs, #0.  */
+           inst.instruction = T_OPCODE_LSL_I;
+           inst.instruction |= Rn;
+           inst.instruction |= Rm << 3;
+           break;
+
+         case T_MNEM_cmp:
+           if (low_regs)
+             {
+               inst.instruction = T_OPCODE_CMP_LR;
+               inst.instruction |= Rn;
+               inst.instruction |= Rm << 3;
+             }
+           else
+             {
+               inst.instruction = T_OPCODE_CMP_HR;
+               inst.instruction |= (Rn & 0x8) << 4;
+               inst.instruction |= (Rn & 0x7);
+               inst.instruction |= Rm << 3;
+             }
+           break;
+         }
+      return;
+    }
+
+  inst.instruction = THUMB_OP16 (inst.instruction);
+
+  /* PR 10443: Do not silently ignore shifted operands.  */
+  constraint (inst.operands[1].shifted,
+             _("shifts in CMP/MOV instructions are only supported in unified syntax"));
+
+  if (inst.operands[1].isreg)
+    {
+      if (Rn < 8 && Rm < 8)
+       {
+         /* A move of two lowregs is encoded as ADD Rd, Rs, #0
+            since a MOV instruction produces unpredictable results.  */
+         if (inst.instruction == T_OPCODE_MOV_I8)
+           inst.instruction = T_OPCODE_ADD_I3;
+         else
+           inst.instruction = T_OPCODE_CMP_LR;
+
+         inst.instruction |= Rn;
+         inst.instruction |= Rm << 3;
+       }
+      else
+       {
+         if (inst.instruction == T_OPCODE_MOV_I8)
+           inst.instruction = T_OPCODE_MOV_HR;
+         else
+           inst.instruction = T_OPCODE_CMP_HR;
+         do_t_cpy ();
+       }
+    }
+  else
+    {
+      constraint (Rn > 7,
+                 _("only lo regs allowed with immediate"));
+      inst.instruction |= Rn << 8;
+      inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM;
+    }
+}
+
+static void
+do_t_mov16 (void)
+{
+  unsigned Rd;
+  bfd_vma imm;
+  bfd_boolean top;
+
+  top = (inst.instruction & 0x00800000) != 0;
+  if (inst.reloc.type == BFD_RELOC_ARM_MOVW)
+    {
+      constraint (top, _(":lower16: not allowed this instruction"));
+      inst.reloc.type = BFD_RELOC_ARM_THUMB_MOVW;
+    }
+  else if (inst.reloc.type == BFD_RELOC_ARM_MOVT)
+    {
+      constraint (!top, _(":upper16: not allowed this instruction"));
+      inst.reloc.type = BFD_RELOC_ARM_THUMB_MOVT;
+    }
+
+  Rd = inst.operands[0].reg;
+  reject_bad_reg (Rd);
+
+  inst.instruction |= Rd << 8;
+  if (inst.reloc.type == BFD_RELOC_UNUSED)
+    {
+      imm = inst.reloc.exp.X_add_number;
+      inst.instruction |= (imm & 0xf000) << 4;
+      inst.instruction |= (imm & 0x0800) << 15;
+      inst.instruction |= (imm & 0x0700) << 4;
+      inst.instruction |= (imm & 0x00ff);
+    }
+}
+
+static void
+do_t_mvn_tst (void)
+{
+  unsigned Rn, Rm;
+
+  Rn = inst.operands[0].reg;
+  Rm = inst.operands[1].reg;
+
+  if (inst.instruction == T_MNEM_cmp
+      || inst.instruction == T_MNEM_cmn)
+    constraint (Rn == REG_PC, BAD_PC);
+  else
+    reject_bad_reg (Rn);
+  reject_bad_reg (Rm);
+
+  if (unified_syntax)
+    {
+      int r0off = (inst.instruction == T_MNEM_mvn
+                  || inst.instruction == T_MNEM_mvns) ? 8 : 16;
+      bfd_boolean narrow;
+
+      if (inst.size_req == 4
+         || inst.instruction > 0xffff
+         || inst.operands[1].shifted
+         || Rn > 7 || Rm > 7)
+       narrow = FALSE;
+      else if (inst.instruction == T_MNEM_cmn
+              || inst.instruction == T_MNEM_tst)
+       narrow = TRUE;
+      else if (THUMB_SETS_FLAGS (inst.instruction))
+       narrow = !in_it_block ();
+      else
+       narrow = in_it_block ();
+
+      if (!inst.operands[1].isreg)
+       {
+         /* For an immediate, we always generate a 32-bit opcode;
+            section relaxation will shrink it later if possible.  */
+         if (inst.instruction < 0xffff)
+           inst.instruction = THUMB_OP32 (inst.instruction);
+         inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
+         inst.instruction |= Rn << r0off;
+         inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
+       }
+      else
+       {
+         /* See if we can do this with a 16-bit instruction.  */
+         if (narrow)
+           {
+             inst.instruction = THUMB_OP16 (inst.instruction);
+             inst.instruction |= Rn;
+             inst.instruction |= Rm << 3;
+           }
+         else
+           {
+             constraint (inst.operands[1].shifted
+                         && inst.operands[1].immisreg,
+                         _("shift must be constant"));
+             if (inst.instruction < 0xffff)
+               inst.instruction = THUMB_OP32 (inst.instruction);
+             inst.instruction |= Rn << r0off;
+             encode_thumb32_shifted_operand (1);
+           }
+       }
+    }
+  else
+    {
+      constraint (inst.instruction > 0xffff
+                 || inst.instruction == T_MNEM_mvns, BAD_THUMB32);
+      constraint (!inst.operands[1].isreg || inst.operands[1].shifted,
+                 _("unshifted register required"));
+      constraint (Rn > 7 || Rm > 7,
+                 BAD_HIREG);
+
+      inst.instruction = THUMB_OP16 (inst.instruction);
+      inst.instruction |= Rn;
+      inst.instruction |= Rm << 3;
+    }
+}
+
+static void
+do_t_mrs (void)
+{
+  unsigned Rd;
+
+  if (do_vfp_nsyn_mrs () == SUCCESS)
+    return;
+
+  Rd = inst.operands[0].reg;
+  reject_bad_reg (Rd);
+  inst.instruction |= Rd << 8;
+
+  if (inst.operands[1].isreg)
+    {
+      unsigned br = inst.operands[1].reg;
+      if (((br & 0x200) == 0) && ((br & 0xf000) != 0xf000))
+       as_bad (_("bad register for mrs"));
+
+      inst.instruction |= br & (0xf << 16);
+      inst.instruction |= (br & 0x300) >> 4;
+      inst.instruction |= (br & SPSR_BIT) >> 2;
+    }
+  else
+    {
+      int flags = inst.operands[1].imm & (PSR_c|PSR_x|PSR_s|PSR_f|SPSR_BIT);
+
+      if (ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_m))
+       {
+         /* PR gas/12698:  The constraint is only applied for m_profile.
+            If the user has specified -march=all, we want to ignore it as
+            we are building for any CPU type, including non-m variants.  */
+         bfd_boolean m_profile =
+           !ARM_FEATURE_CORE_EQUAL (selected_cpu, arm_arch_any);
+         constraint ((flags != 0) && m_profile, _("selected processor does "
+                                                  "not support requested special purpose register"));
+       }
+      else
+       /* mrs only accepts APSR/CPSR/SPSR/CPSR_all/SPSR_all (for non-M profile
+          devices).  */
+       constraint ((flags & ~SPSR_BIT) != (PSR_c|PSR_f),
+                   _("'APSR', 'CPSR' or 'SPSR' expected"));
+
+      inst.instruction |= (flags & SPSR_BIT) >> 2;
+      inst.instruction |= inst.operands[1].imm & 0xff;
+      inst.instruction |= 0xf0000;
+    }
+}
+
+static void
+do_t_msr (void)
+{
+  int flags;
+  unsigned Rn;
+
+  if (do_vfp_nsyn_msr () == SUCCESS)
+    return;
+
+  constraint (!inst.operands[1].isreg,
+             _("Thumb encoding does not support an immediate here"));
+
+  if (inst.operands[0].isreg)
+    flags = (int)(inst.operands[0].reg);
+  else
+    flags = inst.operands[0].imm;
+
+  if (ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_m))
+    {
+      int bits = inst.operands[0].imm & (PSR_c|PSR_x|PSR_s|PSR_f|SPSR_BIT);
+
+      /* PR gas/12698:  The constraint is only applied for m_profile.
+        If the user has specified -march=all, we want to ignore it as
+        we are building for any CPU type, including non-m variants.  */
+      bfd_boolean m_profile =
+       !ARM_FEATURE_CORE_EQUAL (selected_cpu, arm_arch_any);
+      constraint (((ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6_dsp)
+          && (bits & ~(PSR_s | PSR_f)) != 0)
+         || (!ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6_dsp)
+             && bits != PSR_f)) && m_profile,
+         _("selected processor does not support requested special "
+           "purpose register"));
+    }
+  else
+     constraint ((flags & 0xff) != 0, _("selected processor does not support "
+                "requested special purpose register"));
+
+  Rn = inst.operands[1].reg;
+  reject_bad_reg (Rn);
+
+  inst.instruction |= (flags & SPSR_BIT) >> 2;
+  inst.instruction |= (flags & 0xf0000) >> 8;
+  inst.instruction |= (flags & 0x300) >> 4;
+  inst.instruction |= (flags & 0xff);
+  inst.instruction |= Rn << 16;
+}
+
+static void
+do_t_mul (void)
+{
+  bfd_boolean narrow;
+  unsigned Rd, Rn, Rm;
+
+  if (!inst.operands[2].present)
+    inst.operands[2].reg = inst.operands[0].reg;
+
+  Rd = inst.operands[0].reg;
+  Rn = inst.operands[1].reg;
+  Rm = inst.operands[2].reg;
+
+  if (unified_syntax)
+    {
+      if (inst.size_req == 4
+         || (Rd != Rn
+             && Rd != Rm)
+         || Rn > 7
+         || Rm > 7)
+       narrow = FALSE;
+      else if (inst.instruction == T_MNEM_muls)
+       narrow = !in_it_block ();
+      else
+       narrow = in_it_block ();
+    }
+  else
+    {
+      constraint (inst.instruction == T_MNEM_muls, BAD_THUMB32);
+      constraint (Rn > 7 || Rm > 7,
+                 BAD_HIREG);
+      narrow = TRUE;
+    }
+
+  if (narrow)
+    {
+      /* 16-bit MULS/Conditional MUL.  */
+      inst.instruction = THUMB_OP16 (inst.instruction);
+      inst.instruction |= Rd;
+
+      if (Rd == Rn)
+       inst.instruction |= Rm << 3;
+      else if (Rd == Rm)
+       inst.instruction |= Rn << 3;
+      else
+       constraint (1, _("dest must overlap one source register"));
+    }
+  else
+    {
+      constraint (inst.instruction != T_MNEM_mul,
+                 _("Thumb-2 MUL must not set flags"));
+      /* 32-bit MUL.  */
+      inst.instruction = THUMB_OP32 (inst.instruction);
+      inst.instruction |= Rd << 8;
+      inst.instruction |= Rn << 16;
+      inst.instruction |= Rm << 0;
+
+      reject_bad_reg (Rd);
+      reject_bad_reg (Rn);
+      reject_bad_reg (Rm);
+    }
+}
+
+static void
+do_t_mull (void)
+{
+  unsigned RdLo, RdHi, Rn, Rm;
+
+  RdLo = inst.operands[0].reg;
+  RdHi = inst.operands[1].reg;
+  Rn = inst.operands[2].reg;
+  Rm = inst.operands[3].reg;
+
+  reject_bad_reg (RdLo);
+  reject_bad_reg (RdHi);
+  reject_bad_reg (Rn);
+  reject_bad_reg (Rm);
+
+  inst.instruction |= RdLo << 12;
+  inst.instruction |= RdHi << 8;
+  inst.instruction |= Rn << 16;
+  inst.instruction |= Rm;
+
+ if (RdLo == RdHi)
+    as_tsktsk (_("rdhi and rdlo must be different"));
+}
+
+static void
+do_t_nop (void)
+{
+  set_it_insn_type (NEUTRAL_IT_INSN);
+
+  if (unified_syntax)
+    {
+      if (inst.size_req == 4 || inst.operands[0].imm > 15)
+       {
+         inst.instruction = THUMB_OP32 (inst.instruction);
+         inst.instruction |= inst.operands[0].imm;
+       }
+      else
+       {
+         /* PR9722: Check for Thumb2 availability before
+            generating a thumb2 nop instruction.  */
+         if (ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6t2))
+           {
+             inst.instruction = THUMB_OP16 (inst.instruction);
+             inst.instruction |= inst.operands[0].imm << 4;
+           }
+         else
+           inst.instruction = 0x46c0;
+       }
+    }
+  else
+    {
+      constraint (inst.operands[0].present,
+                 _("Thumb does not support NOP with hints"));
+      inst.instruction = 0x46c0;
+    }
+}
 
+static void
+do_t_neg (void)
+{
   if (unified_syntax)
     {
-      int r0off = (inst.instruction == T_MNEM_mov
-                  || inst.instruction == T_MNEM_movs) ? 8 : 16;
-      unsigned long opcode;
       bfd_boolean narrow;
-      bfd_boolean low_regs;
 
-      low_regs = (Rn <= 7 && Rm <= 7);
-      opcode = inst.instruction;
-      if (in_it_block ())
-       narrow = opcode != T_MNEM_movs;
+      if (THUMB_SETS_FLAGS (inst.instruction))
+       narrow = !in_it_block ();
       else
-       narrow = opcode != T_MNEM_movs || low_regs;
-      if (inst.size_req == 4
-         || inst.operands[1].shifted)
+       narrow = in_it_block ();
+      if (inst.operands[0].reg > 7 || inst.operands[1].reg > 7)
+       narrow = FALSE;
+      if (inst.size_req == 4)
        narrow = FALSE;
 
-      /* MOVS PC, LR is encoded as SUBS PC, LR, #0.  */
-      if (opcode == T_MNEM_movs && inst.operands[1].isreg
-         && !inst.operands[1].shifted
-         && Rn == REG_PC
-         && Rm == REG_LR)
-       {
-         inst.instruction = T2_SUBS_PC_LR;
-         return;
-       }
-
-      if (opcode == T_MNEM_cmp)
+      if (!narrow)
        {
-         constraint (Rn == REG_PC, BAD_PC);
-         if (narrow)
-           {
-             /* In the Thumb-2 ISA, use of R13 as Rm is deprecated,
-                but valid.  */
-             warn_deprecated_sp (Rm);
-             /* R15 was documented as a valid choice for Rm in ARMv6,
-                but as UNPREDICTABLE in ARMv7.  ARM's proprietary
-                tools reject R15, so we do too.  */
-             constraint (Rm == REG_PC, BAD_PC);
-           }
-         else
-           reject_bad_reg (Rm);
+         inst.instruction = THUMB_OP32 (inst.instruction);
+         inst.instruction |= inst.operands[0].reg << 8;
+         inst.instruction |= inst.operands[1].reg << 16;
        }
-      else if (opcode == T_MNEM_mov
-              || opcode == T_MNEM_movs)
+      else
        {
-         if (inst.operands[1].isreg)
-           {
-             if (opcode == T_MNEM_movs)
-               {
-                 reject_bad_reg (Rn);
-                 reject_bad_reg (Rm);
-               }
-             else if (narrow)
-               {
-                 /* This is mov.n.  */
-                 if ((Rn == REG_SP || Rn == REG_PC)
-                     && (Rm == REG_SP || Rm == REG_PC))
-                   {
-                     as_warn (_("Use of r%u as a source register is "
-                                "deprecated when r%u is the destination "
-                                "register."), Rm, Rn);
-                   }
-               }
-             else
-               {
-                 /* This is mov.w.  */
-                 constraint (Rn == REG_PC, BAD_PC);
-                 constraint (Rm == REG_PC, BAD_PC);
-                 constraint (Rn == REG_SP && Rm == REG_SP, BAD_SP);
-               }
-           }
-         else
-           reject_bad_reg (Rn);
+         inst.instruction = THUMB_OP16 (inst.instruction);
+         inst.instruction |= inst.operands[0].reg;
+         inst.instruction |= inst.operands[1].reg << 3;
        }
+    }
+  else
+    {
+      constraint (inst.operands[0].reg > 7 || inst.operands[1].reg > 7,
+                 BAD_HIREG);
+      constraint (THUMB_SETS_FLAGS (inst.instruction), BAD_THUMB32);
 
-      if (!inst.operands[1].isreg)
-       {
-         /* Immediate operand.  */
-         if (!in_it_block () && opcode == T_MNEM_mov)
-           narrow = 0;
-         if (low_regs && narrow)
-           {
-             inst.instruction = THUMB_OP16 (opcode);
-             inst.instruction |= Rn << 8;
-             if (inst.size_req == 2)
-               inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM;
-             else
-               inst.relax = opcode;
-           }
-         else
-           {
-             inst.instruction = THUMB_OP32 (inst.instruction);
-             inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
-             inst.instruction |= Rn << r0off;
-             inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
-           }
-       }
-      else if (inst.operands[1].shifted && inst.operands[1].immisreg
-              && (inst.instruction == T_MNEM_mov
-                  || inst.instruction == T_MNEM_movs))
-       {
-         /* Register shifts are encoded as separate shift instructions.  */
-         bfd_boolean flags = (inst.instruction == T_MNEM_movs);
+      inst.instruction = THUMB_OP16 (inst.instruction);
+      inst.instruction |= inst.operands[0].reg;
+      inst.instruction |= inst.operands[1].reg << 3;
+    }
+}
+
+static void
+do_t_orn (void)
+{
+  unsigned Rd, Rn;
+
+  Rd = inst.operands[0].reg;
+  Rn = inst.operands[1].present ? inst.operands[1].reg : Rd;
+
+  reject_bad_reg (Rd);
+  /* Rn == REG_SP is unpredictable; Rn == REG_PC is MVN.  */
+  reject_bad_reg (Rn);
+
+  inst.instruction |= Rd << 8;
+  inst.instruction |= Rn << 16;
+
+  if (!inst.operands[2].isreg)
+    {
+      inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
+      inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
+    }
+  else
+    {
+      unsigned Rm;
+
+      Rm = inst.operands[2].reg;
+      reject_bad_reg (Rm);
+
+      constraint (inst.operands[2].shifted
+                 && inst.operands[2].immisreg,
+                 _("shift must be constant"));
+      encode_thumb32_shifted_operand (2);
+    }
+}
+
+static void
+do_t_pkhbt (void)
+{
+  unsigned Rd, Rn, Rm;
+
+  Rd = inst.operands[0].reg;
+  Rn = inst.operands[1].reg;
+  Rm = inst.operands[2].reg;
+
+  reject_bad_reg (Rd);
+  reject_bad_reg (Rn);
+  reject_bad_reg (Rm);
+
+  inst.instruction |= Rd << 8;
+  inst.instruction |= Rn << 16;
+  inst.instruction |= Rm;
+  if (inst.operands[3].present)
+    {
+      unsigned int val = inst.reloc.exp.X_add_number;
+      constraint (inst.reloc.exp.X_op != O_constant,
+                 _("expression too complex"));
+      inst.instruction |= (val & 0x1c) << 10;
+      inst.instruction |= (val & 0x03) << 6;
+    }
+}
+
+static void
+do_t_pkhtb (void)
+{
+  if (!inst.operands[3].present)
+    {
+      unsigned Rtmp;
+
+      inst.instruction &= ~0x00000020;
+
+      /* PR 10168.  Swap the Rm and Rn registers.  */
+      Rtmp = inst.operands[1].reg;
+      inst.operands[1].reg = inst.operands[2].reg;
+      inst.operands[2].reg = Rtmp;
+    }
+  do_t_pkhbt ();
+}
+
+static void
+do_t_pld (void)
+{
+  if (inst.operands[0].immisreg)
+    reject_bad_reg (inst.operands[0].imm);
+
+  encode_thumb32_addr_mode (0, /*is_t=*/FALSE, /*is_d=*/FALSE);
+}
+
+static void
+do_t_push_pop (void)
+{
+  unsigned mask;
+
+  constraint (inst.operands[0].writeback,
+             _("push/pop do not support {reglist}^"));
+  constraint (inst.reloc.type != BFD_RELOC_UNUSED,
+             _("expression too complex"));
+
+  mask = inst.operands[0].imm;
+  if (inst.size_req != 4 && (mask & ~0xff) == 0)
+    inst.instruction = THUMB_OP16 (inst.instruction) | mask;
+  else if (inst.size_req != 4
+          && (mask & ~0xff) == (1U << (inst.instruction == T_MNEM_push
+                                      ? REG_LR : REG_PC)))
+    {
+      inst.instruction = THUMB_OP16 (inst.instruction);
+      inst.instruction |= THUMB_PP_PC_LR;
+      inst.instruction |= mask & 0xff;
+    }
+  else if (unified_syntax)
+    {
+      inst.instruction = THUMB_OP32 (inst.instruction);
+      encode_thumb2_ldmstm (13, mask, TRUE);
+    }
+  else
+    {
+      inst.error = _("invalid register list to push/pop instruction");
+      return;
+    }
+}
+
+static void
+do_t_rbit (void)
+{
+  unsigned Rd, Rm;
+
+  Rd = inst.operands[0].reg;
+  Rm = inst.operands[1].reg;
+
+  reject_bad_reg (Rd);
+  reject_bad_reg (Rm);
+
+  inst.instruction |= Rd << 8;
+  inst.instruction |= Rm << 16;
+  inst.instruction |= Rm;
+}
+
+static void
+do_t_rev (void)
+{
+  unsigned Rd, Rm;
+
+  Rd = inst.operands[0].reg;
+  Rm = inst.operands[1].reg;
 
-         if (in_it_block ())
-           narrow = !flags;
-         else
-           narrow = flags;
+  reject_bad_reg (Rd);
+  reject_bad_reg (Rm);
 
-         if (inst.size_req == 4)
-           narrow = FALSE;
+  if (Rd <= 7 && Rm <= 7
+      && inst.size_req != 4)
+    {
+      inst.instruction = THUMB_OP16 (inst.instruction);
+      inst.instruction |= Rd;
+      inst.instruction |= Rm << 3;
+    }
+  else if (unified_syntax)
+    {
+      inst.instruction = THUMB_OP32 (inst.instruction);
+      inst.instruction |= Rd << 8;
+      inst.instruction |= Rm << 16;
+      inst.instruction |= Rm;
+    }
+  else
+    inst.error = BAD_HIREG;
+}
 
-         if (!low_regs || inst.operands[1].imm > 7)
-           narrow = FALSE;
+static void
+do_t_rrx (void)
+{
+  unsigned Rd, Rm;
 
-         if (Rn != Rm)
-           narrow = FALSE;
+  Rd = inst.operands[0].reg;
+  Rm = inst.operands[1].reg;
 
-         switch (inst.operands[1].shift_kind)
-           {
-           case SHIFT_LSL:
-             opcode = narrow ? T_OPCODE_LSL_R : THUMB_OP32 (T_MNEM_lsl);
-             break;
-           case SHIFT_ASR:
-             opcode = narrow ? T_OPCODE_ASR_R : THUMB_OP32 (T_MNEM_asr);
-             break;
-           case SHIFT_LSR:
-             opcode = narrow ? T_OPCODE_LSR_R : THUMB_OP32 (T_MNEM_lsr);
-             break;
-           case SHIFT_ROR:
-             opcode = narrow ? T_OPCODE_ROR_R : THUMB_OP32 (T_MNEM_ror);
-             break;
-           default:
-             abort ();
-           }
+  reject_bad_reg (Rd);
+  reject_bad_reg (Rm);
 
-         inst.instruction = opcode;
-         if (narrow)
-           {
-             inst.instruction |= Rn;
-             inst.instruction |= inst.operands[1].imm << 3;
-           }
-         else
-           {
-             if (flags)
-               inst.instruction |= CONDS_BIT;
+  inst.instruction |= Rd << 8;
+  inst.instruction |= Rm;
+}
 
-             inst.instruction |= Rn << 8;
-             inst.instruction |= Rm << 16;
-             inst.instruction |= inst.operands[1].imm;
-           }
-       }
-      else if (!narrow)
-       {
-         /* Some mov with immediate shift have narrow variants.
-            Register shifts are handled above.  */
-         if (low_regs && inst.operands[1].shifted
-             && (inst.instruction == T_MNEM_mov
-                 || inst.instruction == T_MNEM_movs))
-           {
-             if (in_it_block ())
-               narrow = (inst.instruction == T_MNEM_mov);
-             else
-               narrow = (inst.instruction == T_MNEM_movs);
-           }
+static void
+do_t_rsb (void)
+{
+  unsigned Rd, Rs;
 
-         if (narrow)
-           {
-             switch (inst.operands[1].shift_kind)
-               {
-               case SHIFT_LSL: inst.instruction = T_OPCODE_LSL_I; break;
-               case SHIFT_LSR: inst.instruction = T_OPCODE_LSR_I; break;
-               case SHIFT_ASR: inst.instruction = T_OPCODE_ASR_I; break;
-               default: narrow = FALSE; break;
-               }
-           }
+  Rd = inst.operands[0].reg;
+  Rs = (inst.operands[1].present
+       ? inst.operands[1].reg    /* Rd, Rs, foo */
+       : inst.operands[0].reg);  /* Rd, foo -> Rd, Rd, foo */
 
-         if (narrow)
-           {
-             inst.instruction |= Rn;
-             inst.instruction |= Rm << 3;
-             inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
-           }
-         else
-           {
-             inst.instruction = THUMB_OP32 (inst.instruction);
-             inst.instruction |= Rn << r0off;
-             encode_thumb32_shifted_operand (1);
-           }
-       }
+  reject_bad_reg (Rd);
+  reject_bad_reg (Rs);
+  if (inst.operands[2].isreg)
+    reject_bad_reg (inst.operands[2].reg);
+
+  inst.instruction |= Rd << 8;
+  inst.instruction |= Rs << 16;
+  if (!inst.operands[2].isreg)
+    {
+      bfd_boolean narrow;
+
+      if ((inst.instruction & 0x00100000) != 0)
+       narrow = !in_it_block ();
       else
-       switch (inst.instruction)
-         {
-         case T_MNEM_mov:
-           inst.instruction = T_OPCODE_MOV_HR;
-           inst.instruction |= (Rn & 0x8) << 4;
-           inst.instruction |= (Rn & 0x7);
-           inst.instruction |= Rm << 3;
-           break;
+       narrow = in_it_block ();
 
-         case T_MNEM_movs:
-           /* We know we have low registers at this point.
-              Generate LSLS Rd, Rs, #0.  */
-           inst.instruction = T_OPCODE_LSL_I;
-           inst.instruction |= Rn;
-           inst.instruction |= Rm << 3;
-           break;
+      if (Rd > 7 || Rs > 7)
+       narrow = FALSE;
 
-         case T_MNEM_cmp:
-           if (low_regs)
-             {
-               inst.instruction = T_OPCODE_CMP_LR;
-               inst.instruction |= Rn;
-               inst.instruction |= Rm << 3;
-             }
-           else
-             {
-               inst.instruction = T_OPCODE_CMP_HR;
-               inst.instruction |= (Rn & 0x8) << 4;
-               inst.instruction |= (Rn & 0x7);
-               inst.instruction |= Rm << 3;
-             }
-           break;
-         }
-      return;
+      if (inst.size_req == 4 || !unified_syntax)
+       narrow = FALSE;
+
+      if (inst.reloc.exp.X_op != O_constant
+         || inst.reloc.exp.X_add_number != 0)
+       narrow = FALSE;
+
+      /* Turn rsb #0 into 16-bit neg.  We should probably do this via
+        relaxation, but it doesn't seem worth the hassle.  */
+      if (narrow)
+       {
+         inst.reloc.type = BFD_RELOC_UNUSED;
+         inst.instruction = THUMB_OP16 (T_MNEM_negs);
+         inst.instruction |= Rs << 3;
+         inst.instruction |= Rd;
+       }
+      else
+       {
+         inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
+         inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
+       }
     }
+  else
+    encode_thumb32_shifted_operand (2);
+}
 
-  inst.instruction = THUMB_OP16 (inst.instruction);
+static void
+do_t_setend (void)
+{
+  if (warn_on_deprecated
+      && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v8))
+      as_tsktsk (_("setend use is deprecated for ARMv8"));
 
-  /* PR 10443: Do not silently ignore shifted operands.  */
-  constraint (inst.operands[1].shifted,
-             _("shifts in CMP/MOV instructions are only supported in unified syntax"));
+  set_it_insn_type (OUTSIDE_IT_INSN);
+  if (inst.operands[0].imm)
+    inst.instruction |= 0x8;
+}
 
-  if (inst.operands[1].isreg)
+static void
+do_t_shift (void)
+{
+  if (!inst.operands[1].present)
+    inst.operands[1].reg = inst.operands[0].reg;
+
+  if (unified_syntax)
     {
-      if (Rn < 8 && Rm < 8)
+      bfd_boolean narrow;
+      int shift_kind;
+
+      switch (inst.instruction)
        {
-         /* A move of two lowregs is encoded as ADD Rd, Rs, #0
-            since a MOV instruction produces unpredictable results.  */
-         if (inst.instruction == T_OPCODE_MOV_I8)
-           inst.instruction = T_OPCODE_ADD_I3;
-         else
-           inst.instruction = T_OPCODE_CMP_LR;
+       case T_MNEM_asr:
+       case T_MNEM_asrs: shift_kind = SHIFT_ASR; break;
+       case T_MNEM_lsl:
+       case T_MNEM_lsls: shift_kind = SHIFT_LSL; break;
+       case T_MNEM_lsr:
+       case T_MNEM_lsrs: shift_kind = SHIFT_LSR; break;
+       case T_MNEM_ror:
+       case T_MNEM_rors: shift_kind = SHIFT_ROR; break;
+       default: abort ();
+       }
+
+      if (THUMB_SETS_FLAGS (inst.instruction))
+       narrow = !in_it_block ();
+      else
+       narrow = in_it_block ();
+      if (inst.operands[0].reg > 7 || inst.operands[1].reg > 7)
+       narrow = FALSE;
+      if (!inst.operands[2].isreg && shift_kind == SHIFT_ROR)
+       narrow = FALSE;
+      if (inst.operands[2].isreg
+         && (inst.operands[1].reg != inst.operands[0].reg
+             || inst.operands[2].reg > 7))
+       narrow = FALSE;
+      if (inst.size_req == 4)
+       narrow = FALSE;
+
+      reject_bad_reg (inst.operands[0].reg);
+      reject_bad_reg (inst.operands[1].reg);
+
+      if (!narrow)
+       {
+         if (inst.operands[2].isreg)
+           {
+             reject_bad_reg (inst.operands[2].reg);
+             inst.instruction = THUMB_OP32 (inst.instruction);
+             inst.instruction |= inst.operands[0].reg << 8;
+             inst.instruction |= inst.operands[1].reg << 16;
+             inst.instruction |= inst.operands[2].reg;
 
-         inst.instruction |= Rn;
-         inst.instruction |= Rm << 3;
+             /* PR 12854: Error on extraneous shifts.  */
+             constraint (inst.operands[2].shifted,
+                         _("extraneous shift as part of operand to shift insn"));
+           }
+         else
+           {
+             inst.operands[1].shifted = 1;
+             inst.operands[1].shift_kind = shift_kind;
+             inst.instruction = THUMB_OP32 (THUMB_SETS_FLAGS (inst.instruction)
+                                            ? T_MNEM_movs : T_MNEM_mov);
+             inst.instruction |= inst.operands[0].reg << 8;
+             encode_thumb32_shifted_operand (1);
+             /* Prevent the incorrect generation of an ARM_IMMEDIATE fixup.  */
+             inst.reloc.type = BFD_RELOC_UNUSED;
+           }
        }
       else
        {
-         if (inst.instruction == T_OPCODE_MOV_I8)
-           inst.instruction = T_OPCODE_MOV_HR;
+         if (inst.operands[2].isreg)
+           {
+             switch (shift_kind)
+               {
+               case SHIFT_ASR: inst.instruction = T_OPCODE_ASR_R; break;
+               case SHIFT_LSL: inst.instruction = T_OPCODE_LSL_R; break;
+               case SHIFT_LSR: inst.instruction = T_OPCODE_LSR_R; break;
+               case SHIFT_ROR: inst.instruction = T_OPCODE_ROR_R; break;
+               default: abort ();
+               }
+
+             inst.instruction |= inst.operands[0].reg;
+             inst.instruction |= inst.operands[2].reg << 3;
+
+             /* PR 12854: Error on extraneous shifts.  */
+             constraint (inst.operands[2].shifted,
+                         _("extraneous shift as part of operand to shift insn"));
+           }
          else
-           inst.instruction = T_OPCODE_CMP_HR;
-         do_t_cpy ();
+           {
+             switch (shift_kind)
+               {
+               case SHIFT_ASR: inst.instruction = T_OPCODE_ASR_I; break;
+               case SHIFT_LSL: inst.instruction = T_OPCODE_LSL_I; break;
+               case SHIFT_LSR: inst.instruction = T_OPCODE_LSR_I; break;
+               default: abort ();
+               }
+             inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
+             inst.instruction |= inst.operands[0].reg;
+             inst.instruction |= inst.operands[1].reg << 3;
+           }
        }
     }
   else
     {
-      constraint (Rn > 7,
-                 _("only lo regs allowed with immediate"));
-      inst.instruction |= Rn << 8;
-      inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM;
+      constraint (inst.operands[0].reg > 7
+                 || inst.operands[1].reg > 7, BAD_HIREG);
+      constraint (THUMB_SETS_FLAGS (inst.instruction), BAD_THUMB32);
+
+      if (inst.operands[2].isreg)  /* Rd, {Rs,} Rn */
+       {
+         constraint (inst.operands[2].reg > 7, BAD_HIREG);
+         constraint (inst.operands[0].reg != inst.operands[1].reg,
+                     _("source1 and dest must be same register"));
+
+         switch (inst.instruction)
+           {
+           case T_MNEM_asr: inst.instruction = T_OPCODE_ASR_R; break;
+           case T_MNEM_lsl: inst.instruction = T_OPCODE_LSL_R; break;
+           case T_MNEM_lsr: inst.instruction = T_OPCODE_LSR_R; break;
+           case T_MNEM_ror: inst.instruction = T_OPCODE_ROR_R; break;
+           default: abort ();
+           }
+
+         inst.instruction |= inst.operands[0].reg;
+         inst.instruction |= inst.operands[2].reg << 3;
+
+         /* PR 12854: Error on extraneous shifts.  */
+         constraint (inst.operands[2].shifted,
+                     _("extraneous shift as part of operand to shift insn"));
+       }
+      else
+       {
+         switch (inst.instruction)
+           {
+           case T_MNEM_asr: inst.instruction = T_OPCODE_ASR_I; break;
+           case T_MNEM_lsl: inst.instruction = T_OPCODE_LSL_I; break;
+           case T_MNEM_lsr: inst.instruction = T_OPCODE_LSR_I; break;
+           case T_MNEM_ror: inst.error = _("ror #imm not supported"); return;
+           default: abort ();
+           }
+         inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
+         inst.instruction |= inst.operands[0].reg;
+         inst.instruction |= inst.operands[1].reg << 3;
+       }
     }
 }
 
 static void
-do_t_mov16 (void)
+do_t_simd (void)
 {
-  unsigned Rd;
-  bfd_vma imm;
-  bfd_boolean top;
-
-  top = (inst.instruction & 0x00800000) != 0;
-  if (inst.reloc.type == BFD_RELOC_ARM_MOVW)
-    {
-      constraint (top, _(":lower16: not allowed this instruction"));
-      inst.reloc.type = BFD_RELOC_ARM_THUMB_MOVW;
-    }
-  else if (inst.reloc.type == BFD_RELOC_ARM_MOVT)
-    {
-      constraint (!top, _(":upper16: not allowed this instruction"));
-      inst.reloc.type = BFD_RELOC_ARM_THUMB_MOVT;
-    }
+  unsigned Rd, Rn, Rm;
 
   Rd = inst.operands[0].reg;
+  Rn = inst.operands[1].reg;
+  Rm = inst.operands[2].reg;
+
   reject_bad_reg (Rd);
+  reject_bad_reg (Rn);
+  reject_bad_reg (Rm);
 
   inst.instruction |= Rd << 8;
-  if (inst.reloc.type == BFD_RELOC_UNUSED)
-    {
-      imm = inst.reloc.exp.X_add_number;
-      inst.instruction |= (imm & 0xf000) << 4;
-      inst.instruction |= (imm & 0x0800) << 15;
-      inst.instruction |= (imm & 0x0700) << 4;
-      inst.instruction |= (imm & 0x00ff);
-    }
+  inst.instruction |= Rn << 16;
+  inst.instruction |= Rm;
 }
 
 static void
-do_t_mvn_tst (void)
+do_t_simd2 (void)
 {
-  unsigned Rn, Rm;
+  unsigned Rd, Rn, Rm;
 
-  Rn = inst.operands[0].reg;
+  Rd = inst.operands[0].reg;
   Rm = inst.operands[1].reg;
+  Rn = inst.operands[2].reg;
 
-  if (inst.instruction == T_MNEM_cmp
-      || inst.instruction == T_MNEM_cmn)
-    constraint (Rn == REG_PC, BAD_PC);
-  else
-    reject_bad_reg (Rn);
+  reject_bad_reg (Rd);
+  reject_bad_reg (Rn);
   reject_bad_reg (Rm);
 
-  if (unified_syntax)
-    {
-      int r0off = (inst.instruction == T_MNEM_mvn
-                  || inst.instruction == T_MNEM_mvns) ? 8 : 16;
-      bfd_boolean narrow;
+  inst.instruction |= Rd << 8;
+  inst.instruction |= Rn << 16;
+  inst.instruction |= Rm;
+}
 
-      if (inst.size_req == 4
-         || inst.instruction > 0xffff
-         || inst.operands[1].shifted
-         || Rn > 7 || Rm > 7)
-       narrow = FALSE;
-      else if (inst.instruction == T_MNEM_cmn)
-       narrow = TRUE;
-      else if (THUMB_SETS_FLAGS (inst.instruction))
-       narrow = !in_it_block ();
-      else
-       narrow = in_it_block ();
+static void
+do_t_smc (void)
+{
+  unsigned int value = inst.reloc.exp.X_add_number;
+  constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v7a),
+             _("SMC is not permitted on this architecture"));
+  constraint (inst.reloc.exp.X_op != O_constant,
+             _("expression too complex"));
+  inst.reloc.type = BFD_RELOC_UNUSED;
+  inst.instruction |= (value & 0xf000) >> 12;
+  inst.instruction |= (value & 0x0ff0);
+  inst.instruction |= (value & 0x000f) << 16;
+  /* PR gas/15623: SMC instructions must be last in an IT block.  */
+  set_it_insn_type_last ();
+}
 
-      if (!inst.operands[1].isreg)
-       {
-         /* For an immediate, we always generate a 32-bit opcode;
-            section relaxation will shrink it later if possible.  */
-         if (inst.instruction < 0xffff)
-           inst.instruction = THUMB_OP32 (inst.instruction);
-         inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
-         inst.instruction |= Rn << r0off;
-         inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
-       }
-      else
-       {
-         /* See if we can do this with a 16-bit instruction.  */
-         if (narrow)
-           {
-             inst.instruction = THUMB_OP16 (inst.instruction);
-             inst.instruction |= Rn;
-             inst.instruction |= Rm << 3;
-           }
-         else
-           {
-             constraint (inst.operands[1].shifted
-                         && inst.operands[1].immisreg,
-                         _("shift must be constant"));
-             if (inst.instruction < 0xffff)
-               inst.instruction = THUMB_OP32 (inst.instruction);
-             inst.instruction |= Rn << r0off;
-             encode_thumb32_shifted_operand (1);
-           }
-       }
-    }
-  else
-    {
-      constraint (inst.instruction > 0xffff
-                 || inst.instruction == T_MNEM_mvns, BAD_THUMB32);
-      constraint (!inst.operands[1].isreg || inst.operands[1].shifted,
-                 _("unshifted register required"));
-      constraint (Rn > 7 || Rm > 7,
-                 BAD_HIREG);
+static void
+do_t_hvc (void)
+{
+  unsigned int value = inst.reloc.exp.X_add_number;
 
-      inst.instruction = THUMB_OP16 (inst.instruction);
-      inst.instruction |= Rn;
-      inst.instruction |= Rm << 3;
-    }
+  inst.reloc.type = BFD_RELOC_UNUSED;
+  inst.instruction |= (value & 0x0fff);
+  inst.instruction |= (value & 0xf000) << 4;
 }
 
 static void
-do_t_mrs (void)
+do_t_ssat_usat (int bias)
 {
-  unsigned Rd;
-
-  if (do_vfp_nsyn_mrs () == SUCCESS)
-    return;
+  unsigned Rd, Rn;
 
   Rd = inst.operands[0].reg;
+  Rn = inst.operands[2].reg;
+
   reject_bad_reg (Rd);
+  reject_bad_reg (Rn);
+
   inst.instruction |= Rd << 8;
+  inst.instruction |= inst.operands[1].imm - bias;
+  inst.instruction |= Rn << 16;
 
-  if (inst.operands[1].isreg)
+  if (inst.operands[3].present)
     {
-      unsigned br = inst.operands[1].reg;
-      if (((br & 0x200) == 0) && ((br & 0xf000) != 0xf000))
-       as_bad (_("bad register for mrs"));
+      offsetT shift_amount = inst.reloc.exp.X_add_number;
 
-      inst.instruction |= br & (0xf << 16);
-      inst.instruction |= (br & 0x300) >> 4;
-      inst.instruction |= (br & SPSR_BIT) >> 2;
-    }
-  else
-    {
-      int flags = inst.operands[1].imm & (PSR_c|PSR_x|PSR_s|PSR_f|SPSR_BIT);
+      inst.reloc.type = BFD_RELOC_UNUSED;
 
-      if (ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_m))
-       constraint (flags != 0, _("selected processor does not support "
-                   "requested special purpose register"));
-      else
-       /* mrs only accepts APSR/CPSR/SPSR/CPSR_all/SPSR_all (for non-M profile
-          devices).  */
-       constraint ((flags & ~SPSR_BIT) != (PSR_c|PSR_f),
-                   _("'APSR', 'CPSR' or 'SPSR' expected"));
+      constraint (inst.reloc.exp.X_op != O_constant,
+                 _("expression too complex"));
+
+      if (shift_amount != 0)
+       {
+         constraint (shift_amount > 31,
+                     _("shift expression is too large"));
 
-      inst.instruction |= (flags & SPSR_BIT) >> 2;
-      inst.instruction |= inst.operands[1].imm & 0xff;
-      inst.instruction |= 0xf0000;
+         if (inst.operands[3].shift_kind == SHIFT_ASR)
+           inst.instruction |= 0x00200000;  /* sh bit.  */
+
+         inst.instruction |= (shift_amount & 0x1c) << 10;
+         inst.instruction |= (shift_amount & 0x03) << 6;
+       }
     }
 }
 
 static void
-do_t_msr (void)
+do_t_ssat (void)
 {
-  int flags;
-  unsigned Rn;
-
-  if (do_vfp_nsyn_msr () == SUCCESS)
-    return;
-
-  constraint (!inst.operands[1].isreg,
-             _("Thumb encoding does not support an immediate here"));
-
-  if (inst.operands[0].isreg)
-    flags = (int)(inst.operands[0].reg);
-  else
-    flags = inst.operands[0].imm;
+  do_t_ssat_usat (1);
+}
 
-  if (ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_m))
-    {
-      int bits = inst.operands[0].imm & (PSR_c|PSR_x|PSR_s|PSR_f|SPSR_BIT);
+static void
+do_t_ssat16 (void)
+{
+  unsigned Rd, Rn;
 
-      constraint ((ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6_dsp)
-                  && (bits & ~(PSR_s | PSR_f)) != 0)
-                 || (!ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6_dsp)
-                     && bits != PSR_f),
-                 _("selected processor does not support requested special "
-                   "purpose register"));
-    }
-  else
-     constraint ((flags & 0xff) != 0, _("selected processor does not support "
-                "requested special purpose register"));
+  Rd = inst.operands[0].reg;
+  Rn = inst.operands[2].reg;
 
-  Rn = inst.operands[1].reg;
+  reject_bad_reg (Rd);
   reject_bad_reg (Rn);
 
-  inst.instruction |= (flags & SPSR_BIT) >> 2;
-  inst.instruction |= (flags & 0xf0000) >> 8;
-  inst.instruction |= (flags & 0x300) >> 4;
-  inst.instruction |= (flags & 0xff);
+  inst.instruction |= Rd << 8;
+  inst.instruction |= inst.operands[1].imm - 1;
   inst.instruction |= Rn << 16;
 }
 
 static void
-do_t_mul (void)
+do_t_strex (void)
 {
-  bfd_boolean narrow;
-  unsigned Rd, Rn, Rm;
-
-  if (!inst.operands[2].present)
-    inst.operands[2].reg = inst.operands[0].reg;
+  constraint (!inst.operands[2].isreg || !inst.operands[2].preind
+             || inst.operands[2].postind || inst.operands[2].writeback
+             || inst.operands[2].immisreg || inst.operands[2].shifted
+             || inst.operands[2].negative,
+             BAD_ADDR_MODE);
 
-  Rd = inst.operands[0].reg;
-  Rn = inst.operands[1].reg;
-  Rm = inst.operands[2].reg;
+  constraint (inst.operands[2].reg == REG_PC, BAD_PC);
 
-  if (unified_syntax)
-    {
-      if (inst.size_req == 4
-         || (Rd != Rn
-             && Rd != Rm)
-         || Rn > 7
-         || Rm > 7)
-       narrow = FALSE;
-      else if (inst.instruction == T_MNEM_muls)
-       narrow = !in_it_block ();
-      else
-       narrow = in_it_block ();
-    }
-  else
-    {
-      constraint (inst.instruction == T_MNEM_muls, BAD_THUMB32);
-      constraint (Rn > 7 || Rm > 7,
-                 BAD_HIREG);
-      narrow = TRUE;
-    }
+  inst.instruction |= inst.operands[0].reg << 8;
+  inst.instruction |= inst.operands[1].reg << 12;
+  inst.instruction |= inst.operands[2].reg << 16;
+  inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_U8;
+}
 
-  if (narrow)
-    {
-      /* 16-bit MULS/Conditional MUL.  */
-      inst.instruction = THUMB_OP16 (inst.instruction);
-      inst.instruction |= Rd;
+static void
+do_t_strexd (void)
+{
+  if (!inst.operands[2].present)
+    inst.operands[2].reg = inst.operands[1].reg + 1;
 
-      if (Rd == Rn)
-       inst.instruction |= Rm << 3;
-      else if (Rd == Rm)
-       inst.instruction |= Rn << 3;
-      else
-       constraint (1, _("dest must overlap one source register"));
-    }
-  else
-    {
-      constraint (inst.instruction != T_MNEM_mul,
-                 _("Thumb-2 MUL must not set flags"));
-      /* 32-bit MUL.  */
-      inst.instruction = THUMB_OP32 (inst.instruction);
-      inst.instruction |= Rd << 8;
-      inst.instruction |= Rn << 16;
-      inst.instruction |= Rm << 0;
+  constraint (inst.operands[0].reg == inst.operands[1].reg
+             || inst.operands[0].reg == inst.operands[2].reg
+             || inst.operands[0].reg == inst.operands[3].reg,
+             BAD_OVERLAP);
 
-      reject_bad_reg (Rd);
-      reject_bad_reg (Rn);
-      reject_bad_reg (Rm);
-    }
+  inst.instruction |= inst.operands[0].reg;
+  inst.instruction |= inst.operands[1].reg << 12;
+  inst.instruction |= inst.operands[2].reg << 8;
+  inst.instruction |= inst.operands[3].reg << 16;
 }
 
 static void
-do_t_mull (void)
+do_t_sxtah (void)
 {
-  unsigned RdLo, RdHi, Rn, Rm;
+  unsigned Rd, Rn, Rm;
 
-  RdLo = inst.operands[0].reg;
-  RdHi = inst.operands[1].reg;
-  Rn = inst.operands[2].reg;
-  Rm = inst.operands[3].reg;
+  Rd = inst.operands[0].reg;
+  Rn = inst.operands[1].reg;
+  Rm = inst.operands[2].reg;
 
-  reject_bad_reg (RdLo);
-  reject_bad_reg (RdHi);
+  reject_bad_reg (Rd);
   reject_bad_reg (Rn);
   reject_bad_reg (Rm);
 
-  inst.instruction |= RdLo << 12;
-  inst.instruction |= RdHi << 8;
+  inst.instruction |= Rd << 8;
   inst.instruction |= Rn << 16;
   inst.instruction |= Rm;
-
- if (RdLo == RdHi)
-    as_tsktsk (_("rdhi and rdlo must be different"));
+  inst.instruction |= inst.operands[3].imm << 4;
 }
 
 static void
-do_t_nop (void)
+do_t_sxth (void)
 {
-  set_it_insn_type (NEUTRAL_IT_INSN);
+  unsigned Rd, Rm;
 
-  if (unified_syntax)
+  Rd = inst.operands[0].reg;
+  Rm = inst.operands[1].reg;
+
+  reject_bad_reg (Rd);
+  reject_bad_reg (Rm);
+
+  if (inst.instruction <= 0xffff
+      && inst.size_req != 4
+      && Rd <= 7 && Rm <= 7
+      && (!inst.operands[2].present || inst.operands[2].imm == 0))
     {
-      if (inst.size_req == 4 || inst.operands[0].imm > 15)
-       {
-         inst.instruction = THUMB_OP32 (inst.instruction);
-         inst.instruction |= inst.operands[0].imm;
-       }
-      else
-       {
-         /* PR9722: Check for Thumb2 availability before
-            generating a thumb2 nop instruction.  */
-         if (ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6t2))
-           {
-             inst.instruction = THUMB_OP16 (inst.instruction);
-             inst.instruction |= inst.operands[0].imm << 4;
-           }
-         else
-           inst.instruction = 0x46c0;
-       }
+      inst.instruction = THUMB_OP16 (inst.instruction);
+      inst.instruction |= Rd;
+      inst.instruction |= Rm << 3;
+    }
+  else if (unified_syntax)
+    {
+      if (inst.instruction <= 0xffff)
+       inst.instruction = THUMB_OP32 (inst.instruction);
+      inst.instruction |= Rd << 8;
+      inst.instruction |= Rm;
+      inst.instruction |= inst.operands[2].imm << 4;
     }
   else
     {
-      constraint (inst.operands[0].present,
-                 _("Thumb does not support NOP with hints"));
-      inst.instruction = 0x46c0;
+      constraint (inst.operands[2].present && inst.operands[2].imm != 0,
+                 _("Thumb encoding does not support rotation"));
+      constraint (1, BAD_HIREG);
     }
 }
 
 static void
-do_t_neg (void)
+do_t_swi (void)
 {
-  if (unified_syntax)
+  /* We have to do the following check manually as ARM_EXT_OS only applies
+     to ARM_EXT_V6M.  */
+  if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6m))
     {
-      bfd_boolean narrow;
+      if (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_os)
+         /* This only applies to the v6m howver, not later architectures.  */
+         && ! ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v7))
+       as_bad (_("SVC is not permitted on this architecture"));
+      ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used, arm_ext_os);
+    }
 
-      if (THUMB_SETS_FLAGS (inst.instruction))
-       narrow = !in_it_block ();
-      else
-       narrow = in_it_block ();
-      if (inst.operands[0].reg > 7 || inst.operands[1].reg > 7)
-       narrow = FALSE;
-      if (inst.size_req == 4)
-       narrow = FALSE;
+  inst.reloc.type = BFD_RELOC_ARM_SWI;
+}
 
-      if (!narrow)
-       {
-         inst.instruction = THUMB_OP32 (inst.instruction);
-         inst.instruction |= inst.operands[0].reg << 8;
-         inst.instruction |= inst.operands[1].reg << 16;
-       }
-      else
-       {
-         inst.instruction = THUMB_OP16 (inst.instruction);
-         inst.instruction |= inst.operands[0].reg;
-         inst.instruction |= inst.operands[1].reg << 3;
-       }
-    }
-  else
-    {
-      constraint (inst.operands[0].reg > 7 || inst.operands[1].reg > 7,
-                 BAD_HIREG);
-      constraint (THUMB_SETS_FLAGS (inst.instruction), BAD_THUMB32);
+static void
+do_t_tb (void)
+{
+  unsigned Rn, Rm;
+  int half;
 
-      inst.instruction = THUMB_OP16 (inst.instruction);
-      inst.instruction |= inst.operands[0].reg;
-      inst.instruction |= inst.operands[1].reg << 3;
-    }
+  half = (inst.instruction & 0x10) != 0;
+  set_it_insn_type_last ();
+  constraint (inst.operands[0].immisreg,
+             _("instruction requires register index"));
+
+  Rn = inst.operands[0].reg;
+  Rm = inst.operands[0].imm;
+
+  constraint (Rn == REG_SP, BAD_SP);
+  reject_bad_reg (Rm);
+
+  constraint (!half && inst.operands[0].shifted,
+             _("instruction does not allow shifted index"));
+  inst.instruction |= (Rn << 16) | Rm;
 }
 
 static void
-do_t_orn (void)
+do_t_udf (void)
 {
-  unsigned Rd, Rn;
-
-  Rd = inst.operands[0].reg;
-  Rn = inst.operands[1].present ? inst.operands[1].reg : Rd;
-
-  reject_bad_reg (Rd);
-  /* Rn == REG_SP is unpredictable; Rn == REG_PC is MVN.  */
-  reject_bad_reg (Rn);
-
-  inst.instruction |= Rd << 8;
-  inst.instruction |= Rn << 16;
+  if (!inst.operands[0].present)
+    inst.operands[0].imm = 0;
 
-  if (!inst.operands[2].isreg)
+  if ((unsigned int) inst.operands[0].imm > 255 || inst.size_req == 4)
     {
-      inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
-      inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
+      constraint (inst.size_req == 2,
+                  _("immediate value out of range"));
+      inst.instruction = THUMB_OP32 (inst.instruction);
+      inst.instruction |= (inst.operands[0].imm & 0xf000u) << 4;
+      inst.instruction |= (inst.operands[0].imm & 0x0fffu) << 0;
     }
   else
     {
-      unsigned Rm;
+      inst.instruction = THUMB_OP16 (inst.instruction);
+      inst.instruction |= inst.operands[0].imm;
+    }
 
-      Rm = inst.operands[2].reg;
-      reject_bad_reg (Rm);
+  set_it_insn_type (NEUTRAL_IT_INSN);
+}
 
-      constraint (inst.operands[2].shifted
-                 && inst.operands[2].immisreg,
-                 _("shift must be constant"));
-      encode_thumb32_shifted_operand (2);
-    }
+
+static void
+do_t_usat (void)
+{
+  do_t_ssat_usat (0);
 }
 
 static void
-do_t_pkhbt (void)
+do_t_usat16 (void)
 {
-  unsigned Rd, Rn, Rm;
+  unsigned Rd, Rn;
 
   Rd = inst.operands[0].reg;
-  Rn = inst.operands[1].reg;
-  Rm = inst.operands[2].reg;
+  Rn = inst.operands[2].reg;
 
   reject_bad_reg (Rd);
   reject_bad_reg (Rn);
-  reject_bad_reg (Rm);
 
   inst.instruction |= Rd << 8;
+  inst.instruction |= inst.operands[1].imm;
   inst.instruction |= Rn << 16;
-  inst.instruction |= Rm;
-  if (inst.operands[3].present)
-    {
-      unsigned int val = inst.reloc.exp.X_add_number;
-      constraint (inst.reloc.exp.X_op != O_constant,
-                 _("expression too complex"));
-      inst.instruction |= (val & 0x1c) << 10;
-      inst.instruction |= (val & 0x03) << 6;
-    }
 }
 
-static void
-do_t_pkhtb (void)
-{
-  if (!inst.operands[3].present)
-    {
-      unsigned Rtmp;
+/* Neon instruction encoder helpers.  */
 
-      inst.instruction &= ~0x00000020;
+/* Encodings for the different types for various Neon opcodes.  */
 
-      /* PR 10168.  Swap the Rm and Rn registers.  */
-      Rtmp = inst.operands[1].reg;
-      inst.operands[1].reg = inst.operands[2].reg;
-      inst.operands[2].reg = Rtmp;
-    }
-  do_t_pkhbt ();
-}
+/* An "invalid" code for the following tables.  */
+#define N_INV -1u
 
-static void
-do_t_pld (void)
+struct neon_tab_entry
 {
-  if (inst.operands[0].immisreg)
-    reject_bad_reg (inst.operands[0].imm);
+  unsigned integer;
+  unsigned float_or_poly;
+  unsigned scalar_or_imm;
+};
 
-  encode_thumb32_addr_mode (0, /*is_t=*/FALSE, /*is_d=*/FALSE);
-}
+/* Map overloaded Neon opcodes to their respective encodings.  */
+#define NEON_ENC_TAB                                   \
+  X(vabd,      0x0000700, 0x1200d00, N_INV),           \
+  X(vmax,      0x0000600, 0x0000f00, N_INV),           \
+  X(vmin,      0x0000610, 0x0200f00, N_INV),           \
+  X(vpadd,     0x0000b10, 0x1000d00, N_INV),           \
+  X(vpmax,     0x0000a00, 0x1000f00, N_INV),           \
+  X(vpmin,     0x0000a10, 0x1200f00, N_INV),           \
+  X(vadd,      0x0000800, 0x0000d00, N_INV),           \
+  X(vsub,      0x1000800, 0x0200d00, N_INV),           \
+  X(vceq,      0x1000810, 0x0000e00, 0x1b10100),       \
+  X(vcge,      0x0000310, 0x1000e00, 0x1b10080),       \
+  X(vcgt,      0x0000300, 0x1200e00, 0x1b10000),       \
+  /* Register variants of the following two instructions are encoded as
+     vcge / vcgt with the operands reversed.  */       \
+  X(vclt,      0x0000300, 0x1200e00, 0x1b10200),       \
+  X(vcle,      0x0000310, 0x1000e00, 0x1b10180),       \
+  X(vfma,      N_INV, 0x0000c10, N_INV),               \
+  X(vfms,      N_INV, 0x0200c10, N_INV),               \
+  X(vmla,      0x0000900, 0x0000d10, 0x0800040),       \
+  X(vmls,      0x1000900, 0x0200d10, 0x0800440),       \
+  X(vmul,      0x0000910, 0x1000d10, 0x0800840),       \
+  X(vmull,     0x0800c00, 0x0800e00, 0x0800a40), /* polynomial not float.  */ \
+  X(vmlal,     0x0800800, N_INV,     0x0800240),       \
+  X(vmlsl,     0x0800a00, N_INV,     0x0800640),       \
+  X(vqdmlal,   0x0800900, N_INV,     0x0800340),       \
+  X(vqdmlsl,   0x0800b00, N_INV,     0x0800740),       \
+  X(vqdmull,   0x0800d00, N_INV,     0x0800b40),       \
+  X(vqdmulh,    0x0000b00, N_INV,     0x0800c40),      \
+  X(vqrdmulh,   0x1000b00, N_INV,     0x0800d40),      \
+  X(vqrdmlah,   0x3000b10, N_INV,     0x0800e40),      \
+  X(vqrdmlsh,   0x3000c10, N_INV,     0x0800f40),      \
+  X(vshl,      0x0000400, N_INV,     0x0800510),       \
+  X(vqshl,     0x0000410, N_INV,     0x0800710),       \
+  X(vand,      0x0000110, N_INV,     0x0800030),       \
+  X(vbic,      0x0100110, N_INV,     0x0800030),       \
+  X(veor,      0x1000110, N_INV,     N_INV),           \
+  X(vorn,      0x0300110, N_INV,     0x0800010),       \
+  X(vorr,      0x0200110, N_INV,     0x0800010),       \
+  X(vmvn,      0x1b00580, N_INV,     0x0800030),       \
+  X(vshll,     0x1b20300, N_INV,     0x0800a10), /* max shift, immediate.  */ \
+  X(vcvt,       0x1b30600, N_INV,     0x0800e10), /* integer, fixed-point.  */ \
+  X(vdup,       0xe800b10, N_INV,     0x1b00c00), /* arm, scalar.  */ \
+  X(vld1,       0x0200000, 0x0a00000, 0x0a00c00), /* interlv, lane, dup.  */ \
+  X(vst1,      0x0000000, 0x0800000, N_INV),           \
+  X(vld2,      0x0200100, 0x0a00100, 0x0a00d00),       \
+  X(vst2,      0x0000100, 0x0800100, N_INV),           \
+  X(vld3,      0x0200200, 0x0a00200, 0x0a00e00),       \
+  X(vst3,      0x0000200, 0x0800200, N_INV),           \
+  X(vld4,      0x0200300, 0x0a00300, 0x0a00f00),       \
+  X(vst4,      0x0000300, 0x0800300, N_INV),           \
+  X(vmovn,     0x1b20200, N_INV,     N_INV),           \
+  X(vtrn,      0x1b20080, N_INV,     N_INV),           \
+  X(vqmovn,    0x1b20200, N_INV,     N_INV),           \
+  X(vqmovun,   0x1b20240, N_INV,     N_INV),           \
+  X(vnmul,      0xe200a40, 0xe200b40, N_INV),          \
+  X(vnmla,      0xe100a40, 0xe100b40, N_INV),          \
+  X(vnmls,      0xe100a00, 0xe100b00, N_INV),          \
+  X(vfnma,      0xe900a40, 0xe900b40, N_INV),          \
+  X(vfnms,      0xe900a00, 0xe900b00, N_INV),          \
+  X(vcmp,      0xeb40a40, 0xeb40b40, N_INV),           \
+  X(vcmpz,     0xeb50a40, 0xeb50b40, N_INV),           \
+  X(vcmpe,     0xeb40ac0, 0xeb40bc0, N_INV),           \
+  X(vcmpez,     0xeb50ac0, 0xeb50bc0, N_INV),          \
+  X(vseleq,    0xe000a00, N_INV,     N_INV),           \
+  X(vselvs,    0xe100a00, N_INV,     N_INV),           \
+  X(vselge,    0xe200a00, N_INV,     N_INV),           \
+  X(vselgt,    0xe300a00, N_INV,     N_INV),           \
+  X(vmaxnm,    0xe800a00, 0x3000f10, N_INV),           \
+  X(vminnm,    0xe800a40, 0x3200f10, N_INV),           \
+  X(vcvta,     0xebc0a40, 0x3bb0000, N_INV),           \
+  X(vrintr,    0xeb60a40, 0x3ba0400, N_INV),           \
+  X(vrinta,    0xeb80a40, 0x3ba0400, N_INV),           \
+  X(aes,       0x3b00300, N_INV,     N_INV),           \
+  X(sha3op,    0x2000c00, N_INV,     N_INV),           \
+  X(sha1h,     0x3b902c0, N_INV,     N_INV),           \
+  X(sha2op,     0x3ba0380, N_INV,     N_INV)
 
-static void
-do_t_push_pop (void)
+enum neon_opc
 {
-  unsigned mask;
+#define X(OPC,I,F,S) N_MNEM_##OPC
+NEON_ENC_TAB
+#undef X
+};
 
-  constraint (inst.operands[0].writeback,
-             _("push/pop do not support {reglist}^"));
-  constraint (inst.reloc.type != BFD_RELOC_UNUSED,
-             _("expression too complex"));
+static const struct neon_tab_entry neon_enc_tab[] =
+{
+#define X(OPC,I,F,S) { (I), (F), (S) }
+NEON_ENC_TAB
+#undef X
+};
 
-  mask = inst.operands[0].imm;
-  if ((mask & ~0xff) == 0)
-    inst.instruction = THUMB_OP16 (inst.instruction) | mask;
-  else if ((inst.instruction == T_MNEM_push
-           && (mask & ~0xff) == 1 << REG_LR)
-          || (inst.instruction == T_MNEM_pop
-              && (mask & ~0xff) == 1 << REG_PC))
-    {
-      inst.instruction = THUMB_OP16 (inst.instruction);
-      inst.instruction |= THUMB_PP_PC_LR;
-      inst.instruction |= mask & 0xff;
-    }
-  else if (unified_syntax)
-    {
-      inst.instruction = THUMB_OP32 (inst.instruction);
-      encode_thumb2_ldmstm (13, mask, TRUE);
-    }
-  else
-    {
-      inst.error = _("invalid register list to push/pop instruction");
-      return;
-    }
-}
+/* Do not use these macros; instead, use NEON_ENCODE defined below.  */
+#define NEON_ENC_INTEGER_(X) (neon_enc_tab[(X) & 0x0fffffff].integer)
+#define NEON_ENC_ARMREG_(X)  (neon_enc_tab[(X) & 0x0fffffff].integer)
+#define NEON_ENC_POLY_(X)    (neon_enc_tab[(X) & 0x0fffffff].float_or_poly)
+#define NEON_ENC_FLOAT_(X)   (neon_enc_tab[(X) & 0x0fffffff].float_or_poly)
+#define NEON_ENC_SCALAR_(X)  (neon_enc_tab[(X) & 0x0fffffff].scalar_or_imm)
+#define NEON_ENC_IMMED_(X)   (neon_enc_tab[(X) & 0x0fffffff].scalar_or_imm)
+#define NEON_ENC_INTERLV_(X) (neon_enc_tab[(X) & 0x0fffffff].integer)
+#define NEON_ENC_LANE_(X)    (neon_enc_tab[(X) & 0x0fffffff].float_or_poly)
+#define NEON_ENC_DUP_(X)     (neon_enc_tab[(X) & 0x0fffffff].scalar_or_imm)
+#define NEON_ENC_SINGLE_(X) \
+  ((neon_enc_tab[(X) & 0x0fffffff].integer) | ((X) & 0xf0000000))
+#define NEON_ENC_DOUBLE_(X) \
+  ((neon_enc_tab[(X) & 0x0fffffff].float_or_poly) | ((X) & 0xf0000000))
+#define NEON_ENC_FPV8_(X) \
+  ((neon_enc_tab[(X) & 0x0fffffff].integer) | ((X) & 0xf000000))
 
-static void
-do_t_rbit (void)
-{
-  unsigned Rd, Rm;
+#define NEON_ENCODE(type, inst)                                        \
+  do                                                           \
+    {                                                          \
+      inst.instruction = NEON_ENC_##type##_ (inst.instruction);        \
+      inst.is_neon = 1;                                                \
+    }                                                          \
+  while (0)
 
-  Rd = inst.operands[0].reg;
-  Rm = inst.operands[1].reg;
+#define check_neon_suffixes                                            \
+  do                                                                   \
+    {                                                                  \
+      if (!inst.error && inst.vectype.elems > 0 && !inst.is_neon)      \
+       {                                                               \
+         as_bad (_("invalid neon suffix for non neon instruction"));   \
+         return;                                                       \
+       }                                                               \
+    }                                                                  \
+  while (0)
+
+/* Define shapes for instruction operands. The following mnemonic characters
+   are used in this table:
+
+     F - VFP S<n> register
+     D - Neon D<n> register
+     Q - Neon Q<n> register
+     I - Immediate
+     S - Scalar
+     R - ARM register
+     L - D<n> register list
+
+   This table is used to generate various data:
+     - enumerations of the form NS_DDR to be used as arguments to
+       neon_select_shape.
+     - a table classifying shapes into single, double, quad, mixed.
+     - a table used to drive neon_select_shape.  */
+
+#define NEON_SHAPE_DEF                 \
+  X(3, (D, D, D), DOUBLE),             \
+  X(3, (Q, Q, Q), QUAD),               \
+  X(3, (D, D, I), DOUBLE),             \
+  X(3, (Q, Q, I), QUAD),               \
+  X(3, (D, D, S), DOUBLE),             \
+  X(3, (Q, Q, S), QUAD),               \
+  X(2, (D, D), DOUBLE),                        \
+  X(2, (Q, Q), QUAD),                  \
+  X(2, (D, S), DOUBLE),                        \
+  X(2, (Q, S), QUAD),                  \
+  X(2, (D, R), DOUBLE),                        \
+  X(2, (Q, R), QUAD),                  \
+  X(2, (D, I), DOUBLE),                        \
+  X(2, (Q, I), QUAD),                  \
+  X(3, (D, L, D), DOUBLE),             \
+  X(2, (D, Q), MIXED),                 \
+  X(2, (Q, D), MIXED),                 \
+  X(3, (D, Q, I), MIXED),              \
+  X(3, (Q, D, I), MIXED),              \
+  X(3, (Q, D, D), MIXED),              \
+  X(3, (D, Q, Q), MIXED),              \
+  X(3, (Q, Q, D), MIXED),              \
+  X(3, (Q, D, S), MIXED),              \
+  X(3, (D, Q, S), MIXED),              \
+  X(4, (D, D, D, I), DOUBLE),          \
+  X(4, (Q, Q, Q, I), QUAD),            \
+  X(2, (F, F), SINGLE),                        \
+  X(3, (F, F, F), SINGLE),             \
+  X(2, (F, I), SINGLE),                        \
+  X(2, (F, D), MIXED),                 \
+  X(2, (D, F), MIXED),                 \
+  X(3, (F, F, I), MIXED),              \
+  X(4, (R, R, F, F), SINGLE),          \
+  X(4, (F, F, R, R), SINGLE),          \
+  X(3, (D, R, R), DOUBLE),             \
+  X(3, (R, R, D), DOUBLE),             \
+  X(2, (S, R), SINGLE),                        \
+  X(2, (R, S), SINGLE),                        \
+  X(2, (F, R), SINGLE),                        \
+  X(2, (R, F), SINGLE),                        \
+/* Half float shape supported so far.  */\
+  X (2, (H, D), MIXED),                        \
+  X (2, (D, H), MIXED),                        \
+  X (2, (H, F), MIXED),                        \
+  X (2, (F, H), MIXED),                        \
+  X (2, (H, H), HALF),                 \
+  X (2, (H, R), HALF),                 \
+  X (2, (R, H), HALF),                 \
+  X (2, (H, I), HALF),                 \
+  X (3, (H, H, H), HALF),              \
+  X (3, (H, F, I), MIXED),             \
+  X (3, (F, H, I), MIXED)
 
-  reject_bad_reg (Rd);
-  reject_bad_reg (Rm);
+#define S2(A,B)                NS_##A##B
+#define S3(A,B,C)      NS_##A##B##C
+#define S4(A,B,C,D)    NS_##A##B##C##D
 
-  inst.instruction |= Rd << 8;
-  inst.instruction |= Rm << 16;
-  inst.instruction |= Rm;
-}
+#define X(N, L, C) S##N L
 
-static void
-do_t_rev (void)
+enum neon_shape
 {
-  unsigned Rd, Rm;
-
-  Rd = inst.operands[0].reg;
-  Rm = inst.operands[1].reg;
-
-  reject_bad_reg (Rd);
-  reject_bad_reg (Rm);
+  NEON_SHAPE_DEF,
+  NS_NULL
+};
 
-  if (Rd <= 7 && Rm <= 7
-      && inst.size_req != 4)
-    {
-      inst.instruction = THUMB_OP16 (inst.instruction);
-      inst.instruction |= Rd;
-      inst.instruction |= Rm << 3;
-    }
-  else if (unified_syntax)
-    {
-      inst.instruction = THUMB_OP32 (inst.instruction);
-      inst.instruction |= Rd << 8;
-      inst.instruction |= Rm << 16;
-      inst.instruction |= Rm;
-    }
-  else
-    inst.error = BAD_HIREG;
-}
+#undef X
+#undef S2
+#undef S3
+#undef S4
 
-static void
-do_t_rrx (void)
+enum neon_shape_class
 {
-  unsigned Rd, Rm;
-
-  Rd = inst.operands[0].reg;
-  Rm = inst.operands[1].reg;
-
-  reject_bad_reg (Rd);
-  reject_bad_reg (Rm);
+  SC_HALF,
+  SC_SINGLE,
+  SC_DOUBLE,
+  SC_QUAD,
+  SC_MIXED
+};
 
-  inst.instruction |= Rd << 8;
-  inst.instruction |= Rm;
-}
+#define X(N, L, C) SC_##C
 
-static void
-do_t_rsb (void)
+static enum neon_shape_class neon_shape_class[] =
 {
-  unsigned Rd, Rs;
+  NEON_SHAPE_DEF
+};
 
-  Rd = inst.operands[0].reg;
-  Rs = (inst.operands[1].present
-       ? inst.operands[1].reg    /* Rd, Rs, foo */
-       : inst.operands[0].reg);  /* Rd, foo -> Rd, Rd, foo */
+#undef X
 
-  reject_bad_reg (Rd);
-  reject_bad_reg (Rs);
-  if (inst.operands[2].isreg)
-    reject_bad_reg (inst.operands[2].reg);
+enum neon_shape_el
+{
+  SE_H,
+  SE_F,
+  SE_D,
+  SE_Q,
+  SE_I,
+  SE_S,
+  SE_R,
+  SE_L
+};
 
-  inst.instruction |= Rd << 8;
-  inst.instruction |= Rs << 16;
-  if (!inst.operands[2].isreg)
-    {
-      bfd_boolean narrow;
+/* Register widths of above.  */
+static unsigned neon_shape_el_size[] =
+{
+  16,
+  32,
+  64,
+  128,
+  0,
+  32,
+  32,
+  0
+};
 
-      if ((inst.instruction & 0x00100000) != 0)
-       narrow = !in_it_block ();
-      else
-       narrow = in_it_block ();
+struct neon_shape_info
+{
+  unsigned els;
+  enum neon_shape_el el[NEON_MAX_TYPE_ELS];
+};
 
-      if (Rd > 7 || Rs > 7)
-       narrow = FALSE;
+#define S2(A,B)                { SE_##A, SE_##B }
+#define S3(A,B,C)      { SE_##A, SE_##B, SE_##C }
+#define S4(A,B,C,D)    { SE_##A, SE_##B, SE_##C, SE_##D }
 
-      if (inst.size_req == 4 || !unified_syntax)
-       narrow = FALSE;
+#define X(N, L, C) { N, S##N L }
 
-      if (inst.reloc.exp.X_op != O_constant
-         || inst.reloc.exp.X_add_number != 0)
-       narrow = FALSE;
+static struct neon_shape_info neon_shape_tab[] =
+{
+  NEON_SHAPE_DEF
+};
 
-      /* Turn rsb #0 into 16-bit neg.  We should probably do this via
-         relaxation, but it doesn't seem worth the hassle.  */
-      if (narrow)
-       {
-         inst.reloc.type = BFD_RELOC_UNUSED;
-         inst.instruction = THUMB_OP16 (T_MNEM_negs);
-         inst.instruction |= Rs << 3;
-         inst.instruction |= Rd;
-       }
-      else
-       {
-         inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
-         inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
-       }
-    }
-  else
-    encode_thumb32_shifted_operand (2);
-}
+#undef X
+#undef S2
+#undef S3
+#undef S4
 
-static void
-do_t_setend (void)
-{
-  set_it_insn_type (OUTSIDE_IT_INSN);
-  if (inst.operands[0].imm)
-    inst.instruction |= 0x8;
-}
+/* Bit masks used in type checking given instructions.
+  'N_EQK' means the type must be the same as (or based on in some way) the key
+   type, which itself is marked with the 'N_KEY' bit. If the 'N_EQK' bit is
+   set, various other bits can be set as well in order to modify the meaning of
+   the type constraint.  */
 
-static void
-do_t_shift (void)
+enum neon_type_mask
 {
-  if (!inst.operands[1].present)
-    inst.operands[1].reg = inst.operands[0].reg;
-
-  if (unified_syntax)
-    {
-      bfd_boolean narrow;
-      int shift_kind;
+  N_S8   = 0x0000001,
+  N_S16  = 0x0000002,
+  N_S32  = 0x0000004,
+  N_S64  = 0x0000008,
+  N_U8   = 0x0000010,
+  N_U16  = 0x0000020,
+  N_U32  = 0x0000040,
+  N_U64  = 0x0000080,
+  N_I8   = 0x0000100,
+  N_I16  = 0x0000200,
+  N_I32  = 0x0000400,
+  N_I64  = 0x0000800,
+  N_8    = 0x0001000,
+  N_16   = 0x0002000,
+  N_32   = 0x0004000,
+  N_64   = 0x0008000,
+  N_P8   = 0x0010000,
+  N_P16  = 0x0020000,
+  N_F16  = 0x0040000,
+  N_F32  = 0x0080000,
+  N_F64  = 0x0100000,
+  N_P64         = 0x0200000,
+  N_KEY  = 0x1000000, /* Key element (main type specifier).  */
+  N_EQK  = 0x2000000, /* Given operand has the same type & size as the key.  */
+  N_VFP  = 0x4000000, /* VFP mode: operand size must match register width.  */
+  N_UNT  = 0x8000000, /* Must be explicitly untyped.  */
+  N_DBL  = 0x0000001, /* If N_EQK, this operand is twice the size.  */
+  N_HLF  = 0x0000002, /* If N_EQK, this operand is half the size.  */
+  N_SGN  = 0x0000004, /* If N_EQK, this operand is forced to be signed.  */
+  N_UNS  = 0x0000008, /* If N_EQK, this operand is forced to be unsigned.  */
+  N_INT  = 0x0000010, /* If N_EQK, this operand is forced to be integer.  */
+  N_FLT  = 0x0000020, /* If N_EQK, this operand is forced to be float.  */
+  N_SIZ  = 0x0000040, /* If N_EQK, this operand is forced to be size-only.  */
+  N_UTYP = 0,
+  N_MAX_NONSPECIAL = N_P64
+};
 
-      switch (inst.instruction)
-       {
-       case T_MNEM_asr:
-       case T_MNEM_asrs: shift_kind = SHIFT_ASR; break;
-       case T_MNEM_lsl:
-       case T_MNEM_lsls: shift_kind = SHIFT_LSL; break;
-       case T_MNEM_lsr:
-       case T_MNEM_lsrs: shift_kind = SHIFT_LSR; break;
-       case T_MNEM_ror:
-       case T_MNEM_rors: shift_kind = SHIFT_ROR; break;
-       default: abort ();
-       }
+#define N_ALLMODS  (N_DBL | N_HLF | N_SGN | N_UNS | N_INT | N_FLT | N_SIZ)
 
-      if (THUMB_SETS_FLAGS (inst.instruction))
-       narrow = !in_it_block ();
-      else
-       narrow = in_it_block ();
-      if (inst.operands[0].reg > 7 || inst.operands[1].reg > 7)
-       narrow = FALSE;
-      if (!inst.operands[2].isreg && shift_kind == SHIFT_ROR)
-       narrow = FALSE;
-      if (inst.operands[2].isreg
-         && (inst.operands[1].reg != inst.operands[0].reg
-             || inst.operands[2].reg > 7))
-       narrow = FALSE;
-      if (inst.size_req == 4)
-       narrow = FALSE;
+#define N_SU_ALL   (N_S8 | N_S16 | N_S32 | N_S64 | N_U8 | N_U16 | N_U32 | N_U64)
+#define N_SU_32    (N_S8 | N_S16 | N_S32 | N_U8 | N_U16 | N_U32)
+#define N_SU_16_64 (N_S16 | N_S32 | N_S64 | N_U16 | N_U32 | N_U64)
+#define N_S_32     (N_S8 | N_S16 | N_S32)
+#define N_F_16_32  (N_F16 | N_F32)
+#define N_SUF_32   (N_SU_32 | N_F_16_32)
+#define N_I_ALL    (N_I8 | N_I16 | N_I32 | N_I64)
+#define N_IF_32    (N_I8 | N_I16 | N_I32 | N_F16 | N_F32)
+#define N_F_ALL    (N_F16 | N_F32 | N_F64)
 
-      reject_bad_reg (inst.operands[0].reg);
-      reject_bad_reg (inst.operands[1].reg);
+/* Pass this as the first type argument to neon_check_type to ignore types
+   altogether.  */
+#define N_IGNORE_TYPE (N_KEY | N_EQK)
 
-      if (!narrow)
-       {
-         if (inst.operands[2].isreg)
-           {
-             reject_bad_reg (inst.operands[2].reg);
-             inst.instruction = THUMB_OP32 (inst.instruction);
-             inst.instruction |= inst.operands[0].reg << 8;
-             inst.instruction |= inst.operands[1].reg << 16;
-             inst.instruction |= inst.operands[2].reg;
-           }
-         else
-           {
-             inst.operands[1].shifted = 1;
-             inst.operands[1].shift_kind = shift_kind;
-             inst.instruction = THUMB_OP32 (THUMB_SETS_FLAGS (inst.instruction)
-                                            ? T_MNEM_movs : T_MNEM_mov);
-             inst.instruction |= inst.operands[0].reg << 8;
-             encode_thumb32_shifted_operand (1);
-             /* Prevent the incorrect generation of an ARM_IMMEDIATE fixup.  */
-             inst.reloc.type = BFD_RELOC_UNUSED;
-           }
-       }
-      else
-       {
-         if (inst.operands[2].isreg)
-           {
-             switch (shift_kind)
-               {
-               case SHIFT_ASR: inst.instruction = T_OPCODE_ASR_R; break;
-               case SHIFT_LSL: inst.instruction = T_OPCODE_LSL_R; break;
-               case SHIFT_LSR: inst.instruction = T_OPCODE_LSR_R; break;
-               case SHIFT_ROR: inst.instruction = T_OPCODE_ROR_R; break;
-               default: abort ();
-               }
+/* Select a "shape" for the current instruction (describing register types or
+   sizes) from a list of alternatives. Return NS_NULL if the current instruction
+   doesn't fit. For non-polymorphic shapes, checking is usually done as a
+   function of operand parsing, so this function doesn't need to be called.
+   Shapes should be listed in order of decreasing length.  */
 
-             inst.instruction |= inst.operands[0].reg;
-             inst.instruction |= inst.operands[2].reg << 3;
-           }
-         else
-           {
-             switch (shift_kind)
-               {
-               case SHIFT_ASR: inst.instruction = T_OPCODE_ASR_I; break;
-               case SHIFT_LSL: inst.instruction = T_OPCODE_LSL_I; break;
-               case SHIFT_LSR: inst.instruction = T_OPCODE_LSR_I; break;
-               default: abort ();
-               }
-             inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
-             inst.instruction |= inst.operands[0].reg;
-             inst.instruction |= inst.operands[1].reg << 3;
-           }
-       }
-    }
-  else
+static enum neon_shape
+neon_select_shape (enum neon_shape shape, ...)
+{
+  va_list ap;
+  enum neon_shape first_shape = shape;
+
+  /* Fix missing optional operands. FIXME: we don't know at this point how
+     many arguments we should have, so this makes the assumption that we have
+     > 1. This is true of all current Neon opcodes, I think, but may not be
+     true in the future.  */
+  if (!inst.operands[1].present)
+    inst.operands[1] = inst.operands[0];
+
+  va_start (ap, shape);
+
+  for (; shape != NS_NULL; shape = (enum neon_shape) va_arg (ap, int))
     {
-      constraint (inst.operands[0].reg > 7
-                 || inst.operands[1].reg > 7, BAD_HIREG);
-      constraint (THUMB_SETS_FLAGS (inst.instruction), BAD_THUMB32);
+      unsigned j;
+      int matches = 1;
 
-      if (inst.operands[2].isreg)  /* Rd, {Rs,} Rn */
+      for (j = 0; j < neon_shape_tab[shape].els; j++)
        {
-         constraint (inst.operands[2].reg > 7, BAD_HIREG);
-         constraint (inst.operands[0].reg != inst.operands[1].reg,
-                     _("source1 and dest must be same register"));
-
-         switch (inst.instruction)
+         if (!inst.operands[j].present)
            {
-           case T_MNEM_asr: inst.instruction = T_OPCODE_ASR_R; break;
-           case T_MNEM_lsl: inst.instruction = T_OPCODE_LSL_R; break;
-           case T_MNEM_lsr: inst.instruction = T_OPCODE_LSR_R; break;
-           case T_MNEM_ror: inst.instruction = T_OPCODE_ROR_R; break;
-           default: abort ();
+             matches = 0;
+             break;
            }
 
-         inst.instruction |= inst.operands[0].reg;
-         inst.instruction |= inst.operands[2].reg << 3;
-       }
-      else
-       {
-         switch (inst.instruction)
+         switch (neon_shape_tab[shape].el[j])
            {
-           case T_MNEM_asr: inst.instruction = T_OPCODE_ASR_I; break;
-           case T_MNEM_lsl: inst.instruction = T_OPCODE_LSL_I; break;
-           case T_MNEM_lsr: inst.instruction = T_OPCODE_LSR_I; break;
-           case T_MNEM_ror: inst.error = _("ror #imm not supported"); return;
-           default: abort ();
-           }
-         inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
-         inst.instruction |= inst.operands[0].reg;
-         inst.instruction |= inst.operands[1].reg << 3;
-       }
-    }
-}
+             /* If a  .f16,  .16,  .u16,  .s16 type specifier is given over
+                a VFP single precision register operand, it's essentially
+                means only half of the register is used.
+
+                If the type specifier is given after the mnemonics, the
+                information is stored in inst.vectype.  If the type specifier
+                is given after register operand, the information is stored
+                in inst.operands[].vectype.
+
+                When there is only one type specifier, and all the register
+                operands are the same type of hardware register, the type
+                specifier applies to all register operands.
+
+                If no type specifier is given, the shape is inferred from
+                operand information.
+
+                for example:
+                vadd.f16 s0, s1, s2:           NS_HHH
+                vabs.f16 s0, s1:               NS_HH
+                vmov.f16 s0, r1:               NS_HR
+                vmov.f16 r0, s1:               NS_RH
+                vcvt.f16 r0, s1:               NS_RH
+                vcvt.f16.s32   s2, s2, #29:    NS_HFI
+                vcvt.f16.s32   s2, s2:         NS_HF
+             */
+           case SE_H:
+             if (!(inst.operands[j].isreg
+                   && inst.operands[j].isvec
+                   && inst.operands[j].issingle
+                   && !inst.operands[j].isquad
+                   && ((inst.vectype.elems == 1
+                        && inst.vectype.el[0].size == 16)
+                       || (inst.vectype.elems > 1
+                           && inst.vectype.el[j].size == 16)
+                       || (inst.vectype.elems == 0
+                           && inst.operands[j].vectype.type != NT_invtype
+                           && inst.operands[j].vectype.size == 16))))
+               matches = 0;
+             break;
 
-static void
-do_t_simd (void)
-{
-  unsigned Rd, Rn, Rm;
+           case SE_F:
+             if (!(inst.operands[j].isreg
+                   && inst.operands[j].isvec
+                   && inst.operands[j].issingle
+                   && !inst.operands[j].isquad
+                   && ((inst.vectype.elems == 1 && inst.vectype.el[0].size == 32)
+                       || (inst.vectype.elems > 1 && inst.vectype.el[j].size == 32)
+                       || (inst.vectype.elems == 0
+                           && (inst.operands[j].vectype.size == 32
+                               || inst.operands[j].vectype.type == NT_invtype)))))
+               matches = 0;
+             break;
 
-  Rd = inst.operands[0].reg;
-  Rn = inst.operands[1].reg;
-  Rm = inst.operands[2].reg;
+           case SE_D:
+             if (!(inst.operands[j].isreg
+                   && inst.operands[j].isvec
+                   && !inst.operands[j].isquad
+                   && !inst.operands[j].issingle))
+               matches = 0;
+             break;
 
-  reject_bad_reg (Rd);
-  reject_bad_reg (Rn);
-  reject_bad_reg (Rm);
+           case SE_R:
+             if (!(inst.operands[j].isreg
+                   && !inst.operands[j].isvec))
+               matches = 0;
+             break;
 
-  inst.instruction |= Rd << 8;
-  inst.instruction |= Rn << 16;
-  inst.instruction |= Rm;
-}
+           case SE_Q:
+             if (!(inst.operands[j].isreg
+                   && inst.operands[j].isvec
+                   && inst.operands[j].isquad
+                   && !inst.operands[j].issingle))
+               matches = 0;
+             break;
 
-static void
-do_t_simd2 (void)
-{
-  unsigned Rd, Rn, Rm;
+           case SE_I:
+             if (!(!inst.operands[j].isreg
+                   && !inst.operands[j].isscalar))
+               matches = 0;
+             break;
 
-  Rd = inst.operands[0].reg;
-  Rm = inst.operands[1].reg;
-  Rn = inst.operands[2].reg;
+           case SE_S:
+             if (!(!inst.operands[j].isreg
+                   && inst.operands[j].isscalar))
+               matches = 0;
+             break;
 
-  reject_bad_reg (Rd);
-  reject_bad_reg (Rn);
-  reject_bad_reg (Rm);
+           case SE_L:
+             break;
+           }
+         if (!matches)
+           break;
+       }
+      if (matches && (j >= ARM_IT_MAX_OPERANDS || !inst.operands[j].present))
+       /* We've matched all the entries in the shape table, and we don't
+          have any left over operands which have not been matched.  */
+       break;
+    }
 
-  inst.instruction |= Rd << 8;
-  inst.instruction |= Rn << 16;
-  inst.instruction |= Rm;
+  va_end (ap);
+
+  if (shape == NS_NULL && first_shape != NS_NULL)
+    first_error (_("invalid instruction shape"));
+
+  return shape;
 }
 
-static void
-do_t_smc (void)
+/* True if SHAPE is predominantly a quadword operation (most of the time, this
+   means the Q bit should be set).  */
+
+static int
+neon_quad (enum neon_shape shape)
 {
-  unsigned int value = inst.reloc.exp.X_add_number;
-  constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v7a),
-             _("SMC is not permitted on this architecture"));
-  constraint (inst.reloc.exp.X_op != O_constant,
-             _("expression too complex"));
-  inst.reloc.type = BFD_RELOC_UNUSED;
-  inst.instruction |= (value & 0xf000) >> 12;
-  inst.instruction |= (value & 0x0ff0);
-  inst.instruction |= (value & 0x000f) << 16;
+  return neon_shape_class[shape] == SC_QUAD;
 }
 
 static void
-do_t_hvc (void)
+neon_modify_type_size (unsigned typebits, enum neon_el_type *g_type,
+                      unsigned *g_size)
 {
-  unsigned int value = inst.reloc.exp.X_add_number;
-
-  inst.reloc.type = BFD_RELOC_UNUSED;
-  inst.instruction |= (value & 0x0fff);
-  inst.instruction |= (value & 0xf000) << 4;
+  /* Allow modification to be made to types which are constrained to be
+     based on the key element, based on bits set alongside N_EQK.  */
+  if ((typebits & N_EQK) != 0)
+    {
+      if ((typebits & N_HLF) != 0)
+       *g_size /= 2;
+      else if ((typebits & N_DBL) != 0)
+       *g_size *= 2;
+      if ((typebits & N_SGN) != 0)
+       *g_type = NT_signed;
+      else if ((typebits & N_UNS) != 0)
+       *g_type = NT_unsigned;
+      else if ((typebits & N_INT) != 0)
+       *g_type = NT_integer;
+      else if ((typebits & N_FLT) != 0)
+       *g_type = NT_float;
+      else if ((typebits & N_SIZ) != 0)
+       *g_type = NT_untyped;
+    }
 }
 
-static void
-do_t_ssat_usat (int bias)
+/* Return operand OPNO promoted by bits set in THISARG. KEY should be the "key"
+   operand type, i.e. the single type specified in a Neon instruction when it
+   is the only one given.  */
+
+static struct neon_type_el
+neon_type_promote (struct neon_type_el *key, unsigned thisarg)
 {
-  unsigned Rd, Rn;
+  struct neon_type_el dest = *key;
 
-  Rd = inst.operands[0].reg;
-  Rn = inst.operands[2].reg;
+  gas_assert ((thisarg & N_EQK) != 0);
 
-  reject_bad_reg (Rd);
-  reject_bad_reg (Rn);
+  neon_modify_type_size (thisarg, &dest.type, &dest.size);
 
-  inst.instruction |= Rd << 8;
-  inst.instruction |= inst.operands[1].imm - bias;
-  inst.instruction |= Rn << 16;
+  return dest;
+}
 
-  if (inst.operands[3].present)
+/* Convert Neon type and size into compact bitmask representation.  */
+
+static enum neon_type_mask
+type_chk_of_el_type (enum neon_el_type type, unsigned size)
+{
+  switch (type)
     {
-      offsetT shift_amount = inst.reloc.exp.X_add_number;
+    case NT_untyped:
+      switch (size)
+       {
+       case 8:  return N_8;
+       case 16: return N_16;
+       case 32: return N_32;
+       case 64: return N_64;
+       default: ;
+       }
+      break;
 
-      inst.reloc.type = BFD_RELOC_UNUSED;
+    case NT_integer:
+      switch (size)
+       {
+       case 8:  return N_I8;
+       case 16: return N_I16;
+       case 32: return N_I32;
+       case 64: return N_I64;
+       default: ;
+       }
+      break;
 
-      constraint (inst.reloc.exp.X_op != O_constant,
-                 _("expression too complex"));
+    case NT_float:
+      switch (size)
+       {
+       case 16: return N_F16;
+       case 32: return N_F32;
+       case 64: return N_F64;
+       default: ;
+       }
+      break;
 
-      if (shift_amount != 0)
+    case NT_poly:
+      switch (size)
        {
-         constraint (shift_amount > 31,
-                     _("shift expression is too large"));
+       case 8:  return N_P8;
+       case 16: return N_P16;
+       case 64: return N_P64;
+       default: ;
+       }
+      break;
 
-         if (inst.operands[3].shift_kind == SHIFT_ASR)
-           inst.instruction |= 0x00200000;  /* sh bit.  */
+    case NT_signed:
+      switch (size)
+       {
+       case 8:  return N_S8;
+       case 16: return N_S16;
+       case 32: return N_S32;
+       case 64: return N_S64;
+       default: ;
+       }
+      break;
 
-         inst.instruction |= (shift_amount & 0x1c) << 10;
-         inst.instruction |= (shift_amount & 0x03) << 6;
+    case NT_unsigned:
+      switch (size)
+       {
+       case 8:  return N_U8;
+       case 16: return N_U16;
+       case 32: return N_U32;
+       case 64: return N_U64;
+       default: ;
        }
+      break;
+
+    default: ;
     }
-}
 
-static void
-do_t_ssat (void)
-{
-  do_t_ssat_usat (1);
+  return N_UTYP;
 }
 
-static void
-do_t_ssat16 (void)
-{
-  unsigned Rd, Rn;
-
-  Rd = inst.operands[0].reg;
-  Rn = inst.operands[2].reg;
-
-  reject_bad_reg (Rd);
-  reject_bad_reg (Rn);
-
-  inst.instruction |= Rd << 8;
-  inst.instruction |= inst.operands[1].imm - 1;
-  inst.instruction |= Rn << 16;
-}
+/* 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
-do_t_strex (void)
+static int
+el_type_of_type_chk (enum neon_el_type *type, unsigned *size,
+                    enum neon_type_mask mask)
 {
-  constraint (!inst.operands[2].isreg || !inst.operands[2].preind
-             || inst.operands[2].postind || inst.operands[2].writeback
-             || inst.operands[2].immisreg || inst.operands[2].shifted
-             || inst.operands[2].negative,
-             BAD_ADDR_MODE);
-
-  constraint (inst.operands[2].reg == REG_PC, BAD_PC);
-
-  inst.instruction |= inst.operands[0].reg << 8;
-  inst.instruction |= inst.operands[1].reg << 12;
-  inst.instruction |= inst.operands[2].reg << 16;
-  inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_U8;
-}
+  if ((mask & N_EQK) != 0)
+    return FAIL;
 
-static void
-do_t_strexd (void)
-{
-  if (!inst.operands[2].present)
-    inst.operands[2].reg = inst.operands[1].reg + 1;
+  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_F16 | 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 | N_F64 | N_P64)) != 0)
+    *size = 64;
+  else
+    return FAIL;
 
-  constraint (inst.operands[0].reg == inst.operands[1].reg
-             || inst.operands[0].reg == inst.operands[2].reg
-             || inst.operands[0].reg == inst.operands[3].reg,
-             BAD_OVERLAP);
+  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 | N_P64)) != 0)
+    *type = NT_poly;
+  else if ((mask & (N_F_ALL)) != 0)
+    *type = NT_float;
+  else
+    return FAIL;
 
-  inst.instruction |= inst.operands[0].reg;
-  inst.instruction |= inst.operands[1].reg << 12;
-  inst.instruction |= inst.operands[2].reg << 8;
-  inst.instruction |= inst.operands[3].reg << 16;
+  return SUCCESS;
 }
 
-static void
-do_t_sxtah (void)
+/* Modify a bitmask of allowed types. This is only needed for type
+   relaxation.  */
+
+static unsigned
+modify_types_allowed (unsigned allowed, unsigned mods)
 {
-  unsigned Rd, Rn, Rm;
+  unsigned size;
+  enum neon_el_type type;
+  unsigned destmask;
+  int i;
 
-  Rd = inst.operands[0].reg;
-  Rn = inst.operands[1].reg;
-  Rm = inst.operands[2].reg;
+  destmask = 0;
 
-  reject_bad_reg (Rd);
-  reject_bad_reg (Rn);
-  reject_bad_reg (Rm);
+  for (i = 1; i <= N_MAX_NONSPECIAL; i <<= 1)
+    {
+      if (el_type_of_type_chk (&type, &size,
+                              (enum neon_type_mask) (allowed & i)) == SUCCESS)
+       {
+         neon_modify_type_size (mods, &type, &size);
+         destmask |= type_chk_of_el_type (type, size);
+       }
+    }
 
-  inst.instruction |= Rd << 8;
-  inst.instruction |= Rn << 16;
-  inst.instruction |= Rm;
-  inst.instruction |= inst.operands[3].imm << 4;
+  return destmask;
 }
 
-static void
-do_t_sxth (void)
-{
-  unsigned Rd, Rm;
+/* Check type and return type classification.
+   The manual states (paraphrase): If one datatype is given, it indicates the
+   type given in:
+    - the second operand, if there is one
+    - the operand, if there is no second operand
+    - the result, if there are no operands.
+   This isn't quite good enough though, so we use a concept of a "key" datatype
+   which is set on a per-instruction basis, which is the one which matters when
+   only one data type is written.
+   Note: this function has side-effects (e.g. filling in missing operands). All
+   Neon instructions should call it before performing bit encoding.  */
 
-  Rd = inst.operands[0].reg;
-  Rm = inst.operands[1].reg;
+static struct neon_type_el
+neon_check_type (unsigned els, enum neon_shape ns, ...)
+{
+  va_list ap;
+  unsigned i, pass, key_el = 0;
+  unsigned types[NEON_MAX_TYPE_ELS];
+  enum neon_el_type k_type = NT_invtype;
+  unsigned k_size = -1u;
+  struct neon_type_el badtype = {NT_invtype, -1};
+  unsigned key_allowed = 0;
 
-  reject_bad_reg (Rd);
-  reject_bad_reg (Rm);
+  /* Optional registers in Neon instructions are always (not) in operand 1.
+     Fill in the missing operand here, if it was omitted.  */
+  if (els > 1 && !inst.operands[1].present)
+    inst.operands[1] = inst.operands[0];
 
-  if (inst.instruction <= 0xffff
-      && inst.size_req != 4
-      && Rd <= 7 && Rm <= 7
-      && (!inst.operands[2].present || inst.operands[2].imm == 0))
+  /* Suck up all the varargs.  */
+  va_start (ap, ns);
+  for (i = 0; i < els; i++)
     {
-      inst.instruction = THUMB_OP16 (inst.instruction);
-      inst.instruction |= Rd;
-      inst.instruction |= Rm << 3;
+      unsigned thisarg = va_arg (ap, unsigned);
+      if (thisarg == N_IGNORE_TYPE)
+       {
+         va_end (ap);
+         return badtype;
+       }
+      types[i] = thisarg;
+      if ((thisarg & N_KEY) != 0)
+       key_el = i;
     }
-  else if (unified_syntax)
+  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
+     operand. */
+  if (inst.vectype.elems == 1 && els > 1)
     {
-      if (inst.instruction <= 0xffff)
-       inst.instruction = THUMB_OP32 (inst.instruction);
-      inst.instruction |= Rd << 8;
-      inst.instruction |= Rm;
-      inst.instruction |= inst.operands[2].imm << 4;
+      unsigned j;
+      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
+  else if (inst.vectype.elems == 0 && els > 0)
     {
-      constraint (inst.operands[2].present && inst.operands[2].imm != 0,
-                 _("Thumb encoding does not support rotation"));
-      constraint (1, BAD_HIREG);
-    }
-}
+      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;
 
-static void
-do_t_swi (void)
-{
-  /* We have to do the following check manually as ARM_EXT_OS only applies
-     to ARM_EXT_V6M.  */
-  if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6m))
+      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)
     {
-      if (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_os)
-         /* This only applies to the v6m howver, not later architectures.  */
-         && ! ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v7))
-       as_bad (_("SVC is not permitted on this architecture"));
-      ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used, arm_ext_os);
+      first_error (_("type specifier has the wrong number of parts"));
+      return badtype;
     }
 
-  inst.reloc.type = BFD_RELOC_ARM_SWI;
-}
-
-static void
-do_t_tb (void)
-{
-  unsigned Rn, Rm;
-  int half;
+  for (pass = 0; pass < 2; pass++)
+    {
+      for (i = 0; i < els; i++)
+       {
+         unsigned thisarg = types[i];
+         unsigned types_allowed = ((thisarg & N_EQK) != 0 && pass != 0)
+           ? modify_types_allowed (key_allowed, thisarg) : thisarg;
+         enum neon_el_type g_type = inst.vectype.el[i].type;
+         unsigned g_size = inst.vectype.el[i].size;
 
-  half = (inst.instruction & 0x10) != 0;
-  set_it_insn_type_last ();
-  constraint (inst.operands[0].immisreg,
-             _("instruction requires register index"));
+         /* Decay more-specific signed & unsigned types to sign-insensitive
+            integer types if sign-specific variants are unavailable.  */
+         if ((g_type == NT_signed || g_type == NT_unsigned)
+             && (types_allowed & N_SU_ALL) == 0)
+           g_type = NT_integer;
 
-  Rn = inst.operands[0].reg;
-  Rm = inst.operands[0].imm;
+         /* If only untyped args are allowed, decay any more specific types to
+            them. Some instructions only care about signs for some element
+            sizes, so handle that properly.  */
+         if (((types_allowed & N_UNT) == 0)
+             && ((g_size == 8 && (types_allowed & N_8) != 0)
+                 || (g_size == 16 && (types_allowed & N_16) != 0)
+                 || (g_size == 32 && (types_allowed & N_32) != 0)
+                 || (g_size == 64 && (types_allowed & N_64) != 0)))
+           g_type = NT_untyped;
 
-  constraint (Rn == REG_SP, BAD_SP);
-  reject_bad_reg (Rm);
+         if (pass == 0)
+           {
+             if ((thisarg & N_KEY) != 0)
+               {
+                 k_type = g_type;
+                 k_size = g_size;
+                 key_allowed = thisarg & ~N_KEY;
+
+                 /* Check architecture constraint on FP16 extension.  */
+                 if (k_size == 16
+                     && k_type == NT_float
+                     && ! ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_fp16))
+                   {
+                     inst.error = _(BAD_FP16);
+                     return badtype;
+                   }
+               }
+           }
+         else
+           {
+             if ((thisarg & N_VFP) != 0)
+               {
+                 enum neon_shape_el regshape;
+                 unsigned regwidth, match;
 
-  constraint (!half && inst.operands[0].shifted,
-             _("instruction does not allow shifted index"));
-  inst.instruction |= (Rn << 16) | Rm;
-}
+                 /* PR 11136: Catch the case where we are passed a shape of NS_NULL.  */
+                 if (ns == NS_NULL)
+                   {
+                     first_error (_("invalid instruction shape"));
+                     return badtype;
+                   }
+                 regshape = neon_shape_tab[ns].el[i];
+                 regwidth = neon_shape_el_size[regshape];
+
+                 /* In VFP mode, operands must match register widths. If we
+                    have a key operand, use its width, else use the width of
+                    the current operand.  */
+                 if (k_size != -1u)
+                   match = k_size;
+                 else
+                   match = g_size;
 
-static void
-do_t_usat (void)
-{
-  do_t_ssat_usat (0);
-}
+                 /* FP16 will use a single precision register.  */
+                 if (regwidth == 32 && match == 16)
+                   {
+                     if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_fp16))
+                       match = regwidth;
+                     else
+                       {
+                         inst.error = _(BAD_FP16);
+                         return badtype;
+                       }
+                   }
 
-static void
-do_t_usat16 (void)
-{
-  unsigned Rd, Rn;
+                 if (regwidth != match)
+                   {
+                     first_error (_("operand size must match register width"));
+                     return badtype;
+                   }
+               }
 
-  Rd = inst.operands[0].reg;
-  Rn = inst.operands[2].reg;
+             if ((thisarg & N_EQK) == 0)
+               {
+                 unsigned given_type = type_chk_of_el_type (g_type, g_size);
 
-  reject_bad_reg (Rd);
-  reject_bad_reg (Rn);
+                 if ((given_type & types_allowed) == 0)
+                   {
+                     first_error (_("bad type in Neon instruction"));
+                     return badtype;
+                   }
+               }
+             else
+               {
+                 enum neon_el_type mod_k_type = k_type;
+                 unsigned mod_k_size = k_size;
+                 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;
+                   }
+               }
+           }
+       }
+    }
 
-  inst.instruction |= Rd << 8;
-  inst.instruction |= inst.operands[1].imm;
-  inst.instruction |= Rn << 16;
+  return inst.vectype.el[key_el];
 }
 
-/* Neon instruction encoder helpers.  */
-
-/* Encodings for the different types for various Neon opcodes.  */
+/* Neon-style VFP instruction forwarding.  */
 
-/* An "invalid" code for the following tables.  */
-#define N_INV -1u
+/* Thumb VFP instructions have 0xE in the condition field.  */
 
-struct neon_tab_entry
+static void
+do_vfp_cond_or_thumb (void)
 {
-  unsigned integer;
-  unsigned float_or_poly;
-  unsigned scalar_or_imm;
-};
+  inst.is_neon = 1;
 
-/* Map overloaded Neon opcodes to their respective encodings.  */
-#define NEON_ENC_TAB                                   \
-  X(vabd,      0x0000700, 0x1200d00, N_INV),           \
-  X(vmax,      0x0000600, 0x0000f00, N_INV),           \
-  X(vmin,      0x0000610, 0x0200f00, N_INV),           \
-  X(vpadd,     0x0000b10, 0x1000d00, N_INV),           \
-  X(vpmax,     0x0000a00, 0x1000f00, N_INV),           \
-  X(vpmin,     0x0000a10, 0x1200f00, N_INV),           \
-  X(vadd,      0x0000800, 0x0000d00, N_INV),           \
-  X(vsub,      0x1000800, 0x0200d00, N_INV),           \
-  X(vceq,      0x1000810, 0x0000e00, 0x1b10100),       \
-  X(vcge,      0x0000310, 0x1000e00, 0x1b10080),       \
-  X(vcgt,      0x0000300, 0x1200e00, 0x1b10000),       \
-  /* Register variants of the following two instructions are encoded as
-     vcge / vcgt with the operands reversed.  */       \
-  X(vclt,      0x0000300, 0x1200e00, 0x1b10200),       \
-  X(vcle,      0x0000310, 0x1000e00, 0x1b10180),       \
-  X(vfma,      N_INV, 0x0000c10, N_INV),               \
-  X(vfms,      N_INV, 0x0200c10, N_INV),               \
-  X(vmla,      0x0000900, 0x0000d10, 0x0800040),       \
-  X(vmls,      0x1000900, 0x0200d10, 0x0800440),       \
-  X(vmul,      0x0000910, 0x1000d10, 0x0800840),       \
-  X(vmull,     0x0800c00, 0x0800e00, 0x0800a40), /* polynomial not float.  */ \
-  X(vmlal,     0x0800800, N_INV,     0x0800240),       \
-  X(vmlsl,     0x0800a00, N_INV,     0x0800640),       \
-  X(vqdmlal,   0x0800900, N_INV,     0x0800340),       \
-  X(vqdmlsl,   0x0800b00, N_INV,     0x0800740),       \
-  X(vqdmull,   0x0800d00, N_INV,     0x0800b40),       \
-  X(vqdmulh,    0x0000b00, N_INV,     0x0800c40),      \
-  X(vqrdmulh,   0x1000b00, N_INV,     0x0800d40),      \
-  X(vshl,      0x0000400, N_INV,     0x0800510),       \
-  X(vqshl,     0x0000410, N_INV,     0x0800710),       \
-  X(vand,      0x0000110, N_INV,     0x0800030),       \
-  X(vbic,      0x0100110, N_INV,     0x0800030),       \
-  X(veor,      0x1000110, N_INV,     N_INV),           \
-  X(vorn,      0x0300110, N_INV,     0x0800010),       \
-  X(vorr,      0x0200110, N_INV,     0x0800010),       \
-  X(vmvn,      0x1b00580, N_INV,     0x0800030),       \
-  X(vshll,     0x1b20300, N_INV,     0x0800a10), /* max shift, immediate.  */ \
-  X(vcvt,       0x1b30600, N_INV,     0x0800e10), /* integer, fixed-point.  */ \
-  X(vdup,       0xe800b10, N_INV,     0x1b00c00), /* arm, scalar.  */ \
-  X(vld1,       0x0200000, 0x0a00000, 0x0a00c00), /* interlv, lane, dup.  */ \
-  X(vst1,      0x0000000, 0x0800000, N_INV),           \
-  X(vld2,      0x0200100, 0x0a00100, 0x0a00d00),       \
-  X(vst2,      0x0000100, 0x0800100, N_INV),           \
-  X(vld3,      0x0200200, 0x0a00200, 0x0a00e00),       \
-  X(vst3,      0x0000200, 0x0800200, N_INV),           \
-  X(vld4,      0x0200300, 0x0a00300, 0x0a00f00),       \
-  X(vst4,      0x0000300, 0x0800300, N_INV),           \
-  X(vmovn,     0x1b20200, N_INV,     N_INV),           \
-  X(vtrn,      0x1b20080, N_INV,     N_INV),           \
-  X(vqmovn,    0x1b20200, N_INV,     N_INV),           \
-  X(vqmovun,   0x1b20240, N_INV,     N_INV),           \
-  X(vnmul,      0xe200a40, 0xe200b40, N_INV),          \
-  X(vnmla,      0xe100a40, 0xe100b40, N_INV),          \
-  X(vnmls,      0xe100a00, 0xe100b00, N_INV),          \
-  X(vfnma,      0xe900a40, 0xe900b40, N_INV),          \
-  X(vfnms,      0xe900a00, 0xe900b00, N_INV),          \
-  X(vcmp,      0xeb40a40, 0xeb40b40, N_INV),           \
-  X(vcmpz,     0xeb50a40, 0xeb50b40, N_INV),           \
-  X(vcmpe,     0xeb40ac0, 0xeb40bc0, N_INV),           \
-  X(vcmpez,     0xeb50ac0, 0xeb50bc0, N_INV)
+  if (thumb_mode)
+    inst.instruction |= 0xe0000000;
+  else
+    inst.instruction |= inst.cond << 28;
+}
 
-enum neon_opc
-{
-#define X(OPC,I,F,S) N_MNEM_##OPC
-NEON_ENC_TAB
-#undef X
-};
+/* Look up and encode a simple mnemonic, for use as a helper function for the
+   Neon-style VFP syntax.  This avoids duplication of bits of the insns table,
+   etc.  It is assumed that operand parsing has already been done, and that the
+   operands are in the form expected by the given opcode (this isn't necessarily
+   the same as the form in which they were parsed, hence some massaging must
+   take place before this function is called).
+   Checks current arch version against that in the looked-up opcode.  */
 
-static const struct neon_tab_entry neon_enc_tab[] =
+static void
+do_vfp_nsyn_opcode (const char *opname)
 {
-#define X(OPC,I,F,S) { (I), (F), (S) }
-NEON_ENC_TAB
-#undef X
-};
-
-/* Do not use these macros; instead, use NEON_ENCODE defined below.  */
-#define NEON_ENC_INTEGER_(X) (neon_enc_tab[(X) & 0x0fffffff].integer)
-#define NEON_ENC_ARMREG_(X)  (neon_enc_tab[(X) & 0x0fffffff].integer)
-#define NEON_ENC_POLY_(X)    (neon_enc_tab[(X) & 0x0fffffff].float_or_poly)
-#define NEON_ENC_FLOAT_(X)   (neon_enc_tab[(X) & 0x0fffffff].float_or_poly)
-#define NEON_ENC_SCALAR_(X)  (neon_enc_tab[(X) & 0x0fffffff].scalar_or_imm)
-#define NEON_ENC_IMMED_(X)   (neon_enc_tab[(X) & 0x0fffffff].scalar_or_imm)
-#define NEON_ENC_INTERLV_(X) (neon_enc_tab[(X) & 0x0fffffff].integer)
-#define NEON_ENC_LANE_(X)    (neon_enc_tab[(X) & 0x0fffffff].float_or_poly)
-#define NEON_ENC_DUP_(X)     (neon_enc_tab[(X) & 0x0fffffff].scalar_or_imm)
-#define NEON_ENC_SINGLE_(X) \
-  ((neon_enc_tab[(X) & 0x0fffffff].integer) | ((X) & 0xf0000000))
-#define NEON_ENC_DOUBLE_(X) \
-  ((neon_enc_tab[(X) & 0x0fffffff].float_or_poly) | ((X) & 0xf0000000))
-
-#define NEON_ENCODE(type, inst)                                        \
-  do                                                           \
-    {                                                          \
-      inst.instruction = NEON_ENC_##type##_ (inst.instruction);        \
-      inst.is_neon = 1;                                                \
-    }                                                          \
-  while (0)
+  const struct asm_opcode *opcode;
 
-#define check_neon_suffixes                                            \
-  do                                                                   \
-    {                                                                  \
-      if (!inst.error && inst.vectype.elems > 0 && !inst.is_neon)      \
-       {                                                               \
-         as_bad (_("invalid neon suffix for non neon instruction"));   \
-         return;                                                       \
-       }                                                               \
-    }                                                                  \
-  while (0)
+  opcode = (const struct asm_opcode *) hash_find (arm_ops_hsh, opname);
 
-/* Define shapes for instruction operands. The following mnemonic characters
-   are used in this table:
+  if (!opcode)
+    abort ();
 
-     F - VFP S<n> register
-     D - Neon D<n> register
-     Q - Neon Q<n> register
-     I - Immediate
-     S - Scalar
-     R - ARM register
-     L - D<n> register list
+  constraint (!ARM_CPU_HAS_FEATURE (cpu_variant,
+               thumb_mode ? *opcode->tvariant : *opcode->avariant),
+             _(BAD_FPU));
 
-   This table is used to generate various data:
-     - enumerations of the form NS_DDR to be used as arguments to
-       neon_select_shape.
-     - a table classifying shapes into single, double, quad, mixed.
-     - a table used to drive neon_select_shape.  */
+  inst.is_neon = 1;
 
-#define NEON_SHAPE_DEF                 \
-  X(3, (D, D, D), DOUBLE),             \
-  X(3, (Q, Q, Q), QUAD),               \
-  X(3, (D, D, I), DOUBLE),             \
-  X(3, (Q, Q, I), QUAD),               \
-  X(3, (D, D, S), DOUBLE),             \
-  X(3, (Q, Q, S), QUAD),               \
-  X(2, (D, D), DOUBLE),                        \
-  X(2, (Q, Q), QUAD),                  \
-  X(2, (D, S), DOUBLE),                        \
-  X(2, (Q, S), QUAD),                  \
-  X(2, (D, R), DOUBLE),                        \
-  X(2, (Q, R), QUAD),                  \
-  X(2, (D, I), DOUBLE),                        \
-  X(2, (Q, I), QUAD),                  \
-  X(3, (D, L, D), DOUBLE),             \
-  X(2, (D, Q), MIXED),                 \
-  X(2, (Q, D), MIXED),                 \
-  X(3, (D, Q, I), MIXED),              \
-  X(3, (Q, D, I), MIXED),              \
-  X(3, (Q, D, D), MIXED),              \
-  X(3, (D, Q, Q), MIXED),              \
-  X(3, (Q, Q, D), MIXED),              \
-  X(3, (Q, D, S), MIXED),              \
-  X(3, (D, Q, S), MIXED),              \
-  X(4, (D, D, D, I), DOUBLE),          \
-  X(4, (Q, Q, Q, I), QUAD),            \
-  X(2, (F, F), SINGLE),                        \
-  X(3, (F, F, F), SINGLE),             \
-  X(2, (F, I), SINGLE),                        \
-  X(2, (F, D), MIXED),                 \
-  X(2, (D, F), MIXED),                 \
-  X(3, (F, F, I), MIXED),              \
-  X(4, (R, R, F, F), SINGLE),          \
-  X(4, (F, F, R, R), SINGLE),          \
-  X(3, (D, R, R), DOUBLE),             \
-  X(3, (R, R, D), DOUBLE),             \
-  X(2, (S, R), SINGLE),                        \
-  X(2, (R, S), SINGLE),                        \
-  X(2, (F, R), SINGLE),                        \
-  X(2, (R, F), SINGLE)
+  if (thumb_mode)
+    {
+      inst.instruction = opcode->tvalue;
+      opcode->tencode ();
+    }
+  else
+    {
+      inst.instruction = (inst.cond << 28) | opcode->avalue;
+      opcode->aencode ();
+    }
+}
 
-#define S2(A,B)                NS_##A##B
-#define S3(A,B,C)      NS_##A##B##C
-#define S4(A,B,C,D)    NS_##A##B##C##D
+static void
+do_vfp_nsyn_add_sub (enum neon_shape rs)
+{
+  int is_add = (inst.instruction & 0x0fffffff) == N_MNEM_vadd;
 
-#define X(N, L, C) S##N L
+  if (rs == NS_FFF || rs == NS_HHH)
+    {
+      if (is_add)
+       do_vfp_nsyn_opcode ("fadds");
+      else
+       do_vfp_nsyn_opcode ("fsubs");
 
-enum neon_shape
-{
-  NEON_SHAPE_DEF,
-  NS_NULL
-};
+      /* ARMv8.2 fp16 instruction.  */
+      if (rs == NS_HHH)
+       do_scalar_fp16_v82_encode ();
+    }
+  else
+    {
+      if (is_add)
+       do_vfp_nsyn_opcode ("faddd");
+      else
+       do_vfp_nsyn_opcode ("fsubd");
+    }
+}
 
-#undef X
-#undef S2
-#undef S3
-#undef S4
+/* Check operand types to see if this is a VFP instruction, and if so call
+   PFN ().  */
 
-enum neon_shape_class
+static int
+try_vfp_nsyn (int args, void (*pfn) (enum neon_shape))
 {
-  SC_SINGLE,
-  SC_DOUBLE,
-  SC_QUAD,
-  SC_MIXED
-};
+  enum neon_shape rs;
+  struct neon_type_el et;
 
-#define X(N, L, C) SC_##C
+  switch (args)
+    {
+    case 2:
+      rs = neon_select_shape (NS_HH, NS_FF, NS_DD, NS_NULL);
+      et = neon_check_type (2, rs, N_EQK | N_VFP, N_F_ALL | N_KEY | N_VFP);
+      break;
 
-static enum neon_shape_class neon_shape_class[] =
-{
-  NEON_SHAPE_DEF
-};
+    case 3:
+      rs = neon_select_shape (NS_HHH, NS_FFF, NS_DDD, NS_NULL);
+      et = neon_check_type (3, rs, N_EQK | N_VFP, N_EQK | N_VFP,
+                           N_F_ALL | N_KEY | N_VFP);
+      break;
 
-#undef X
+    default:
+      abort ();
+    }
 
-enum neon_shape_el
-{
-  SE_F,
-  SE_D,
-  SE_Q,
-  SE_I,
-  SE_S,
-  SE_R,
-  SE_L
-};
+  if (et.type != NT_invtype)
+    {
+      pfn (rs);
+      return SUCCESS;
+    }
 
-/* Register widths of above.  */
-static unsigned neon_shape_el_size[] =
+  inst.error = NULL;
+  return FAIL;
+}
+
+static void
+do_vfp_nsyn_mla_mls (enum neon_shape rs)
 {
-  32,
-  64,
-  128,
-  0,
-  32,
-  32,
-  0
-};
+  int is_mla = (inst.instruction & 0x0fffffff) == N_MNEM_vmla;
 
-struct neon_shape_info
+  if (rs == NS_FFF || rs == NS_HHH)
+    {
+      if (is_mla)
+       do_vfp_nsyn_opcode ("fmacs");
+      else
+       do_vfp_nsyn_opcode ("fnmacs");
+
+      /* ARMv8.2 fp16 instruction.  */
+      if (rs == NS_HHH)
+       do_scalar_fp16_v82_encode ();
+    }
+  else
+    {
+      if (is_mla)
+       do_vfp_nsyn_opcode ("fmacd");
+      else
+       do_vfp_nsyn_opcode ("fnmacd");
+    }
+}
+
+static void
+do_vfp_nsyn_fma_fms (enum neon_shape rs)
 {
-  unsigned els;
-  enum neon_shape_el el[NEON_MAX_TYPE_ELS];
-};
+  int is_fma = (inst.instruction & 0x0fffffff) == N_MNEM_vfma;
 
-#define S2(A,B)                { SE_##A, SE_##B }
-#define S3(A,B,C)      { SE_##A, SE_##B, SE_##C }
-#define S4(A,B,C,D)    { SE_##A, SE_##B, SE_##C, SE_##D }
+  if (rs == NS_FFF || rs == NS_HHH)
+    {
+      if (is_fma)
+       do_vfp_nsyn_opcode ("ffmas");
+      else
+       do_vfp_nsyn_opcode ("ffnmas");
 
-#define X(N, L, C) { N, S##N L }
+      /* ARMv8.2 fp16 instruction.  */
+      if (rs == NS_HHH)
+       do_scalar_fp16_v82_encode ();
+    }
+  else
+    {
+      if (is_fma)
+       do_vfp_nsyn_opcode ("ffmad");
+      else
+       do_vfp_nsyn_opcode ("ffnmad");
+    }
+}
 
-static struct neon_shape_info neon_shape_tab[] =
+static void
+do_vfp_nsyn_mul (enum neon_shape rs)
 {
-  NEON_SHAPE_DEF
-};
+  if (rs == NS_FFF || rs == NS_HHH)
+    {
+      do_vfp_nsyn_opcode ("fmuls");
 
-#undef X
-#undef S2
-#undef S3
-#undef S4
+      /* ARMv8.2 fp16 instruction.  */
+      if (rs == NS_HHH)
+       do_scalar_fp16_v82_encode ();
+    }
+  else
+    do_vfp_nsyn_opcode ("fmuld");
+}
 
-/* Bit masks used in type checking given instructions.
-  'N_EQK' means the type must be the same as (or based on in some way) the key
-   type, which itself is marked with the 'N_KEY' bit. If the 'N_EQK' bit is
-   set, various other bits can be set as well in order to modify the meaning of
-   the type constraint.  */
+static void
+do_vfp_nsyn_abs_neg (enum neon_shape rs)
+{
+  int is_neg = (inst.instruction & 0x80) != 0;
+  neon_check_type (2, rs, N_EQK | N_VFP, N_F_ALL | N_VFP | N_KEY);
 
-enum neon_type_mask
+  if (rs == NS_FF || rs == NS_HH)
+    {
+      if (is_neg)
+       do_vfp_nsyn_opcode ("fnegs");
+      else
+       do_vfp_nsyn_opcode ("fabss");
+
+      /* ARMv8.2 fp16 instruction.  */
+      if (rs == NS_HH)
+       do_scalar_fp16_v82_encode ();
+    }
+  else
+    {
+      if (is_neg)
+       do_vfp_nsyn_opcode ("fnegd");
+      else
+       do_vfp_nsyn_opcode ("fabsd");
+    }
+}
+
+/* Encode single-precision (only!) VFP fldm/fstm instructions. Double precision
+   insns belong to Neon, and are handled elsewhere.  */
+
+static void
+do_vfp_nsyn_ldm_stm (int is_dbmode)
 {
-  N_S8   = 0x0000001,
-  N_S16  = 0x0000002,
-  N_S32  = 0x0000004,
-  N_S64  = 0x0000008,
-  N_U8   = 0x0000010,
-  N_U16  = 0x0000020,
-  N_U32  = 0x0000040,
-  N_U64  = 0x0000080,
-  N_I8   = 0x0000100,
-  N_I16  = 0x0000200,
-  N_I32  = 0x0000400,
-  N_I64  = 0x0000800,
-  N_8    = 0x0001000,
-  N_16   = 0x0002000,
-  N_32   = 0x0004000,
-  N_64   = 0x0008000,
-  N_P8   = 0x0010000,
-  N_P16  = 0x0020000,
-  N_F16  = 0x0040000,
-  N_F32  = 0x0080000,
-  N_F64  = 0x0100000,
-  N_KEY  = 0x1000000, /* Key element (main type specifier).  */
-  N_EQK  = 0x2000000, /* Given operand has the same type & size as the key.  */
-  N_VFP  = 0x4000000, /* VFP mode: operand size must match register width.  */
-  N_DBL  = 0x0000001, /* If N_EQK, this operand is twice the size.  */
-  N_HLF  = 0x0000002, /* If N_EQK, this operand is half the size.  */
-  N_SGN  = 0x0000004, /* If N_EQK, this operand is forced to be signed.  */
-  N_UNS  = 0x0000008, /* If N_EQK, this operand is forced to be unsigned.  */
-  N_INT  = 0x0000010, /* If N_EQK, this operand is forced to be integer.  */
-  N_FLT  = 0x0000020, /* If N_EQK, this operand is forced to be float.  */
-  N_SIZ  = 0x0000040, /* If N_EQK, this operand is forced to be size-only.  */
-  N_UTYP = 0,
-  N_MAX_NONSPECIAL = N_F64
-};
+  int is_ldm = (inst.instruction & (1 << 20)) != 0;
+  if (is_ldm)
+    {
+      if (is_dbmode)
+       do_vfp_nsyn_opcode ("fldmdbs");
+      else
+       do_vfp_nsyn_opcode ("fldmias");
+    }
+  else
+    {
+      if (is_dbmode)
+       do_vfp_nsyn_opcode ("fstmdbs");
+      else
+       do_vfp_nsyn_opcode ("fstmias");
+    }
+}
 
-#define N_ALLMODS  (N_DBL | N_HLF | N_SGN | N_UNS | N_INT | N_FLT | N_SIZ)
+static void
+do_vfp_nsyn_sqrt (void)
+{
+  enum neon_shape rs = neon_select_shape (NS_HH, NS_FF, NS_DD, NS_NULL);
+  neon_check_type (2, rs, N_EQK | N_VFP, N_F_ALL | N_KEY | N_VFP);
 
-#define N_SU_ALL   (N_S8 | N_S16 | N_S32 | N_S64 | N_U8 | N_U16 | N_U32 | N_U64)
-#define N_SU_32    (N_S8 | N_S16 | N_S32 | N_U8 | N_U16 | N_U32)
-#define N_SU_16_64 (N_S16 | N_S32 | N_S64 | N_U16 | N_U32 | N_U64)
-#define N_SUF_32   (N_SU_32 | N_F32)
-#define N_I_ALL    (N_I8 | N_I16 | N_I32 | N_I64)
-#define N_IF_32    (N_I8 | N_I16 | N_I32 | N_F32)
+  if (rs == NS_FF || rs == NS_HH)
+    {
+      do_vfp_nsyn_opcode ("fsqrts");
 
-/* Pass this as the first type argument to neon_check_type to ignore types
-   altogether.  */
-#define N_IGNORE_TYPE (N_KEY | N_EQK)
+      /* ARMv8.2 fp16 instruction.  */
+      if (rs == NS_HH)
+       do_scalar_fp16_v82_encode ();
+    }
+  else
+    do_vfp_nsyn_opcode ("fsqrtd");
+}
 
-/* Select a "shape" for the current instruction (describing register types or
-   sizes) from a list of alternatives. Return NS_NULL if the current instruction
-   doesn't fit. For non-polymorphic shapes, checking is usually done as a
-   function of operand parsing, so this function doesn't need to be called.
-   Shapes should be listed in order of decreasing length.  */
+static void
+do_vfp_nsyn_div (void)
+{
+  enum neon_shape rs = neon_select_shape (NS_HHH, NS_FFF, NS_DDD, NS_NULL);
+  neon_check_type (3, rs, N_EQK | N_VFP, N_EQK | N_VFP,
+                  N_F_ALL | N_KEY | N_VFP);
 
-static enum neon_shape
-neon_select_shape (enum neon_shape shape, ...)
+  if (rs == NS_FFF || rs == NS_HHH)
+    {
+      do_vfp_nsyn_opcode ("fdivs");
+
+      /* ARMv8.2 fp16 instruction.  */
+      if (rs == NS_HHH)
+       do_scalar_fp16_v82_encode ();
+    }
+  else
+    do_vfp_nsyn_opcode ("fdivd");
+}
+
+static void
+do_vfp_nsyn_nmul (void)
 {
-  va_list ap;
-  enum neon_shape first_shape = shape;
+  enum neon_shape rs = neon_select_shape (NS_HHH, NS_FFF, NS_DDD, NS_NULL);
+  neon_check_type (3, rs, N_EQK | N_VFP, N_EQK | N_VFP,
+                  N_F_ALL | N_KEY | N_VFP);
 
-  /* Fix missing optional operands. FIXME: we don't know at this point how
-     many arguments we should have, so this makes the assumption that we have
-     > 1. This is true of all current Neon opcodes, I think, but may not be
-     true in the future.  */
-  if (!inst.operands[1].present)
-    inst.operands[1] = inst.operands[0];
+  if (rs == NS_FFF || rs == NS_HHH)
+    {
+      NEON_ENCODE (SINGLE, inst);
+      do_vfp_sp_dyadic ();
 
-  va_start (ap, shape);
+      /* ARMv8.2 fp16 instruction.  */
+      if (rs == NS_HHH)
+       do_scalar_fp16_v82_encode ();
+    }
+  else
+    {
+      NEON_ENCODE (DOUBLE, inst);
+      do_vfp_dp_rd_rn_rm ();
+    }
+  do_vfp_cond_or_thumb ();
 
-  for (; shape != NS_NULL; shape = (enum neon_shape) va_arg (ap, int))
+}
+
+static void
+do_vfp_nsyn_cmp (void)
+{
+  enum neon_shape rs;
+  if (inst.operands[1].isreg)
     {
-      unsigned j;
-      int matches = 1;
+      rs = neon_select_shape (NS_HH, NS_FF, NS_DD, NS_NULL);
+      neon_check_type (2, rs, N_EQK | N_VFP, N_F_ALL | N_KEY | N_VFP);
 
-      for (j = 0; j < neon_shape_tab[shape].els; j++)
-        {
-          if (!inst.operands[j].present)
-            {
-              matches = 0;
-              break;
-            }
-
-          switch (neon_shape_tab[shape].el[j])
-            {
-            case SE_F:
-              if (!(inst.operands[j].isreg
-                    && inst.operands[j].isvec
-                    && inst.operands[j].issingle
-                    && !inst.operands[j].isquad))
-                matches = 0;
-              break;
-
-            case SE_D:
-              if (!(inst.operands[j].isreg
-                    && inst.operands[j].isvec
-                    && !inst.operands[j].isquad
-                    && !inst.operands[j].issingle))
-                matches = 0;
-              break;
-
-            case SE_R:
-              if (!(inst.operands[j].isreg
-                    && !inst.operands[j].isvec))
-                matches = 0;
-              break;
-
-            case SE_Q:
-              if (!(inst.operands[j].isreg
-                    && inst.operands[j].isvec
-                    && inst.operands[j].isquad
-                    && !inst.operands[j].issingle))
-                matches = 0;
-              break;
-
-            case SE_I:
-              if (!(!inst.operands[j].isreg
-                    && !inst.operands[j].isscalar))
-                matches = 0;
-              break;
-
-            case SE_S:
-              if (!(!inst.operands[j].isreg
-                    && inst.operands[j].isscalar))
-                matches = 0;
-              break;
-
-            case SE_L:
-              break;
-            }
-         if (!matches)
-           break;
-        }
-      if (matches)
-        break;
+      if (rs == NS_FF || rs == NS_HH)
+       {
+         NEON_ENCODE (SINGLE, inst);
+         do_vfp_sp_monadic ();
+       }
+      else
+       {
+         NEON_ENCODE (DOUBLE, inst);
+         do_vfp_dp_rd_rm ();
+       }
     }
+  else
+    {
+      rs = neon_select_shape (NS_HI, NS_FI, NS_DI, NS_NULL);
+      neon_check_type (2, rs, N_F_ALL | N_KEY | N_VFP, N_EQK);
 
-  va_end (ap);
+      switch (inst.instruction & 0x0fffffff)
+       {
+       case N_MNEM_vcmp:
+         inst.instruction += N_MNEM_vcmpz - N_MNEM_vcmp;
+         break;
+       case N_MNEM_vcmpe:
+         inst.instruction += N_MNEM_vcmpez - N_MNEM_vcmpe;
+         break;
+       default:
+         abort ();
+       }
 
-  if (shape == NS_NULL && first_shape != NS_NULL)
-    first_error (_("invalid instruction shape"));
+      if (rs == NS_FI || rs == NS_HI)
+       {
+         NEON_ENCODE (SINGLE, inst);
+         do_vfp_sp_compare_z ();
+       }
+      else
+       {
+         NEON_ENCODE (DOUBLE, inst);
+         do_vfp_dp_rd ();
+       }
+    }
+  do_vfp_cond_or_thumb ();
 
-  return shape;
+  /* ARMv8.2 fp16 instruction.  */
+  if (rs == NS_HI || rs == NS_HH)
+    do_scalar_fp16_v82_encode ();
 }
 
-/* True if SHAPE is predominantly a quadword operation (most of the time, this
-   means the Q bit should be set).  */
+static void
+nsyn_insert_sp (void)
+{
+  inst.operands[1] = inst.operands[0];
+  memset (&inst.operands[0], '\0', sizeof (inst.operands[0]));
+  inst.operands[0].reg = REG_SP;
+  inst.operands[0].isreg = 1;
+  inst.operands[0].writeback = 1;
+  inst.operands[0].present = 1;
+}
 
-static int
-neon_quad (enum neon_shape shape)
+static void
+do_vfp_nsyn_push (void)
 {
-  return neon_shape_class[shape] == SC_QUAD;
+  nsyn_insert_sp ();
+  if (inst.operands[1].issingle)
+    do_vfp_nsyn_opcode ("fstmdbs");
+  else
+    do_vfp_nsyn_opcode ("fstmdbd");
 }
 
 static void
-neon_modify_type_size (unsigned typebits, enum neon_el_type *g_type,
-                       unsigned *g_size)
+do_vfp_nsyn_pop (void)
 {
-  /* Allow modification to be made to types which are constrained to be
-     based on the key element, based on bits set alongside N_EQK.  */
-  if ((typebits & N_EQK) != 0)
-    {
-      if ((typebits & N_HLF) != 0)
-       *g_size /= 2;
-      else if ((typebits & N_DBL) != 0)
-       *g_size *= 2;
-      if ((typebits & N_SGN) != 0)
-       *g_type = NT_signed;
-      else if ((typebits & N_UNS) != 0)
-        *g_type = NT_unsigned;
-      else if ((typebits & N_INT) != 0)
-        *g_type = NT_integer;
-      else if ((typebits & N_FLT) != 0)
-        *g_type = NT_float;
-      else if ((typebits & N_SIZ) != 0)
-        *g_type = NT_untyped;
-    }
+  nsyn_insert_sp ();
+  if (inst.operands[1].issingle)
+    do_vfp_nsyn_opcode ("fldmias");
+  else
+    do_vfp_nsyn_opcode ("fldmiad");
 }
 
-/* Return operand OPNO promoted by bits set in THISARG. KEY should be the "key"
-   operand type, i.e. the single type specified in a Neon instruction when it
-   is the only one given.  */
+/* Fix up Neon data-processing instructions, ORing in the correct bits for
+   ARM mode or Thumb mode and moving the encoded bit 24 to bit 28.  */
 
-static struct neon_type_el
-neon_type_promote (struct neon_type_el *key, unsigned thisarg)
+static void
+neon_dp_fixup (struct arm_it* insn)
 {
-  struct neon_type_el dest = *key;
+  unsigned int i = insn->instruction;
+  insn->is_neon = 1;
 
-  gas_assert ((thisarg & N_EQK) != 0);
+  if (thumb_mode)
+    {
+      /* The U bit is at bit 24 by default. Move to bit 28 in Thumb mode.  */
+      if (i & (1 << 24))
+       i |= 1 << 28;
 
-  neon_modify_type_size (thisarg, &dest.type, &dest.size);
+      i &= ~(1 << 24);
 
-  return dest;
+      i |= 0xef000000;
+    }
+  else
+    i |= 0xf2000000;
+
+  insn->instruction = i;
 }
 
-/* Convert Neon type and size into compact bitmask representation.  */
+/* Turn a size (8, 16, 32, 64) into the respective bit number minus 3
+   (0, 1, 2, 3).  */
 
-static enum neon_type_mask
-type_chk_of_el_type (enum neon_el_type type, unsigned size)
+static unsigned
+neon_logbits (unsigned x)
 {
-  switch (type)
-    {
-    case NT_untyped:
-      switch (size)
-        {
-        case 8:  return N_8;
-        case 16: return N_16;
-        case 32: return N_32;
-        case 64: return N_64;
-        default: ;
-        }
-      break;
-
-    case NT_integer:
-      switch (size)
-        {
-        case 8:  return N_I8;
-        case 16: return N_I16;
-        case 32: return N_I32;
-        case 64: return N_I64;
-        default: ;
-        }
-      break;
+  return ffs (x) - 4;
+}
 
-    case NT_float:
-      switch (size)
-        {
-       case 16: return N_F16;
-        case 32: return N_F32;
-        case 64: return N_F64;
-        default: ;
-        }
-      break;
+#define LOW4(R) ((R) & 0xf)
+#define HI1(R) (((R) >> 4) & 1)
 
-    case NT_poly:
-      switch (size)
-        {
-        case 8:  return N_P8;
-        case 16: return N_P16;
-        default: ;
-        }
-      break;
+/* Encode insns with bit pattern:
 
-    case NT_signed:
-      switch (size)
-        {
-        case 8:  return N_S8;
-        case 16: return N_S16;
-        case 32: return N_S32;
-        case 64: return N_S64;
-        default: ;
-        }
-      break;
+  |28/24|23|22 |21 20|19 16|15 12|11    8|7|6|5|4|3  0|
+  |  U  |x |D  |size | Rn  | Rd  |x x x x|N|Q|M|x| Rm |
 
-    case NT_unsigned:
-      switch (size)
-        {
-        case 8:  return N_U8;
-        case 16: return N_U16;
-        case 32: return N_U32;
-        case 64: return N_U64;
-        default: ;
-        }
-      break;
+  SIZE is passed in bits. -1 means size field isn't changed, in case it has a
+  different meaning for some instruction.  */
 
-    default: ;
-    }
+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;
+  inst.instruction |= HI1 (inst.operands[1].reg) << 7;
+  inst.instruction |= LOW4 (inst.operands[2].reg);
+  inst.instruction |= HI1 (inst.operands[2].reg) << 5;
+  inst.instruction |= (isquad != 0) << 6;
+  inst.instruction |= (ubit != 0) << 24;
+  if (size != -1)
+    inst.instruction |= neon_logbits (size) << 20;
 
-  return N_UTYP;
+  neon_dp_fixup (&inst);
 }
 
-/* Convert compact Neon bitmask type representation to a type and size. Only
-   handles the case where a single bit is set in the mask.  */
+/* Encode instructions of the form:
 
-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;
+  |28/24|23|22|21 20|19 18|17 16|15 12|11      7|6|5|4|3  0|
+  |  U  |x |D |x  x |size |x  x | Rd  |x x x x x|Q|M|x| Rm |
 
-  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 | N_F64)) != 0)
-    *size = 64;
-  else
-    return FAIL;
+  Don't write size if SIZE == -1.  */
 
-  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 | N_F64)) != 0)
-    *type = NT_float;
-  else
-    return FAIL;
+static void
+neon_two_same (int qbit, 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);
+  inst.instruction |= HI1 (inst.operands[1].reg) << 5;
+  inst.instruction |= (qbit != 0) << 6;
+  inst.instruction |= (ubit != 0) << 24;
 
-  return SUCCESS;
+  if (size != -1)
+    inst.instruction |= neon_logbits (size) << 18;
+
+  neon_dp_fixup (&inst);
 }
 
-/* Modify a bitmask of allowed types. This is only needed for type
-   relaxation.  */
+/* Neon instruction encoders, in approximate order of appearance.  */
 
-static unsigned
-modify_types_allowed (unsigned allowed, unsigned mods)
+static void
+do_neon_dyadic_i_su (void)
 {
-  unsigned size;
-  enum neon_el_type type;
-  unsigned destmask;
-  int i;
-
-  destmask = 0;
-
-  for (i = 1; i <= N_MAX_NONSPECIAL; i <<= 1)
-    {
-      if (el_type_of_type_chk (&type, &size,
-                               (enum neon_type_mask) (allowed & i)) == SUCCESS)
-        {
-          neon_modify_type_size (mods, &type, &size);
-          destmask |= type_chk_of_el_type (type, size);
-        }
-    }
-
-  return destmask;
+  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
+  struct neon_type_el et = neon_check_type (3, rs,
+    N_EQK, N_EQK, N_SU_32 | N_KEY);
+  neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
 }
 
-/* Check type and return type classification.
-   The manual states (paraphrase): If one datatype is given, it indicates the
-   type given in:
-    - the second operand, if there is one
-    - the operand, if there is no second operand
-    - the result, if there are no operands.
-   This isn't quite good enough though, so we use a concept of a "key" datatype
-   which is set on a per-instruction basis, which is the one which matters when
-   only one data type is written.
-   Note: this function has side-effects (e.g. filling in missing operands). All
-   Neon instructions should call it before performing bit encoding.  */
+static void
+do_neon_dyadic_i64_su (void)
+{
+  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
+  struct neon_type_el et = neon_check_type (3, rs,
+    N_EQK, N_EQK, N_SU_ALL | N_KEY);
+  neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
+}
 
-static struct neon_type_el
-neon_check_type (unsigned els, enum neon_shape ns, ...)
+static void
+neon_imm_shift (int write_ubit, int uval, int isquad, struct neon_type_el et,
+               unsigned immbits)
 {
-  va_list ap;
-  unsigned i, pass, key_el = 0;
-  unsigned types[NEON_MAX_TYPE_ELS];
-  enum neon_el_type k_type = NT_invtype;
-  unsigned k_size = -1u;
-  struct neon_type_el badtype = {NT_invtype, -1};
-  unsigned key_allowed = 0;
+  unsigned size = et.size >> 3;
+  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
+  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
+  inst.instruction |= LOW4 (inst.operands[1].reg);
+  inst.instruction |= HI1 (inst.operands[1].reg) << 5;
+  inst.instruction |= (isquad != 0) << 6;
+  inst.instruction |= immbits << 16;
+  inst.instruction |= (size >> 3) << 7;
+  inst.instruction |= (size & 0x7) << 19;
+  if (write_ubit)
+    inst.instruction |= (uval != 0) << 24;
 
-  /* Optional registers in Neon instructions are always (not) in operand 1.
-     Fill in the missing operand here, if it was omitted.  */
-  if (els > 1 && !inst.operands[1].present)
-    inst.operands[1] = inst.operands[0];
+  neon_dp_fixup (&inst);
+}
 
-  /* Suck up all the varargs.  */
-  va_start (ap, ns);
-  for (i = 0; i < els; i++)
+static void
+do_neon_shl_imm (void)
+{
+  if (!inst.operands[2].isreg)
     {
-      unsigned thisarg = va_arg (ap, unsigned);
-      if (thisarg == N_IGNORE_TYPE)
-        {
-          va_end (ap);
-          return badtype;
-        }
-      types[i] = thisarg;
-      if ((thisarg & N_KEY) != 0)
-        key_el = i;
-    }
-  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;
-        }
+      enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
+      struct neon_type_el et = neon_check_type (2, rs, N_EQK, N_KEY | N_I_ALL);
+      int imm = inst.operands[2].imm;
 
-  /* 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
-     operand. */
-  if (inst.vectype.elems == 1 && els > 1)
-    {
-      unsigned j;
-      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]);
+      constraint (imm < 0 || (unsigned)imm >= et.size,
+                 _("immediate out of range for shift"));
+      NEON_ENCODE (IMMED, inst);
+      neon_imm_shift (FALSE, 0, neon_quad (rs), et, imm);
     }
-  else if (inst.vectype.elems == 0 && els > 0)
+  else
     {
-      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;
+      enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
+      struct neon_type_el et = neon_check_type (3, rs,
+       N_EQK, N_SU_ALL | N_KEY, N_EQK | N_SGN);
+      unsigned int tmp;
 
-      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;
+      /* VSHL/VQSHL 3-register variants have syntax such as:
+          vshl.xx Dd, Dm, Dn
+        whereas other 3-register operations encoded by neon_three_same have
+        syntax like:
+          vadd.xx Dd, Dn, Dm
+        (i.e. with Dn & Dm reversed). Swap operands[1].reg and operands[2].reg
+        here.  */
+      tmp = inst.operands[2].reg;
+      inst.operands[2].reg = inst.operands[1].reg;
+      inst.operands[1].reg = tmp;
+      NEON_ENCODE (INTEGER, inst);
+      neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
     }
+}
 
-  for (pass = 0; pass < 2; pass++)
+static void
+do_neon_qshl_imm (void)
+{
+  if (!inst.operands[2].isreg)
     {
-      for (i = 0; i < els; i++)
-        {
-          unsigned thisarg = types[i];
-          unsigned types_allowed = ((thisarg & N_EQK) != 0 && pass != 0)
-            ? modify_types_allowed (key_allowed, thisarg) : thisarg;
-          enum neon_el_type g_type = inst.vectype.el[i].type;
-          unsigned g_size = inst.vectype.el[i].size;
-
-          /* Decay more-specific signed & unsigned types to sign-insensitive
-            integer types if sign-specific variants are unavailable.  */
-          if ((g_type == NT_signed || g_type == NT_unsigned)
-             && (types_allowed & N_SU_ALL) == 0)
-           g_type = NT_integer;
-
-          /* If only untyped args are allowed, decay any more specific types to
-            them. Some instructions only care about signs for some element
-            sizes, so handle that properly.  */
-          if ((g_size == 8 && (types_allowed & N_8) != 0)
-             || (g_size == 16 && (types_allowed & N_16) != 0)
-             || (g_size == 32 && (types_allowed & N_32) != 0)
-             || (g_size == 64 && (types_allowed & N_64) != 0))
-           g_type = NT_untyped;
-
-          if (pass == 0)
-            {
-              if ((thisarg & N_KEY) != 0)
-                {
-                  k_type = g_type;
-                  k_size = g_size;
-                  key_allowed = thisarg & ~N_KEY;
-                }
-            }
-          else
-            {
-              if ((thisarg & N_VFP) != 0)
-                {
-                  enum neon_shape_el regshape;
-                  unsigned regwidth, match;
+      enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
+      struct neon_type_el et = neon_check_type (2, rs, N_EQK, N_SU_ALL | N_KEY);
+      int imm = inst.operands[2].imm;
 
-                 /* PR 11136: Catch the case where we are passed a shape of NS_NULL.  */
-                 if (ns == NS_NULL)
-                   {
-                     first_error (_("invalid instruction shape"));
-                     return badtype;
-                   }
-                  regshape = neon_shape_tab[ns].el[i];
-                  regwidth = neon_shape_el_size[regshape];
-
-                  /* In VFP mode, operands must match register widths. If we
-                     have a key operand, use its width, else use the width of
-                     the current operand.  */
-                  if (k_size != -1u)
-                    match = k_size;
-                  else
-                    match = g_size;
-
-                  if (regwidth != match)
-                    {
-                      first_error (_("operand size must match register width"));
-                      return badtype;
-                    }
-                }
-
-              if ((thisarg & N_EQK) == 0)
-                {
-                  unsigned given_type = type_chk_of_el_type (g_type, g_size);
-
-                  if ((given_type & types_allowed) == 0)
-                    {
-                     first_error (_("bad type in Neon instruction"));
-                     return badtype;
-                    }
-                }
-              else
-                {
-                  enum neon_el_type mod_k_type = k_type;
-                  unsigned mod_k_size = k_size;
-                  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;
-                    }
-                }
-            }
-        }
+      constraint (imm < 0 || (unsigned)imm >= et.size,
+                 _("immediate out of range for shift"));
+      NEON_ENCODE (IMMED, inst);
+      neon_imm_shift (TRUE, et.type == NT_unsigned, neon_quad (rs), et, imm);
     }
+  else
+    {
+      enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
+      struct neon_type_el et = neon_check_type (3, rs,
+       N_EQK, N_SU_ALL | N_KEY, N_EQK | N_SGN);
+      unsigned int tmp;
 
-  return inst.vectype.el[key_el];
+      /* See note in do_neon_shl_imm.  */
+      tmp = inst.operands[2].reg;
+      inst.operands[2].reg = inst.operands[1].reg;
+      inst.operands[1].reg = tmp;
+      NEON_ENCODE (INTEGER, inst);
+      neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
+    }
 }
 
-/* Neon-style VFP instruction forwarding.  */
-
-/* Thumb VFP instructions have 0xE in the condition field.  */
-
 static void
-do_vfp_cond_or_thumb (void)
+do_neon_rshl (void)
 {
-  inst.is_neon = 1;
+  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
+  struct neon_type_el et = neon_check_type (3, rs,
+    N_EQK, N_EQK, N_SU_ALL | N_KEY);
+  unsigned int tmp;
 
-  if (thumb_mode)
-    inst.instruction |= 0xe0000000;
-  else
-    inst.instruction |= inst.cond << 28;
+  tmp = inst.operands[2].reg;
+  inst.operands[2].reg = inst.operands[1].reg;
+  inst.operands[1].reg = tmp;
+  neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
 }
 
-/* Look up and encode a simple mnemonic, for use as a helper function for the
-   Neon-style VFP syntax.  This avoids duplication of bits of the insns table,
-   etc.  It is assumed that operand parsing has already been done, and that the
-   operands are in the form expected by the given opcode (this isn't necessarily
-   the same as the form in which they were parsed, hence some massaging must
-   take place before this function is called).
-   Checks current arch version against that in the looked-up opcode.  */
-
-static void
-do_vfp_nsyn_opcode (const char *opname)
+static int
+neon_cmode_for_logic_imm (unsigned immediate, unsigned *immbits, int size)
 {
-  const struct asm_opcode *opcode;
-
-  opcode = (const struct asm_opcode *) hash_find (arm_ops_hsh, opname);
-
-  if (!opcode)
-    abort ();
-
-  constraint (!ARM_CPU_HAS_FEATURE (cpu_variant,
-                thumb_mode ? *opcode->tvariant : *opcode->avariant),
-              _(BAD_FPU));
+  /* Handle .I8 pseudo-instructions.  */
+  if (size == 8)
+    {
+      /* Unfortunately, this will make everything apart from zero out-of-range.
+        FIXME is this the intended semantics? There doesn't seem much point in
+        accepting .I8 if so.  */
+      immediate |= immediate << 8;
+      size = 16;
+    }
 
-  inst.is_neon = 1;
+  if (size >= 32)
+    {
+      if (immediate == (immediate & 0x000000ff))
+       {
+         *immbits = immediate;
+         return 0x1;
+       }
+      else if (immediate == (immediate & 0x0000ff00))
+       {
+         *immbits = immediate >> 8;
+         return 0x3;
+       }
+      else if (immediate == (immediate & 0x00ff0000))
+       {
+         *immbits = immediate >> 16;
+         return 0x5;
+       }
+      else if (immediate == (immediate & 0xff000000))
+       {
+         *immbits = immediate >> 24;
+         return 0x7;
+       }
+      if ((immediate & 0xffff) != (immediate >> 16))
+       goto bad_immediate;
+      immediate &= 0xffff;
+    }
 
-  if (thumb_mode)
+  if (immediate == (immediate & 0x000000ff))
     {
-      inst.instruction = opcode->tvalue;
-      opcode->tencode ();
+      *immbits = immediate;
+      return 0x9;
     }
-  else
+  else if (immediate == (immediate & 0x0000ff00))
     {
-      inst.instruction = (inst.cond << 28) | opcode->avalue;
-      opcode->aencode ();
+      *immbits = immediate >> 8;
+      return 0xb;
     }
+
+  bad_immediate:
+  first_error (_("immediate value out of range"));
+  return FAIL;
 }
 
 static void
-do_vfp_nsyn_add_sub (enum neon_shape rs)
+do_neon_logic (void)
 {
-  int is_add = (inst.instruction & 0x0fffffff) == N_MNEM_vadd;
+  if (inst.operands[2].present && inst.operands[2].isreg)
+    {
+      enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
+      neon_check_type (3, rs, N_IGNORE_TYPE);
+      /* U bit and size field were set as part of the bitmask.  */
+      NEON_ENCODE (INTEGER, inst);
+      neon_three_same (neon_quad (rs), 0, -1);
+    }
+  else
+    {
+      const int three_ops_form = (inst.operands[2].present
+                                 && !inst.operands[2].isreg);
+      const int immoperand = (three_ops_form ? 2 : 1);
+      enum neon_shape rs = (three_ops_form
+                           ? neon_select_shape (NS_DDI, NS_QQI, NS_NULL)
+                           : neon_select_shape (NS_DI, NS_QI, NS_NULL));
+      struct neon_type_el et = neon_check_type (2, rs,
+       N_I8 | N_I16 | N_I32 | N_I64 | N_F32 | N_KEY, N_EQK);
+      enum neon_opc opcode = (enum neon_opc) inst.instruction & 0x0fffffff;
+      unsigned immbits;
+      int cmode;
+
+      if (et.type == NT_invtype)
+       return;
+
+      if (three_ops_form)
+       constraint (inst.operands[0].reg != inst.operands[1].reg,
+                   _("first and second operands shall be the same register"));
+
+      NEON_ENCODE (IMMED, inst);
+
+      immbits = inst.operands[immoperand].imm;
+      if (et.size == 64)
+       {
+         /* .i64 is a pseudo-op, so the immediate must be a repeating
+            pattern.  */
+         if (immbits != (inst.operands[immoperand].regisimm ?
+                         inst.operands[immoperand].reg : 0))
+           {
+             /* Set immbits to an invalid constant.  */
+             immbits = 0xdeadbeef;
+           }
+       }
+
+      switch (opcode)
+       {
+       case N_MNEM_vbic:
+         cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size);
+         break;
 
-  if (rs == NS_FFF)
-    {
-      if (is_add)
-        do_vfp_nsyn_opcode ("fadds");
-      else
-        do_vfp_nsyn_opcode ("fsubs");
-    }
-  else
-    {
-      if (is_add)
-        do_vfp_nsyn_opcode ("faddd");
-      else
-        do_vfp_nsyn_opcode ("fsubd");
-    }
-}
+       case N_MNEM_vorr:
+         cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size);
+         break;
 
-/* Check operand types to see if this is a VFP instruction, and if so call
-   PFN ().  */
+       case N_MNEM_vand:
+         /* Pseudo-instruction for VBIC.  */
+         neon_invert_size (&immbits, 0, et.size);
+         cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size);
+         break;
 
-static int
-try_vfp_nsyn (int args, void (*pfn) (enum neon_shape))
-{
-  enum neon_shape rs;
-  struct neon_type_el et;
+       case N_MNEM_vorn:
+         /* Pseudo-instruction for VORR.  */
+         neon_invert_size (&immbits, 0, et.size);
+         cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size);
+         break;
 
-  switch (args)
-    {
-    case 2:
-      rs = neon_select_shape (NS_FF, NS_DD, NS_NULL);
-      et = neon_check_type (2, rs,
-        N_EQK | N_VFP, N_F32 | N_F64 | N_KEY | N_VFP);
-      break;
+       default:
+         abort ();
+       }
 
-    case 3:
-      rs = neon_select_shape (NS_FFF, NS_DDD, NS_NULL);
-      et = neon_check_type (3, rs,
-        N_EQK | N_VFP, N_EQK | N_VFP, N_F32 | N_F64 | N_KEY | N_VFP);
-      break;
+      if (cmode == FAIL)
+       return;
 
-    default:
-      abort ();
-    }
+      inst.instruction |= neon_quad (rs) << 6;
+      inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
+      inst.instruction |= HI1 (inst.operands[0].reg) << 22;
+      inst.instruction |= cmode << 8;
+      neon_write_immbits (immbits);
 
-  if (et.type != NT_invtype)
-    {
-      pfn (rs);
-      return SUCCESS;
+      neon_dp_fixup (&inst);
     }
-
-  inst.error = NULL;
-  return FAIL;
 }
 
 static void
-do_vfp_nsyn_mla_mls (enum neon_shape rs)
+do_neon_bitfield (void)
 {
-  int is_mla = (inst.instruction & 0x0fffffff) == N_MNEM_vmla;
-
-  if (rs == NS_FFF)
-    {
-      if (is_mla)
-        do_vfp_nsyn_opcode ("fmacs");
-      else
-        do_vfp_nsyn_opcode ("fnmacs");
-    }
-  else
-    {
-      if (is_mla)
-        do_vfp_nsyn_opcode ("fmacd");
-      else
-        do_vfp_nsyn_opcode ("fnmacd");
-    }
+  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
+  neon_check_type (3, rs, N_IGNORE_TYPE);
+  neon_three_same (neon_quad (rs), 0, -1);
 }
 
 static void
-do_vfp_nsyn_fma_fms (enum neon_shape rs)
+neon_dyadic_misc (enum neon_el_type ubit_meaning, unsigned types,
+                 unsigned destbits)
 {
-  int is_fma = (inst.instruction & 0x0fffffff) == N_MNEM_vfma;
-
-  if (rs == NS_FFF)
+  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
+  struct neon_type_el et = neon_check_type (3, rs, N_EQK | destbits, N_EQK,
+                                           types | N_KEY);
+  if (et.type == NT_float)
     {
-      if (is_fma)
-        do_vfp_nsyn_opcode ("ffmas");
-      else
-        do_vfp_nsyn_opcode ("ffnmas");
+      NEON_ENCODE (FLOAT, inst);
+      neon_three_same (neon_quad (rs), 0, et.size == 16 ? (int) et.size : -1);
     }
   else
     {
-      if (is_fma)
-        do_vfp_nsyn_opcode ("ffmad");
-      else
-        do_vfp_nsyn_opcode ("ffnmad");
+      NEON_ENCODE (INTEGER, inst);
+      neon_three_same (neon_quad (rs), et.type == ubit_meaning, et.size);
     }
 }
 
 static void
-do_vfp_nsyn_mul (enum neon_shape rs)
+do_neon_dyadic_if_su (void)
 {
-  if (rs == NS_FFF)
-    do_vfp_nsyn_opcode ("fmuls");
-  else
-    do_vfp_nsyn_opcode ("fmuld");
+  neon_dyadic_misc (NT_unsigned, N_SUF_32, 0);
 }
 
 static void
-do_vfp_nsyn_abs_neg (enum neon_shape rs)
+do_neon_dyadic_if_su_d (void)
 {
-  int is_neg = (inst.instruction & 0x80) != 0;
-  neon_check_type (2, rs, N_EQK | N_VFP, N_F32 | N_F64 | N_VFP | N_KEY);
-
-  if (rs == NS_FF)
-    {
-      if (is_neg)
-        do_vfp_nsyn_opcode ("fnegs");
-      else
-        do_vfp_nsyn_opcode ("fabss");
-    }
-  else
-    {
-      if (is_neg)
-        do_vfp_nsyn_opcode ("fnegd");
-      else
-        do_vfp_nsyn_opcode ("fabsd");
-    }
+  /* 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);
 }
 
-/* Encode single-precision (only!) VFP fldm/fstm instructions. Double precision
-   insns belong to Neon, and are handled elsewhere.  */
-
 static void
-do_vfp_nsyn_ldm_stm (int is_dbmode)
+do_neon_dyadic_if_i_d (void)
 {
-  int is_ldm = (inst.instruction & (1 << 20)) != 0;
-  if (is_ldm)
-    {
-      if (is_dbmode)
-        do_vfp_nsyn_opcode ("fldmdbs");
-      else
-        do_vfp_nsyn_opcode ("fldmias");
-    }
-  else
-    {
-      if (is_dbmode)
-        do_vfp_nsyn_opcode ("fstmdbs");
-      else
-        do_vfp_nsyn_opcode ("fstmias");
-    }
+  /* The "untyped" case can't happen. Do this to stop the "U" bit being
+     affected if we specify unsigned args.  */
+  neon_dyadic_misc (NT_untyped, N_IF_32, 0);
 }
 
-static void
-do_vfp_nsyn_sqrt (void)
+enum vfp_or_neon_is_neon_bits
 {
-  enum neon_shape rs = neon_select_shape (NS_FF, NS_DD, NS_NULL);
-  neon_check_type (2, rs, N_EQK | N_VFP, N_F32 | N_F64 | N_KEY | N_VFP);
+  NEON_CHECK_CC = 1,
+  NEON_CHECK_ARCH = 2,
+  NEON_CHECK_ARCH8 = 4
+};
 
-  if (rs == NS_FF)
-    do_vfp_nsyn_opcode ("fsqrts");
-  else
-    do_vfp_nsyn_opcode ("fsqrtd");
-}
+/* Call this function if an instruction which may have belonged to the VFP or
+   Neon instruction sets, but turned out to be a Neon instruction (due to the
+   operand types involved, etc.). We have to check and/or fix-up a couple of
+   things:
 
-static void
-do_vfp_nsyn_div (void)
-{
-  enum neon_shape rs = neon_select_shape (NS_FFF, NS_DDD, NS_NULL);
-  neon_check_type (3, rs, N_EQK | N_VFP, N_EQK | N_VFP,
-    N_F32 | N_F64 | N_KEY | N_VFP);
+     - Make sure the user hasn't attempted to make a Neon instruction
+       conditional.
+     - Alter the value in the condition code field if necessary.
+     - Make sure that the arch supports Neon instructions.
 
-  if (rs == NS_FFF)
-    do_vfp_nsyn_opcode ("fdivs");
-  else
-    do_vfp_nsyn_opcode ("fdivd");
-}
+   Which of these operations take place depends on bits from enum
+   vfp_or_neon_is_neon_bits.
 
-static void
-do_vfp_nsyn_nmul (void)
-{
-  enum neon_shape rs = neon_select_shape (NS_FFF, NS_DDD, NS_NULL);
-  neon_check_type (3, rs, N_EQK | N_VFP, N_EQK | N_VFP,
-    N_F32 | N_F64 | N_KEY | N_VFP);
+   WARNING: This function has side effects! If NEON_CHECK_CC is used and the
+   current instruction's condition is COND_ALWAYS, the condition field is
+   changed to inst.uncond_value. This is necessary because instructions shared
+   between VFP and Neon may be conditional for the VFP variants only, and the
+   unconditional Neon version must have, e.g., 0xF in the condition field.  */
 
-  if (rs == NS_FFF)
+static int
+vfp_or_neon_is_neon (unsigned check)
+{
+  /* Conditions are always legal in Thumb mode (IT blocks).  */
+  if (!thumb_mode && (check & NEON_CHECK_CC))
     {
-      NEON_ENCODE (SINGLE, inst);
-      do_vfp_sp_dyadic ();
+      if (inst.cond != COND_ALWAYS)
+       {
+         first_error (_(BAD_COND));
+         return FAIL;
+       }
+      if (inst.uncond_value != -1)
+       inst.instruction |= inst.uncond_value << 28;
     }
-  else
+
+  if ((check & NEON_CHECK_ARCH)
+      && !mark_feature_used (&fpu_neon_ext_v1))
     {
-      NEON_ENCODE (DOUBLE, inst);
-      do_vfp_dp_rd_rn_rm ();
+      first_error (_(BAD_FPU));
+      return FAIL;
     }
-  do_vfp_cond_or_thumb ();
-}
 
-static void
-do_vfp_nsyn_cmp (void)
-{
-  if (inst.operands[1].isreg)
+  if ((check & NEON_CHECK_ARCH8)
+      && !mark_feature_used (&fpu_neon_ext_armv8))
     {
-      enum neon_shape rs = neon_select_shape (NS_FF, NS_DD, NS_NULL);
-      neon_check_type (2, rs, N_EQK | N_VFP, N_F32 | N_F64 | N_KEY | N_VFP);
-
-      if (rs == NS_FF)
-        {
-          NEON_ENCODE (SINGLE, inst);
-          do_vfp_sp_monadic ();
-        }
-      else
-        {
-          NEON_ENCODE (DOUBLE, inst);
-          do_vfp_dp_rd_rm ();
-        }
+      first_error (_(BAD_FPU));
+      return FAIL;
     }
-  else
-    {
-      enum neon_shape rs = neon_select_shape (NS_FI, NS_DI, NS_NULL);
-      neon_check_type (2, rs, N_F32 | N_F64 | N_KEY | N_VFP, N_EQK);
 
-      switch (inst.instruction & 0x0fffffff)
-        {
-        case N_MNEM_vcmp:
-          inst.instruction += N_MNEM_vcmpz - N_MNEM_vcmp;
-          break;
-        case N_MNEM_vcmpe:
-          inst.instruction += N_MNEM_vcmpez - N_MNEM_vcmpe;
-          break;
-        default:
-          abort ();
-        }
-
-      if (rs == NS_FI)
-        {
-          NEON_ENCODE (SINGLE, inst);
-          do_vfp_sp_compare_z ();
-        }
-      else
-        {
-          NEON_ENCODE (DOUBLE, inst);
-          do_vfp_dp_rd ();
-        }
-    }
-  do_vfp_cond_or_thumb ();
+  return SUCCESS;
 }
 
 static void
-nsyn_insert_sp (void)
+do_neon_addsub_if_i (void)
 {
-  inst.operands[1] = inst.operands[0];
-  memset (&inst.operands[0], '\0', sizeof (inst.operands[0]));
-  inst.operands[0].reg = REG_SP;
-  inst.operands[0].isreg = 1;
-  inst.operands[0].writeback = 1;
-  inst.operands[0].present = 1;
-}
+  if (try_vfp_nsyn (3, do_vfp_nsyn_add_sub) == SUCCESS)
+    return;
 
-static void
-do_vfp_nsyn_push (void)
-{
-  nsyn_insert_sp ();
-  if (inst.operands[1].issingle)
-    do_vfp_nsyn_opcode ("fstmdbs");
-  else
-    do_vfp_nsyn_opcode ("fstmdbd");
+  if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
+    return;
+
+  /* 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
+   result to be:
+     V<op> A,B     (A is operand 0, B is operand 2)
+   to mean:
+     V<op> A,B,A
+   not:
+     V<op> A,B,B
+   so handle that case specially.  */
+
 static void
-do_vfp_nsyn_pop (void)
+neon_exchange_operands (void)
 {
-  nsyn_insert_sp ();
-  if (inst.operands[1].issingle)
-    do_vfp_nsyn_opcode ("fldmias");
+  if (inst.operands[1].present)
+    {
+      void *scratch = xmalloc (sizeof (inst.operands[0]));
+
+      /* Swap operands[1] and operands[2].  */
+      memcpy (scratch, &inst.operands[1], sizeof (inst.operands[0]));
+      inst.operands[1] = inst.operands[2];
+      memcpy (&inst.operands[2], scratch, sizeof (inst.operands[0]));
+      free (scratch);
+    }
   else
-    do_vfp_nsyn_opcode ("fldmiad");
+    {
+      inst.operands[1] = inst.operands[2];
+      inst.operands[2] = inst.operands[0];
+    }
 }
 
-/* Fix up Neon data-processing instructions, ORing in the correct bits for
-   ARM mode or Thumb mode and moving the encoded bit 24 to bit 28.  */
-
 static void
-neon_dp_fixup (struct arm_it* insn)
+neon_compare (unsigned regtypes, unsigned immtypes, int invert)
 {
-  unsigned int i = insn->instruction;
-  insn->is_neon = 1;
-
-  if (thumb_mode)
+  if (inst.operands[2].isreg)
+    {
+      if (invert)
+       neon_exchange_operands ();
+      neon_dyadic_misc (NT_unsigned, regtypes, N_SIZ);
+    }
+  else
     {
-      /* The U bit is at bit 24 by default. Move to bit 28 in Thumb mode.  */
-      if (i & (1 << 24))
-        i |= 1 << 28;
+      enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
+      struct neon_type_el et = neon_check_type (2, rs,
+       N_EQK | N_SIZ, immtypes | N_KEY);
 
-      i &= ~(1 << 24);
+      NEON_ENCODE (IMMED, inst);
+      inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
+      inst.instruction |= HI1 (inst.operands[0].reg) << 22;
+      inst.instruction |= LOW4 (inst.operands[1].reg);
+      inst.instruction |= HI1 (inst.operands[1].reg) << 5;
+      inst.instruction |= neon_quad (rs) << 6;
+      inst.instruction |= (et.type == NT_float) << 10;
+      inst.instruction |= neon_logbits (et.size) << 18;
 
-      i |= 0xef000000;
+      neon_dp_fixup (&inst);
     }
-  else
-    i |= 0xf2000000;
-
-  insn->instruction = i;
 }
 
-/* Turn a size (8, 16, 32, 64) into the respective bit number minus 3
-   (0, 1, 2, 3).  */
-
-static unsigned
-neon_logbits (unsigned x)
+static void
+do_neon_cmp (void)
 {
-  return ffs (x) - 4;
+  neon_compare (N_SUF_32, N_S_32 | N_F_16_32, FALSE);
 }
 
-#define LOW4(R) ((R) & 0xf)
-#define HI1(R) (((R) >> 4) & 1)
-
-/* Encode insns with bit pattern:
-
-  |28/24|23|22 |21 20|19 16|15 12|11    8|7|6|5|4|3  0|
-  |  U  |x |D  |size | Rn  | Rd  |x x x x|N|Q|M|x| Rm |
-
-  SIZE is passed in bits. -1 means size field isn't changed, in case it has a
-  different meaning for some instruction.  */
-
 static void
-neon_three_same (int isquad, int ubit, int size)
+do_neon_cmp_inv (void)
 {
-  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
-  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
-  inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
-  inst.instruction |= HI1 (inst.operands[1].reg) << 7;
-  inst.instruction |= LOW4 (inst.operands[2].reg);
-  inst.instruction |= HI1 (inst.operands[2].reg) << 5;
-  inst.instruction |= (isquad != 0) << 6;
-  inst.instruction |= (ubit != 0) << 24;
-  if (size != -1)
-    inst.instruction |= neon_logbits (size) << 20;
+  neon_compare (N_SUF_32, N_S_32 | N_F_16_32, TRUE);
+}
 
-  neon_dp_fixup (&inst);
+static void
+do_neon_ceq (void)
+{
+  neon_compare (N_IF_32, N_IF_32, FALSE);
 }
 
-/* Encode instructions of the form:
+/* For multiply instructions, we have the possibility of 16-bit or 32-bit
+   scalars, which are encoded in 5 bits, M : Rm.
+   For 16-bit scalars, the register is encoded in Rm[2:0] and the index in
+   M:Rm[3], and for 32-bit scalars, the register is encoded in Rm[3:0] and the
+   index in M.  */
 
-  |28/24|23|22|21 20|19 18|17 16|15 12|11      7|6|5|4|3  0|
-  |  U  |x |D |x  x |size |x  x | Rd  |x x x x x|Q|M|x| Rm |
+static unsigned
+neon_scalar_for_mul (unsigned scalar, unsigned elsize)
+{
+  unsigned regno = NEON_SCALAR_REG (scalar);
+  unsigned elno = NEON_SCALAR_INDEX (scalar);
 
-  Don't write size if SIZE == -1.  */
+  switch (elsize)
+    {
+    case 16:
+      if (regno > 7 || elno > 3)
+       goto bad_scalar;
+      return regno | (elno << 3);
 
-static void
-neon_two_same (int qbit, 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);
-  inst.instruction |= HI1 (inst.operands[1].reg) << 5;
-  inst.instruction |= (qbit != 0) << 6;
-  inst.instruction |= (ubit != 0) << 24;
+    case 32:
+      if (regno > 15 || elno > 1)
+       goto bad_scalar;
+      return regno | (elno << 4);
 
-  if (size != -1)
-    inst.instruction |= neon_logbits (size) << 18;
+    default:
+    bad_scalar:
+      first_error (_("scalar out of range for multiply instruction"));
+    }
 
-  neon_dp_fixup (&inst);
+  return 0;
 }
 
-/* Neon instruction encoders, in approximate order of appearance.  */
+/* Encode multiply / multiply-accumulate scalar instructions.  */
 
 static void
-do_neon_dyadic_i_su (void)
+neon_mul_mac (struct neon_type_el et, int ubit)
 {
-  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
-  struct neon_type_el et = neon_check_type (3, rs,
-    N_EQK, N_EQK, N_SU_32 | N_KEY);
-  neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
-}
+  unsigned scalar;
 
-static void
-do_neon_dyadic_i64_su (void)
-{
-  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
-  struct neon_type_el et = neon_check_type (3, rs,
-    N_EQK, N_EQK, N_SU_ALL | N_KEY);
-  neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
-}
+  /* Give a more helpful error message if we have an invalid type.  */
+  if (et.type == NT_invtype)
+    return;
 
-static void
-neon_imm_shift (int write_ubit, int uval, int isquad, struct neon_type_el et,
-                unsigned immbits)
-{
-  unsigned size = et.size >> 3;
+  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);
-  inst.instruction |= HI1 (inst.operands[1].reg) << 5;
-  inst.instruction |= (isquad != 0) << 6;
-  inst.instruction |= immbits << 16;
-  inst.instruction |= (size >> 3) << 7;
-  inst.instruction |= (size & 0x7) << 19;
-  if (write_ubit)
-    inst.instruction |= (uval != 0) << 24;
+  inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
+  inst.instruction |= HI1 (inst.operands[1].reg) << 7;
+  inst.instruction |= LOW4 (scalar);
+  inst.instruction |= HI1 (scalar) << 5;
+  inst.instruction |= (et.type == NT_float) << 8;
+  inst.instruction |= neon_logbits (et.size) << 20;
+  inst.instruction |= (ubit != 0) << 24;
 
   neon_dp_fixup (&inst);
 }
 
 static void
-do_neon_shl_imm (void)
+do_neon_mac_maybe_scalar (void)
 {
-  if (!inst.operands[2].isreg)
+  if (try_vfp_nsyn (3, do_vfp_nsyn_mla_mls) == SUCCESS)
+    return;
+
+  if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
+    return;
+
+  if (inst.operands[2].isscalar)
     {
-      enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
-      struct neon_type_el et = neon_check_type (2, rs, N_EQK, N_KEY | N_I_ALL);
-      NEON_ENCODE (IMMED, inst);
-      neon_imm_shift (FALSE, 0, neon_quad (rs), et, inst.operands[2].imm);
+      enum neon_shape rs = neon_select_shape (NS_DDS, NS_QQS, NS_NULL);
+      struct neon_type_el et = neon_check_type (3, rs,
+       N_EQK, N_EQK, N_I16 | N_I32 | N_F_16_32 | N_KEY);
+      NEON_ENCODE (SCALAR, inst);
+      neon_mul_mac (et, neon_quad (rs));
     }
   else
     {
-      enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
-      struct neon_type_el et = neon_check_type (3, rs,
-        N_EQK, N_SU_ALL | N_KEY, N_EQK | N_SGN);
-      unsigned int tmp;
-
-      /* VSHL/VQSHL 3-register variants have syntax such as:
-           vshl.xx Dd, Dm, Dn
-         whereas other 3-register operations encoded by neon_three_same have
-         syntax like:
-           vadd.xx Dd, Dn, Dm
-         (i.e. with Dn & Dm reversed). Swap operands[1].reg and operands[2].reg
-         here.  */
-      tmp = inst.operands[2].reg;
-      inst.operands[2].reg = inst.operands[1].reg;
-      inst.operands[1].reg = tmp;
-      NEON_ENCODE (INTEGER, inst);
-      neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
+      /* The "untyped" case can't happen.  Do this to stop the "U" bit being
+        affected if we specify unsigned args.  */
+      neon_dyadic_misc (NT_untyped, N_IF_32, 0);
     }
 }
 
 static void
-do_neon_qshl_imm (void)
+do_neon_fmac (void)
 {
-  if (!inst.operands[2].isreg)
-    {
-      enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
-      struct neon_type_el et = neon_check_type (2, rs, N_EQK, N_SU_ALL | N_KEY);
+  if (try_vfp_nsyn (3, do_vfp_nsyn_fma_fms) == SUCCESS)
+    return;
 
-      NEON_ENCODE (IMMED, inst);
-      neon_imm_shift (TRUE, et.type == NT_unsigned, neon_quad (rs), et,
-                      inst.operands[2].imm);
-    }
-  else
-    {
-      enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
-      struct neon_type_el et = neon_check_type (3, rs,
-        N_EQK, N_SU_ALL | N_KEY, N_EQK | N_SGN);
-      unsigned int tmp;
+  if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
+    return;
 
-      /* See note in do_neon_shl_imm.  */
-      tmp = inst.operands[2].reg;
-      inst.operands[2].reg = inst.operands[1].reg;
-      inst.operands[1].reg = tmp;
-      NEON_ENCODE (INTEGER, inst);
-      neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
-    }
+  neon_dyadic_misc (NT_untyped, N_IF_32, 0);
 }
 
 static void
-do_neon_rshl (void)
+do_neon_tst (void)
 {
   enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
   struct neon_type_el et = neon_check_type (3, rs,
-    N_EQK, N_EQK, N_SU_ALL | N_KEY);
-  unsigned int tmp;
-
-  tmp = inst.operands[2].reg;
-  inst.operands[2].reg = inst.operands[1].reg;
-  inst.operands[1].reg = tmp;
-  neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
+    N_EQK, N_EQK, N_8 | N_16 | N_32 | N_KEY);
+  neon_three_same (neon_quad (rs), 0, et.size);
 }
 
-static int
-neon_cmode_for_logic_imm (unsigned immediate, unsigned *immbits, int size)
+/* VMUL with 3 registers allows the P8 type. The scalar version supports the
+   same types as the MAC equivalents. The polynomial type for this instruction
+   is encoded the same as the integer type.  */
+
+static void
+do_neon_mul (void)
 {
-  /* Handle .I8 pseudo-instructions.  */
-  if (size == 8)
-    {
-      /* Unfortunately, this will make everything apart from zero out-of-range.
-         FIXME is this the intended semantics? There doesn't seem much point in
-         accepting .I8 if so.  */
-      immediate |= immediate << 8;
-      size = 16;
-    }
+  if (try_vfp_nsyn (3, do_vfp_nsyn_mul) == SUCCESS)
+    return;
 
-  if (size >= 32)
+  if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
+    return;
+
+  if (inst.operands[2].isscalar)
+    do_neon_mac_maybe_scalar ();
+  else
+    neon_dyadic_misc (NT_poly, N_I8 | N_I16 | N_I32 | N_F16 | N_F32 | N_P8, 0);
+}
+
+static void
+do_neon_qdmulh (void)
+{
+  if (inst.operands[2].isscalar)
     {
-      if (immediate == (immediate & 0x000000ff))
-       {
-         *immbits = immediate;
-         return 0x1;
-       }
-      else if (immediate == (immediate & 0x0000ff00))
-       {
-         *immbits = immediate >> 8;
-         return 0x3;
-       }
-      else if (immediate == (immediate & 0x00ff0000))
-       {
-         *immbits = immediate >> 16;
-         return 0x5;
-       }
-      else if (immediate == (immediate & 0xff000000))
-       {
-         *immbits = immediate >> 24;
-         return 0x7;
-       }
-      if ((immediate & 0xffff) != (immediate >> 16))
-       goto bad_immediate;
-      immediate &= 0xffff;
+      enum neon_shape rs = neon_select_shape (NS_DDS, NS_QQS, NS_NULL);
+      struct neon_type_el et = neon_check_type (3, rs,
+       N_EQK, N_EQK, N_S16 | N_S32 | N_KEY);
+      NEON_ENCODE (SCALAR, inst);
+      neon_mul_mac (et, neon_quad (rs));
     }
-
-  if (immediate == (immediate & 0x000000ff))
+  else
     {
-      *immbits = immediate;
-      return 0x9;
+      enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
+      struct neon_type_el et = neon_check_type (3, rs,
+       N_EQK, N_EQK, N_S16 | N_S32 | N_KEY);
+      NEON_ENCODE (INTEGER, inst);
+      /* The U bit (rounding) comes from bit mask.  */
+      neon_three_same (neon_quad (rs), 0, et.size);
     }
-  else if (immediate == (immediate & 0x0000ff00))
+}
+
+static void
+do_neon_qrdmlah (void)
+{
+  /* Check we're on the correct architecture.  */
+  if (!mark_feature_used (&fpu_neon_ext_armv8))
+    inst.error =
+      _("instruction form not available on this architecture.");
+  else if (!mark_feature_used (&fpu_neon_ext_v8_1))
     {
-      *immbits = immediate >> 8;
-      return 0xb;
+      as_warn (_("this instruction implies use of ARMv8.1 AdvSIMD."));
+      record_feature_use (&fpu_neon_ext_v8_1);
     }
 
-  bad_immediate:
-  first_error (_("immediate value out of range"));
-  return FAIL;
+  if (inst.operands[2].isscalar)
+    {
+      enum neon_shape rs = neon_select_shape (NS_DDS, NS_QQS, NS_NULL);
+      struct neon_type_el et = neon_check_type (3, rs,
+       N_EQK, N_EQK, N_S16 | N_S32 | N_KEY);
+      NEON_ENCODE (SCALAR, inst);
+      neon_mul_mac (et, neon_quad (rs));
+    }
+  else
+    {
+      enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
+      struct neon_type_el et = neon_check_type (3, rs,
+       N_EQK, N_EQK, N_S16 | N_S32 | N_KEY);
+      NEON_ENCODE (INTEGER, inst);
+      /* The U bit (rounding) comes from bit mask.  */
+      neon_three_same (neon_quad (rs), 0, et.size);
+    }
 }
 
-/* True if IMM has form 0bAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD for bits
-   A, B, C, D.  */
-
-static int
-neon_bits_same_in_bytes (unsigned imm)
+static void
+do_neon_fcmp_absolute (void)
 {
-  return ((imm & 0x000000ff) == 0 || (imm & 0x000000ff) == 0x000000ff)
-         && ((imm & 0x0000ff00) == 0 || (imm & 0x0000ff00) == 0x0000ff00)
-         && ((imm & 0x00ff0000) == 0 || (imm & 0x00ff0000) == 0x00ff0000)
-         && ((imm & 0xff000000) == 0 || (imm & 0xff000000) == 0xff000000);
+  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
+  struct neon_type_el et = neon_check_type (3, rs, N_EQK, N_EQK,
+                                           N_F_16_32 | N_KEY);
+  /* Size field comes from bit mask.  */
+  neon_three_same (neon_quad (rs), 1, et.size == 16 ? (int) et.size : -1);
 }
 
-/* For immediate of above form, return 0bABCD.  */
-
-static unsigned
-neon_squash_bits (unsigned imm)
+static void
+do_neon_fcmp_absolute_inv (void)
 {
-  return (imm & 0x01) | ((imm & 0x0100) >> 7) | ((imm & 0x010000) >> 14)
-         | ((imm & 0x01000000) >> 21);
+  neon_exchange_operands ();
+  do_neon_fcmp_absolute ();
 }
 
-/* Compress quarter-float representation to 0b...000 abcdefgh.  */
-
-static unsigned
-neon_qfloat_bits (unsigned imm)
+static void
+do_neon_step (void)
 {
-  return ((imm >> 19) & 0x7f) | ((imm >> 24) & 0x80);
+  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
+  struct neon_type_el et = neon_check_type (3, rs, N_EQK, N_EQK,
+                                           N_F_16_32 | N_KEY);
+  neon_three_same (neon_quad (rs), 0, et.size == 16 ? (int) et.size : -1);
 }
 
-/* Returns CMODE. IMMBITS [7:0] is set to bits suitable for inserting into
-   the instruction. *OP is passed as the initial value of the op field, and
-   may be set to a different value depending on the constant (i.e.
-   "MOV I64, 0bAAAAAAAABBBB..." which uses OP = 1 despite being MOV not
-   MVN).  If the immediate looks like a repeated pattern then also
-   try smaller element sizes.  */
-
-static int
-neon_cmode_for_move_imm (unsigned immlo, unsigned immhi, int float_p,
-                        unsigned *immbits, int *op, int size,
-                        enum neon_el_type type)
+static void
+do_neon_abs_neg (void)
 {
-  /* Only permit float immediates (including 0.0/-0.0) if the operand type is
-     float.  */
-  if (type == NT_float && !float_p)
-    return FAIL;
+  enum neon_shape rs;
+  struct neon_type_el et;
 
-  if (type == NT_float && is_quarter_float (immlo) && immhi == 0)
-    {
-      if (size != 32 || *op == 1)
-        return FAIL;
-      *immbits = neon_qfloat_bits (immlo);
-      return 0xf;
-    }
+  if (try_vfp_nsyn (2, do_vfp_nsyn_abs_neg) == SUCCESS)
+    return;
 
-  if (size == 64)
-    {
-      if (neon_bits_same_in_bytes (immhi)
-         && neon_bits_same_in_bytes (immlo))
-       {
-         if (*op == 1)
-           return FAIL;
-         *immbits = (neon_squash_bits (immhi) << 4)
-                    | neon_squash_bits (immlo);
-         *op = 1;
-         return 0xe;
-       }
+  if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
+    return;
 
-      if (immhi != immlo)
-       return FAIL;
-    }
+  rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
+  et = neon_check_type (2, rs, N_EQK, N_S_32 | N_F_16_32 | N_KEY);
 
-  if (size >= 32)
-    {
-      if (immlo == (immlo & 0x000000ff))
-       {
-         *immbits = immlo;
-         return 0x0;
-       }
-      else if (immlo == (immlo & 0x0000ff00))
-       {
-         *immbits = immlo >> 8;
-         return 0x2;
-       }
-      else if (immlo == (immlo & 0x00ff0000))
-       {
-         *immbits = immlo >> 16;
-         return 0x4;
-       }
-      else if (immlo == (immlo & 0xff000000))
-       {
-         *immbits = immlo >> 24;
-         return 0x6;
-       }
-      else if (immlo == ((immlo & 0x0000ff00) | 0x000000ff))
-       {
-         *immbits = (immlo >> 8) & 0xff;
-         return 0xc;
-       }
-      else if (immlo == ((immlo & 0x00ff0000) | 0x0000ffff))
-       {
-         *immbits = (immlo >> 16) & 0xff;
-         return 0xd;
-       }
+  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
+  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
+  inst.instruction |= LOW4 (inst.operands[1].reg);
+  inst.instruction |= HI1 (inst.operands[1].reg) << 5;
+  inst.instruction |= neon_quad (rs) << 6;
+  inst.instruction |= (et.type == NT_float) << 10;
+  inst.instruction |= neon_logbits (et.size) << 18;
 
-      if ((immlo & 0xffff) != (immlo >> 16))
-       return FAIL;
-      immlo &= 0xffff;
-    }
+  neon_dp_fixup (&inst);
+}
 
-  if (size >= 16)
-    {
-      if (immlo == (immlo & 0x000000ff))
-       {
-         *immbits = immlo;
-         return 0x8;
-       }
-      else if (immlo == (immlo & 0x0000ff00))
-       {
-         *immbits = immlo >> 8;
-         return 0xa;
-       }
+static void
+do_neon_sli (void)
+{
+  enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
+  struct neon_type_el et = neon_check_type (2, rs,
+    N_EQK, N_8 | N_16 | N_32 | N_64 | N_KEY);
+  int imm = inst.operands[2].imm;
+  constraint (imm < 0 || (unsigned)imm >= et.size,
+             _("immediate out of range for insert"));
+  neon_imm_shift (FALSE, 0, neon_quad (rs), et, imm);
+}
 
-      if ((immlo & 0xff) != (immlo >> 8))
-       return FAIL;
-      immlo &= 0xff;
-    }
+static void
+do_neon_sri (void)
+{
+  enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
+  struct neon_type_el et = neon_check_type (2, rs,
+    N_EQK, N_8 | N_16 | N_32 | N_64 | N_KEY);
+  int imm = inst.operands[2].imm;
+  constraint (imm < 1 || (unsigned)imm > et.size,
+             _("immediate out of range for insert"));
+  neon_imm_shift (FALSE, 0, neon_quad (rs), et, et.size - imm);
+}
 
-  if (immlo == (immlo & 0x000000ff))
+static void
+do_neon_qshlu_imm (void)
+{
+  enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
+  struct neon_type_el et = neon_check_type (2, rs,
+    N_EQK | N_UNS, N_S8 | N_S16 | N_S32 | N_S64 | N_KEY);
+  int imm = inst.operands[2].imm;
+  constraint (imm < 0 || (unsigned)imm >= et.size,
+             _("immediate out of range for shift"));
+  /* Only encodes the 'U present' variant of the instruction.
+     In this case, signed types have OP (bit 8) set to 0.
+     Unsigned types have OP set to 1.  */
+  inst.instruction |= (et.type == NT_unsigned) << 8;
+  /* The rest of the bits are the same as other immediate shifts.  */
+  neon_imm_shift (FALSE, 0, neon_quad (rs), et, imm);
+}
+
+static void
+do_neon_qmovn (void)
+{
+  struct neon_type_el et = neon_check_type (2, NS_DQ,
+    N_EQK | N_HLF, N_SU_16_64 | N_KEY);
+  /* Saturating move where operands can be signed or unsigned, and the
+     destination has the same signedness.  */
+  NEON_ENCODE (INTEGER, inst);
+  if (et.type == NT_unsigned)
+    inst.instruction |= 0xc0;
+  else
+    inst.instruction |= 0x80;
+  neon_two_same (0, 1, et.size / 2);
+}
+
+static void
+do_neon_qmovun (void)
+{
+  struct neon_type_el et = neon_check_type (2, NS_DQ,
+    N_EQK | N_HLF | N_UNS, N_S16 | N_S32 | N_S64 | N_KEY);
+  /* Saturating move with unsigned results. Operands must be signed.  */
+  NEON_ENCODE (INTEGER, inst);
+  neon_two_same (0, 1, et.size / 2);
+}
+
+static void
+do_neon_rshift_sat_narrow (void)
+{
+  /* FIXME: Types for narrowing. If operands are signed, results can be signed
+     or unsigned. If operands are unsigned, results must also be unsigned.  */
+  struct neon_type_el et = neon_check_type (2, NS_DQI,
+    N_EQK | N_HLF, N_SU_16_64 | N_KEY);
+  int imm = inst.operands[2].imm;
+  /* This gets the bounds check, size encoding and immediate bits calculation
+     right.  */
+  et.size /= 2;
+
+  /* VQ{R}SHRN.I<size> <Dd>, <Qm>, #0 is a synonym for
+     VQMOVN.I<size> <Dd>, <Qm>.  */
+  if (imm == 0)
     {
-      /* Don't allow MVN with 8-bit immediate.  */
-      if (*op == 1)
-       return FAIL;
-      *immbits = immlo;
-      return 0xe;
+      inst.operands[2].present = 0;
+      inst.instruction = N_MNEM_vqmovn;
+      do_neon_qmovn ();
+      return;
     }
 
-  return FAIL;
+  constraint (imm < 1 || (unsigned)imm > et.size,
+             _("immediate out of range"));
+  neon_imm_shift (TRUE, et.type == NT_unsigned, 0, et, et.size - imm);
 }
 
-/* Write immediate bits [7:0] to the following locations:
+static void
+do_neon_rshift_sat_narrow_u (void)
+{
+  /* FIXME: Types for narrowing. If operands are signed, results can be signed
+     or unsigned. If operands are unsigned, results must also be unsigned.  */
+  struct neon_type_el et = neon_check_type (2, NS_DQI,
+    N_EQK | N_HLF | N_UNS, N_S16 | N_S32 | N_S64 | N_KEY);
+  int imm = inst.operands[2].imm;
+  /* This gets the bounds check, size encoding and immediate bits calculation
+     right.  */
+  et.size /= 2;
 
-  |28/24|23     19|18 16|15                    4|3     0|
-  |  a  |x x x x x|b c d|x x x x x x x x x x x x|e f g h|
+  /* VQSHRUN.I<size> <Dd>, <Qm>, #0 is a synonym for
+     VQMOVUN.I<size> <Dd>, <Qm>.  */
+  if (imm == 0)
+    {
+      inst.operands[2].present = 0;
+      inst.instruction = N_MNEM_vqmovun;
+      do_neon_qmovun ();
+      return;
+    }
 
-  This function is used by VMOV/VMVN/VORR/VBIC.  */
+  constraint (imm < 1 || (unsigned)imm > et.size,
+             _("immediate out of range"));
+  /* FIXME: The manual is kind of unclear about what value U should have in
+     VQ{R}SHRUN instructions, but U=0, op=0 definitely encodes VRSHR, so it
+     must be 1.  */
+  neon_imm_shift (TRUE, 1, 0, et, et.size - imm);
+}
 
 static void
-neon_write_immbits (unsigned immbits)
+do_neon_movn (void)
 {
-  inst.instruction |= immbits & 0xf;
-  inst.instruction |= ((immbits >> 4) & 0x7) << 16;
-  inst.instruction |= ((immbits >> 7) & 0x1) << 24;
+  struct neon_type_el et = neon_check_type (2, NS_DQ,
+    N_EQK | N_HLF, N_I16 | N_I32 | N_I64 | N_KEY);
+  NEON_ENCODE (INTEGER, inst);
+  neon_two_same (0, 1, et.size / 2);
 }
 
-/* Invert low-order SIZE bits of XHI:XLO.  */
-
 static void
-neon_invert_size (unsigned *xlo, unsigned *xhi, int size)
+do_neon_rshift_narrow (void)
 {
-  unsigned immlo = xlo ? *xlo : 0;
-  unsigned immhi = xhi ? *xhi : 0;
+  struct neon_type_el et = neon_check_type (2, NS_DQI,
+    N_EQK | N_HLF, N_I16 | N_I32 | N_I64 | N_KEY);
+  int imm = inst.operands[2].imm;
+  /* This gets the bounds check, size encoding and immediate bits calculation
+     right.  */
+  et.size /= 2;
 
-  switch (size)
+  /* If immediate is zero then we are a pseudo-instruction for
+     VMOVN.I<size> <Dd>, <Qm>  */
+  if (imm == 0)
     {
-    case 8:
-      immlo = (~immlo) & 0xff;
-      break;
-
-    case 16:
-      immlo = (~immlo) & 0xffff;
-      break;
-
-    case 64:
-      immhi = (~immhi) & 0xffffffff;
-      /* fall through.  */
-
-    case 32:
-      immlo = (~immlo) & 0xffffffff;
-      break;
-
-    default:
-      abort ();
+      inst.operands[2].present = 0;
+      inst.instruction = N_MNEM_vmovn;
+      do_neon_movn ();
+      return;
     }
 
-  if (xlo)
-    *xlo = immlo;
-
-  if (xhi)
-    *xhi = immhi;
+  constraint (imm < 1 || (unsigned)imm > et.size,
+             _("immediate out of range for narrowing operation"));
+  neon_imm_shift (FALSE, 0, 0, et, et.size - imm);
 }
 
 static void
-do_neon_logic (void)
+do_neon_shll (void)
 {
-  if (inst.operands[2].present && inst.operands[2].isreg)
+  /* FIXME: Type checking when lengthening.  */
+  struct neon_type_el et = neon_check_type (2, NS_QDI,
+    N_EQK | N_DBL, N_I8 | N_I16 | N_I32 | N_KEY);
+  unsigned imm = inst.operands[2].imm;
+
+  if (imm == et.size)
     {
-      enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
-      neon_check_type (3, rs, N_IGNORE_TYPE);
-      /* U bit and size field were set as part of the bitmask.  */
+      /* Maximum shift variant.  */
       NEON_ENCODE (INTEGER, inst);
-      neon_three_same (neon_quad (rs), 0, -1);
+      inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
+      inst.instruction |= HI1 (inst.operands[0].reg) << 22;
+      inst.instruction |= LOW4 (inst.operands[1].reg);
+      inst.instruction |= HI1 (inst.operands[1].reg) << 5;
+      inst.instruction |= neon_logbits (et.size) << 18;
+
+      neon_dp_fixup (&inst);
     }
   else
     {
-      const int three_ops_form = (inst.operands[2].present
-                                 && !inst.operands[2].isreg);
-      const int immoperand = (three_ops_form ? 2 : 1);
-      enum neon_shape rs = (three_ops_form
-                           ? neon_select_shape (NS_DDI, NS_QQI, NS_NULL)
-                           : neon_select_shape (NS_DI, NS_QI, NS_NULL));
-      struct neon_type_el et = neon_check_type (2, rs,
-        N_I8 | N_I16 | N_I32 | N_I64 | N_F32 | N_KEY, N_EQK);
-      enum neon_opc opcode = (enum neon_opc) inst.instruction & 0x0fffffff;
-      unsigned immbits;
-      int cmode;
-
-      if (et.type == NT_invtype)
-        return;
+      /* A more-specific type check for non-max versions.  */
+      et = neon_check_type (2, NS_QDI,
+       N_EQK | N_DBL, N_SU_32 | N_KEY);
+      NEON_ENCODE (IMMED, inst);
+      neon_imm_shift (TRUE, et.type == NT_unsigned, 0, et, imm);
+    }
+}
 
-      if (three_ops_form)
-       constraint (inst.operands[0].reg != inst.operands[1].reg,
-                   _("first and second operands shall be the same register"));
+/* Check the various types for the VCVT instruction, and return which version
+   the current instruction is.  */
 
-      NEON_ENCODE (IMMED, inst);
+#define CVT_FLAVOUR_VAR                                                              \
+  CVT_VAR (s32_f32, N_S32, N_F32, whole_reg,   "ftosls", "ftosis", "ftosizs") \
+  CVT_VAR (u32_f32, N_U32, N_F32, whole_reg,   "ftouls", "ftouis", "ftouizs") \
+  CVT_VAR (f32_s32, N_F32, N_S32, whole_reg,   "fsltos", "fsitos", NULL)      \
+  CVT_VAR (f32_u32, N_F32, N_U32, whole_reg,   "fultos", "fuitos", NULL)      \
+  /* Half-precision conversions.  */                                         \
+  CVT_VAR (s16_f16, N_S16, N_F16 | N_KEY, whole_reg, NULL, NULL, NULL)       \
+  CVT_VAR (u16_f16, N_U16, N_F16 | N_KEY, whole_reg, NULL, NULL, NULL)       \
+  CVT_VAR (f16_s16, N_F16 | N_KEY, N_S16, whole_reg, NULL, NULL, NULL)       \
+  CVT_VAR (f16_u16, N_F16 | N_KEY, N_U16, whole_reg, NULL, NULL, NULL)       \
+  CVT_VAR (f32_f16, N_F32, N_F16, whole_reg,   NULL,     NULL,     NULL)      \
+  CVT_VAR (f16_f32, N_F16, N_F32, whole_reg,   NULL,     NULL,     NULL)      \
+  /* New VCVT instructions introduced by ARMv8.2 fp16 extension.             \
+     Compared with single/double precision variants, only the co-processor    \
+     field is different, so the encoding flow is reused here.  */            \
+  CVT_VAR (f16_s32, N_F16 | N_KEY, N_S32, N_VFP, "fsltos", "fsitos", NULL)    \
+  CVT_VAR (f16_u32, N_F16 | N_KEY, N_U32, N_VFP, "fultos", "fuitos", NULL)    \
+  CVT_VAR (u32_f16, N_U32, N_F16 | N_KEY, N_VFP, "ftouls", "ftouis", "ftouizs")\
+  CVT_VAR (s32_f16, N_S32, N_F16 | N_KEY, N_VFP, "ftosls", "ftosis", "ftosizs")\
+  /* VFP instructions.  */                                                   \
+  CVT_VAR (f32_f64, N_F32, N_F64, N_VFP,       NULL,     "fcvtsd", NULL)      \
+  CVT_VAR (f64_f32, N_F64, N_F32, N_VFP,       NULL,     "fcvtds", NULL)      \
+  CVT_VAR (s32_f64, N_S32, N_F64 | key, N_VFP, "ftosld", "ftosid", "ftosizd") \
+  CVT_VAR (u32_f64, N_U32, N_F64 | key, N_VFP, "ftould", "ftouid", "ftouizd") \
+  CVT_VAR (f64_s32, N_F64 | key, N_S32, N_VFP, "fsltod", "fsitod", NULL)      \
+  CVT_VAR (f64_u32, N_F64 | key, N_U32, N_VFP, "fultod", "fuitod", NULL)      \
+  /* VFP instructions with bitshift.  */                                     \
+  CVT_VAR (f32_s16, N_F32 | key, N_S16, N_VFP, "fshtos", NULL,     NULL)      \
+  CVT_VAR (f32_u16, N_F32 | key, N_U16, N_VFP, "fuhtos", NULL,     NULL)      \
+  CVT_VAR (f64_s16, N_F64 | key, N_S16, N_VFP, "fshtod", NULL,     NULL)      \
+  CVT_VAR (f64_u16, N_F64 | key, N_U16, N_VFP, "fuhtod", NULL,     NULL)      \
+  CVT_VAR (s16_f32, N_S16, N_F32 | key, N_VFP, "ftoshs", NULL,     NULL)      \
+  CVT_VAR (u16_f32, N_U16, N_F32 | key, N_VFP, "ftouhs", NULL,     NULL)      \
+  CVT_VAR (s16_f64, N_S16, N_F64 | key, N_VFP, "ftoshd", NULL,     NULL)      \
+  CVT_VAR (u16_f64, N_U16, N_F64 | key, N_VFP, "ftouhd", NULL,     NULL)
+
+#define CVT_VAR(C, X, Y, R, BSN, CN, ZN) \
+  neon_cvt_flavour_##C,
+
+/* The different types of conversions we can do.  */
+enum neon_cvt_flavour
+{
+  CVT_FLAVOUR_VAR
+  neon_cvt_flavour_invalid,
+  neon_cvt_flavour_first_fp = neon_cvt_flavour_f32_f64
+};
 
-      immbits = inst.operands[immoperand].imm;
-      if (et.size == 64)
-       {
-         /* .i64 is a pseudo-op, so the immediate must be a repeating
-            pattern.  */
-         if (immbits != (inst.operands[immoperand].regisimm ?
-                         inst.operands[immoperand].reg : 0))
-           {
-             /* Set immbits to an invalid constant.  */
-             immbits = 0xdeadbeef;
-           }
-       }
+#undef CVT_VAR
 
-      switch (opcode)
-        {
-        case N_MNEM_vbic:
-          cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size);
-          break;
-
-        case N_MNEM_vorr:
-          cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size);
-          break;
-
-        case N_MNEM_vand:
-          /* Pseudo-instruction for VBIC.  */
-          neon_invert_size (&immbits, 0, et.size);
-          cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size);
-          break;
-
-        case N_MNEM_vorn:
-          /* Pseudo-instruction for VORR.  */
-          neon_invert_size (&immbits, 0, et.size);
-          cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size);
-          break;
-
-        default:
-          abort ();
-        }
+static enum neon_cvt_flavour
+get_neon_cvt_flavour (enum neon_shape rs)
+{
+#define CVT_VAR(C,X,Y,R,BSN,CN,ZN)                     \
+  et = neon_check_type (2, rs, (R) | (X), (R) | (Y));  \
+  if (et.type != NT_invtype)                           \
+    {                                                  \
+      inst.error = NULL;                               \
+      return (neon_cvt_flavour_##C);                   \
+    }
 
-      if (cmode == FAIL)
-        return;
+  struct neon_type_el et;
+  unsigned whole_reg = (rs == NS_FFI || rs == NS_FD || rs == NS_DF
+                       || rs == NS_FF) ? N_VFP : 0;
+  /* The instruction versions which take an immediate take one register
+     argument, which is extended to the width of the full register. Thus the
+     "source" and "destination" registers must have the same width.  Hack that
+     here by making the size equal to the key (wider, in this case) operand.  */
+  unsigned key = (rs == NS_QQI || rs == NS_DDI || rs == NS_FFI) ? N_KEY : 0;
 
-      inst.instruction |= neon_quad (rs) << 6;
-      inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
-      inst.instruction |= HI1 (inst.operands[0].reg) << 22;
-      inst.instruction |= cmode << 8;
-      neon_write_immbits (immbits);
+  CVT_FLAVOUR_VAR;
 
-      neon_dp_fixup (&inst);
-    }
+  return neon_cvt_flavour_invalid;
+#undef CVT_VAR
 }
 
-static void
-do_neon_bitfield (void)
+enum neon_cvt_mode
 {
-  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
-  neon_check_type (3, rs, N_IGNORE_TYPE);
-  neon_three_same (neon_quad (rs), 0, -1);
-}
+  neon_cvt_mode_a,
+  neon_cvt_mode_n,
+  neon_cvt_mode_p,
+  neon_cvt_mode_m,
+  neon_cvt_mode_z,
+  neon_cvt_mode_x,
+  neon_cvt_mode_r
+};
+
+/* Neon-syntax VFP conversions.  */
 
 static void
-neon_dyadic_misc (enum neon_el_type ubit_meaning, unsigned types,
-                  unsigned destbits)
+do_vfp_nsyn_cvt (enum neon_shape rs, enum neon_cvt_flavour flavour)
 {
-  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
-  struct neon_type_el et = neon_check_type (3, rs, N_EQK | destbits, N_EQK,
-                                            types | N_KEY);
-  if (et.type == NT_float)
+  const char *opname = 0;
+
+  if (rs == NS_DDI || rs == NS_QQI || rs == NS_FFI
+      || rs == NS_FHI || rs == NS_HFI)
     {
-      NEON_ENCODE (FLOAT, inst);
-      neon_three_same (neon_quad (rs), 0, -1);
+      /* Conversions with immediate bitshift.  */
+      const char *enc[] =
+       {
+#define CVT_VAR(C,A,B,R,BSN,CN,ZN) BSN,
+         CVT_FLAVOUR_VAR
+         NULL
+#undef CVT_VAR
+       };
+
+      if (flavour < (int) ARRAY_SIZE (enc))
+       {
+         opname = enc[flavour];
+         constraint (inst.operands[0].reg != inst.operands[1].reg,
+                     _("operands 0 and 1 must be the same register"));
+         inst.operands[1] = inst.operands[2];
+         memset (&inst.operands[2], '\0', sizeof (inst.operands[2]));
+       }
     }
   else
     {
-      NEON_ENCODE (INTEGER, inst);
-      neon_three_same (neon_quad (rs), et.type == ubit_meaning, et.size);
+      /* Conversions without bitshift.  */
+      const char *enc[] =
+       {
+#define CVT_VAR(C,A,B,R,BSN,CN,ZN) CN,
+         CVT_FLAVOUR_VAR
+         NULL
+#undef CVT_VAR
+       };
+
+      if (flavour < (int) ARRAY_SIZE (enc))
+       opname = enc[flavour];
     }
-}
 
-static void
-do_neon_dyadic_if_su (void)
-{
-  neon_dyadic_misc (NT_unsigned, N_SUF_32, 0);
-}
+  if (opname)
+    do_vfp_nsyn_opcode (opname);
 
-static void
-do_neon_dyadic_if_su_d (void)
-{
-  /* 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);
+  /* ARMv8.2 fp16 VCVT instruction.  */
+  if (flavour == neon_cvt_flavour_s32_f16
+      || flavour == neon_cvt_flavour_u32_f16
+      || flavour == neon_cvt_flavour_f16_u32
+      || flavour == neon_cvt_flavour_f16_s32)
+    do_scalar_fp16_v82_encode ();
 }
 
 static void
-do_neon_dyadic_if_i_d (void)
+do_vfp_nsyn_cvtz (void)
 {
-  /* The "untyped" case can't happen. Do this to stop the "U" bit being
-     affected if we specify unsigned args.  */
-  neon_dyadic_misc (NT_untyped, N_IF_32, 0);
+  enum neon_shape rs = neon_select_shape (NS_FH, NS_FF, NS_FD, NS_NULL);
+  enum neon_cvt_flavour flavour = get_neon_cvt_flavour (rs);
+  const char *enc[] =
+    {
+#define CVT_VAR(C,A,B,R,BSN,CN,ZN) ZN,
+      CVT_FLAVOUR_VAR
+      NULL
+#undef CVT_VAR
+    };
+
+  if (flavour < (int) ARRAY_SIZE (enc) && enc[flavour])
+    do_vfp_nsyn_opcode (enc[flavour]);
 }
 
-enum vfp_or_neon_is_neon_bits
+static void
+do_vfp_nsyn_cvt_fpv8 (enum neon_cvt_flavour flavour,
+                     enum neon_cvt_mode mode)
 {
-  NEON_CHECK_CC = 1,
-  NEON_CHECK_ARCH = 2
-};
-
-/* Call this function if an instruction which may have belonged to the VFP or
-   Neon instruction sets, but turned out to be a Neon instruction (due to the
-   operand types involved, etc.). We have to check and/or fix-up a couple of
-   things:
+  int sz, op;
+  int rm;
 
-     - Make sure the user hasn't attempted to make a Neon instruction
-       conditional.
-     - Alter the value in the condition code field if necessary.
-     - Make sure that the arch supports Neon instructions.
+  /* Targets like FPv5-SP-D16 don't support FP v8 instructions with
+     D register operands.  */
+  if (flavour == neon_cvt_flavour_s32_f64
+      || flavour == neon_cvt_flavour_u32_f64)
+    constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_armv8),
+               _(BAD_FPU));
 
-   Which of these operations take place depends on bits from enum
-   vfp_or_neon_is_neon_bits.
+  if (flavour == neon_cvt_flavour_s32_f16
+      || flavour == neon_cvt_flavour_u32_f16)
+    constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_fp16),
+               _(BAD_FP16));
 
-   WARNING: This function has side effects! If NEON_CHECK_CC is used and the
-   current instruction's condition is COND_ALWAYS, the condition field is
-   changed to inst.uncond_value. This is necessary because instructions shared
-   between VFP and Neon may be conditional for the VFP variants only, and the
-   unconditional Neon version must have, e.g., 0xF in the condition field.  */
+  set_it_insn_type (OUTSIDE_IT_INSN);
 
-static int
-vfp_or_neon_is_neon (unsigned check)
-{
-  /* Conditions are always legal in Thumb mode (IT blocks).  */
-  if (!thumb_mode && (check & NEON_CHECK_CC))
+  switch (flavour)
     {
-      if (inst.cond != COND_ALWAYS)
-        {
-          first_error (_(BAD_COND));
-          return FAIL;
-        }
-      if (inst.uncond_value != -1)
-        inst.instruction |= inst.uncond_value << 28;
+    case neon_cvt_flavour_s32_f64:
+      sz = 1;
+      op = 1;
+      break;
+    case neon_cvt_flavour_s32_f32:
+      sz = 0;
+      op = 1;
+      break;
+    case neon_cvt_flavour_s32_f16:
+      sz = 0;
+      op = 1;
+      break;
+    case neon_cvt_flavour_u32_f64:
+      sz = 1;
+      op = 0;
+      break;
+    case neon_cvt_flavour_u32_f32:
+      sz = 0;
+      op = 0;
+      break;
+    case neon_cvt_flavour_u32_f16:
+      sz = 0;
+      op = 0;
+      break;
+    default:
+      first_error (_("invalid instruction shape"));
+      return;
     }
 
-  if ((check & NEON_CHECK_ARCH)
-      && !ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_v1))
+  switch (mode)
     {
-      first_error (_(BAD_FPU));
-      return FAIL;
+    case neon_cvt_mode_a: rm = 0; break;
+    case neon_cvt_mode_n: rm = 1; break;
+    case neon_cvt_mode_p: rm = 2; break;
+    case neon_cvt_mode_m: rm = 3; break;
+    default: first_error (_("invalid rounding mode")); return;
     }
 
-  return SUCCESS;
+  NEON_ENCODE (FPV8, inst);
+  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
+  encode_arm_vfp_reg (inst.operands[1].reg, sz == 1 ? VFP_REG_Dm : VFP_REG_Sm);
+  inst.instruction |= sz << 8;
+
+  /* ARMv8.2 fp16 VCVT instruction.  */
+  if (flavour == neon_cvt_flavour_s32_f16
+      ||flavour == neon_cvt_flavour_u32_f16)
+    do_scalar_fp16_v82_encode ();
+  inst.instruction |= op << 7;
+  inst.instruction |= rm << 16;
+  inst.instruction |= 0xf0000000;
+  inst.is_neon = TRUE;
 }
 
 static void
-do_neon_addsub_if_i (void)
+do_neon_cvt_1 (enum neon_cvt_mode mode)
 {
-  if (try_vfp_nsyn (3, do_vfp_nsyn_add_sub) == SUCCESS)
-    return;
+  enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_FFI, NS_DD, NS_QQ,
+                                         NS_FD, NS_DF, NS_FF, NS_QD, NS_DQ,
+                                         NS_FH, NS_HF, NS_FHI, NS_HFI,
+                                         NS_NULL);
+  enum neon_cvt_flavour flavour = get_neon_cvt_flavour (rs);
 
-  if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
+  if (flavour == neon_cvt_flavour_invalid)
     return;
 
-  /* 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
-   result to be:
-     V<op> A,B     (A is operand 0, B is operand 2)
-   to mean:
-     V<op> A,B,A
-   not:
-     V<op> A,B,B
-   so handle that case specially.  */
-
-static void
-neon_exchange_operands (void)
-{
-  void *scratch = alloca (sizeof (inst.operands[0]));
-  if (inst.operands[1].present)
+  /* PR11109: Handle round-to-zero for VCVT conversions.  */
+  if (mode == neon_cvt_mode_z
+      && ARM_CPU_HAS_FEATURE (cpu_variant, fpu_arch_vfp_v2)
+      && (flavour == neon_cvt_flavour_s16_f16
+         || flavour == neon_cvt_flavour_u16_f16
+         || flavour == neon_cvt_flavour_s32_f32
+         || flavour == neon_cvt_flavour_u32_f32
+         || flavour == neon_cvt_flavour_s32_f64
+         || flavour == neon_cvt_flavour_u32_f64)
+      && (rs == NS_FD || rs == NS_FF))
     {
-      /* Swap operands[1] and operands[2].  */
-      memcpy (scratch, &inst.operands[1], sizeof (inst.operands[0]));
-      inst.operands[1] = inst.operands[2];
-      memcpy (&inst.operands[2], scratch, sizeof (inst.operands[0]));
+      do_vfp_nsyn_cvtz ();
+      return;
     }
-  else
+
+  /* ARMv8.2 fp16 VCVT conversions.  */
+  if (mode == neon_cvt_mode_z
+      && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_fp16)
+      && (flavour == neon_cvt_flavour_s32_f16
+         || flavour == neon_cvt_flavour_u32_f16)
+      && (rs == NS_FH))
     {
-      inst.operands[1] = inst.operands[2];
-      inst.operands[2] = inst.operands[0];
+      do_vfp_nsyn_cvtz ();
+      do_scalar_fp16_v82_encode ();
+      return;
     }
-}
 
-static void
-neon_compare (unsigned regtypes, unsigned immtypes, int invert)
-{
-  if (inst.operands[2].isreg)
+  /* VFP rather than Neon conversions.  */
+  if (flavour >= neon_cvt_flavour_first_fp)
     {
-      if (invert)
-        neon_exchange_operands ();
-      neon_dyadic_misc (NT_unsigned, regtypes, N_SIZ);
+      if (mode == neon_cvt_mode_x || mode == neon_cvt_mode_z)
+       do_vfp_nsyn_cvt (rs, flavour);
+      else
+       do_vfp_nsyn_cvt_fpv8 (flavour, mode);
+
+      return;
     }
-  else
+
+  switch (rs)
     {
-      enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
-      struct neon_type_el et = neon_check_type (2, rs,
-        N_EQK | N_SIZ, immtypes | N_KEY);
+    case NS_DDI:
+    case NS_QQI:
+      {
+       unsigned immbits;
+       unsigned enctab[] = {0x0000100, 0x1000100, 0x0, 0x1000000,
+                            0x0000100, 0x1000100, 0x0, 0x1000000};
+
+       if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
+         return;
+
+       /* Fixed-point conversion with #0 immediate is encoded as an
+          integer conversion.  */
+       if (inst.operands[2].present && inst.operands[2].imm == 0)
+         goto int_encode;
+       NEON_ENCODE (IMMED, inst);
+       if (flavour != neon_cvt_flavour_invalid)
+         inst.instruction |= enctab[flavour];
+       inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
+       inst.instruction |= HI1 (inst.operands[0].reg) << 22;
+       inst.instruction |= LOW4 (inst.operands[1].reg);
+       inst.instruction |= HI1 (inst.operands[1].reg) << 5;
+       inst.instruction |= neon_quad (rs) << 6;
+       inst.instruction |= 1 << 21;
+       if (flavour < neon_cvt_flavour_s16_f16)
+         {
+           inst.instruction |= 1 << 21;
+           immbits = 32 - inst.operands[2].imm;
+           inst.instruction |= immbits << 16;
+         }
+       else
+         {
+           inst.instruction |= 3 << 20;
+           immbits = 16 - inst.operands[2].imm;
+           inst.instruction |= immbits << 16;
+           inst.instruction &= ~(1 << 9);
+         }
+
+       neon_dp_fixup (&inst);
+      }
+      break;
+
+    case NS_DD:
+    case NS_QQ:
+      if (mode != neon_cvt_mode_x && mode != neon_cvt_mode_z)
+       {
+         NEON_ENCODE (FLOAT, inst);
+         set_it_insn_type (OUTSIDE_IT_INSN);
+
+         if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH8) == FAIL)
+           return;
+
+         inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
+         inst.instruction |= HI1 (inst.operands[0].reg) << 22;
+         inst.instruction |= LOW4 (inst.operands[1].reg);
+         inst.instruction |= HI1 (inst.operands[1].reg) << 5;
+         inst.instruction |= neon_quad (rs) << 6;
+         inst.instruction |= (flavour == neon_cvt_flavour_u16_f16
+                              || flavour == neon_cvt_flavour_u32_f32) << 7;
+         inst.instruction |= mode << 8;
+         if (flavour == neon_cvt_flavour_u16_f16
+             || flavour == neon_cvt_flavour_s16_f16)
+           /* Mask off the original size bits and reencode them.  */
+           inst.instruction = ((inst.instruction & 0xfff3ffff) | (1 << 18));
+
+         if (thumb_mode)
+           inst.instruction |= 0xfc000000;
+         else
+           inst.instruction |= 0xf0000000;
+       }
+      else
+       {
+    int_encode:
+         {
+           unsigned enctab[] = { 0x100, 0x180, 0x0, 0x080,
+                                 0x100, 0x180, 0x0, 0x080};
+
+           NEON_ENCODE (INTEGER, inst);
+
+           if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
+             return;
+
+           if (flavour != neon_cvt_flavour_invalid)
+             inst.instruction |= enctab[flavour];
+
+           inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
+           inst.instruction |= HI1 (inst.operands[0].reg) << 22;
+           inst.instruction |= LOW4 (inst.operands[1].reg);
+           inst.instruction |= HI1 (inst.operands[1].reg) << 5;
+           inst.instruction |= neon_quad (rs) << 6;
+           if (flavour >= neon_cvt_flavour_s16_f16
+               && flavour <= neon_cvt_flavour_f16_u16)
+             /* Half precision.  */
+             inst.instruction |= 1 << 18;
+           else
+             inst.instruction |= 2 << 18;
+
+           neon_dp_fixup (&inst);
+         }
+       }
+      break;
+
+    /* Half-precision conversions for Advanced SIMD -- neon.  */
+    case NS_QD:
+    case NS_DQ:
+
+      if ((rs == NS_DQ)
+         && (inst.vectype.el[0].size != 16 || inst.vectype.el[1].size != 32))
+         {
+           as_bad (_("operand size must match register width"));
+           break;
+         }
+
+      if ((rs == NS_QD)
+         && ((inst.vectype.el[0].size != 32 || inst.vectype.el[1].size != 16)))
+         {
+           as_bad (_("operand size must match register width"));
+           break;
+         }
+
+      if (rs == NS_DQ)
+       inst.instruction = 0x3b60600;
+      else
+       inst.instruction = 0x3b60700;
 
-      NEON_ENCODE (IMMED, inst);
       inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
       inst.instruction |= HI1 (inst.operands[0].reg) << 22;
       inst.instruction |= LOW4 (inst.operands[1].reg);
       inst.instruction |= HI1 (inst.operands[1].reg) << 5;
-      inst.instruction |= neon_quad (rs) << 6;
-      inst.instruction |= (et.type == NT_float) << 10;
-      inst.instruction |= neon_logbits (et.size) << 18;
-
       neon_dp_fixup (&inst);
+      break;
+
+    default:
+      /* Some VFP conversions go here (s32 <-> f32, u32 <-> f32).  */
+      if (mode == neon_cvt_mode_x || mode == neon_cvt_mode_z)
+       do_vfp_nsyn_cvt (rs, flavour);
+      else
+       do_vfp_nsyn_cvt_fpv8 (flavour, mode);
     }
 }
 
 static void
-do_neon_cmp (void)
+do_neon_cvtr (void)
 {
-  neon_compare (N_SUF_32, N_S8 | N_S16 | N_S32 | N_F32, FALSE);
+  do_neon_cvt_1 (neon_cvt_mode_x);
 }
 
 static void
-do_neon_cmp_inv (void)
+do_neon_cvt (void)
 {
-  neon_compare (N_SUF_32, N_S8 | N_S16 | N_S32 | N_F32, TRUE);
+  do_neon_cvt_1 (neon_cvt_mode_z);
 }
 
 static void
-do_neon_ceq (void)
-{
-  neon_compare (N_IF_32, N_IF_32, FALSE);
-}
-
-/* For multiply instructions, we have the possibility of 16-bit or 32-bit
-   scalars, which are encoded in 5 bits, M : Rm.
-   For 16-bit scalars, the register is encoded in Rm[2:0] and the index in
-   M:Rm[3], and for 32-bit scalars, the register is encoded in Rm[3:0] and the
-   index in M.  */
-
-static unsigned
-neon_scalar_for_mul (unsigned scalar, unsigned elsize)
+do_neon_cvta (void)
 {
-  unsigned regno = NEON_SCALAR_REG (scalar);
-  unsigned elno = NEON_SCALAR_INDEX (scalar);
-
-  switch (elsize)
-    {
-    case 16:
-      if (regno > 7 || elno > 3)
-        goto bad_scalar;
-      return regno | (elno << 3);
-
-    case 32:
-      if (regno > 15 || elno > 1)
-        goto bad_scalar;
-      return regno | (elno << 4);
-
-    default:
-    bad_scalar:
-      first_error (_("scalar out of range for multiply instruction"));
-    }
-
-  return 0;
+  do_neon_cvt_1 (neon_cvt_mode_a);
 }
 
-/* Encode multiply / multiply-accumulate scalar instructions.  */
-
 static void
-neon_mul_mac (struct neon_type_el et, int ubit)
+do_neon_cvtn (void)
 {
-  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;
-  inst.instruction |= HI1 (inst.operands[1].reg) << 7;
-  inst.instruction |= LOW4 (scalar);
-  inst.instruction |= HI1 (scalar) << 5;
-  inst.instruction |= (et.type == NT_float) << 8;
-  inst.instruction |= neon_logbits (et.size) << 20;
-  inst.instruction |= (ubit != 0) << 24;
-
-  neon_dp_fixup (&inst);
+  do_neon_cvt_1 (neon_cvt_mode_n);
 }
 
 static void
-do_neon_mac_maybe_scalar (void)
+do_neon_cvtp (void)
 {
-  if (try_vfp_nsyn (3, do_vfp_nsyn_mla_mls) == SUCCESS)
-    return;
-
-  if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
-    return;
-
-  if (inst.operands[2].isscalar)
-    {
-      enum neon_shape rs = neon_select_shape (NS_DDS, NS_QQS, NS_NULL);
-      struct neon_type_el et = neon_check_type (3, rs,
-        N_EQK, N_EQK, N_I16 | N_I32 | N_F32 | N_KEY);
-      NEON_ENCODE (SCALAR, inst);
-      neon_mul_mac (et, neon_quad (rs));
-    }
-  else
-    {
-      /* The "untyped" case can't happen.  Do this to stop the "U" bit being
-        affected if we specify unsigned args.  */
-      neon_dyadic_misc (NT_untyped, N_IF_32, 0);
-    }
+  do_neon_cvt_1 (neon_cvt_mode_p);
 }
 
 static void
-do_neon_fmac (void)
+do_neon_cvtm (void)
 {
-  if (try_vfp_nsyn (3, do_vfp_nsyn_fma_fms) == SUCCESS)
-    return;
-
-  if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
-    return;
-
-  neon_dyadic_misc (NT_untyped, N_IF_32, 0);
+  do_neon_cvt_1 (neon_cvt_mode_m);
 }
 
 static void
-do_neon_tst (void)
+do_neon_cvttb_2 (bfd_boolean t, bfd_boolean to, bfd_boolean is_double)
 {
-  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
-  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 (neon_quad (rs), 0, et.size);
-}
+  if (is_double)
+    mark_feature_used (&fpu_vfp_ext_armv8);
 
-/* VMUL with 3 registers allows the P8 type. The scalar version supports the
-   same types as the MAC equivalents. The polynomial type for this instruction
-   is encoded the same as the integer type.  */
+  encode_arm_vfp_reg (inst.operands[0].reg,
+                     (is_double && !to) ? VFP_REG_Dd : VFP_REG_Sd);
+  encode_arm_vfp_reg (inst.operands[1].reg,
+                     (is_double && to) ? VFP_REG_Dm : VFP_REG_Sm);
+  inst.instruction |= to ? 0x10000 : 0;
+  inst.instruction |= t ? 0x80 : 0;
+  inst.instruction |= is_double ? 0x100 : 0;
+  do_vfp_cond_or_thumb ();
+}
 
 static void
-do_neon_mul (void)
+do_neon_cvttb_1 (bfd_boolean t)
 {
-  if (try_vfp_nsyn (3, do_vfp_nsyn_mul) == SUCCESS)
-    return;
+  enum neon_shape rs = neon_select_shape (NS_HF, NS_HD, NS_FH, NS_FF, NS_FD,
+                                         NS_DF, NS_DH, NS_NULL);
 
-  if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
+  if (rs == NS_NULL)
     return;
-
-  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)
-{
-  if (inst.operands[2].isscalar)
+  else if (neon_check_type (2, rs, N_F16, N_F32 | N_VFP).type != NT_invtype)
     {
-      enum neon_shape rs = neon_select_shape (NS_DDS, NS_QQS, NS_NULL);
-      struct neon_type_el et = neon_check_type (3, rs,
-        N_EQK, N_EQK, N_S16 | N_S32 | N_KEY);
-      NEON_ENCODE (SCALAR, inst);
-      neon_mul_mac (et, neon_quad (rs));
+      inst.error = NULL;
+      do_neon_cvttb_2 (t, /*to=*/TRUE, /*is_double=*/FALSE);
+    }
+  else if (neon_check_type (2, rs, N_F32 | N_VFP, N_F16).type != NT_invtype)
+    {
+      inst.error = NULL;
+      do_neon_cvttb_2 (t, /*to=*/FALSE, /*is_double=*/FALSE);
+    }
+  else if (neon_check_type (2, rs, N_F16, N_F64 | N_VFP).type != NT_invtype)
+    {
+      /* The VCVTB and VCVTT instructions with D-register operands
+         don't work for SP only targets.  */
+      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_armv8),
+                 _(BAD_FPU));
+
+      inst.error = NULL;
+      do_neon_cvttb_2 (t, /*to=*/TRUE, /*is_double=*/TRUE);
     }
-  else
+  else if (neon_check_type (2, rs, N_F64 | N_VFP, N_F16).type != NT_invtype)
     {
-      enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
-      struct neon_type_el et = neon_check_type (3, rs,
-        N_EQK, N_EQK, N_S16 | N_S32 | N_KEY);
-      NEON_ENCODE (INTEGER, inst);
-      /* The U bit (rounding) comes from bit mask.  */
-      neon_three_same (neon_quad (rs), 0, et.size);
+      /* The VCVTB and VCVTT instructions with D-register operands
+         don't work for SP only targets.  */
+      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_armv8),
+                 _(BAD_FPU));
+
+      inst.error = NULL;
+      do_neon_cvttb_2 (t, /*to=*/FALSE, /*is_double=*/TRUE);
     }
+  else
+    return;
 }
 
 static void
-do_neon_fcmp_absolute (void)
+do_neon_cvtb (void)
 {
-  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
-  neon_check_type (3, rs, N_EQK, N_EQK, N_F32 | N_KEY);
-  /* Size field comes from bit mask.  */
-  neon_three_same (neon_quad (rs), 1, -1);
+  do_neon_cvttb_1 (FALSE);
 }
 
-static void
-do_neon_fcmp_absolute_inv (void)
-{
-  neon_exchange_operands ();
-  do_neon_fcmp_absolute ();
-}
 
 static void
-do_neon_step (void)
+do_neon_cvtt (void)
 {
-  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
-  neon_check_type (3, rs, N_EQK, N_EQK, N_F32 | N_KEY);
-  neon_three_same (neon_quad (rs), 0, -1);
+  do_neon_cvttb_1 (TRUE);
 }
 
 static void
-do_neon_abs_neg (void)
+neon_move_immediate (void)
 {
-  enum neon_shape rs;
-  struct neon_type_el et;
+  enum neon_shape rs = neon_select_shape (NS_DI, NS_QI, NS_NULL);
+  struct neon_type_el et = neon_check_type (2, rs,
+    N_I8 | N_I16 | N_I32 | N_I64 | N_F32 | N_KEY, N_EQK);
+  unsigned immlo, immhi = 0, immbits;
+  int op, cmode, float_p;
 
-  if (try_vfp_nsyn (2, do_vfp_nsyn_abs_neg) == SUCCESS)
-    return;
+  constraint (et.type == NT_invtype,
+             _("operand size must be specified for immediate VMOV"));
 
-  if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
-    return;
+  /* We start out as an MVN instruction if OP = 1, MOV otherwise.  */
+  op = (inst.instruction & (1 << 5)) != 0;
 
-  rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
-  et = neon_check_type (2, rs, N_EQK, N_S8 | N_S16 | N_S32 | N_F32 | N_KEY);
+  immlo = inst.operands[1].imm;
+  if (inst.operands[1].regisimm)
+    immhi = inst.operands[1].reg;
+
+  constraint (et.size < 32 && (immlo & ~((1 << et.size) - 1)) != 0,
+             _("immediate has bits set outside the operand size"));
+
+  float_p = inst.operands[1].immisfloat;
+
+  if ((cmode = neon_cmode_for_move_imm (immlo, immhi, float_p, &immbits, &op,
+                                       et.size, et.type)) == FAIL)
+    {
+      /* Invert relevant bits only.  */
+      neon_invert_size (&immlo, &immhi, et.size);
+      /* Flip from VMOV/VMVN to VMVN/VMOV. Some immediate types are unavailable
+        with one or the other; those cases are caught by
+        neon_cmode_for_move_imm.  */
+      op = !op;
+      if ((cmode = neon_cmode_for_move_imm (immlo, immhi, float_p, &immbits,
+                                           &op, et.size, et.type)) == FAIL)
+       {
+         first_error (_("immediate out of range"));
+         return;
+       }
+    }
+
+  inst.instruction &= ~(1 << 5);
+  inst.instruction |= op << 5;
 
   inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
   inst.instruction |= HI1 (inst.operands[0].reg) << 22;
-  inst.instruction |= LOW4 (inst.operands[1].reg);
-  inst.instruction |= HI1 (inst.operands[1].reg) << 5;
   inst.instruction |= neon_quad (rs) << 6;
-  inst.instruction |= (et.type == NT_float) << 10;
-  inst.instruction |= neon_logbits (et.size) << 18;
+  inst.instruction |= cmode << 8;
+
+  neon_write_immbits (immbits);
+}
+
+static void
+do_neon_mvn (void)
+{
+  if (inst.operands[1].isreg)
+    {
+      enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
+
+      NEON_ENCODE (INTEGER, inst);
+      inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
+      inst.instruction |= HI1 (inst.operands[0].reg) << 22;
+      inst.instruction |= LOW4 (inst.operands[1].reg);
+      inst.instruction |= HI1 (inst.operands[1].reg) << 5;
+      inst.instruction |= neon_quad (rs) << 6;
+    }
+  else
+    {
+      NEON_ENCODE (IMMED, inst);
+      neon_move_immediate ();
+    }
 
   neon_dp_fixup (&inst);
 }
 
+/* Encode instructions of form:
+
+  |28/24|23|22|21 20|19 16|15 12|11    8|7|6|5|4|3  0|
+  |  U  |x |D |size | Rn  | Rd  |x x x x|N|x|M|x| Rm |  */
+
 static void
-do_neon_sli (void)
+neon_mixed_length (struct neon_type_el et, unsigned size)
 {
-  enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
-  struct neon_type_el et = neon_check_type (2, rs,
-    N_EQK, N_8 | N_16 | N_32 | N_64 | N_KEY);
-  int imm = inst.operands[2].imm;
-  constraint (imm < 0 || (unsigned)imm >= et.size,
-              _("immediate out of range for insert"));
-  neon_imm_shift (FALSE, 0, neon_quad (rs), et, imm);
+  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
+  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
+  inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
+  inst.instruction |= HI1 (inst.operands[1].reg) << 7;
+  inst.instruction |= LOW4 (inst.operands[2].reg);
+  inst.instruction |= HI1 (inst.operands[2].reg) << 5;
+  inst.instruction |= (et.type == NT_unsigned) << 24;
+  inst.instruction |= neon_logbits (size) << 20;
+
+  neon_dp_fixup (&inst);
 }
 
 static void
-do_neon_sri (void)
+do_neon_dyadic_long (void)
 {
-  enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
-  struct neon_type_el et = neon_check_type (2, rs,
-    N_EQK, N_8 | N_16 | N_32 | N_64 | N_KEY);
-  int imm = inst.operands[2].imm;
-  constraint (imm < 1 || (unsigned)imm > et.size,
-              _("immediate out of range for insert"));
-  neon_imm_shift (FALSE, 0, neon_quad (rs), et, et.size - imm);
+  /* FIXME: Type checking for lengthening op.  */
+  struct neon_type_el et = neon_check_type (3, NS_QDD,
+    N_EQK | N_DBL, N_EQK, N_SU_32 | N_KEY);
+  neon_mixed_length (et, et.size);
 }
 
 static void
-do_neon_qshlu_imm (void)
+do_neon_abal (void)
 {
-  enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
-  struct neon_type_el et = neon_check_type (2, rs,
-    N_EQK | N_UNS, N_S8 | N_S16 | N_S32 | N_S64 | N_KEY);
-  int imm = inst.operands[2].imm;
-  constraint (imm < 0 || (unsigned)imm >= et.size,
-              _("immediate out of range for shift"));
-  /* Only encodes the 'U present' variant of the instruction.
-     In this case, signed types have OP (bit 8) set to 0.
-     Unsigned types have OP set to 1.  */
-  inst.instruction |= (et.type == NT_unsigned) << 8;
-  /* The rest of the bits are the same as other immediate shifts.  */
-  neon_imm_shift (FALSE, 0, neon_quad (rs), et, imm);
+  struct neon_type_el et = neon_check_type (3, NS_QDD,
+    N_EQK | N_INT | N_DBL, N_EQK, N_SU_32 | N_KEY);
+  neon_mixed_length (et, et.size);
 }
 
 static void
-do_neon_qmovn (void)
+neon_mac_reg_scalar_long (unsigned regtypes, unsigned scalartypes)
 {
-  struct neon_type_el et = neon_check_type (2, NS_DQ,
-    N_EQK | N_HLF, N_SU_16_64 | N_KEY);
-  /* Saturating move where operands can be signed or unsigned, and the
-     destination has the same signedness.  */
-  NEON_ENCODE (INTEGER, inst);
-  if (et.type == NT_unsigned)
-    inst.instruction |= 0xc0;
+  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);
+      NEON_ENCODE (SCALAR, inst);
+      neon_mul_mac (et, et.type == NT_unsigned);
+    }
   else
-    inst.instruction |= 0x80;
-  neon_two_same (0, 1, et.size / 2);
+    {
+      struct neon_type_el et = neon_check_type (3, NS_QDD,
+       N_EQK | N_DBL, N_EQK, scalartypes | N_KEY);
+      NEON_ENCODE (INTEGER, inst);
+      neon_mixed_length (et, et.size);
+    }
 }
 
 static void
-do_neon_qmovun (void)
+do_neon_mac_maybe_scalar_long (void)
 {
-  struct neon_type_el et = neon_check_type (2, NS_DQ,
-    N_EQK | N_HLF | N_UNS, N_S16 | N_S32 | N_S64 | N_KEY);
-  /* Saturating move with unsigned results. Operands must be signed.  */
-  NEON_ENCODE (INTEGER, inst);
-  neon_two_same (0, 1, et.size / 2);
+  neon_mac_reg_scalar_long (N_S16 | N_S32 | N_U16 | N_U32, N_SU_32);
 }
 
 static void
-do_neon_rshift_sat_narrow (void)
+do_neon_dyadic_wide (void)
 {
-  /* FIXME: Types for narrowing. If operands are signed, results can be signed
-     or unsigned. If operands are unsigned, results must also be unsigned.  */
-  struct neon_type_el et = neon_check_type (2, NS_DQI,
-    N_EQK | N_HLF, N_SU_16_64 | N_KEY);
-  int imm = inst.operands[2].imm;
-  /* This gets the bounds check, size encoding and immediate bits calculation
-     right.  */
-  et.size /= 2;
-
-  /* VQ{R}SHRN.I<size> <Dd>, <Qm>, #0 is a synonym for
-     VQMOVN.I<size> <Dd>, <Qm>.  */
-  if (imm == 0)
-    {
-      inst.operands[2].present = 0;
-      inst.instruction = N_MNEM_vqmovn;
-      do_neon_qmovn ();
-      return;
-    }
-
-  constraint (imm < 1 || (unsigned)imm > et.size,
-              _("immediate out of range"));
-  neon_imm_shift (TRUE, et.type == NT_unsigned, 0, et, et.size - imm);
+  struct neon_type_el et = neon_check_type (3, NS_QQD,
+    N_EQK | N_DBL, N_EQK | N_DBL, N_SU_32 | N_KEY);
+  neon_mixed_length (et, et.size);
 }
 
 static void
-do_neon_rshift_sat_narrow_u (void)
+do_neon_dyadic_narrow (void)
 {
-  /* FIXME: Types for narrowing. If operands are signed, results can be signed
-     or unsigned. If operands are unsigned, results must also be unsigned.  */
-  struct neon_type_el et = neon_check_type (2, NS_DQI,
-    N_EQK | N_HLF | N_UNS, N_S16 | N_S32 | N_S64 | N_KEY);
-  int imm = inst.operands[2].imm;
-  /* This gets the bounds check, size encoding and immediate bits calculation
-     right.  */
-  et.size /= 2;
-
-  /* VQSHRUN.I<size> <Dd>, <Qm>, #0 is a synonym for
-     VQMOVUN.I<size> <Dd>, <Qm>.  */
-  if (imm == 0)
-    {
-      inst.operands[2].present = 0;
-      inst.instruction = N_MNEM_vqmovun;
-      do_neon_qmovun ();
-      return;
-    }
+  struct neon_type_el et = neon_check_type (3, NS_QDD,
+    N_EQK | N_DBL, N_EQK, N_I16 | N_I32 | N_I64 | N_KEY);
+  /* Operand sign is unimportant, and the U bit is part of the opcode,
+     so force the operand type to integer.  */
+  et.type = NT_integer;
+  neon_mixed_length (et, et.size / 2);
+}
 
-  constraint (imm < 1 || (unsigned)imm > et.size,
-              _("immediate out of range"));
-  /* FIXME: The manual is kind of unclear about what value U should have in
-     VQ{R}SHRUN instructions, but U=0, op=0 definitely encodes VRSHR, so it
-     must be 1.  */
-  neon_imm_shift (TRUE, 1, 0, et, et.size - imm);
+static void
+do_neon_mul_sat_scalar_long (void)
+{
+  neon_mac_reg_scalar_long (N_S16 | N_S32, N_S16 | N_S32);
 }
 
 static void
-do_neon_movn (void)
+do_neon_vmull (void)
 {
-  struct neon_type_el et = neon_check_type (2, NS_DQ,
-    N_EQK | N_HLF, N_I16 | N_I32 | N_I64 | N_KEY);
-  NEON_ENCODE (INTEGER, inst);
-  neon_two_same (0, 1, et.size / 2);
+  if (inst.operands[2].isscalar)
+    do_neon_mac_maybe_scalar_long ();
+  else
+    {
+      struct neon_type_el et = neon_check_type (3, NS_QDD,
+       N_EQK | N_DBL, N_EQK, N_SU_32 | N_P8 | N_P64 | N_KEY);
+
+      if (et.type == NT_poly)
+       NEON_ENCODE (POLY, inst);
+      else
+       NEON_ENCODE (INTEGER, inst);
+
+      /* For polynomial encoding the U bit must be zero, and the size must
+        be 8 (encoded as 0b00) or, on ARMv8 or later 64 (encoded, non
+        obviously, as 0b10).  */
+      if (et.size == 64)
+       {
+         /* Check we're on the correct architecture.  */
+         if (!mark_feature_used (&fpu_crypto_ext_armv8))
+           inst.error =
+             _("Instruction form not available on this architecture.");
+
+         et.size = 32;
+       }
+
+      neon_mixed_length (et, et.size);
+    }
 }
 
 static void
-do_neon_rshift_narrow (void)
+do_neon_ext (void)
 {
-  struct neon_type_el et = neon_check_type (2, NS_DQI,
-    N_EQK | N_HLF, N_I16 | N_I32 | N_I64 | N_KEY);
-  int imm = inst.operands[2].imm;
-  /* This gets the bounds check, size encoding and immediate bits calculation
-     right.  */
-  et.size /= 2;
+  enum neon_shape rs = neon_select_shape (NS_DDDI, NS_QQQI, NS_NULL);
+  struct neon_type_el et = neon_check_type (3, rs,
+    N_EQK, N_EQK, N_8 | N_16 | N_32 | N_64 | N_KEY);
+  unsigned imm = (inst.operands[3].imm * et.size) / 8;
 
-  /* If immediate is zero then we are a pseudo-instruction for
-     VMOVN.I<size> <Dd>, <Qm>  */
-  if (imm == 0)
-    {
-      inst.operands[2].present = 0;
-      inst.instruction = N_MNEM_vmovn;
-      do_neon_movn ();
-      return;
-    }
+  constraint (imm >= (unsigned) (neon_quad (rs) ? 16 : 8),
+             _("shift out of range"));
+  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
+  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
+  inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
+  inst.instruction |= HI1 (inst.operands[1].reg) << 7;
+  inst.instruction |= LOW4 (inst.operands[2].reg);
+  inst.instruction |= HI1 (inst.operands[2].reg) << 5;
+  inst.instruction |= neon_quad (rs) << 6;
+  inst.instruction |= imm << 8;
 
-  constraint (imm < 1 || (unsigned)imm > et.size,
-              _("immediate out of range for narrowing operation"));
-  neon_imm_shift (FALSE, 0, 0, et, et.size - imm);
+  neon_dp_fixup (&inst);
 }
 
 static void
-do_neon_shll (void)
+do_neon_rev (void)
 {
-  /* FIXME: Type checking when lengthening.  */
-  struct neon_type_el et = neon_check_type (2, NS_QDI,
-    N_EQK | N_DBL, N_I8 | N_I16 | N_I32 | N_KEY);
-  unsigned imm = inst.operands[2].imm;
+  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
+  struct neon_type_el et = neon_check_type (2, rs,
+    N_EQK, N_8 | N_16 | N_32 | N_KEY);
+  unsigned op = (inst.instruction >> 7) & 3;
+  /* N (width of reversed regions) is encoded as part of the bitmask. We
+     extract it here to check the elements to be reversed are smaller.
+     Otherwise we'd get a reserved instruction.  */
+  unsigned elsize = (op == 2) ? 16 : (op == 1) ? 32 : (op == 0) ? 64 : 0;
+  gas_assert (elsize != 0);
+  constraint (et.size >= elsize,
+             _("elements must be smaller than reversal region"));
+  neon_two_same (neon_quad (rs), 1, et.size);
+}
 
-  if (imm == et.size)
+static void
+do_neon_dup (void)
+{
+  if (inst.operands[1].isscalar)
     {
-      /* Maximum shift variant.  */
-      NEON_ENCODE (INTEGER, inst);
+      enum neon_shape rs = neon_select_shape (NS_DS, NS_QS, NS_NULL);
+      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;
+
+      if (vfp_or_neon_is_neon (NEON_CHECK_CC) == FAIL)
+       return;
+
+      NEON_ENCODE (SCALAR, inst);
       inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
       inst.instruction |= HI1 (inst.operands[0].reg) << 22;
-      inst.instruction |= LOW4 (inst.operands[1].reg);
-      inst.instruction |= HI1 (inst.operands[1].reg) << 5;
-      inst.instruction |= neon_logbits (et.size) << 18;
+      inst.instruction |= LOW4 (dm);
+      inst.instruction |= HI1 (dm) << 5;
+      inst.instruction |= neon_quad (rs) << 6;
+      inst.instruction |= x << 17;
+      inst.instruction |= sizebits << 16;
 
       neon_dp_fixup (&inst);
     }
   else
     {
-      /* A more-specific type check for non-max versions.  */
-      et = neon_check_type (2, NS_QDI,
-        N_EQK | N_DBL, N_SU_32 | N_KEY);
-      NEON_ENCODE (IMMED, inst);
-      neon_imm_shift (TRUE, et.type == NT_unsigned, 0, et, imm);
+      enum neon_shape rs = neon_select_shape (NS_DR, NS_QR, NS_NULL);
+      struct neon_type_el et = neon_check_type (2, rs,
+       N_8 | N_16 | N_32 | N_KEY, N_EQK);
+      /* Duplicate ARM register to lanes of vector.  */
+      NEON_ENCODE (ARMREG, inst);
+      switch (et.size)
+       {
+       case 8:  inst.instruction |= 0x400000; break;
+       case 16: inst.instruction |= 0x000020; break;
+       case 32: inst.instruction |= 0x000000; break;
+       default: break;
+       }
+      inst.instruction |= LOW4 (inst.operands[1].reg) << 12;
+      inst.instruction |= LOW4 (inst.operands[0].reg) << 16;
+      inst.instruction |= HI1 (inst.operands[0].reg) << 7;
+      inst.instruction |= neon_quad (rs) << 21;
+      /* The encoding for this instruction is identical for the ARM and Thumb
+        variants, except for the condition field.  */
+      do_vfp_cond_or_thumb ();
     }
 }
 
-/* Check the various types for the VCVT instruction, and return which version
-   the current instruction is.  */
+/* VMOV has particularly many variations. It can be one of:
+     0. VMOV<c><q> <Qd>, <Qm>
+     1. VMOV<c><q> <Dd>, <Dm>
+   (Register operations, which are VORR with Rm = Rn.)
+     2. VMOV<c><q>.<dt> <Qd>, #<imm>
+     3. VMOV<c><q>.<dt> <Dd>, #<imm>
+   (Immediate loads.)
+     4. VMOV<c><q>.<size> <Dn[x]>, <Rd>
+   (ARM register to scalar.)
+     5. VMOV<c><q> <Dm>, <Rd>, <Rn>
+   (Two ARM registers to vector.)
+     6. VMOV<c><q>.<dt> <Rd>, <Dn[x]>
+   (Scalar to ARM register.)
+     7. VMOV<c><q> <Rd>, <Rn>, <Dm>
+   (Vector to two ARM registers.)
+     8. VMOV.F32 <Sd>, <Sm>
+     9. VMOV.F64 <Dd>, <Dm>
+   (VFP register moves.)
+    10. VMOV.F32 <Sd>, #imm
+    11. VMOV.F64 <Dd>, #imm
+   (VFP float immediate load.)
+    12. VMOV <Rd>, <Sm>
+   (VFP single to ARM reg.)
+    13. VMOV <Sd>, <Rm>
+   (ARM reg to VFP single.)
+    14. VMOV <Rd>, <Re>, <Sn>, <Sm>
+   (Two ARM regs to two VFP singles.)
+    15. VMOV <Sd>, <Se>, <Rn>, <Rm>
+   (Two VFP singles to two ARM regs.)
 
-static int
-neon_cvt_flavour (enum neon_shape rs)
-{
-#define CVT_VAR(C,X,Y)                                                 \
-  et = neon_check_type (2, rs, whole_reg | (X), whole_reg | (Y));      \
-  if (et.type != NT_invtype)                                           \
-    {                                                                  \
-      inst.error = NULL;                                               \
-      return (C);                                                      \
-    }
-  struct neon_type_el et;
-  unsigned whole_reg = (rs == NS_FFI || rs == NS_FD || rs == NS_DF
-                        || rs == NS_FF) ? N_VFP : 0;
-  /* The instruction versions which take an immediate take one register
-     argument, which is extended to the width of the full register. Thus the
-     "source" and "destination" registers must have the same width.  Hack that
-     here by making the size equal to the key (wider, in this case) operand.  */
-  unsigned key = (rs == NS_QQI || rs == NS_DDI || rs == NS_FFI) ? N_KEY : 0;
+   These cases can be disambiguated using neon_select_shape, except cases 1/9
+   and 3/11 which depend on the operand type too.
 
-  CVT_VAR (0, N_S32, N_F32);
-  CVT_VAR (1, N_U32, N_F32);
-  CVT_VAR (2, N_F32, N_S32);
-  CVT_VAR (3, N_F32, N_U32);
-  /* Half-precision conversions.  */
-  CVT_VAR (4, N_F32, N_F16);
-  CVT_VAR (5, N_F16, N_F32);
-
-  whole_reg = N_VFP;
-
-  /* VFP instructions.  */
-  CVT_VAR (6, N_F32, N_F64);
-  CVT_VAR (7, N_F64, N_F32);
-  CVT_VAR (8, N_S32, N_F64 | key);
-  CVT_VAR (9, N_U32, N_F64 | key);
-  CVT_VAR (10, N_F64 | key, N_S32);
-  CVT_VAR (11, N_F64 | key, N_U32);
-  /* VFP instructions with bitshift.  */
-  CVT_VAR (12, N_F32 | key, N_S16);
-  CVT_VAR (13, N_F32 | key, N_U16);
-  CVT_VAR (14, N_F64 | key, N_S16);
-  CVT_VAR (15, N_F64 | key, N_U16);
-  CVT_VAR (16, N_S16, N_F32 | key);
-  CVT_VAR (17, N_U16, N_F32 | key);
-  CVT_VAR (18, N_S16, N_F64 | key);
-  CVT_VAR (19, N_U16, N_F64 | key);
+   All the encoded bits are hardcoded by this function.
 
-  return -1;
-#undef CVT_VAR
-}
+   Cases 4, 6 may be used with VFPv1 and above (only 32-bit transfers!).
+   Cases 5, 7 may be used with VFPv2 and above.
 
-/* Neon-syntax VFP conversions.  */
+   FIXME: Some of the checking may be a bit sloppy (in a couple of cases you
+   can specify a type where it doesn't make sense to, and is ignored).  */
 
 static void
-do_vfp_nsyn_cvt (enum neon_shape rs, int flavour)
+do_neon_mov (void)
 {
-  const char *opname = 0;
+  enum neon_shape rs = neon_select_shape (NS_RRFF, NS_FFRR, NS_DRR, NS_RRD,
+                                         NS_QQ, NS_DD, NS_QI, NS_DI, NS_SR,
+                                         NS_RS, NS_FF, NS_FI, NS_RF, NS_FR,
+                                         NS_HR, NS_RH, NS_HI, NS_NULL);
+  struct neon_type_el et;
+  const char *ldconst = 0;
 
-  if (rs == NS_DDI || rs == NS_QQI || rs == NS_FFI)
-    {
-      /* Conversions with immediate bitshift.  */
-      const char *enc[] =
-        {
-          "ftosls",
-          "ftouls",
-          "fsltos",
-          "fultos",
-          NULL,
-          NULL,
-         NULL,
-         NULL,
-          "ftosld",
-          "ftould",
-          "fsltod",
-          "fultod",
-          "fshtos",
-          "fuhtos",
-          "fshtod",
-          "fuhtod",
-          "ftoshs",
-          "ftouhs",
-          "ftoshd",
-          "ftouhd"
-        };
-
-      if (flavour >= 0 && flavour < (int) ARRAY_SIZE (enc))
-        {
-          opname = enc[flavour];
-          constraint (inst.operands[0].reg != inst.operands[1].reg,
-                      _("operands 0 and 1 must be the same register"));
-          inst.operands[1] = inst.operands[2];
-          memset (&inst.operands[2], '\0', sizeof (inst.operands[2]));
-        }
-    }
-  else
+  switch (rs)
     {
-      /* Conversions without bitshift.  */
-      const char *enc[] =
-        {
-          "ftosis",
-          "ftouis",
-          "fsitos",
-          "fuitos",
-         "NULL",
-         "NULL",
-          "fcvtsd",
-          "fcvtds",
-          "ftosid",
-          "ftouid",
-          "fsitod",
-          "fuitod"
-        };
-
-      if (flavour >= 0 && flavour < (int) ARRAY_SIZE (enc))
-        opname = enc[flavour];
-    }
+    case NS_DD:  /* case 1/9.  */
+      et = neon_check_type (2, rs, N_EQK, N_F64 | N_KEY);
+      /* It is not an error here if no type is given.  */
+      inst.error = NULL;
+      if (et.type == NT_float && et.size == 64)
+       {
+         do_vfp_nsyn_opcode ("fcpyd");
+         break;
+       }
+      /* fall through.  */
 
-  if (opname)
-    do_vfp_nsyn_opcode (opname);
-}
+    case NS_QQ:  /* case 0/1.  */
+      {
+       if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
+         return;
+       /* The architecture manual I have doesn't explicitly state which
+          value the U bit should have for register->register moves, but
+          the equivalent VORR instruction has U = 0, so do that.  */
+       inst.instruction = 0x0200110;
+       inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
+       inst.instruction |= HI1 (inst.operands[0].reg) << 22;
+       inst.instruction |= LOW4 (inst.operands[1].reg);
+       inst.instruction |= HI1 (inst.operands[1].reg) << 5;
+       inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
+       inst.instruction |= HI1 (inst.operands[1].reg) << 7;
+       inst.instruction |= neon_quad (rs) << 6;
+
+       neon_dp_fixup (&inst);
+      }
+      break;
 
-static void
-do_vfp_nsyn_cvtz (void)
-{
-  enum neon_shape rs = neon_select_shape (NS_FF, NS_FD, NS_NULL);
-  int flavour = neon_cvt_flavour (rs);
-  const char *enc[] =
-    {
-      "ftosizs",
-      "ftouizs",
-      NULL,
-      NULL,
-      NULL,
-      NULL,
-      NULL,
-      NULL,
-      "ftosizd",
-      "ftouizd"
-    };
+    case NS_DI:  /* case 3/11.  */
+      et = neon_check_type (2, rs, N_EQK, N_F64 | N_KEY);
+      inst.error = NULL;
+      if (et.type == NT_float && et.size == 64)
+       {
+         /* case 11 (fconstd).  */
+         ldconst = "fconstd";
+         goto encode_fconstd;
+       }
+      /* fall through.  */
 
-  if (flavour >= 0 && flavour < (int) ARRAY_SIZE (enc) && enc[flavour])
-    do_vfp_nsyn_opcode (enc[flavour]);
-}
+    case NS_QI:  /* case 2/3.  */
+      if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
+       return;
+      inst.instruction = 0x0800010;
+      neon_move_immediate ();
+      neon_dp_fixup (&inst);
+      break;
 
-static void
-do_neon_cvt_1 (bfd_boolean round_to_zero ATTRIBUTE_UNUSED)
-{
-  enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_FFI, NS_DD, NS_QQ,
-    NS_FD, NS_DF, NS_FF, NS_QD, NS_DQ, NS_NULL);
-  int flavour = neon_cvt_flavour (rs);
+    case NS_SR:  /* case 4.  */
+      {
+       unsigned bcdebits = 0;
+       int logsize;
+       unsigned dn = NEON_SCALAR_REG (inst.operands[0].reg);
+       unsigned x = NEON_SCALAR_INDEX (inst.operands[0].reg);
+
+       /* .<size> is optional here, defaulting to .32. */
+       if (inst.vectype.elems == 0
+           && inst.operands[0].vectype.type == NT_invtype
+           && inst.operands[1].vectype.type == NT_invtype)
+         {
+           inst.vectype.el[0].type = NT_untyped;
+           inst.vectype.el[0].size = 32;
+           inst.vectype.elems = 1;
+         }
 
-  /* PR11109: Handle round-to-zero for VCVT conversions.  */
-  if (round_to_zero
-      && ARM_CPU_HAS_FEATURE (cpu_variant, fpu_arch_vfp_v2)
-      && (flavour == 0 || flavour == 1 || flavour == 8 || flavour == 9)
-      && (rs == NS_FD || rs == NS_FF))
-    {
-      do_vfp_nsyn_cvtz ();
-      return;
-    }
+       et = neon_check_type (2, NS_NULL, N_8 | N_16 | N_32 | N_KEY, N_EQK);
+       logsize = neon_logbits (et.size);
 
-  /* VFP rather than Neon conversions.  */
-  if (flavour >= 6)
-    {
-      do_vfp_nsyn_cvt (rs, flavour);
-      return;
-    }
+       constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v1),
+                   _(BAD_FPU));
+       constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_v1)
+                   && et.size != 32, _(BAD_FPU));
+       constraint (et.type == NT_invtype, _("bad type for scalar"));
+       constraint (x >= 64 / et.size, _("scalar index out of range"));
 
-  switch (rs)
-    {
-    case NS_DDI:
-    case NS_QQI:
-      {
-        unsigned immbits;
-        unsigned enctab[] = { 0x0000100, 0x1000100, 0x0, 0x1000000 };
-
-        if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
-          return;
-
-        /* Fixed-point conversion with #0 immediate is encoded as an
-           integer conversion.  */
-        if (inst.operands[2].present && inst.operands[2].imm == 0)
-          goto int_encode;
-       immbits = 32 - inst.operands[2].imm;
-        NEON_ENCODE (IMMED, inst);
-        if (flavour != -1)
-          inst.instruction |= enctab[flavour];
-        inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
-        inst.instruction |= HI1 (inst.operands[0].reg) << 22;
-        inst.instruction |= LOW4 (inst.operands[1].reg);
-        inst.instruction |= HI1 (inst.operands[1].reg) << 5;
-        inst.instruction |= neon_quad (rs) << 6;
-        inst.instruction |= 1 << 21;
-        inst.instruction |= immbits << 16;
-
-        neon_dp_fixup (&inst);
+       switch (et.size)
+         {
+         case 8:  bcdebits = 0x8; break;
+         case 16: bcdebits = 0x1; break;
+         case 32: bcdebits = 0x0; break;
+         default: ;
+         }
+
+       bcdebits |= x << logsize;
+
+       inst.instruction = 0xe000b10;
+       do_vfp_cond_or_thumb ();
+       inst.instruction |= LOW4 (dn) << 16;
+       inst.instruction |= HI1 (dn) << 7;
+       inst.instruction |= inst.operands[1].reg << 12;
+       inst.instruction |= (bcdebits & 3) << 5;
+       inst.instruction |= (bcdebits >> 2) << 21;
       }
       break;
 
-    case NS_DD:
-    case NS_QQ:
-    int_encode:
+    case NS_DRR:  /* case 5 (fmdrr).  */
+      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v2),
+                 _(BAD_FPU));
+
+      inst.instruction = 0xc400b10;
+      do_vfp_cond_or_thumb ();
+      inst.instruction |= LOW4 (inst.operands[0].reg);
+      inst.instruction |= HI1 (inst.operands[0].reg) << 5;
+      inst.instruction |= inst.operands[1].reg << 12;
+      inst.instruction |= inst.operands[2].reg << 16;
+      break;
+
+    case NS_RS:  /* case 6.  */
       {
-        unsigned enctab[] = { 0x100, 0x180, 0x0, 0x080 };
+       unsigned logsize;
+       unsigned dn = NEON_SCALAR_REG (inst.operands[1].reg);
+       unsigned x = NEON_SCALAR_INDEX (inst.operands[1].reg);
+       unsigned abcdebits = 0;
+
+       /* .<dt> is optional here, defaulting to .32. */
+       if (inst.vectype.elems == 0
+           && inst.operands[0].vectype.type == NT_invtype
+           && inst.operands[1].vectype.type == NT_invtype)
+         {
+           inst.vectype.el[0].type = NT_untyped;
+           inst.vectype.el[0].size = 32;
+           inst.vectype.elems = 1;
+         }
+
+       et = neon_check_type (2, NS_NULL,
+                             N_EQK, N_S8 | N_S16 | N_U8 | N_U16 | N_32 | N_KEY);
+       logsize = neon_logbits (et.size);
+
+       constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v1),
+                   _(BAD_FPU));
+       constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_v1)
+                   && et.size != 32, _(BAD_FPU));
+       constraint (et.type == NT_invtype, _("bad type for scalar"));
+       constraint (x >= 64 / et.size, _("scalar index out of range"));
+
+       switch (et.size)
+         {
+         case 8:  abcdebits = (et.type == NT_signed) ? 0x08 : 0x18; break;
+         case 16: abcdebits = (et.type == NT_signed) ? 0x01 : 0x11; break;
+         case 32: abcdebits = 0x00; break;
+         default: ;
+         }
+
+       abcdebits |= x << logsize;
+       inst.instruction = 0xe100b10;
+       do_vfp_cond_or_thumb ();
+       inst.instruction |= LOW4 (dn) << 16;
+       inst.instruction |= HI1 (dn) << 7;
+       inst.instruction |= inst.operands[0].reg << 12;
+       inst.instruction |= (abcdebits & 3) << 5;
+       inst.instruction |= (abcdebits >> 2) << 21;
+      }
+      break;
 
-        NEON_ENCODE (INTEGER, inst);
+    case NS_RRD:  /* case 7 (fmrrd).  */
+      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v2),
+                 _(BAD_FPU));
 
-        if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
-          return;
+      inst.instruction = 0xc500b10;
+      do_vfp_cond_or_thumb ();
+      inst.instruction |= inst.operands[0].reg << 12;
+      inst.instruction |= inst.operands[1].reg << 16;
+      inst.instruction |= LOW4 (inst.operands[2].reg);
+      inst.instruction |= HI1 (inst.operands[2].reg) << 5;
+      break;
 
-        if (flavour != -1)
-          inst.instruction |= enctab[flavour];
+    case NS_FF:  /* case 8 (fcpys).  */
+      do_vfp_nsyn_opcode ("fcpys");
+      break;
 
-        inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
-        inst.instruction |= HI1 (inst.operands[0].reg) << 22;
-        inst.instruction |= LOW4 (inst.operands[1].reg);
-        inst.instruction |= HI1 (inst.operands[1].reg) << 5;
-        inst.instruction |= neon_quad (rs) << 6;
-        inst.instruction |= 2 << 18;
+    case NS_HI:
+    case NS_FI:  /* case 10 (fconsts).  */
+      ldconst = "fconsts";
+      encode_fconstd:
+      if (is_quarter_float (inst.operands[1].imm))
+       {
+         inst.operands[1].imm = neon_qfloat_bits (inst.operands[1].imm);
+         do_vfp_nsyn_opcode (ldconst);
 
-        neon_dp_fixup (&inst);
-      }
-    break;
+         /* ARMv8.2 fp16 vmov.f16 instruction.  */
+         if (rs == NS_HI)
+           do_scalar_fp16_v82_encode ();
+       }
+      else
+       first_error (_("immediate out of range"));
+      break;
 
-    /* Half-precision conversions for Advanced SIMD -- neon.  */
-    case NS_QD:
-    case NS_DQ:
+    case NS_RH:
+    case NS_RF:  /* case 12 (fmrs).  */
+      do_vfp_nsyn_opcode ("fmrs");
+      /* ARMv8.2 fp16 vmov.f16 instruction.  */
+      if (rs == NS_RH)
+       do_scalar_fp16_v82_encode ();
+      break;
 
-      if ((rs == NS_DQ)
-         && (inst.vectype.el[0].size != 16 || inst.vectype.el[1].size != 32))
-         {
-           as_bad (_("operand size must match register width"));
-           break;
-         }
+    case NS_HR:
+    case NS_FR:  /* case 13 (fmsr).  */
+      do_vfp_nsyn_opcode ("fmsr");
+      /* ARMv8.2 fp16 vmov.f16 instruction.  */
+      if (rs == NS_HR)
+       do_scalar_fp16_v82_encode ();
+      break;
 
-      if ((rs == NS_QD)
-         && ((inst.vectype.el[0].size != 32 || inst.vectype.el[1].size != 16)))
-         {
-           as_bad (_("operand size must match register width"));
-           break;
-         }
+    /* The encoders for the fmrrs and fmsrr instructions expect three operands
+       (one of which is a list), but we have parsed four.  Do some fiddling to
+       make the operands what do_vfp_reg2_from_sp2 and do_vfp_sp2_from_reg2
+       expect.  */
+    case NS_RRFF:  /* case 14 (fmrrs).  */
+      constraint (inst.operands[3].reg != inst.operands[2].reg + 1,
+                 _("VFP registers must be adjacent"));
+      inst.operands[2].imm = 2;
+      memset (&inst.operands[3], '\0', sizeof (inst.operands[3]));
+      do_vfp_nsyn_opcode ("fmrrs");
+      break;
 
-      if (rs == NS_DQ)
-        inst.instruction = 0x3b60600;
-      else
-       inst.instruction = 0x3b60700;
+    case NS_FFRR:  /* case 15 (fmsrr).  */
+      constraint (inst.operands[1].reg != inst.operands[0].reg + 1,
+                 _("VFP registers must be adjacent"));
+      inst.operands[1] = inst.operands[2];
+      inst.operands[2] = inst.operands[3];
+      inst.operands[0].imm = 2;
+      memset (&inst.operands[3], '\0', sizeof (inst.operands[3]));
+      do_vfp_nsyn_opcode ("fmsrr");
+      break;
 
-      inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
-      inst.instruction |= HI1 (inst.operands[0].reg) << 22;
-      inst.instruction |= LOW4 (inst.operands[1].reg);
-      inst.instruction |= HI1 (inst.operands[1].reg) << 5;
-      neon_dp_fixup (&inst);
+    case NS_NULL:
+      /* neon_select_shape has determined that the instruction
+        shape is wrong and has already set the error message.  */
       break;
 
     default:
-      /* Some VFP conversions go here (s32 <-> f32, u32 <-> f32).  */
-      do_vfp_nsyn_cvt (rs, flavour);
+      abort ();
     }
 }
 
 static void
-do_neon_cvtr (void)
+do_neon_rshift_round_imm (void)
 {
-  do_neon_cvt_1 (FALSE);
-}
+  enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
+  struct neon_type_el et = neon_check_type (2, rs, N_EQK, N_SU_ALL | N_KEY);
+  int imm = inst.operands[2].imm;
 
-static void
-do_neon_cvt (void)
-{
-  do_neon_cvt_1 (TRUE);
+  /* imm == 0 case is encoded as VMOV for V{R}SHR.  */
+  if (imm == 0)
+    {
+      inst.operands[2].present = 0;
+      do_neon_mov ();
+      return;
+    }
+
+  constraint (imm < 1 || (unsigned)imm > et.size,
+             _("immediate out of range for shift"));
+  neon_imm_shift (TRUE, et.type == NT_unsigned, neon_quad (rs), et,
+                 et.size - imm);
 }
 
 static void
-do_neon_cvtb (void)
+do_neon_movhf (void)
 {
-  inst.instruction = 0xeb20a40;
+  enum neon_shape rs = neon_select_shape (NS_HH, NS_NULL);
+  constraint (rs != NS_HH, _("invalid suffix"));
 
-  /* The sizes are attached to the mnemonic.  */
-  if (inst.vectype.el[0].type != NT_invtype
-      && inst.vectype.el[0].size == 16)
-    inst.instruction |= 0x00010000;
+  constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_armv8),
+             _(BAD_FPU));
 
-  /* Programmer's syntax: the sizes are attached to the operands.  */
-  else if (inst.operands[0].vectype.type != NT_invtype
-          && inst.operands[0].vectype.size == 16)
-    inst.instruction |= 0x00010000;
+  do_vfp_sp_monadic ();
 
-  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
-  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Sm);
-  do_vfp_cond_or_thumb ();
+  inst.is_neon = 1;
+  inst.instruction |= 0xf0000000;
 }
 
-
 static void
-do_neon_cvtt (void)
+do_neon_movl (void)
 {
-  do_neon_cvtb ();
-  inst.instruction |= 0x80;
+  struct neon_type_el et = neon_check_type (2, NS_QD,
+    N_EQK | N_DBL, N_SU_32 | N_KEY);
+  unsigned sizebits = et.size >> 3;
+  inst.instruction |= sizebits << 19;
+  neon_two_same (0, et.type == NT_unsigned, -1);
 }
 
 static void
-neon_move_immediate (void)
+do_neon_trn (void)
 {
-  enum neon_shape rs = neon_select_shape (NS_DI, NS_QI, NS_NULL);
+  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
   struct neon_type_el et = neon_check_type (2, rs,
-    N_I8 | N_I16 | N_I32 | N_I64 | N_F32 | N_KEY, N_EQK);
-  unsigned immlo, immhi = 0, immbits;
-  int op, cmode, float_p;
-
-  constraint (et.type == NT_invtype,
-              _("operand size must be specified for immediate VMOV"));
-
-  /* We start out as an MVN instruction if OP = 1, MOV otherwise.  */
-  op = (inst.instruction & (1 << 5)) != 0;
-
-  immlo = inst.operands[1].imm;
-  if (inst.operands[1].regisimm)
-    immhi = inst.operands[1].reg;
-
-  constraint (et.size < 32 && (immlo & ~((1 << et.size) - 1)) != 0,
-              _("immediate has bits set outside the operand size"));
-
-  float_p = inst.operands[1].immisfloat;
-
-  if ((cmode = neon_cmode_for_move_imm (immlo, immhi, float_p, &immbits, &op,
-                                        et.size, et.type)) == FAIL)
-    {
-      /* Invert relevant bits only.  */
-      neon_invert_size (&immlo, &immhi, et.size);
-      /* Flip from VMOV/VMVN to VMVN/VMOV. Some immediate types are unavailable
-         with one or the other; those cases are caught by
-         neon_cmode_for_move_imm.  */
-      op = !op;
-      if ((cmode = neon_cmode_for_move_imm (immlo, immhi, float_p, &immbits,
-                                           &op, et.size, et.type)) == FAIL)
-        {
-          first_error (_("immediate out of range"));
-          return;
-        }
-    }
-
-  inst.instruction &= ~(1 << 5);
-  inst.instruction |= op << 5;
-
-  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
-  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
-  inst.instruction |= neon_quad (rs) << 6;
-  inst.instruction |= cmode << 8;
-
-  neon_write_immbits (immbits);
+    N_EQK, N_8 | N_16 | N_32 | N_KEY);
+  NEON_ENCODE (INTEGER, inst);
+  neon_two_same (neon_quad (rs), 1, et.size);
 }
 
 static void
-do_neon_mvn (void)
+do_neon_zip_uzp (void)
 {
-  if (inst.operands[1].isreg)
-    {
-      enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
-
-      NEON_ENCODE (INTEGER, inst);
-      inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
-      inst.instruction |= HI1 (inst.operands[0].reg) << 22;
-      inst.instruction |= LOW4 (inst.operands[1].reg);
-      inst.instruction |= HI1 (inst.operands[1].reg) << 5;
-      inst.instruction |= neon_quad (rs) << 6;
-    }
-  else
+  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
+  struct neon_type_el et = neon_check_type (2, rs,
+    N_EQK, N_8 | N_16 | N_32 | N_KEY);
+  if (rs == NS_DD && et.size == 32)
     {
-      NEON_ENCODE (IMMED, inst);
-      neon_move_immediate ();
+      /* Special case: encode as VTRN.32 <Dd>, <Dm>.  */
+      inst.instruction = N_MNEM_vtrn;
+      do_neon_trn ();
+      return;
     }
-
-  neon_dp_fixup (&inst);
-}
-
-/* Encode instructions of form:
-
-  |28/24|23|22|21 20|19 16|15 12|11    8|7|6|5|4|3  0|
-  |  U  |x |D |size | Rn  | Rd  |x x x x|N|x|M|x| Rm |  */
-
-static void
-neon_mixed_length (struct neon_type_el et, unsigned 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;
-  inst.instruction |= HI1 (inst.operands[1].reg) << 7;
-  inst.instruction |= LOW4 (inst.operands[2].reg);
-  inst.instruction |= HI1 (inst.operands[2].reg) << 5;
-  inst.instruction |= (et.type == NT_unsigned) << 24;
-  inst.instruction |= neon_logbits (size) << 20;
-
-  neon_dp_fixup (&inst);
-}
-
-static void
-do_neon_dyadic_long (void)
-{
-  /* FIXME: Type checking for lengthening op.  */
-  struct neon_type_el et = neon_check_type (3, NS_QDD,
-    N_EQK | N_DBL, N_EQK, N_SU_32 | N_KEY);
-  neon_mixed_length (et, et.size);
+  neon_two_same (neon_quad (rs), 1, et.size);
 }
 
 static void
-do_neon_abal (void)
+do_neon_sat_abs_neg (void)
 {
-  struct neon_type_el et = neon_check_type (3, NS_QDD,
-    N_EQK | N_INT | N_DBL, N_EQK, N_SU_32 | N_KEY);
-  neon_mixed_length (et, et.size);
+  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
+  struct neon_type_el et = neon_check_type (2, rs,
+    N_EQK, N_S8 | N_S16 | N_S32 | N_KEY);
+  neon_two_same (neon_quad (rs), 1, et.size);
 }
 
 static void
-neon_mac_reg_scalar_long (unsigned regtypes, unsigned scalartypes)
+do_neon_pair_long (void)
 {
-  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);
-      NEON_ENCODE (SCALAR, inst);
-      neon_mul_mac (et, et.type == NT_unsigned);
-    }
-  else
-    {
-      struct neon_type_el et = neon_check_type (3, NS_QDD,
-        N_EQK | N_DBL, N_EQK, scalartypes | N_KEY);
-      NEON_ENCODE (INTEGER, inst);
-      neon_mixed_length (et, et.size);
-    }
+  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
+  struct neon_type_el et = neon_check_type (2, rs, N_EQK, N_SU_32 | N_KEY);
+  /* Unsigned is encoded in OP field (bit 7) for these instruction.  */
+  inst.instruction |= (et.type == NT_unsigned) << 7;
+  neon_two_same (neon_quad (rs), 1, et.size);
 }
 
 static void
-do_neon_mac_maybe_scalar_long (void)
+do_neon_recip_est (void)
 {
-  neon_mac_reg_scalar_long (N_S16 | N_S32 | N_U16 | N_U32, N_SU_32);
+  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
+  struct neon_type_el et = neon_check_type (2, rs,
+    N_EQK | N_FLT, N_F_16_32 | N_U32 | N_KEY);
+  inst.instruction |= (et.type == NT_float) << 8;
+  neon_two_same (neon_quad (rs), 1, et.size);
 }
 
 static void
-do_neon_dyadic_wide (void)
+do_neon_cls (void)
 {
-  struct neon_type_el et = neon_check_type (3, NS_QQD,
-    N_EQK | N_DBL, N_EQK | N_DBL, N_SU_32 | N_KEY);
-  neon_mixed_length (et, et.size);
+  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
+  struct neon_type_el et = neon_check_type (2, rs,
+    N_EQK, N_S8 | N_S16 | N_S32 | N_KEY);
+  neon_two_same (neon_quad (rs), 1, et.size);
 }
 
 static void
-do_neon_dyadic_narrow (void)
-{
-  struct neon_type_el et = neon_check_type (3, NS_QDD,
-    N_EQK | N_DBL, N_EQK, N_I16 | N_I32 | N_I64 | N_KEY);
-  /* Operand sign is unimportant, and the U bit is part of the opcode,
-     so force the operand type to integer.  */
-  et.type = NT_integer;
-  neon_mixed_length (et, et.size / 2);
+do_neon_clz (void)
+{
+  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
+  struct neon_type_el et = neon_check_type (2, rs,
+    N_EQK, N_I8 | N_I16 | N_I32 | N_KEY);
+  neon_two_same (neon_quad (rs), 1, et.size);
 }
 
 static void
-do_neon_mul_sat_scalar_long (void)
+do_neon_cnt (void)
 {
-  neon_mac_reg_scalar_long (N_S16 | N_S32, N_S16 | N_S32);
+  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
+  struct neon_type_el et = neon_check_type (2, rs,
+    N_EQK | N_INT, N_8 | N_KEY);
+  neon_two_same (neon_quad (rs), 1, et.size);
 }
 
 static void
-do_neon_vmull (void)
+do_neon_swp (void)
 {
-  if (inst.operands[2].isscalar)
-    do_neon_mac_maybe_scalar_long ();
-  else
-    {
-      struct neon_type_el et = neon_check_type (3, NS_QDD,
-        N_EQK | N_DBL, N_EQK, N_SU_32 | N_P8 | N_KEY);
-      if (et.type == NT_poly)
-        NEON_ENCODE (POLY, inst);
-      else
-        NEON_ENCODE (INTEGER, inst);
-      /* For polynomial encoding, size field must be 0b00 and the U bit must be
-         zero. Should be OK as-is.  */
-      neon_mixed_length (et, et.size);
-    }
+  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
+  neon_two_same (neon_quad (rs), 1, -1);
 }
 
 static void
-do_neon_ext (void)
+do_neon_tbl_tbx (void)
 {
-  enum neon_shape rs = neon_select_shape (NS_DDDI, NS_QQQI, NS_NULL);
-  struct neon_type_el et = neon_check_type (3, rs,
-    N_EQK, N_EQK, N_8 | N_16 | N_32 | N_64 | N_KEY);
-  unsigned imm = (inst.operands[3].imm * et.size) / 8;
+  unsigned listlenbits;
+  neon_check_type (3, NS_DLD, N_EQK, N_EQK, N_8 | N_KEY);
 
-  constraint (imm >= (unsigned) (neon_quad (rs) ? 16 : 8),
-             _("shift out of range"));
+  if (inst.operands[1].imm < 1 || inst.operands[1].imm > 4)
+    {
+      first_error (_("bad list length for table lookup"));
+      return;
+    }
+
+  listlenbits = inst.operands[1].imm - 1;
   inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
   inst.instruction |= HI1 (inst.operands[0].reg) << 22;
   inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
   inst.instruction |= HI1 (inst.operands[1].reg) << 7;
   inst.instruction |= LOW4 (inst.operands[2].reg);
   inst.instruction |= HI1 (inst.operands[2].reg) << 5;
-  inst.instruction |= neon_quad (rs) << 6;
-  inst.instruction |= imm << 8;
+  inst.instruction |= listlenbits << 8;
 
   neon_dp_fixup (&inst);
 }
 
 static void
-do_neon_rev (void)
+do_neon_ldm_stm (void)
 {
-  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
-  struct neon_type_el et = neon_check_type (2, rs,
-    N_EQK, N_8 | N_16 | N_32 | N_KEY);
-  unsigned op = (inst.instruction >> 7) & 3;
-  /* N (width of reversed regions) is encoded as part of the bitmask. We
-     extract it here to check the elements to be reversed are smaller.
-     Otherwise we'd get a reserved instruction.  */
-  unsigned elsize = (op == 2) ? 16 : (op == 1) ? 32 : (op == 0) ? 64 : 0;
-  gas_assert (elsize != 0);
-  constraint (et.size >= elsize,
-              _("elements must be smaller than reversal region"));
-  neon_two_same (neon_quad (rs), 1, et.size);
+  /* P, U and L bits are part of bitmask.  */
+  int is_dbmode = (inst.instruction & (1 << 24)) != 0;
+  unsigned offsetbits = inst.operands[1].imm * 2;
+
+  if (inst.operands[1].issingle)
+    {
+      do_vfp_nsyn_ldm_stm (is_dbmode);
+      return;
+    }
+
+  constraint (is_dbmode && !inst.operands[0].writeback,
+             _("writeback (!) must be used for VLDMDB and VSTMDB"));
+
+  constraint (inst.operands[1].imm < 1 || inst.operands[1].imm > 16,
+             _("register list must contain at least 1 and at most 16 "
+               "registers"));
+
+  inst.instruction |= inst.operands[0].reg << 16;
+  inst.instruction |= inst.operands[0].writeback << 21;
+  inst.instruction |= LOW4 (inst.operands[1].reg) << 12;
+  inst.instruction |= HI1 (inst.operands[1].reg) << 22;
+
+  inst.instruction |= offsetbits;
+
+  do_vfp_cond_or_thumb ();
 }
 
 static void
-do_neon_dup (void)
+do_neon_ldr_str (void)
 {
-  if (inst.operands[1].isscalar)
-    {
-      enum neon_shape rs = neon_select_shape (NS_DS, NS_QS, NS_NULL);
-      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;
+  int is_ldr = (inst.instruction & (1 << 20)) != 0;
 
-      if (vfp_or_neon_is_neon (NEON_CHECK_CC) == FAIL)
-        return;
+  /* Use of PC in vstr in ARM mode is deprecated in ARMv7.
+     And is UNPREDICTABLE in thumb mode.  */
+  if (!is_ldr
+      && inst.operands[1].reg == REG_PC
+      && (ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v7) || thumb_mode))
+    {
+      if (thumb_mode)
+       inst.error = _("Use of PC here is UNPREDICTABLE");
+      else if (warn_on_deprecated)
+       as_tsktsk (_("Use of PC here is deprecated"));
+    }
 
-      NEON_ENCODE (SCALAR, inst);
-      inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
-      inst.instruction |= HI1 (inst.operands[0].reg) << 22;
-      inst.instruction |= LOW4 (dm);
-      inst.instruction |= HI1 (dm) << 5;
-      inst.instruction |= neon_quad (rs) << 6;
-      inst.instruction |= x << 17;
-      inst.instruction |= sizebits << 16;
+  if (inst.operands[0].issingle)
+    {
+      if (is_ldr)
+       do_vfp_nsyn_opcode ("flds");
+      else
+       do_vfp_nsyn_opcode ("fsts");
 
-      neon_dp_fixup (&inst);
+      /* ARMv8.2 vldr.16/vstr.16 instruction.  */
+      if (inst.vectype.el[0].size == 16)
+       do_scalar_fp16_v82_encode ();
     }
   else
     {
-      enum neon_shape rs = neon_select_shape (NS_DR, NS_QR, NS_NULL);
-      struct neon_type_el et = neon_check_type (2, rs,
-        N_8 | N_16 | N_32 | N_KEY, N_EQK);
-      /* Duplicate ARM register to lanes of vector.  */
-      NEON_ENCODE (ARMREG, inst);
-      switch (et.size)
-        {
-        case 8:  inst.instruction |= 0x400000; break;
-        case 16: inst.instruction |= 0x000020; break;
-        case 32: inst.instruction |= 0x000000; break;
-        default: break;
-        }
-      inst.instruction |= LOW4 (inst.operands[1].reg) << 12;
-      inst.instruction |= LOW4 (inst.operands[0].reg) << 16;
-      inst.instruction |= HI1 (inst.operands[0].reg) << 7;
-      inst.instruction |= neon_quad (rs) << 21;
-      /* The encoding for this instruction is identical for the ARM and Thumb
-         variants, except for the condition field.  */
-      do_vfp_cond_or_thumb ();
+      if (is_ldr)
+       do_vfp_nsyn_opcode ("fldd");
+      else
+       do_vfp_nsyn_opcode ("fstd");
     }
 }
 
-/* VMOV has particularly many variations. It can be one of:
-     0. VMOV<c><q> <Qd>, <Qm>
-     1. VMOV<c><q> <Dd>, <Dm>
-   (Register operations, which are VORR with Rm = Rn.)
-     2. VMOV<c><q>.<dt> <Qd>, #<imm>
-     3. VMOV<c><q>.<dt> <Dd>, #<imm>
-   (Immediate loads.)
-     4. VMOV<c><q>.<size> <Dn[x]>, <Rd>
-   (ARM register to scalar.)
-     5. VMOV<c><q> <Dm>, <Rd>, <Rn>
-   (Two ARM registers to vector.)
-     6. VMOV<c><q>.<dt> <Rd>, <Dn[x]>
-   (Scalar to ARM register.)
-     7. VMOV<c><q> <Rd>, <Rn>, <Dm>
-   (Vector to two ARM registers.)
-     8. VMOV.F32 <Sd>, <Sm>
-     9. VMOV.F64 <Dd>, <Dm>
-   (VFP register moves.)
-    10. VMOV.F32 <Sd>, #imm
-    11. VMOV.F64 <Dd>, #imm
-   (VFP float immediate load.)
-    12. VMOV <Rd>, <Sm>
-   (VFP single to ARM reg.)
-    13. VMOV <Sd>, <Rm>
-   (ARM reg to VFP single.)
-    14. VMOV <Rd>, <Re>, <Sn>, <Sm>
-   (Two ARM regs to two VFP singles.)
-    15. VMOV <Sd>, <Se>, <Rn>, <Rm>
-   (Two VFP singles to two ARM regs.)
-
-   These cases can be disambiguated using neon_select_shape, except cases 1/9
-   and 3/11 which depend on the operand type too.
-
-   All the encoded bits are hardcoded by this function.
-
-   Cases 4, 6 may be used with VFPv1 and above (only 32-bit transfers!).
-   Cases 5, 7 may be used with VFPv2 and above.
-
-   FIXME: Some of the checking may be a bit sloppy (in a couple of cases you
-   can specify a type where it doesn't make sense to, and is ignored).  */
+/* "interleave" version also handles non-interleaving register VLD1/VST1
+   instructions.  */
 
 static void
-do_neon_mov (void)
+do_neon_ld_st_interleave (void)
 {
-  enum neon_shape rs = neon_select_shape (NS_RRFF, NS_FFRR, NS_DRR, NS_RRD,
-    NS_QQ, NS_DD, NS_QI, NS_DI, NS_SR, NS_RS, NS_FF, NS_FI, NS_RF, NS_FR,
-    NS_NULL);
-  struct neon_type_el et;
-  const char *ldconst = 0;
-
-  switch (rs)
+  struct neon_type_el et = neon_check_type (1, NS_NULL,
+                                           N_8 | N_16 | N_32 | N_64);
+  unsigned alignbits = 0;
+  unsigned idx;
+  /* The bits in this table go:
+     0: register stride of one (0) or two (1)
+     1,2: register list length, minus one (1, 2, 3, 4).
+     3,4: <n> in instruction type, minus one (VLD<n> / VST<n>).
+     We use -1 for invalid entries.  */
+  const int typetable[] =
     {
-    case NS_DD:  /* case 1/9.  */
-      et = neon_check_type (2, rs, N_EQK, N_F64 | N_KEY);
-      /* It is not an error here if no type is given.  */
-      inst.error = NULL;
-      if (et.type == NT_float && et.size == 64)
-        {
-          do_vfp_nsyn_opcode ("fcpyd");
-          break;
-        }
-      /* fall through.  */
+      0x7,  -1, 0xa,  -1, 0x6,  -1, 0x2,  -1, /* VLD1 / VST1.  */
+       -1,  -1, 0x8, 0x9,  -1,  -1, 0x3,  -1, /* VLD2 / VST2.  */
+       -1,  -1,  -1,  -1, 0x4, 0x5,  -1,  -1, /* VLD3 / VST3.  */
+       -1,  -1,  -1,  -1,  -1,  -1, 0x0, 0x1  /* VLD4 / VST4.  */
+    };
+  int typebits;
 
-    case NS_QQ:  /* case 0/1.  */
+  if (et.type == NT_invtype)
+    return;
+
+  if (inst.operands[1].immisalign)
+    switch (inst.operands[1].imm >> 8)
       {
-        if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
-          return;
-        /* The architecture manual I have doesn't explicitly state which
-           value the U bit should have for register->register moves, but
-           the equivalent VORR instruction has U = 0, so do that.  */
-        inst.instruction = 0x0200110;
-        inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
-        inst.instruction |= HI1 (inst.operands[0].reg) << 22;
-        inst.instruction |= LOW4 (inst.operands[1].reg);
-        inst.instruction |= HI1 (inst.operands[1].reg) << 5;
-        inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
-        inst.instruction |= HI1 (inst.operands[1].reg) << 7;
-        inst.instruction |= neon_quad (rs) << 6;
-
-        neon_dp_fixup (&inst);
+      case 64: alignbits = 1; break;
+      case 128:
+       if (NEON_REGLIST_LENGTH (inst.operands[0].imm) != 2
+           && NEON_REGLIST_LENGTH (inst.operands[0].imm) != 4)
+         goto bad_alignment;
+       alignbits = 2;
+       break;
+      case 256:
+       if (NEON_REGLIST_LENGTH (inst.operands[0].imm) != 4)
+         goto bad_alignment;
+       alignbits = 3;
+       break;
+      default:
+      bad_alignment:
+       first_error (_("bad alignment"));
+       return;
       }
-      break;
 
-    case NS_DI:  /* case 3/11.  */
-      et = neon_check_type (2, rs, N_EQK, N_F64 | N_KEY);
-      inst.error = NULL;
-      if (et.type == NT_float && et.size == 64)
-        {
-          /* case 11 (fconstd).  */
-          ldconst = "fconstd";
-          goto encode_fconstd;
-        }
-      /* fall through.  */
+  inst.instruction |= alignbits << 4;
+  inst.instruction |= neon_logbits (et.size) << 6;
 
-    case NS_QI:  /* case 2/3.  */
-      if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
-        return;
-      inst.instruction = 0x0800010;
-      neon_move_immediate ();
-      neon_dp_fixup (&inst);
-      break;
+  /* Bits [4:6] of the immediate in a list specifier encode register stride
+     (minus 1) in bit 4, and list length in bits [5:6]. We put the <n> of
+     VLD<n>/VST<n> in bits [9:8] of the initial bitmask. Suck it out here, look
+     up the right value for "type" in a table based on this value and the given
+     list style, then stick it back.  */
+  idx = ((inst.operands[0].imm >> 4) & 7)
+       | (((inst.instruction >> 8) & 3) << 3);
 
-    case NS_SR:  /* case 4.  */
-      {
-        unsigned bcdebits = 0;
-        int logsize;
-        unsigned dn = NEON_SCALAR_REG (inst.operands[0].reg);
-        unsigned x = NEON_SCALAR_INDEX (inst.operands[0].reg);
-
-        et = neon_check_type (2, NS_NULL, N_8 | N_16 | N_32 | N_KEY, N_EQK);
-        logsize = neon_logbits (et.size);
-
-        constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v1),
-                    _(BAD_FPU));
-        constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_v1)
-                    && et.size != 32, _(BAD_FPU));
-        constraint (et.type == NT_invtype, _("bad type for scalar"));
-        constraint (x >= 64 / et.size, _("scalar index out of range"));
-
-        switch (et.size)
-          {
-          case 8:  bcdebits = 0x8; break;
-          case 16: bcdebits = 0x1; break;
-          case 32: bcdebits = 0x0; break;
-          default: ;
-          }
-
-        bcdebits |= x << logsize;
-
-        inst.instruction = 0xe000b10;
-        do_vfp_cond_or_thumb ();
-        inst.instruction |= LOW4 (dn) << 16;
-        inst.instruction |= HI1 (dn) << 7;
-        inst.instruction |= inst.operands[1].reg << 12;
-        inst.instruction |= (bcdebits & 3) << 5;
-        inst.instruction |= (bcdebits >> 2) << 21;
-      }
-      break;
+  typebits = typetable[idx];
+
+  constraint (typebits == -1, _("bad list type for instruction"));
+  constraint (((inst.instruction >> 8) & 3) && et.size == 64,
+             _("bad element type for instruction"));
+
+  inst.instruction &= ~0xf00;
+  inst.instruction |= typebits << 8;
+}
+
+/* Check alignment is valid for do_neon_ld_st_lane and do_neon_ld_dup.
+   *DO_ALIGN is set to 1 if the relevant alignment bit should be set, 0
+   otherwise. The variable arguments are a list of pairs of legal (size, align)
+   values, terminated with -1.  */
+
+static int
+neon_alignment_bit (int size, int align, int *do_alignment, ...)
+{
+  va_list ap;
+  int result = FAIL, thissize, thisalign;
+
+  if (!inst.operands[1].immisalign)
+    {
+      *do_alignment = 0;
+      return SUCCESS;
+    }
 
-    case NS_DRR:  /* case 5 (fmdrr).  */
-      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v2),
-                  _(BAD_FPU));
+  va_start (ap, do_alignment);
 
-      inst.instruction = 0xc400b10;
-      do_vfp_cond_or_thumb ();
-      inst.instruction |= LOW4 (inst.operands[0].reg);
-      inst.instruction |= HI1 (inst.operands[0].reg) << 5;
-      inst.instruction |= inst.operands[1].reg << 12;
-      inst.instruction |= inst.operands[2].reg << 16;
-      break;
+  do
+    {
+      thissize = va_arg (ap, int);
+      if (thissize == -1)
+       break;
+      thisalign = va_arg (ap, int);
 
-    case NS_RS:  /* case 6.  */
-      {
-        unsigned logsize;
-        unsigned dn = NEON_SCALAR_REG (inst.operands[1].reg);
-        unsigned x = NEON_SCALAR_INDEX (inst.operands[1].reg);
-        unsigned abcdebits = 0;
+      if (size == thissize && align == thisalign)
+       result = SUCCESS;
+    }
+  while (result != SUCCESS);
 
-       et = neon_check_type (2, NS_NULL,
-                             N_EQK, N_S8 | N_S16 | N_U8 | N_U16 | N_32 | N_KEY);
-        logsize = neon_logbits (et.size);
-
-        constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v1),
-                    _(BAD_FPU));
-        constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_v1)
-                    && et.size != 32, _(BAD_FPU));
-        constraint (et.type == NT_invtype, _("bad type for scalar"));
-        constraint (x >= 64 / et.size, _("scalar index out of range"));
-
-        switch (et.size)
-          {
-          case 8:  abcdebits = (et.type == NT_signed) ? 0x08 : 0x18; break;
-          case 16: abcdebits = (et.type == NT_signed) ? 0x01 : 0x11; break;
-          case 32: abcdebits = 0x00; break;
-          default: ;
-          }
-
-        abcdebits |= x << logsize;
-        inst.instruction = 0xe100b10;
-        do_vfp_cond_or_thumb ();
-        inst.instruction |= LOW4 (dn) << 16;
-        inst.instruction |= HI1 (dn) << 7;
-        inst.instruction |= inst.operands[0].reg << 12;
-        inst.instruction |= (abcdebits & 3) << 5;
-        inst.instruction |= (abcdebits >> 2) << 21;
-      }
-      break;
+  va_end (ap);
 
-    case NS_RRD:  /* case 7 (fmrrd).  */
-      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v2),
-                  _(BAD_FPU));
+  if (result == SUCCESS)
+    *do_alignment = 1;
+  else
+    first_error (_("unsupported alignment for instruction"));
 
-      inst.instruction = 0xc500b10;
-      do_vfp_cond_or_thumb ();
-      inst.instruction |= inst.operands[0].reg << 12;
-      inst.instruction |= inst.operands[1].reg << 16;
-      inst.instruction |= LOW4 (inst.operands[2].reg);
-      inst.instruction |= HI1 (inst.operands[2].reg) << 5;
-      break;
+  return result;
+}
 
-    case NS_FF:  /* case 8 (fcpys).  */
-      do_vfp_nsyn_opcode ("fcpys");
-      break;
+static void
+do_neon_ld_st_lane (void)
+{
+  struct neon_type_el et = neon_check_type (1, NS_NULL, N_8 | N_16 | N_32);
+  int align_good, do_alignment = 0;
+  int logsize = neon_logbits (et.size);
+  int align = inst.operands[1].imm >> 8;
+  int n = (inst.instruction >> 8) & 3;
+  int max_el = 64 / et.size;
 
-    case NS_FI:  /* case 10 (fconsts).  */
-      ldconst = "fconsts";
-      encode_fconstd:
-      if (is_quarter_float (inst.operands[1].imm))
-        {
-          inst.operands[1].imm = neon_qfloat_bits (inst.operands[1].imm);
-          do_vfp_nsyn_opcode (ldconst);
-        }
-      else
-        first_error (_("immediate out of range"));
-      break;
+  if (et.type == NT_invtype)
+    return;
 
-    case NS_RF:  /* case 12 (fmrs).  */
-      do_vfp_nsyn_opcode ("fmrs");
+  constraint (NEON_REGLIST_LENGTH (inst.operands[0].imm) != n + 1,
+             _("bad list length"));
+  constraint (NEON_LANE (inst.operands[0].imm) >= max_el,
+             _("scalar index out of range"));
+  constraint (n != 0 && NEON_REG_STRIDE (inst.operands[0].imm) == 2
+             && et.size == 8,
+             _("stride of 2 unavailable when element size is 8"));
+
+  switch (n)
+    {
+    case 0:  /* VLD1 / VST1.  */
+      align_good = neon_alignment_bit (et.size, align, &do_alignment, 16, 16,
+                                      32, 32, -1);
+      if (align_good == FAIL)
+       return;
+      if (do_alignment)
+       {
+         unsigned alignbits = 0;
+         switch (et.size)
+           {
+           case 16: alignbits = 0x1; break;
+           case 32: alignbits = 0x3; break;
+           default: ;
+           }
+         inst.instruction |= alignbits << 4;
+       }
       break;
 
-    case NS_FR:  /* case 13 (fmsr).  */
-      do_vfp_nsyn_opcode ("fmsr");
+    case 1:  /* VLD2 / VST2.  */
+      align_good = neon_alignment_bit (et.size, align, &do_alignment, 8, 16,
+                     16, 32, 32, 64, -1);
+      if (align_good == FAIL)
+       return;
+      if (do_alignment)
+       inst.instruction |= 1 << 4;
       break;
 
-    /* The encoders for the fmrrs and fmsrr instructions expect three operands
-       (one of which is a list), but we have parsed four.  Do some fiddling to
-       make the operands what do_vfp_reg2_from_sp2 and do_vfp_sp2_from_reg2
-       expect.  */
-    case NS_RRFF:  /* case 14 (fmrrs).  */
-      constraint (inst.operands[3].reg != inst.operands[2].reg + 1,
-                  _("VFP registers must be adjacent"));
-      inst.operands[2].imm = 2;
-      memset (&inst.operands[3], '\0', sizeof (inst.operands[3]));
-      do_vfp_nsyn_opcode ("fmrrs");
+    case 2:  /* VLD3 / VST3.  */
+      constraint (inst.operands[1].immisalign,
+                 _("can't use alignment with this instruction"));
       break;
 
-    case NS_FFRR:  /* case 15 (fmsrr).  */
-      constraint (inst.operands[1].reg != inst.operands[0].reg + 1,
-                  _("VFP registers must be adjacent"));
-      inst.operands[1] = inst.operands[2];
-      inst.operands[2] = inst.operands[3];
-      inst.operands[0].imm = 2;
-      memset (&inst.operands[3], '\0', sizeof (inst.operands[3]));
-      do_vfp_nsyn_opcode ("fmsrr");
+    case 3:  /* VLD4 / VST4.  */
+      align_good = neon_alignment_bit (et.size, align, &do_alignment, 8, 32,
+                                      16, 64, 32, 64, 32, 128, -1);
+      if (align_good == FAIL)
+       return;
+      if (do_alignment)
+       {
+         unsigned alignbits = 0;
+         switch (et.size)
+           {
+           case 8:  alignbits = 0x1; break;
+           case 16: alignbits = 0x1; break;
+           case 32: alignbits = (align == 64) ? 0x1 : 0x2; break;
+           default: ;
+           }
+         inst.instruction |= alignbits << 4;
+       }
       break;
 
-    default:
-      abort ();
+    default: ;
     }
+
+  /* Reg stride of 2 is encoded in bit 5 when size==16, bit 6 when size==32.  */
+  if (n != 0 && NEON_REG_STRIDE (inst.operands[0].imm) == 2)
+    inst.instruction |= 1 << (4 + logsize);
+
+  inst.instruction |= NEON_LANE (inst.operands[0].imm) << (logsize + 5);
+  inst.instruction |= logsize << 10;
 }
 
+/* Encode single n-element structure to all lanes VLD<n> instructions.  */
+
 static void
-do_neon_rshift_round_imm (void)
+do_neon_ld_dup (void)
 {
-  enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
-  struct neon_type_el et = neon_check_type (2, rs, N_EQK, N_SU_ALL | N_KEY);
-  int imm = inst.operands[2].imm;
+  struct neon_type_el et = neon_check_type (1, NS_NULL, N_8 | N_16 | N_32);
+  int align_good, do_alignment = 0;
 
-  /* imm == 0 case is encoded as VMOV for V{R}SHR.  */
-  if (imm == 0)
+  if (et.type == NT_invtype)
+    return;
+
+  switch ((inst.instruction >> 8) & 3)
     {
-      inst.operands[2].present = 0;
-      do_neon_mov ();
-      return;
-    }
+    case 0:  /* VLD1.  */
+      gas_assert (NEON_REG_STRIDE (inst.operands[0].imm) != 2);
+      align_good = neon_alignment_bit (et.size, inst.operands[1].imm >> 8,
+                                      &do_alignment, 16, 16, 32, 32, -1);
+      if (align_good == FAIL)
+       return;
+      switch (NEON_REGLIST_LENGTH (inst.operands[0].imm))
+       {
+       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;
 
-  constraint (imm < 1 || (unsigned)imm > et.size,
-              _("immediate out of range for shift"));
-  neon_imm_shift (TRUE, et.type == NT_unsigned, neon_quad (rs), et,
-                  et.size - imm);
-}
+    case 1:  /* VLD2.  */
+      align_good = neon_alignment_bit (et.size, inst.operands[1].imm >> 8,
+                                      &do_alignment, 8, 16, 16, 32, 32, 64,
+                                      -1);
+      if (align_good == FAIL)
+       return;
+      constraint (NEON_REGLIST_LENGTH (inst.operands[0].imm) != 2,
+                 _("bad list length"));
+      if (NEON_REG_STRIDE (inst.operands[0].imm) == 2)
+       inst.instruction |= 1 << 5;
+      inst.instruction |= neon_logbits (et.size) << 6;
+      break;
 
-static void
-do_neon_movl (void)
-{
-  struct neon_type_el et = neon_check_type (2, NS_QD,
-    N_EQK | N_DBL, N_SU_32 | N_KEY);
-  unsigned sizebits = et.size >> 3;
-  inst.instruction |= sizebits << 19;
-  neon_two_same (0, et.type == NT_unsigned, -1);
-}
+    case 2:  /* VLD3.  */
+      constraint (inst.operands[1].immisalign,
+                 _("can't use alignment with this instruction"));
+      constraint (NEON_REGLIST_LENGTH (inst.operands[0].imm) != 3,
+                 _("bad list length"));
+      if (NEON_REG_STRIDE (inst.operands[0].imm) == 2)
+       inst.instruction |= 1 << 5;
+      inst.instruction |= neon_logbits (et.size) << 6;
+      break;
 
-static void
-do_neon_trn (void)
-{
-  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
-  struct neon_type_el et = neon_check_type (2, rs,
-    N_EQK, N_8 | N_16 | N_32 | N_KEY);
-  NEON_ENCODE (INTEGER, inst);
-  neon_two_same (neon_quad (rs), 1, et.size);
-}
+    case 3:  /* VLD4.  */
+      {
+       int align = inst.operands[1].imm >> 8;
+       align_good = neon_alignment_bit (et.size, align, &do_alignment, 8, 32,
+                                        16, 64, 32, 64, 32, 128, -1);
+       if (align_good == FAIL)
+         return;
+       constraint (NEON_REGLIST_LENGTH (inst.operands[0].imm) != 4,
+                   _("bad list length"));
+       if (NEON_REG_STRIDE (inst.operands[0].imm) == 2)
+         inst.instruction |= 1 << 5;
+       if (et.size == 32 && align == 128)
+         inst.instruction |= 0x3 << 6;
+       else
+         inst.instruction |= neon_logbits (et.size) << 6;
+      }
+      break;
 
-static void
-do_neon_zip_uzp (void)
-{
-  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
-  struct neon_type_el et = neon_check_type (2, rs,
-    N_EQK, N_8 | N_16 | N_32 | N_KEY);
-  if (rs == NS_DD && et.size == 32)
-    {
-      /* Special case: encode as VTRN.32 <Dd>, <Dm>.  */
-      inst.instruction = N_MNEM_vtrn;
-      do_neon_trn ();
-      return;
+    default: ;
     }
-  neon_two_same (neon_quad (rs), 1, et.size);
-}
 
-static void
-do_neon_sat_abs_neg (void)
-{
-  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
-  struct neon_type_el et = neon_check_type (2, rs,
-    N_EQK, N_S8 | N_S16 | N_S32 | N_KEY);
-  neon_two_same (neon_quad (rs), 1, et.size);
+  inst.instruction |= do_alignment << 4;
 }
 
-static void
-do_neon_pair_long (void)
-{
-  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
-  struct neon_type_el et = neon_check_type (2, rs, N_EQK, N_SU_32 | N_KEY);
-  /* Unsigned is encoded in OP field (bit 7) for these instruction.  */
-  inst.instruction |= (et.type == NT_unsigned) << 7;
-  neon_two_same (neon_quad (rs), 1, et.size);
-}
+/* Disambiguate VLD<n> and VST<n> instructions, and fill in common bits (those
+   apart from bits [11:4].  */
 
 static void
-do_neon_recip_est (void)
+do_neon_ldx_stx (void)
 {
-  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
-  struct neon_type_el et = neon_check_type (2, rs,
-    N_EQK | N_FLT, N_F32 | N_U32 | N_KEY);
-  inst.instruction |= (et.type == NT_float) << 8;
-  neon_two_same (neon_quad (rs), 1, et.size);
-}
+  if (inst.operands[1].isreg)
+    constraint (inst.operands[1].reg == REG_PC, BAD_PC);
 
-static void
-do_neon_cls (void)
-{
-  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
-  struct neon_type_el et = neon_check_type (2, rs,
-    N_EQK, N_S8 | N_S16 | N_S32 | N_KEY);
-  neon_two_same (neon_quad (rs), 1, et.size);
-}
+  switch (NEON_LANE (inst.operands[0].imm))
+    {
+    case NEON_INTERLEAVE_LANES:
+      NEON_ENCODE (INTERLV, inst);
+      do_neon_ld_st_interleave ();
+      break;
+
+    case NEON_ALL_LANES:
+      NEON_ENCODE (DUP, inst);
+      if (inst.instruction == N_INV)
+       {
+         first_error ("only loads support such operands");
+         break;
+       }
+      do_neon_ld_dup ();
+      break;
+
+    default:
+      NEON_ENCODE (LANE, inst);
+      do_neon_ld_st_lane ();
+    }
+
+  /* L bit comes from bit mask.  */
+  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
+  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
+  inst.instruction |= inst.operands[1].reg << 16;
 
-static void
-do_neon_clz (void)
-{
-  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
-  struct neon_type_el et = neon_check_type (2, rs,
-    N_EQK, N_I8 | N_I16 | N_I32 | N_KEY);
-  neon_two_same (neon_quad (rs), 1, et.size);
-}
+  if (inst.operands[1].postind)
+    {
+      int postreg = inst.operands[1].imm & 0xf;
+      constraint (!inst.operands[1].immisreg,
+                 _("post-index must be a register"));
+      constraint (postreg == 0xd || postreg == 0xf,
+                 _("bad register for post-index"));
+      inst.instruction |= postreg;
+    }
+  else
+    {
+      constraint (inst.operands[1].immisreg, BAD_ADDR_MODE);
+      constraint (inst.reloc.exp.X_op != O_constant
+                 || inst.reloc.exp.X_add_number != 0,
+                 BAD_ADDR_MODE);
 
-static void
-do_neon_cnt (void)
-{
-  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
-  struct neon_type_el et = neon_check_type (2, rs,
-    N_EQK | N_INT, N_8 | N_KEY);
-  neon_two_same (neon_quad (rs), 1, et.size);
-}
+      if (inst.operands[1].writeback)
+       {
+         inst.instruction |= 0xd;
+       }
+      else
+       inst.instruction |= 0xf;
+    }
 
-static void
-do_neon_swp (void)
-{
-  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
-  neon_two_same (neon_quad (rs), 1, -1);
+  if (thumb_mode)
+    inst.instruction |= 0xf9000000;
+  else
+    inst.instruction |= 0xf4000000;
 }
 
+/* FP v8.  */
 static void
-do_neon_tbl_tbx (void)
+do_vfp_nsyn_fpv8 (enum neon_shape rs)
 {
-  unsigned listlenbits;
-  neon_check_type (3, NS_DLD, N_EQK, N_EQK, N_8 | N_KEY);
+  /* Targets like FPv5-SP-D16 don't support FP v8 instructions with
+     D register operands.  */
+  if (neon_shape_class[rs] == SC_DOUBLE)
+    constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_armv8),
+               _(BAD_FPU));
 
-  if (inst.operands[1].imm < 1 || inst.operands[1].imm > 4)
+  NEON_ENCODE (FPV8, inst);
+
+  if (rs == NS_FFF || rs == NS_HHH)
     {
-      first_error (_("bad list length for table lookup"));
-      return;
+      do_vfp_sp_dyadic ();
+
+      /* ARMv8.2 fp16 instruction.  */
+      if (rs == NS_HHH)
+       do_scalar_fp16_v82_encode ();
     }
+  else
+    do_vfp_dp_rd_rn_rm ();
 
-  listlenbits = inst.operands[1].imm - 1;
-  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
-  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
-  inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
-  inst.instruction |= HI1 (inst.operands[1].reg) << 7;
-  inst.instruction |= LOW4 (inst.operands[2].reg);
-  inst.instruction |= HI1 (inst.operands[2].reg) << 5;
-  inst.instruction |= listlenbits << 8;
+  if (rs == NS_DDD)
+    inst.instruction |= 0x100;
 
-  neon_dp_fixup (&inst);
+  inst.instruction |= 0xf0000000;
 }
 
 static void
-do_neon_ldm_stm (void)
+do_vsel (void)
 {
-  /* P, U and L bits are part of bitmask.  */
-  int is_dbmode = (inst.instruction & (1 << 24)) != 0;
-  unsigned offsetbits = inst.operands[1].imm * 2;
-
-  if (inst.operands[1].issingle)
-    {
-      do_vfp_nsyn_ldm_stm (is_dbmode);
-      return;
-    }
+  set_it_insn_type (OUTSIDE_IT_INSN);
 
-  constraint (is_dbmode && !inst.operands[0].writeback,
-              _("writeback (!) must be used for VLDMDB and VSTMDB"));
+  if (try_vfp_nsyn (3, do_vfp_nsyn_fpv8) != SUCCESS)
+    first_error (_("invalid instruction shape"));
+}
 
-  constraint (inst.operands[1].imm < 1 || inst.operands[1].imm > 16,
-              _("register list must contain at least 1 and at most 16 "
-                "registers"));
+static void
+do_vmaxnm (void)
+{
+  set_it_insn_type (OUTSIDE_IT_INSN);
 
-  inst.instruction |= inst.operands[0].reg << 16;
-  inst.instruction |= inst.operands[0].writeback << 21;
-  inst.instruction |= LOW4 (inst.operands[1].reg) << 12;
-  inst.instruction |= HI1 (inst.operands[1].reg) << 22;
+  if (try_vfp_nsyn (3, do_vfp_nsyn_fpv8) == SUCCESS)
+    return;
 
-  inst.instruction |= offsetbits;
+  if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH8) == FAIL)
+    return;
 
-  do_vfp_cond_or_thumb ();
+  neon_dyadic_misc (NT_untyped, N_F_16_32, 0);
 }
 
 static void
-do_neon_ldr_str (void)
+do_vrint_1 (enum neon_cvt_mode mode)
 {
-  int is_ldr = (inst.instruction & (1 << 20)) != 0;
+  enum neon_shape rs = neon_select_shape (NS_HH, NS_FF, NS_DD, NS_QQ, NS_NULL);
+  struct neon_type_el et;
 
-  /* Use of PC in vstr in ARM mode is deprecated in ARMv7.
-     And is UNPREDICTABLE in thumb mode.  */
-  if (!is_ldr 
-      && inst.operands[1].reg == REG_PC
-      && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v7))
-    {
-      if (!thumb_mode && warn_on_deprecated)
-       as_warn (_("Use of PC here is deprecated"));
-      else
-       inst.error = _("Use of PC here is UNPREDICTABLE");
-    }
+  if (rs == NS_NULL)
+    return;
 
-  if (inst.operands[0].issingle)
+  /* Targets like FPv5-SP-D16 don't support FP v8 instructions with
+     D register operands.  */
+  if (neon_shape_class[rs] == SC_DOUBLE)
+    constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_armv8),
+               _(BAD_FPU));
+
+  et = neon_check_type (2, rs, N_EQK | N_VFP, N_F_ALL | N_KEY
+                       | N_VFP);
+  if (et.type != NT_invtype)
     {
-      if (is_ldr)
-        do_vfp_nsyn_opcode ("flds");
+      /* VFP encodings.  */
+      if (mode == neon_cvt_mode_a || mode == neon_cvt_mode_n
+         || mode == neon_cvt_mode_p || mode == neon_cvt_mode_m)
+       set_it_insn_type (OUTSIDE_IT_INSN);
+
+      NEON_ENCODE (FPV8, inst);
+      if (rs == NS_FF || rs == NS_HH)
+       do_vfp_sp_monadic ();
       else
-        do_vfp_nsyn_opcode ("fsts");
+       do_vfp_dp_rd_rm ();
+
+      switch (mode)
+       {
+       case neon_cvt_mode_r: inst.instruction |= 0x00000000; break;
+       case neon_cvt_mode_z: inst.instruction |= 0x00000080; break;
+       case neon_cvt_mode_x: inst.instruction |= 0x00010000; break;
+       case neon_cvt_mode_a: inst.instruction |= 0xf0000000; break;
+       case neon_cvt_mode_n: inst.instruction |= 0xf0010000; break;
+       case neon_cvt_mode_p: inst.instruction |= 0xf0020000; break;
+       case neon_cvt_mode_m: inst.instruction |= 0xf0030000; break;
+       default: abort ();
+       }
+
+      inst.instruction |= (rs == NS_DD) << 8;
+      do_vfp_cond_or_thumb ();
+
+      /* ARMv8.2 fp16 vrint instruction.  */
+      if (rs == NS_HH)
+      do_scalar_fp16_v82_encode ();
     }
   else
     {
-      if (is_ldr)
-        do_vfp_nsyn_opcode ("fldd");
-      else
-        do_vfp_nsyn_opcode ("fstd");
-    }
-}
+      /* Neon encodings (or something broken...).  */
+      inst.error = NULL;
+      et = neon_check_type (2, rs, N_EQK, N_F_16_32 | N_KEY);
 
-/* "interleave" version also handles non-interleaving register VLD1/VST1
-   instructions.  */
+      if (et.type == NT_invtype)
+       return;
 
-static void
-do_neon_ld_st_interleave (void)
-{
-  struct neon_type_el et = neon_check_type (1, NS_NULL,
-                                            N_8 | N_16 | N_32 | N_64);
-  unsigned alignbits = 0;
-  unsigned idx;
-  /* The bits in this table go:
-     0: register stride of one (0) or two (1)
-     1,2: register list length, minus one (1, 2, 3, 4).
-     3,4: <n> in instruction type, minus one (VLD<n> / VST<n>).
-     We use -1 for invalid entries.  */
-  const int typetable[] =
-    {
-      0x7,  -1, 0xa,  -1, 0x6,  -1, 0x2,  -1, /* VLD1 / VST1.  */
-       -1,  -1, 0x8, 0x9,  -1,  -1, 0x3,  -1, /* VLD2 / VST2.  */
-       -1,  -1,  -1,  -1, 0x4, 0x5,  -1,  -1, /* VLD3 / VST3.  */
-       -1,  -1,  -1,  -1,  -1,  -1, 0x0, 0x1  /* VLD4 / VST4.  */
-    };
-  int typebits;
+      set_it_insn_type (OUTSIDE_IT_INSN);
+      NEON_ENCODE (FLOAT, inst);
 
-  if (et.type == NT_invtype)
-    return;
+      if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH8) == FAIL)
+       return;
 
-  if (inst.operands[1].immisalign)
-    switch (inst.operands[1].imm >> 8)
-      {
-      case 64: alignbits = 1; break;
-      case 128:
-        if (NEON_REGLIST_LENGTH (inst.operands[0].imm) != 2
-           && NEON_REGLIST_LENGTH (inst.operands[0].imm) != 4)
-          goto bad_alignment;
-        alignbits = 2;
-        break;
-      case 256:
-        if (NEON_REGLIST_LENGTH (inst.operands[0].imm) != 4)
-          goto bad_alignment;
-        alignbits = 3;
-        break;
-      default:
-      bad_alignment:
-        first_error (_("bad alignment"));
-        return;
-      }
+      inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
+      inst.instruction |= HI1 (inst.operands[0].reg) << 22;
+      inst.instruction |= LOW4 (inst.operands[1].reg);
+      inst.instruction |= HI1 (inst.operands[1].reg) << 5;
+      inst.instruction |= neon_quad (rs) << 6;
+      /* Mask off the original size bits and reencode them.  */
+      inst.instruction = ((inst.instruction & 0xfff3ffff)
+                         | neon_logbits (et.size) << 18);
 
-  inst.instruction |= alignbits << 4;
-  inst.instruction |= neon_logbits (et.size) << 6;
+      switch (mode)
+       {
+       case neon_cvt_mode_z: inst.instruction |= 3 << 7; break;
+       case neon_cvt_mode_x: inst.instruction |= 1 << 7; break;
+       case neon_cvt_mode_a: inst.instruction |= 2 << 7; break;
+       case neon_cvt_mode_n: inst.instruction |= 0 << 7; break;
+       case neon_cvt_mode_p: inst.instruction |= 7 << 7; break;
+       case neon_cvt_mode_m: inst.instruction |= 5 << 7; break;
+       case neon_cvt_mode_r: inst.error = _("invalid rounding mode"); break;
+       default: abort ();
+       }
 
-  /* Bits [4:6] of the immediate in a list specifier encode register stride
-     (minus 1) in bit 4, and list length in bits [5:6]. We put the <n> of
-     VLD<n>/VST<n> in bits [9:8] of the initial bitmask. Suck it out here, look
-     up the right value for "type" in a table based on this value and the given
-     list style, then stick it back.  */
-  idx = ((inst.operands[0].imm >> 4) & 7)
-        | (((inst.instruction >> 8) & 3) << 3);
+      if (thumb_mode)
+       inst.instruction |= 0xfc000000;
+      else
+       inst.instruction |= 0xf0000000;
+    }
+}
 
-  typebits = typetable[idx];
+static void
+do_vrintx (void)
+{
+  do_vrint_1 (neon_cvt_mode_x);
+}
 
-  constraint (typebits == -1, _("bad list type for instruction"));
+static void
+do_vrintz (void)
+{
+  do_vrint_1 (neon_cvt_mode_z);
+}
 
-  inst.instruction &= ~0xf00;
-  inst.instruction |= typebits << 8;
+static void
+do_vrintr (void)
+{
+  do_vrint_1 (neon_cvt_mode_r);
 }
 
-/* Check alignment is valid for do_neon_ld_st_lane and do_neon_ld_dup.
-   *DO_ALIGN is set to 1 if the relevant alignment bit should be set, 0
-   otherwise. The variable arguments are a list of pairs of legal (size, align)
-   values, terminated with -1.  */
+static void
+do_vrinta (void)
+{
+  do_vrint_1 (neon_cvt_mode_a);
+}
 
-static int
-neon_alignment_bit (int size, int align, int *do_align, ...)
+static void
+do_vrintn (void)
 {
-  va_list ap;
-  int result = FAIL, thissize, thisalign;
+  do_vrint_1 (neon_cvt_mode_n);
+}
 
-  if (!inst.operands[1].immisalign)
-    {
-      *do_align = 0;
-      return SUCCESS;
-    }
+static void
+do_vrintp (void)
+{
+  do_vrint_1 (neon_cvt_mode_p);
+}
 
-  va_start (ap, do_align);
+static void
+do_vrintm (void)
+{
+  do_vrint_1 (neon_cvt_mode_m);
+}
 
-  do
-    {
-      thissize = va_arg (ap, int);
-      if (thissize == -1)
-        break;
-      thisalign = va_arg (ap, int);
+/* Crypto v1 instructions.  */
+static void
+do_crypto_2op_1 (unsigned elttype, int op)
+{
+  set_it_insn_type (OUTSIDE_IT_INSN);
 
-      if (size == thissize && align == thisalign)
-        result = SUCCESS;
-    }
-  while (result != SUCCESS);
+  if (neon_check_type (2, NS_QQ, N_EQK | N_UNT, elttype | N_UNT | N_KEY).type
+      == NT_invtype)
+    return;
 
-  va_end (ap);
+  inst.error = NULL;
 
-  if (result == SUCCESS)
-    *do_align = 1;
-  else
-    first_error (_("unsupported alignment for instruction"));
+  NEON_ENCODE (INTEGER, inst);
+  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
+  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
+  inst.instruction |= LOW4 (inst.operands[1].reg);
+  inst.instruction |= HI1 (inst.operands[1].reg) << 5;
+  if (op != -1)
+    inst.instruction |= op << 6;
 
-  return result;
+  if (thumb_mode)
+    inst.instruction |= 0xfc000000;
+  else
+    inst.instruction |= 0xf0000000;
 }
 
 static void
-do_neon_ld_st_lane (void)
+do_crypto_3op_1 (int u, int op)
 {
-  struct neon_type_el et = neon_check_type (1, NS_NULL, N_8 | N_16 | N_32);
-  int align_good, do_align = 0;
-  int logsize = neon_logbits (et.size);
-  int align = inst.operands[1].imm >> 8;
-  int n = (inst.instruction >> 8) & 3;
-  int max_el = 64 / et.size;
+  set_it_insn_type (OUTSIDE_IT_INSN);
 
-  if (et.type == NT_invtype)
+  if (neon_check_type (3, NS_QQQ, N_EQK | N_UNT, N_EQK | N_UNT,
+                      N_32 | N_UNT | N_KEY).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,
-              _("scalar index out of range"));
-  constraint (n != 0 && NEON_REG_STRIDE (inst.operands[0].imm) == 2
-              && et.size == 8,
-              _("stride of 2 unavailable when element size is 8"));
-
-  switch (n)
-    {
-    case 0:  /* VLD1 / VST1.  */
-      align_good = neon_alignment_bit (et.size, align, &do_align, 16, 16,
-                                       32, 32, -1);
-      if (align_good == FAIL)
-        return;
-      if (do_align)
-        {
-          unsigned alignbits = 0;
-          switch (et.size)
-            {
-            case 16: alignbits = 0x1; break;
-            case 32: alignbits = 0x3; break;
-            default: ;
-            }
-          inst.instruction |= alignbits << 4;
-        }
-      break;
-
-    case 1:  /* VLD2 / VST2.  */
-      align_good = neon_alignment_bit (et.size, align, &do_align, 8, 16, 16, 32,
-                                       32, 64, -1);
-      if (align_good == FAIL)
-        return;
-      if (do_align)
-        inst.instruction |= 1 << 4;
-      break;
-
-    case 2:  /* VLD3 / VST3.  */
-      constraint (inst.operands[1].immisalign,
-                  _("can't use alignment with this instruction"));
-      break;
+  inst.error = NULL;
 
-    case 3:  /* VLD4 / VST4.  */
-      align_good = neon_alignment_bit (et.size, align, &do_align, 8, 32,
-                                       16, 64, 32, 64, 32, 128, -1);
-      if (align_good == FAIL)
-        return;
-      if (do_align)
-        {
-          unsigned alignbits = 0;
-          switch (et.size)
-            {
-            case 8:  alignbits = 0x1; break;
-            case 16: alignbits = 0x1; break;
-            case 32: alignbits = (align == 64) ? 0x1 : 0x2; break;
-            default: ;
-            }
-          inst.instruction |= alignbits << 4;
-        }
-      break;
+  NEON_ENCODE (INTEGER, inst);
+  neon_three_same (1, u, 8 << op);
+}
 
-    default: ;
-    }
+static void
+do_aese (void)
+{
+  do_crypto_2op_1 (N_8, 0);
+}
 
-  /* Reg stride of 2 is encoded in bit 5 when size==16, bit 6 when size==32.  */
-  if (n != 0 && NEON_REG_STRIDE (inst.operands[0].imm) == 2)
-    inst.instruction |= 1 << (4 + logsize);
+static void
+do_aesd (void)
+{
+  do_crypto_2op_1 (N_8, 1);
+}
 
-  inst.instruction |= NEON_LANE (inst.operands[0].imm) << (logsize + 5);
-  inst.instruction |= logsize << 10;
+static void
+do_aesmc (void)
+{
+  do_crypto_2op_1 (N_8, 2);
 }
 
-/* Encode single n-element structure to all lanes VLD<n> instructions.  */
+static void
+do_aesimc (void)
+{
+  do_crypto_2op_1 (N_8, 3);
+}
 
 static void
-do_neon_ld_dup (void)
+do_sha1c (void)
 {
-  struct neon_type_el et = neon_check_type (1, NS_NULL, N_8 | N_16 | N_32);
-  int align_good, do_align = 0;
+  do_crypto_3op_1 (0, 0);
+}
 
-  if (et.type == NT_invtype)
-    return;
+static void
+do_sha1p (void)
+{
+  do_crypto_3op_1 (0, 1);
+}
 
-  switch ((inst.instruction >> 8) & 3)
-    {
-    case 0:  /* VLD1.  */
-      gas_assert (NEON_REG_STRIDE (inst.operands[0].imm) != 2);
-      align_good = neon_alignment_bit (et.size, inst.operands[1].imm >> 8,
-                                       &do_align, 16, 16, 32, 32, -1);
-      if (align_good == FAIL)
-        return;
-      switch (NEON_REGLIST_LENGTH (inst.operands[0].imm))
-        {
-        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;
+static void
+do_sha1m (void)
+{
+  do_crypto_3op_1 (0, 2);
+}
 
-    case 1:  /* VLD2.  */
-      align_good = neon_alignment_bit (et.size, inst.operands[1].imm >> 8,
-                                       &do_align, 8, 16, 16, 32, 32, 64, -1);
-      if (align_good == FAIL)
-        return;
-      constraint (NEON_REGLIST_LENGTH (inst.operands[0].imm) != 2,
-                  _("bad list length"));
-      if (NEON_REG_STRIDE (inst.operands[0].imm) == 2)
-        inst.instruction |= 1 << 5;
-      inst.instruction |= neon_logbits (et.size) << 6;
-      break;
+static void
+do_sha1su0 (void)
+{
+  do_crypto_3op_1 (0, 3);
+}
 
-    case 2:  /* VLD3.  */
-      constraint (inst.operands[1].immisalign,
-                  _("can't use alignment with this instruction"));
-      constraint (NEON_REGLIST_LENGTH (inst.operands[0].imm) != 3,
-                  _("bad list length"));
-      if (NEON_REG_STRIDE (inst.operands[0].imm) == 2)
-        inst.instruction |= 1 << 5;
-      inst.instruction |= neon_logbits (et.size) << 6;
-      break;
+static void
+do_sha256h (void)
+{
+  do_crypto_3op_1 (1, 0);
+}
 
-    case 3:  /* VLD4.  */
-      {
-        int align = inst.operands[1].imm >> 8;
-        align_good = neon_alignment_bit (et.size, align, &do_align, 8, 32,
-                                         16, 64, 32, 64, 32, 128, -1);
-        if (align_good == FAIL)
-          return;
-        constraint (NEON_REGLIST_LENGTH (inst.operands[0].imm) != 4,
-                    _("bad list length"));
-        if (NEON_REG_STRIDE (inst.operands[0].imm) == 2)
-          inst.instruction |= 1 << 5;
-        if (et.size == 32 && align == 128)
-          inst.instruction |= 0x3 << 6;
-        else
-          inst.instruction |= neon_logbits (et.size) << 6;
-      }
-      break;
+static void
+do_sha256h2 (void)
+{
+  do_crypto_3op_1 (1, 1);
+}
 
-    default: ;
-    }
+static void
+do_sha256su1 (void)
+{
+  do_crypto_3op_1 (1, 2);
+}
 
-  inst.instruction |= do_align << 4;
+static void
+do_sha1h (void)
+{
+  do_crypto_2op_1 (N_32, -1);
 }
 
-/* Disambiguate VLD<n> and VST<n> instructions, and fill in common bits (those
-   apart from bits [11:4].  */
+static void
+do_sha1su1 (void)
+{
+  do_crypto_2op_1 (N_32, 0);
+}
 
 static void
-do_neon_ldx_stx (void)
+do_sha256su0 (void)
 {
-  if (inst.operands[1].isreg)
-    constraint (inst.operands[1].reg == REG_PC, BAD_PC);
+  do_crypto_2op_1 (N_32, 1);
+}
 
-  switch (NEON_LANE (inst.operands[0].imm))
-    {
-    case NEON_INTERLEAVE_LANES:
-      NEON_ENCODE (INTERLV, inst);
-      do_neon_ld_st_interleave ();
-      break;
+static void
+do_crc32_1 (unsigned int poly, unsigned int sz)
+{
+  unsigned int Rd = inst.operands[0].reg;
+  unsigned int Rn = inst.operands[1].reg;
+  unsigned int Rm = inst.operands[2].reg;
 
-    case NEON_ALL_LANES:
-      NEON_ENCODE (DUP, inst);
-      do_neon_ld_dup ();
-      break;
+  set_it_insn_type (OUTSIDE_IT_INSN);
+  inst.instruction |= LOW4 (Rd) << (thumb_mode ? 8 : 12);
+  inst.instruction |= LOW4 (Rn) << 16;
+  inst.instruction |= LOW4 (Rm);
+  inst.instruction |= sz << (thumb_mode ? 4 : 21);
+  inst.instruction |= poly << (thumb_mode ? 20 : 9);
 
-    default:
-      NEON_ENCODE (LANE, inst);
-      do_neon_ld_st_lane ();
-    }
+  if (Rd == REG_PC || Rn == REG_PC || Rm == REG_PC)
+    as_warn (UNPRED_REG ("r15"));
+  if (thumb_mode && (Rd == REG_SP || Rn == REG_SP || Rm == REG_SP))
+    as_warn (UNPRED_REG ("r13"));
+}
 
-  /* L bit comes from bit mask.  */
-  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
-  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
-  inst.instruction |= inst.operands[1].reg << 16;
+static void
+do_crc32b (void)
+{
+  do_crc32_1 (0, 0);
+}
 
-  if (inst.operands[1].postind)
-    {
-      int postreg = inst.operands[1].imm & 0xf;
-      constraint (!inst.operands[1].immisreg,
-                  _("post-index must be a register"));
-      constraint (postreg == 0xd || postreg == 0xf,
-                  _("bad register for post-index"));
-      inst.instruction |= postreg;
-    }
-  else if (inst.operands[1].writeback)
-    {
-      inst.instruction |= 0xd;
-    }
-  else
-    inst.instruction |= 0xf;
+static void
+do_crc32h (void)
+{
+  do_crc32_1 (0, 1);
+}
 
-  if (thumb_mode)
-    inst.instruction |= 0xf9000000;
-  else
-    inst.instruction |= 0xf4000000;
+static void
+do_crc32w (void)
+{
+  do_crc32_1 (0, 2);
+}
+
+static void
+do_crc32cb (void)
+{
+  do_crc32_1 (1, 0);
+}
+
+static void
+do_crc32ch (void)
+{
+  do_crc32_1 (1, 1);
+}
+
+static void
+do_crc32cw (void)
+{
+  do_crc32_1 (1, 2);
 }
+
 \f
 /* Overall per-instruction processing. */
 
@@ -15410,16 +17402,39 @@ fix_new_arm (fragS *     frag,
   switch (exp->X_op)
     {
     case O_constant:
+      if (pc_rel)
+       {
+         /* Create an absolute valued symbol, so we have something to
+            refer to in the object file.  Unfortunately for us, gas's
+            generic expression parsing will already have folded out
+            any use of .set foo/.type foo %function that may have
+            been used to set type information of the target location,
+            that's being specified symbolically.  We have to presume
+            the user knows what they are doing.  */
+         char name[16 + 8];
+         symbolS *symbol;
+
+         sprintf (name, "*ABS*0x%lx", (unsigned long)exp->X_add_number);
+
+         symbol = symbol_find_or_make (name);
+         S_SET_SEGMENT (symbol, absolute_section);
+         symbol_set_frag (symbol, &zero_address_frag);
+         S_SET_VALUE (symbol, exp->X_add_number);
+         exp->X_op = O_symbol;
+         exp->X_add_symbol = symbol;
+         exp->X_add_number = 0;
+       }
+      /* FALLTHROUGH */
     case O_symbol:
     case O_add:
     case O_subtract:
       new_fix = fix_new_exp (frag, where, size, exp, pc_rel,
-                             (enum bfd_reloc_code_real) reloc);
+                            (enum bfd_reloc_code_real) reloc);
       break;
 
     default:
       new_fix = (fixS *) fix_new (frag, where, size, make_expr_symbol (exp), 0,
-                                  pc_rel, (enum bfd_reloc_code_real) reloc);
+                                 pc_rel, (enum bfd_reloc_code_real) reloc);
       break;
     }
 
@@ -15546,8 +17561,8 @@ enum opcode_tag
                           and carries 0xF in its ARM condition field.  */
   OT_csuffix,          /* Instruction takes a conditional suffix.  */
   OT_csuffixF,         /* Some forms of the instruction take a conditional
-                           suffix, others place 0xF where the condition field
-                           would be.  */
+                          suffix, others place 0xF where the condition field
+                          would be.  */
   OT_cinfix3,          /* Instruction takes a conditional infix,
                           beginning at character index 3.  (In
                           unified mode, it becomes a suffix.)  */
@@ -15647,13 +17662,13 @@ opcode_lookup (char **str)
       int offset = 2;
 
       /* The .w and .n suffixes are only valid if the unified syntax is in
-         use.  */
+        use.  */
       if (unified_syntax && end[1] == 'w')
        inst.size_req = 4;
       else if (unified_syntax && end[1] == 'n')
        inst.size_req = 2;
       else
-        offset = 0;
+       offset = 0;
 
       inst.vectype.elems = 0;
 
@@ -15662,19 +17677,19 @@ opcode_lookup (char **str)
       if (end[offset] == '.')
        {
          /* See if we have a Neon type suffix (possible in either unified or
-             non-unified ARM syntax mode).  */
-          if (parse_neon_type (&inst.vectype, str) == FAIL)
+            non-unified ARM syntax mode).  */
+         if (parse_neon_type (&inst.vectype, str) == FAIL)
            return NULL;
-        }
+       }
       else if (end[offset] != '\0' && end[offset] != ' ')
-        return NULL;
+       return NULL;
     }
   else
     *str = end;
 
   /* Look for unaffixed or special-case affixed mnemonic.  */
   opcode = (const struct asm_opcode *) hash_find_n (arm_ops_hsh, base,
-                                                    end - base);
+                                                   end - base);
   if (opcode)
     {
       /* step U */
@@ -15685,7 +17700,7 @@ opcode_lookup (char **str)
        }
 
       if (warn_on_deprecated && unified_syntax)
-       as_warn (_("conditional infixes are deprecated in unified syntax"));
+       as_tsktsk (_("conditional infixes are deprecated in unified syntax"));
       affix = base + (opcode->tag - OT_odd_infix_0);
       cond = (const struct asm_cond *) hash_find_n (arm_cond_hsh, affix, 2);
       gas_assert (cond);
@@ -15703,7 +17718,7 @@ opcode_lookup (char **str)
   affix = end - 2;
   cond = (const struct asm_cond *) hash_find_n (arm_cond_hsh, affix, 2);
   opcode = (const struct asm_opcode *) hash_find_n (arm_ops_hsh, base,
-                                                    affix - base);
+                                                   affix - base);
   if (opcode && cond)
     {
       /* step CE */
@@ -15721,7 +17736,7 @@ opcode_lookup (char **str)
          /* else fall through */
 
        case OT_csuffix:
-        case OT_csuffixF:
+       case OT_csuffixF:
        case OT_csuf_or_in3:
          inst.cond = cond->value;
          return opcode;
@@ -15757,7 +17772,7 @@ opcode_lookup (char **str)
   memcpy (save, affix, 2);
   memmove (affix, affix + 2, (end - affix) - 2);
   opcode = (const struct asm_opcode *) hash_find_n (arm_ops_hsh, base,
-                                                    (end - base) - 2);
+                                                   (end - base) - 2);
   memmove (affix + 2, affix, (end - affix) - 2);
   memcpy (affix, save, 2);
 
@@ -15771,7 +17786,7 @@ opcode_lookup (char **str)
       if (warn_on_deprecated && unified_syntax
          && (opcode->tag == OT_cinfix3
              || opcode->tag == OT_cinfix3_deprecated))
-       as_warn (_("conditional infixes are deprecated in unified syntax"));
+       as_tsktsk (_("conditional infixes are deprecated in unified syntax"));
 
       inst.cond = cond->value;
       return opcode;
@@ -15797,6 +17812,8 @@ new_automatic_it_block (int cond)
   now_it.block_length = 1;
   mapping_state (MAP_THUMB);
   now_it.insn = output_it_inst (cond, now_it.mask, NULL);
+  now_it.warn_deprecated = FALSE;
+  now_it.insn_cond = TRUE;
 }
 
 /* Close an automatic IT block.
@@ -15817,16 +17834,16 @@ now_it_add_mask (int cond)
 {
 #define CLEAR_BIT(value, nbit)  ((value) & ~(1 << (nbit)))
 #define SET_BIT_VALUE(value, bitvalue, nbit)  (CLEAR_BIT (value, nbit) \
-                                              | ((bitvalue) << (nbit)))
+                                             | ((bitvalue) << (nbit)))
   const int resulting_bit = (cond & 1);
 
   now_it.mask &= 0xf;
   now_it.mask = SET_BIT_VALUE (now_it.mask,
-                                   resulting_bit,
-                                  (5 - now_it.block_length));
+                                  resulting_bit,
+                                 (5 - now_it.block_length));
   now_it.mask = SET_BIT_VALUE (now_it.mask,
-                                   1,
-                                   ((5 - now_it.block_length) - 1) );
+                                  1,
+                                  ((5 - now_it.block_length) - 1) );
   output_it_inst (now_it.cc, now_it.mask, now_it.insn);
 
 #undef CLEAR_BIT
@@ -15843,49 +17860,49 @@ now_it_add_mask (int cond)
 
    Rationale:
      1) md_assemble () calls it_fsm_pre_encode () before calling tencode (),
-        initializing the IT insn type with a generic initial value depending
-        on the inst.condition.
+       initializing the IT insn type with a generic initial value depending
+       on the inst.condition.
      2) During the tencode function, two things may happen:
-        a) The tencode function overrides the IT insn type by
-           calling either set_it_insn_type (type) or set_it_insn_type_last ().
-        b) The tencode function queries the IT block state by
-           calling in_it_block () (i.e. to determine narrow/not narrow mode).
-
-        Both set_it_insn_type and in_it_block run the internal FSM state
-        handling function (handle_it_state), because: a) setting the IT insn
-        type may incur in an invalid state (exiting the function),
-        and b) querying the state requires the FSM to be updated.
-        Specifically we want to avoid creating an IT block for conditional
-        branches, so it_fsm_pre_encode is actually a guess and we can't
-        determine whether an IT block is required until the tencode () routine
-        has decided what type of instruction this actually it.
-        Because of this, if set_it_insn_type and in_it_block have to be used,
-        set_it_insn_type has to be called first.
-
-        set_it_insn_type_last () is a wrapper of set_it_insn_type (type), that
-        determines the insn IT type depending on the inst.cond code.
-        When a tencode () routine encodes an instruction that can be
-        either outside an IT block, or, in the case of being inside, has to be
-        the last one, set_it_insn_type_last () will determine the proper
-        IT instruction type based on the inst.cond code. Otherwise,
-        set_it_insn_type can be called for overriding that logic or
-        for covering other cases.
-
-        Calling handle_it_state () may not transition the IT block state to
-        OUTSIDE_IT_BLOCK immediatelly, since the (current) state could be
-        still queried. Instead, if the FSM determines that the state should
-        be transitioned to OUTSIDE_IT_BLOCK, a flag is marked to be closed
-        after the tencode () function: that's what it_fsm_post_encode () does.
-
-        Since in_it_block () calls the state handling function to get an
-        updated state, an error may occur (due to invalid insns combination).
-        In that case, inst.error is set.
-        Therefore, inst.error has to be checked after the execution of
-        the tencode () routine.
+       a) The tencode function overrides the IT insn type by
+          calling either set_it_insn_type (type) or set_it_insn_type_last ().
+       b) The tencode function queries the IT block state by
+          calling in_it_block () (i.e. to determine narrow/not narrow mode).
+
+       Both set_it_insn_type and in_it_block run the internal FSM state
+       handling function (handle_it_state), because: a) setting the IT insn
+       type may incur in an invalid state (exiting the function),
+       and b) querying the state requires the FSM to be updated.
+       Specifically we want to avoid creating an IT block for conditional
+       branches, so it_fsm_pre_encode is actually a guess and we can't
+       determine whether an IT block is required until the tencode () routine
+       has decided what type of instruction this actually it.
+       Because of this, if set_it_insn_type and in_it_block have to be used,
+       set_it_insn_type has to be called first.
+
+       set_it_insn_type_last () is a wrapper of set_it_insn_type (type), that
+       determines the insn IT type depending on the inst.cond code.
+       When a tencode () routine encodes an instruction that can be
+       either outside an IT block, or, in the case of being inside, has to be
+       the last one, set_it_insn_type_last () will determine the proper
+       IT instruction type based on the inst.cond code. Otherwise,
+       set_it_insn_type can be called for overriding that logic or
+       for covering other cases.
+
+       Calling handle_it_state () may not transition the IT block state to
+       OUTSIDE_IT_BLOCK immediatelly, since the (current) state could be
+       still queried. Instead, if the FSM determines that the state should
+       be transitioned to OUTSIDE_IT_BLOCK, a flag is marked to be closed
+       after the tencode () function: that's what it_fsm_post_encode () does.
+
+       Since in_it_block () calls the state handling function to get an
+       updated state, an error may occur (due to invalid insns combination).
+       In that case, inst.error is set.
+       Therefore, inst.error has to be checked after the execution of
+       the tencode () routine.
 
      3) Back in md_assemble(), it_fsm_post_encode () is called to commit
-        any pending state change (if any) that didn't take place in
-        handle_it_state () as explained above.  */
+       any pending state change (if any) that didn't take place in
+       handle_it_state () as explained above.  */
 
 static void
 it_fsm_pre_encode (void)
@@ -15904,6 +17921,7 @@ static int
 handle_it_state (void)
 {
   now_it.state_handled = 1;
+  now_it.insn_cond = FALSE;
 
   switch (now_it.state)
     {
@@ -15925,7 +17943,7 @@ handle_it_state (void)
          else
            {
              if ((implicit_it_mode & IMPLICIT_IT_MODE_THUMB)
-                 && ARM_CPU_HAS_FEATURE (cpu_variant, arm_arch_t2))
+                 && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6t2))
                {
                  /* Automatically generate the IT instruction.  */
                  new_automatic_it_block (inst.cond);
@@ -15981,6 +17999,7 @@ handle_it_state (void)
            }
          else
            {
+             now_it.insn_cond = TRUE;
              now_it_add_mask (inst.cond);
            }
 
@@ -15992,6 +18011,7 @@ handle_it_state (void)
 
        case NEUTRAL_IT_INSN:
          now_it.block_length++;
+         now_it.insn_cond = TRUE;
 
          if (now_it.block_length > 4)
            force_automatic_it_block_close ();
@@ -16014,6 +18034,7 @@ handle_it_state (void)
        now_it.mask <<= 1;
        now_it.mask &= 0x1f;
        is_last = (now_it.mask == 0x10);
+       now_it.insn_cond = TRUE;
 
        switch (inst.it_insn_type)
          {
@@ -16058,6 +18079,28 @@ handle_it_state (void)
   return SUCCESS;
 }
 
+struct depr_insn_mask
+{
+  unsigned long pattern;
+  unsigned long mask;
+  const char* description;
+};
+
+/* List of 16-bit instruction patterns deprecated in an IT block in
+   ARMv8.  */
+static const struct depr_insn_mask depr_it_insns[] = {
+  { 0xc000, 0xc000, N_("Short branches, Undefined, SVC, LDM/STM") },
+  { 0xb000, 0xb000, N_("Miscellaneous 16-bit instructions") },
+  { 0xa000, 0xb800, N_("ADR") },
+  { 0x4800, 0xf800, N_("Literal loads") },
+  { 0x4478, 0xf478, N_("Hi-register ADD, MOV, CMP, BX, BLX using pc") },
+  { 0x4487, 0xfc87, N_("Hi-register ADD, MOV, CMP using pc") },
+  /* NOTE: 0x00dd is not the real encoding, instead, it is the 'tvalue'
+     field in asm_opcode. 'tvalue' is used at the stage this check happen.  */
+  { 0x00dd, 0x7fff, N_("ADD/SUB sp, sp #imm") },
+  { 0, 0, NULL }
+};
+
 static void
 it_fsm_post_encode (void)
 {
@@ -16066,6 +18109,44 @@ it_fsm_post_encode (void)
   if (!now_it.state_handled)
     handle_it_state ();
 
+  if (now_it.insn_cond
+      && !now_it.warn_deprecated
+      && warn_on_deprecated
+      && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v8))
+    {
+      if (inst.instruction >= 0x10000)
+       {
+         as_tsktsk (_("IT blocks containing 32-bit Thumb instructions are "
+                    "deprecated in ARMv8"));
+         now_it.warn_deprecated = TRUE;
+       }
+      else
+       {
+         const struct depr_insn_mask *p = depr_it_insns;
+
+         while (p->mask != 0)
+           {
+             if ((inst.instruction & p->mask) == p->pattern)
+               {
+                 as_tsktsk (_("IT blocks containing 16-bit Thumb instructions "
+                            "of the following class are deprecated in ARMv8: "
+                            "%s"), p->description);
+                 now_it.warn_deprecated = TRUE;
+                 break;
+               }
+
+             ++p;
+           }
+       }
+
+      if (now_it.block_length > 1)
+       {
+         as_tsktsk (_("IT blocks containing more than one conditional "
+                    "instruction are deprecated in ARMv8"));
+         now_it.warn_deprecated = TRUE;
+       }
+    }
+
   is_last = (now_it.mask == 0x10);
   if (is_last)
     {
@@ -16094,6 +18175,56 @@ in_it_block (void)
   return now_it.state != OUTSIDE_IT_BLOCK;
 }
 
+/* Whether OPCODE only has T32 encoding.  Since this function is only used by
+   t32_insn_ok, OPCODE enabled by v6t2 extension bit do not need to be listed
+   here, hence the "known" in the function name.  */
+
+static bfd_boolean
+known_t32_only_insn (const struct asm_opcode *opcode)
+{
+  /* Original Thumb-1 wide instruction.  */
+  if (opcode->tencode == do_t_blx
+      || opcode->tencode == do_t_branch23
+      || ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_msr)
+      || ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_barrier))
+    return TRUE;
+
+  /* Wide-only instruction added to ARMv8-M.  */
+  if (ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_v8m)
+      || ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_atomics)
+      || ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_v6t2_v8m)
+      || ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_div))
+    return TRUE;
+
+  return FALSE;
+}
+
+/* Whether wide instruction variant can be used if available for a valid OPCODE
+   in ARCH.  */
+
+static bfd_boolean
+t32_insn_ok (arm_feature_set arch, const struct asm_opcode *opcode)
+{
+  if (known_t32_only_insn (opcode))
+    return TRUE;
+
+  /* Instruction with narrow and wide encoding added to ARMv8-M.  Availability
+     of variant T3 of B.W is checked in do_t_branch.  */
+  if (ARM_CPU_HAS_FEATURE (arch, arm_ext_v8m)
+      && opcode->tencode == do_t_branch)
+    return TRUE;
+
+  /* Wide instruction variants of all instructions with narrow *and* wide
+     variants become available with ARMv6t2.  Other opcodes are either
+     narrow-only or wide-only and are thus available if OPCODE is valid.  */
+  if (ARM_CPU_HAS_FEATURE (arch, arm_ext_v6t2))
+    return TRUE;
+
+  /* OPCODE with narrow only instruction variant or wide variant not
+     available.  */
+  return FALSE;
+}
+
 void
 md_assemble (char *str)
 {
@@ -16117,14 +18248,14 @@ md_assemble (char *str)
       /* 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))
+         && ! create_neon_reg_alias (str, p))
        as_bad (_("bad instruction `%s'"), str);
 
       return;
     }
 
   if (warn_on_deprecated && opcode->tag == OT_cinfix3_deprecated)
-    as_warn (_("s suffix on comparison instruction is deprecated"));
+    as_tsktsk (_("s suffix on comparison instruction is deprecated"));
 
   /* The value which unconditional instructions should have in place of the
      condition field.  */
@@ -16143,7 +18274,7 @@ md_assemble (char *str)
          || (thumb_mode == 1
              && !ARM_CPU_HAS_FEATURE (variant, *opcode->tvariant)))
        {
-         as_bad (_("selected processor does not support Thumb mode `%s'"), str);
+         as_bad (_("selected processor does not support `%s' in Thumb mode"), str);
          return;
        }
       if (inst.cond != COND_ALWAYS && !unified_syntax
@@ -16153,39 +18284,43 @@ md_assemble (char *str)
          return;
        }
 
-      if (!ARM_CPU_HAS_FEATURE (variant, arm_ext_v6t2))
+      /* Two things are addressed here:
+        1) Implicit require narrow instructions on Thumb-1.
+           This avoids relaxation accidentally introducing Thumb-2
+           instructions.
+        2) Reject wide instructions in non Thumb-2 cores.
+
+        Only instructions with narrow and wide variants need to be handled
+        but selecting all non wide-only instructions is easier.  */
+      if (!ARM_CPU_HAS_FEATURE (variant, arm_ext_v6t2)
+         && !t32_insn_ok (variant, opcode))
        {
-         if (opcode->tencode != do_t_blx && opcode->tencode != do_t_branch23
-             && !(ARM_CPU_HAS_FEATURE(*opcode->tvariant, arm_ext_msr)
-                  || ARM_CPU_HAS_FEATURE(*opcode->tvariant, arm_ext_barrier)))
+         if (inst.size_req == 0)
+           inst.size_req = 2;
+         else if (inst.size_req == 4)
            {
-             /* Two things are addressed here.
-                1) Implicit require narrow instructions on Thumb-1.
-                   This avoids relaxation accidentally introducing Thumb-2
-                    instructions.
-                2) Reject wide instructions in non Thumb-2 cores.  */
-             if (inst.size_req == 0)
-               inst.size_req = 2;
-             else if (inst.size_req == 4)
-               {
-                 as_bad (_("selected processor does not support Thumb-2 mode `%s'"), str);
-                 return;
-               }
+             if (ARM_CPU_HAS_FEATURE (variant, arm_ext_v8m))
+               as_bad (_("selected processor does not support 32bit wide "
+                         "variant of instruction `%s'"), str);
+             else
+               as_bad (_("selected processor does not support `%s' in "
+                         "Thumb-2 mode"), str);
+             return;
            }
        }
 
       inst.instruction = opcode->tvalue;
 
       if (!parse_operands (p, opcode->operands, /*thumb=*/TRUE))
-        {
-          /* Prepare the it_insn_type for those encodings that don't set
-             it.  */
-          it_fsm_pre_encode ();
+       {
+         /* Prepare the it_insn_type for those encodings that don't set
+            it.  */
+         it_fsm_pre_encode ();
 
-          opcode->tencode ();
+         opcode->tencode ();
 
-          it_fsm_post_encode ();
-        }
+         it_fsm_post_encode ();
+       }
 
       if (!(inst.error || inst.relax))
        {
@@ -16199,19 +18334,20 @@ md_assemble (char *str)
        }
 
       /* Something has gone badly wrong if we try to relax a fixed size
-         instruction.  */
+        instruction.  */
       gas_assert (inst.size_req == 0 || !inst.relax);
 
       ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
                              *opcode->tvariant);
       /* Many Thumb-2 instructions also have Thumb-1 variants, so explicitly
-        set those bits when Thumb-2 32-bit instructions are seen.  ie.
-        anything other than bl/blx and v6-M instructions.
-        This is overly pessimistic for relaxable instructions.  */
-      if (((inst.size == 4 && (inst.instruction & 0xf800e800) != 0xf000e800)
-          || inst.relax)
-         && !(ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_msr)
-              || ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_barrier)))
+        set those bits when Thumb-2 32-bit instructions are seen.  The impact
+        of relaxable instructions will be considered later after we finish all
+        relaxation.  */
+      if (ARM_FEATURE_CORE_EQUAL (cpu_variant, arm_arch_any))
+       variant = arm_arch_none;
+      else
+       variant = cpu_variant;
+      if (inst.size == 4 && !t32_insn_ok (variant, opcode))
        ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
                                arm_ext_v6t2);
 
@@ -16234,7 +18370,7 @@ md_assemble (char *str)
          && !(opcode->avariant &&
               ARM_CPU_HAS_FEATURE (cpu_variant, *opcode->avariant)))
        {
-         as_bad (_("selected processor does not support ARM mode `%s'"), str);
+         as_bad (_("selected processor does not support `%s' in ARM mode"), str);
          return;
        }
       if (inst.size_req)
@@ -16245,18 +18381,18 @@ md_assemble (char *str)
 
       inst.instruction = opcode->avalue;
       if (opcode->tag == OT_unconditionalF)
-       inst.instruction |= 0xF << 28;
+       inst.instruction |= 0xFU << 28;
       else
        inst.instruction |= inst.cond << 28;
       inst.size = INSN_SIZE;
       if (!parse_operands (p, opcode->operands, /*thumb=*/FALSE))
-        {
-          it_fsm_pre_encode ();
-          opcode->aencode ();
-          it_fsm_post_encode ();
-        }
+       {
+         it_fsm_pre_encode ();
+         opcode->aencode ();
+         it_fsm_post_encode ();
+       }
       /* Arm mode bx is marked as both v4T and v5 because it's still required
-         on a hypothetical non-thumb v5 core.  */
+        on a hypothetical non-thumb v5 core.  */
       if (is_bx)
        ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used, arm_ext_v4t);
       else
@@ -16465,7 +18601,7 @@ static const struct reg_entry reg_names[] =
   REGDEF(R10_fiq,512|(10<<16),RNB), REGDEF(r10_fiq,512|(10<<16),RNB),
   REGDEF(R11_fiq,512|(11<<16),RNB), REGDEF(r11_fiq,512|(11<<16),RNB),
   REGDEF(R12_fiq,512|(12<<16),RNB), REGDEF(r12_fiq,512|(12<<16),RNB),
-  REGDEF(SP_fiq,512|(13<<16),RNB), REGDEF(SP_fiq,512|(13<<16),RNB),
+  REGDEF(SP_fiq,512|(13<<16),RNB), REGDEF(sp_fiq,512|(13<<16),RNB),
   REGDEF(LR_fiq,512|(14<<16),RNB), REGDEF(lr_fiq,512|(14<<16),RNB),
   REGDEF(SPSR_fiq,512|(14<<16)|SPSR_BIT,RNB), REGDEF(spsr_fiq,512|(14<<16)|SPSR_BIT,RNB),
 
@@ -16476,7 +18612,7 @@ static const struct reg_entry reg_names[] =
   SPLRBANK(12,MON,RNB), SPLRBANK(12,mon,RNB),
   REGDEF(elr_hyp,768|(14<<16),RNB), REGDEF(ELR_hyp,768|(14<<16),RNB),
   REGDEF(sp_hyp,768|(15<<16),RNB), REGDEF(SP_hyp,768|(15<<16),RNB),
-  REGDEF(spsr_hyp,768|(14<<16)|SPSR_BIT,RNB), 
+  REGDEF(spsr_hyp,768|(14<<16)|SPSR_BIT,RNB),
   REGDEF(SPSR_hyp,768|(14<<16)|SPSR_BIT,RNB),
 
   /* FPA registers.  */
@@ -16634,8 +18770,8 @@ static const struct asm_psr v7m_psrs[] =
   {"psp",        9 }, {"PSP",          9 },
   {"primask",    16}, {"PRIMASK",      16},
   {"basepri",    17}, {"BASEPRI",      17},
-  {"basepri_max", 18}, {"BASEPRI_MAX", 18}, /* Typo, preserved for backwards compatibility.  */
-  {"basepri_mask",18}, {"BASEPRI_MASK",        18},
+  {"basepri_max", 18}, {"BASEPRI_MAX", 18},
+  {"basepri_max", 18}, {"BASEPRI_MASK",        18}, /* Typo, preserved for backwards compatibility.  */
   {"faultmask",          19}, {"FAULTMASK",    19},
   {"control",    20}, {"CONTROL",      20}
 };
@@ -16668,11 +18804,11 @@ static struct reloc_entry reloc_names[] =
   { "tpoff",   BFD_RELOC_ARM_TLS_LE32},  { "TPOFF",   BFD_RELOC_ARM_TLS_LE32},
   { "got_prel", BFD_RELOC_ARM_GOT_PREL}, { "GOT_PREL", BFD_RELOC_ARM_GOT_PREL},
   { "tlsdesc", BFD_RELOC_ARM_TLS_GOTDESC},
-       { "TLSDESC", BFD_RELOC_ARM_TLS_GOTDESC},
+       { "TLSDESC", BFD_RELOC_ARM_TLS_GOTDESC},
   { "tlscall", BFD_RELOC_ARM_TLS_CALL},
-       { "TLSCALL", BFD_RELOC_ARM_TLS_CALL},
+       { "TLSCALL", BFD_RELOC_ARM_TLS_CALL},
   { "tlsdescseq", BFD_RELOC_ARM_TLS_DESCSEQ},
-       { "TLSDESCSEQ", BFD_RELOC_ARM_TLS_DESCSEQ}
+       { "TLSDESCSEQ", BFD_RELOC_ARM_TLS_DESCSEQ}
 };
 #endif
 
@@ -16696,22 +18832,32 @@ static const struct asm_cond conds[] =
   {"al", 0xe}
 };
 
+#define UL_BARRIER(L,U,CODE,FEAT) \
+  { L, CODE, ARM_FEATURE_CORE_LOW (FEAT) }, \
+  { U, CODE, ARM_FEATURE_CORE_LOW (FEAT) }
+
 static struct asm_barrier_opt barrier_opt_names[] =
 {
-  { "sy",    0xf }, { "SY",    0xf },
-  { "un",    0x7 }, { "UN",    0x7 },
-  { "st",    0xe }, { "ST",    0xe },
-  { "unst",  0x6 }, { "UNST",  0x6 },
-  { "ish",   0xb }, { "ISH",   0xb },
-  { "sh",    0xb }, { "SH",    0xb },
-  { "ishst", 0xa }, { "ISHST", 0xa },
-  { "shst",  0xa }, { "SHST",  0xa },
-  { "nsh",   0x7 }, { "NSH",   0x7 },
-  { "nshst", 0x6 }, { "NSHST", 0x6 },
-  { "osh",   0x3 }, { "OSH",   0x3 },
-  { "oshst", 0x2 }, { "OSHST", 0x2 }
+  UL_BARRIER ("sy",    "SY",    0xf, ARM_EXT_BARRIER),
+  UL_BARRIER ("st",    "ST",    0xe, ARM_EXT_BARRIER),
+  UL_BARRIER ("ld",    "LD",    0xd, ARM_EXT_V8),
+  UL_BARRIER ("ish",   "ISH",   0xb, ARM_EXT_BARRIER),
+  UL_BARRIER ("sh",    "SH",    0xb, ARM_EXT_BARRIER),
+  UL_BARRIER ("ishst", "ISHST", 0xa, ARM_EXT_BARRIER),
+  UL_BARRIER ("shst",  "SHST",  0xa, ARM_EXT_BARRIER),
+  UL_BARRIER ("ishld", "ISHLD", 0x9, ARM_EXT_V8),
+  UL_BARRIER ("un",    "UN",    0x7, ARM_EXT_BARRIER),
+  UL_BARRIER ("nsh",   "NSH",   0x7, ARM_EXT_BARRIER),
+  UL_BARRIER ("unst",  "UNST",  0x6, ARM_EXT_BARRIER),
+  UL_BARRIER ("nshst", "NSHST", 0x6, ARM_EXT_BARRIER),
+  UL_BARRIER ("nshld", "NSHLD", 0x5, ARM_EXT_V8),
+  UL_BARRIER ("osh",   "OSH",   0x3, ARM_EXT_BARRIER),
+  UL_BARRIER ("oshst", "OSHST", 0x2, ARM_EXT_BARRIER),
+  UL_BARRIER ("oshld", "OSHLD", 0x1, ARM_EXT_V8)
 };
 
+#undef UL_BARRIER
+
 /* Table of ARM-format instructions.   */
 
 /* Macros for gluing together operand strings.  N.B. In all cases
@@ -16769,38 +18915,6 @@ static struct asm_barrier_opt barrier_opt_names[] =
 #define tC3w(mnem, aop, top, nops, ops, ae, te) \
       TxC3w (mnem, aop, T_MNEM##top, nops, ops, ae, te)
 
-/* Mnemonic with a conditional infix in an unusual place.  Each and every variant has to
-   appear in the condition table.  */
-#define TxCM_(m1, m2, m3, op, top, nops, ops, ae, te)  \
-  { m1 #m2 m3, OPS##nops ops, sizeof (#m2) == 1 ? OT_odd_infix_unc : OT_odd_infix_0 + sizeof (m1) - 1, \
-    0x##op, top, ARM_VARIANT, THUMB_VARIANT, do_##ae, do_##te }
-
-#define TxCM(m1, m2, op, top, nops, ops, ae, te)       \
-  TxCM_ (m1,   , m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, eq, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, ne, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, cs, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, hs, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, cc, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, ul, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, lo, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, mi, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, pl, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, vs, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, vc, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, hi, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, ls, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, ge, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, lt, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, gt, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, le, m2, op, top, nops, ops, ae, te),      \
-  TxCM_ (m1, al, m2, op, top, nops, ops, ae, te)
-
-#define TCM(m1,m2, aop, top, nops, ops, ae, te)                \
-      TxCM (m1,m2, aop, 0x##top, nops, ops, ae, te)
-#define tCM(m1,m2, aop, top, nops, ops, ae, te)                \
-      TxCM (m1,m2, aop, T_MNEM##top, nops, ops, ae, te)
-
 /* Mnemonic that cannot be conditionalized.  The ARM condition-code
    field is still 0xE.  Many of the Thumb variants can be executed
    conditionally, so this is checked separately.  */
@@ -16808,6 +18922,13 @@ static struct asm_barrier_opt barrier_opt_names[] =
   { mnem, OPS##nops ops, OT_unconditional, 0x##op, 0x##top, ARM_VARIANT, \
     THUMB_VARIANT, do_##ae, do_##te }
 
+/* Same as TUE but the encoding function for ARM and Thumb modes is the same.
+   Used by mnemonics that have very minimal differences in the encoding for
+   ARM and Thumb variants and can be handled in a common function.  */
+#define TUEc(mnem, op, top, nops, ops, en) \
+  { mnem, OPS##nops ops, OT_unconditional, 0x##op, 0x##top, ARM_VARIANT, \
+    THUMB_VARIANT, do_##en, do_##en }
+
 /* Mnemonic that cannot be conditionalized, and bears 0xF in its ARM
    condition code field.  */
 #define TUF(mnem, op, top, nops, ops, ae, te)                          \
@@ -16916,8 +19037,8 @@ static struct asm_barrier_opt barrier_opt_names[] =
 
 static const struct asm_opcode insns[] =
 {
-#define ARM_VARIANT &arm_ext_v1 /* Core ARM Instructions.  */
-#define THUMB_VARIANT &arm_ext_v4t
+#define ARM_VARIANT    & arm_ext_v1 /* Core ARM Instructions.  */
+#define THUMB_VARIANT  & arm_ext_v4t
  tCE("and",    0000000, _and,     3, (RR, oRR, SH), arit, t_arit3c),
  tC3("ands",   0100000, _ands,    3, (RR, oRR, SH), arit, t_arit3c),
  tCE("eor",    0200000, _eor,     3, (RR, oRR, SH), arit, t_arit3c),
@@ -16949,7 +19070,7 @@ static const struct asm_opcode insns[] =
   CL("cmnp",   170f000,           2, (RR, SH),      cmp),
 
  tCE("mov",    1a00000, _mov,     2, (RR, SH),      mov,  t_mov_cmp),
- tC3("movs",   1b00000, _movs,    2, (RR, SH),      mov,  t_mov_cmp),
+ tC3("movs",   1b00000, _movs,    2, (RR, SHG),     mov,  t_mov_cmp),
  tCE("mvn",    1e00000, _mvn,     2, (RR, SH),      mov,  t_mvn_tst),
  tC3("mvns",   1f00000, _mvns,    2, (RR, SH),      mov,  t_mvn_tst),
 
@@ -16976,6 +19097,7 @@ static const struct asm_opcode insns[] =
  tCE("adr",    28f0000, _adr,     2, (RR, EXP),     adr,  t_adr),
   C3(adrl,     28f0000,           2, (RR, EXP),     adrl),
  tCE("nop",    1a00000, _nop,     1, (oI255c),      nop,  t_nop),
+ tCE("udf",    7f000f0, _udf,     1, (oIffffb),     bkpt, t_udf),
 
   /* Thumb-compatibility pseudo ops.  */
  tCE("lsl",    1a00000, _lsl,     3, (RR, oRR, SH), shift, t_shift),
@@ -17092,8 +19214,8 @@ static const struct asm_opcode insns[] =
  tC3("strh",   00000b0, _strh,     2, (RRnpc_npcsp, ADDRGLDRS), ldstv4, t_ldst),
  tC3("ldrsh",  01000f0, _ldrsh,    2, (RRnpc_npcsp, ADDRGLDRS), ldstv4, t_ldst),
  tC3("ldrsb",  01000d0, _ldrsb,    2, (RRnpc_npcsp, ADDRGLDRS), ldstv4, t_ldst),
- tCM("ld","sh",        01000f0, _ldrsh,    2, (RRnpc_npcsp, ADDRGLDRS), ldstv4, t_ldst),
- tCM("ld","sb",        01000d0, _ldrsb,    2, (RRnpc_npcsp, ADDRGLDRS), ldstv4, t_ldst),
+ tC3("ldsh",   01000f0, _ldrsh,    2, (RRnpc_npcsp, ADDRGLDRS), ldstv4, t_ldst),
+ tC3("ldsb",   01000d0, _ldrsb,    2, (RRnpc_npcsp, ADDRGLDRS), ldstv4, t_ldst),
 
 #undef  ARM_VARIANT
 #define ARM_VARIANT  & arm_ext_v4t_5
@@ -17126,9 +19248,9 @@ static const struct asm_opcode insns[] =
  TUF("mrc2",   e100010, fe100010, 6, (RCP, I7b, RR, RCN, RCN, oI7b),   co_reg, co_reg),
 
 #undef  ARM_VARIANT
-#define ARM_VARIANT  & arm_ext_v5exp /*  ARM Architecture 5TExP.  */
-#undef THUMB_VARIANT
-#define THUMB_VARIANT &arm_ext_v5exp
+#define ARM_VARIANT    & arm_ext_v5exp /*  ARM Architecture 5TExP.  */
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT  & arm_ext_v5exp
 
  TCE("smlabb", 1000080, fb100000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smla, t_mla),
  TCE("smlatb", 10000a0, fb100020, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smla, t_mla),
@@ -17157,9 +19279,9 @@ static const struct asm_opcode insns[] =
  TCE("qdsub",  1600050, fa80f0b0, 3, (RRnpc, RRnpc, RRnpc),        rd_rm_rn, t_simd2),
 
 #undef  ARM_VARIANT
-#define ARM_VARIANT  & arm_ext_v5e /*  ARM Architecture 5TE.  */
-#undef THUMB_VARIANT
-#define THUMB_VARIANT &arm_ext_v6t2
+#define ARM_VARIANT    & arm_ext_v5e /*  ARM Architecture 5TE.  */
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT  & arm_ext_v6t2
 
  TUF("pld",    450f000, f810f000, 1, (ADDR),                pld,  t_pld),
  TC3("ldrd",   00000d0, e8500000, 3, (RRnpc_npcsp, oRRnpc_npcsp, ADDRGLDRS),
@@ -17192,11 +19314,14 @@ static const struct asm_opcode insns[] =
  TUF("setend",    1010000, b650,     1, (ENDI),                     setend, t_setend),
 
 #undef  THUMB_VARIANT
-#define THUMB_VARIANT  & arm_ext_v6t2
+#define THUMB_VARIANT  & arm_ext_v6t2_v8m
 
  TCE("ldrex",  1900f9f, e8500f00, 2, (RRnpc_npcsp, ADDR),        ldrex, t_ldrex),
  TCE("strex",  1800f90, e8400000, 3, (RRnpc_npcsp, RRnpc_npcsp, ADDR),
                                      strex,  t_strex),
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT  & arm_ext_v6t2
+
  TUF("mcrr2",  c400000, fc400000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c),
  TUF("mrrc2",  c500000, fc500000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c),
 
@@ -17207,62 +19332,68 @@ static const struct asm_opcode insns[] =
 #undef  THUMB_VARIANT
 #define THUMB_VARIANT  & arm_ext_v6_notm
  TUF("rfeia",  8900a00, e990c000, 1, (RRw),                       rfe, rfe),
+ TUF("rfe",    8900a00, e990c000, 1, (RRw),                       rfe, rfe),
   UF(rfeib,    9900a00,           1, (RRw),                       rfe),
   UF(rfeda,    8100a00,           1, (RRw),                       rfe),
  TUF("rfedb",  9100a00, e810c000, 1, (RRw),                       rfe, rfe),
  TUF("rfefd",  8900a00, e990c000, 1, (RRw),                       rfe, rfe),
-  UF(rfefa,    9900a00,           1, (RRw),                       rfe),
 UF(rfeea,    8100a00,           1, (RRw),                       rfe),
TUF("rfeed",  9100a00, e810c000, 1, (RRw),                       rfe, rfe),
+  UF(rfefa,    8100a00,           1, (RRw),                       rfe),
TUF("rfeea",  9100a00, e810c000, 1, (RRw),                       rfe, rfe),
 UF(rfeed,    9900a00,           1, (RRw),                       rfe),
  TUF("srsia",  8c00500, e980c000, 2, (oRRw, I31w),                srs,  srs),
+ TUF("srs",    8c00500, e980c000, 2, (oRRw, I31w),                srs,  srs),
+ TUF("srsea",  8c00500, e980c000, 2, (oRRw, I31w),                srs,  srs),
   UF(srsib,    9c00500,           2, (oRRw, I31w),                srs),
+  UF(srsfa,    9c00500,           2, (oRRw, I31w),                srs),
   UF(srsda,    8400500,           2, (oRRw, I31w),                srs),
+  UF(srsed,    8400500,           2, (oRRw, I31w),                srs),
  TUF("srsdb",  9400500, e800c000, 2, (oRRw, I31w),                srs,  srs),
+ TUF("srsfd",  9400500, e800c000, 2, (oRRw, I31w),                srs,  srs),
+ TUF("cps",    1020000, f3af8100, 1, (I31b),                     imm0, t_cps),
 
 /*  ARM V6 not included in V7M (eg. integer SIMD).  */
 #undef  THUMB_VARIANT
 #define THUMB_VARIANT  & arm_ext_v6_dsp
- TUF("cps",    1020000, f3af8100, 1, (I31b),                     imm0, t_cps),
  TCE("pkhbt",  6800010, eac00000, 4, (RRnpc, RRnpc, RRnpc, oSHll),   pkhbt, t_pkhbt),
  TCE("pkhtb",  6800050, eac00020, 4, (RRnpc, RRnpc, RRnpc, oSHar),   pkhtb, t_pkhtb),
  TCE("qadd16", 6200f10, fa90f010, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
  TCE("qadd8",  6200f90, fa80f010, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
  TCE("qasx",   6200f30, faa0f010, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
  /* Old name for QASX.  */
- TCE("qaddsubx",       6200f30, faa0f010, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
+ TCE("qaddsubx",6200f30, faa0f010, 3, (RRnpc, RRnpc, RRnpc),      rd_rn_rm, t_simd),
  TCE("qsax",   6200f50, fae0f010, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
  /* Old name for QSAX.  */
- TCE("qsubaddx",       6200f50, fae0f010, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
+ TCE("qsubaddx",6200f50, fae0f010, 3, (RRnpc, RRnpc, RRnpc),      rd_rn_rm, t_simd),
  TCE("qsub16", 6200f70, fad0f010, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
  TCE("qsub8",  6200ff0, fac0f010, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
  TCE("sadd16", 6100f10, fa90f000, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
  TCE("sadd8",  6100f90, fa80f000, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
  TCE("sasx",   6100f30, faa0f000, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
  /* Old name for SASX.  */
- TCE("saddsubx",       6100f30, faa0f000, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
+ TCE("saddsubx",6100f30, faa0f000, 3, (RRnpc, RRnpc, RRnpc),      rd_rn_rm, t_simd),
  TCE("shadd16",        6300f10, fa90f020, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
  TCE("shadd8", 6300f90, fa80f020, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
- TCE("shasx",     6300f30, faa0f020, 3, (RRnpc, RRnpc, RRnpc),    rd_rn_rm, t_simd),
+ TCE("shasx",   6300f30, faa0f020, 3, (RRnpc, RRnpc, RRnpc),      rd_rn_rm, t_simd),
  /* Old name for SHASX.  */
  TCE("shaddsubx", 6300f30, faa0f020, 3, (RRnpc, RRnpc, RRnpc),    rd_rn_rm, t_simd),
- TCE("shsax",      6300f50, fae0f020, 3, (RRnpc, RRnpc, RRnpc),           rd_rn_rm, t_simd),
+ TCE("shsax",     6300f50, fae0f020, 3, (RRnpc, RRnpc, RRnpc),    rd_rn_rm, t_simd),
  /* Old name for SHSAX.  */
  TCE("shsubaddx", 6300f50, fae0f020, 3, (RRnpc, RRnpc, RRnpc),    rd_rn_rm, t_simd),
  TCE("shsub16",        6300f70, fad0f020, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
  TCE("shsub8", 6300ff0, fac0f020, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
  TCE("ssax",   6100f50, fae0f000, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
  /* Old name for SSAX.  */
- TCE("ssubaddx",       6100f50, fae0f000, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
+ TCE("ssubaddx",6100f50, fae0f000, 3, (RRnpc, RRnpc, RRnpc),      rd_rn_rm, t_simd),
  TCE("ssub16", 6100f70, fad0f000, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
  TCE("ssub8",  6100ff0, fac0f000, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
  TCE("uadd16", 6500f10, fa90f040, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
  TCE("uadd8",  6500f90, fa80f040, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
  TCE("uasx",   6500f30, faa0f040, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
  /* Old name for UASX.  */
- TCE("uaddsubx",       6500f30, faa0f040, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
+ TCE("uaddsubx",6500f30, faa0f040, 3, (RRnpc, RRnpc, RRnpc),      rd_rn_rm, t_simd),
  TCE("uhadd16",        6700f10, fa90f060, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
  TCE("uhadd8", 6700f90, fa80f060, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
- TCE("uhasx",     6700f30, faa0f060, 3, (RRnpc, RRnpc, RRnpc),    rd_rn_rm, t_simd),
+ TCE("uhasx",   6700f30, faa0f060, 3, (RRnpc, RRnpc, RRnpc),      rd_rn_rm, t_simd),
  /* Old name for UHASX.  */
  TCE("uhaddsubx", 6700f30, faa0f060, 3, (RRnpc, RRnpc, RRnpc),    rd_rn_rm, t_simd),
  TCE("uhsax",     6700f50, fae0f060, 3, (RRnpc, RRnpc, RRnpc),    rd_rn_rm, t_simd),
@@ -17272,7 +19403,7 @@ static const struct asm_opcode insns[] =
  TCE("uhsub8", 6700ff0, fac0f060, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
  TCE("uqadd16",        6600f10, fa90f050, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
  TCE("uqadd8", 6600f90, fa80f050, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
- TCE("uqasx",     6600f30, faa0f050, 3, (RRnpc, RRnpc, RRnpc),    rd_rn_rm, t_simd),
+ TCE("uqasx",   6600f30, faa0f050, 3, (RRnpc, RRnpc, RRnpc),      rd_rn_rm, t_simd),
  /* Old name for UQASX.  */
  TCE("uqaddsubx", 6600f30, faa0f050, 3, (RRnpc, RRnpc, RRnpc),    rd_rn_rm, t_simd),
  TCE("uqsax",     6600f50, fae0f050, 3, (RRnpc, RRnpc, RRnpc),    rd_rn_rm, t_simd),
@@ -17283,7 +19414,7 @@ static const struct asm_opcode insns[] =
  TCE("usub16", 6500f70, fad0f040, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
  TCE("usax",   6500f50, fae0f040, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
  /* Old name for USAX.  */
- TCE("usubaddx",       6500f50, fae0f040, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
+ TCE("usubaddx",6500f50, fae0f040, 3, (RRnpc, RRnpc, RRnpc),      rd_rn_rm, t_simd),
  TCE("usub8",  6500ff0, fac0f040, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
  TCE("sxtah",  6b00070, fa00f080, 4, (RRnpc, RRnpc, RRnpc, oROR), sxtah, t_sxtah),
  TCE("sxtab16",        6800070, fa20f080, 4, (RRnpc, RRnpc, RRnpc, oROR), sxtah, t_sxtah),
@@ -17336,20 +19467,20 @@ static const struct asm_opcode insns[] =
                                       RRnpcb), strexd, t_strexd),
 
 #undef  THUMB_VARIANT
-#define THUMB_VARIANT  & arm_ext_v6t2
+#define THUMB_VARIANT  & arm_ext_v6t2_v8m
  TCE("ldrexb", 1d00f9f, e8d00f4f, 2, (RRnpc_npcsp,RRnpcb),
      rd_rn,  rd_rn),
  TCE("ldrexh", 1f00f9f, e8d00f5f, 2, (RRnpc_npcsp, RRnpcb),
      rd_rn,  rd_rn),
  TCE("strexb", 1c00f90, e8c00f40, 3, (RRnpc_npcsp, RRnpc_npcsp, ADDR),
-     strex, rm_rd_rn),
+     strex, t_strexbh),
  TCE("strexh", 1e00f90, e8c00f50, 3, (RRnpc_npcsp, RRnpc_npcsp, ADDR),
-     strex, rm_rd_rn), 
+     strex, t_strexbh),
  TUF("clrex",  57ff01f, f3bf8f2f, 0, (),                             noargs, noargs),
 
 #undef  ARM_VARIANT
 #define ARM_VARIANT    & arm_ext_sec
-#undef THUMB_VARIANT
+#undef  THUMB_VARIANT
 #define THUMB_VARIANT  & arm_ext_sec
 
  TCE("smc",    1600070, f7f08000, 1, (EXPi), smc, t_smc),
@@ -17362,8 +19493,15 @@ static const struct asm_opcode insns[] =
  TCE("hvc",    1400070, f7e08000, 1, (EXPi), hvc, t_hvc),
  TCE("eret",   160006e, f3de8f00, 0, (), noargs, noargs),
 
+#undef ARM_VARIANT
+#define        ARM_VARIANT    & arm_ext_pan
+#undef THUMB_VARIANT
+#define        THUMB_VARIANT  & arm_ext_pan
+
+ TUF("setpan", 1100000, b610, 1, (I7), setpan, t_setpan),
+
 #undef  ARM_VARIANT
-#define ARM_VARIANT  & arm_ext_v6t2
+#define ARM_VARIANT    & arm_ext_v6t2
 #undef  THUMB_VARIANT
 #define THUMB_VARIANT  & arm_ext_v6t2
 
@@ -17373,8 +19511,6 @@ static const struct asm_opcode insns[] =
  TCE("ubfx",   7e00050, f3c00000, 4, (RR, RR, I31, I32),          bfx, t_bfx),
 
  TCE("mls",    0600090, fb000010, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mlas, t_mla),
- TCE("movw",   3000000, f2400000, 2, (RRnpc, HALF),                mov16, t_mov16),
- TCE("movt",   3400000, f2c00000, 2, (RRnpc, HALF),                mov16, t_mov16),
  TCE("rbit",   6ff0f30, fa90f0a0, 2, (RR, RR),                     rd_rm, t_rbit),
 
  TC3("ldrht",  03000b0, f8300e00, 2, (RRnpc_npcsp, ADDR), ldsttv4, t_ldstt),
@@ -17382,8 +19518,13 @@ static const struct asm_opcode insns[] =
  TC3("ldrsbt", 03000d0, f9100e00, 2, (RRnpc_npcsp, ADDR), ldsttv4, t_ldstt),
  TC3("strht",  02000b0, f8200e00, 2, (RRnpc_npcsp, ADDR), ldsttv4, t_ldstt),
 
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT  & arm_ext_v6t2_v8m
+ TCE("movw",   3000000, f2400000, 2, (RRnpc, HALF),                mov16, t_mov16),
+ TCE("movt",   3400000, f2c00000, 2, (RRnpc, HALF),                mov16, t_mov16),
+
  /* Thumb-only instructions.  */
-#undef ARM_VARIANT
+#undef  ARM_VARIANT
 #define ARM_VARIANT NULL
   TUE("cbnz",     0,           b900,     2, (RR, EXP), 0, t_cbz),
   TUE("cbz",      0,           b100,     2, (RR, EXP), 0, t_cbz),
@@ -17393,6 +19534,8 @@ static const struct asm_opcode insns[] =
     -mimplicit-it=[never | arm] modes.  */
 #undef  ARM_VARIANT
 #define ARM_VARIANT  & arm_ext_v1
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT  & arm_ext_v6t2
 
  TUE("it",        bf08,        bf08,     1, (COND),   it,    t_it),
  TUE("itt",       bf0c,        bf0c,     1, (COND),   it,    t_it),
@@ -17439,9 +19582,9 @@ static const struct asm_opcode insns[] =
 #undef  THUMB_VARIANT
 #define THUMB_VARIANT  & arm_ext_barrier
 
- TUF("dmb",    57ff050, f3bf8f50, 1, (oBARRIER_I15), barrier,  t_barrier),
- TUF("dsb",    57ff040, f3bf8f40, 1, (oBARRIER_I15), barrier,  t_barrier),
- TUF("isb",    57ff060, f3bf8f60, 1, (oBARRIER_I15), barrier,  t_barrier),
+ TUF("dmb",    57ff050, f3bf8f50, 1, (oBARRIER_I15), barrier, barrier),
+ TUF("dsb",    57ff040, f3bf8f40, 1, (oBARRIER_I15), barrier, barrier),
+ TUF("isb",    57ff060, f3bf8f60, 1, (oBARRIER_I15), barrier, barrier),
 
  /* ARM V7 instructions.  */
 #undef  ARM_VARIANT
@@ -17452,15 +19595,119 @@ static const struct asm_opcode insns[] =
  TUF("pli",    450f000, f910f000, 1, (ADDR),     pli,      t_pld),
  TCE("dbg",    320f0f0, f3af80f0, 1, (I15),      dbg,      t_dbg),
 
-#undef ARM_VARIANT
+#undef  ARM_VARIANT
 #define ARM_VARIANT    & arm_ext_mp
-#undef THUMB_VARIANT
+#undef  THUMB_VARIANT
 #define THUMB_VARIANT  & arm_ext_mp
 
  TUF("pldw",   410f000, f830f000, 1, (ADDR),   pld,    t_pld),
 
+ /* AArchv8 instructions.  */
+#undef  ARM_VARIANT
+#define ARM_VARIANT   & arm_ext_v8
+
+/* Instructions shared between armv8-a and armv8-m.  */
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT & arm_ext_atomics
+
+ TCE("lda",    1900c9f, e8d00faf, 2, (RRnpc, RRnpcb),  rd_rn,  rd_rn),
+ TCE("ldab",   1d00c9f, e8d00f8f, 2, (RRnpc, RRnpcb),  rd_rn,  rd_rn),
+ TCE("ldah",   1f00c9f, e8d00f9f, 2, (RRnpc, RRnpcb),  rd_rn,  rd_rn),
+ TCE("stl",    180fc90, e8c00faf, 2, (RRnpc, RRnpcb),  rm_rn,  rd_rn),
+ TCE("stlb",   1c0fc90, e8c00f8f, 2, (RRnpc, RRnpcb),  rm_rn,  rd_rn),
+ TCE("stlh",   1e0fc90, e8c00f9f, 2, (RRnpc, RRnpcb),  rm_rn,  rd_rn),
+ TCE("ldaex",  1900e9f, e8d00fef, 2, (RRnpc, RRnpcb),  rd_rn,  rd_rn),
+ TCE("ldaexb", 1d00e9f, e8d00fcf, 2, (RRnpc,RRnpcb),   rd_rn,  rd_rn),
+ TCE("ldaexh", 1f00e9f, e8d00fdf, 2, (RRnpc, RRnpcb),  rd_rn,  rd_rn),
+ TCE("stlex",  1800e90, e8c00fe0, 3, (RRnpc, RRnpc, RRnpcb),
+                                                       stlex,  t_stlex),
+ TCE("stlexb", 1c00e90, e8c00fc0, 3, (RRnpc, RRnpc, RRnpcb),
+                                                       stlex, t_stlex),
+ TCE("stlexh", 1e00e90, e8c00fd0, 3, (RRnpc, RRnpc, RRnpcb),
+                                                       stlex, t_stlex),
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT & arm_ext_v8
+
+ tCE("sevl",   320f005, _sevl,    0, (),               noargs, t_hint),
+ TUE("hlt",    1000070, ba80,     1, (oIffffb),        bkpt,   t_hlt),
+ TCE("ldaexd", 1b00e9f, e8d000ff, 3, (RRnpc, oRRnpc, RRnpcb),
+                                                       ldrexd, t_ldrexd),
+ TCE("stlexd", 1a00e90, e8c000f0, 4, (RRnpc, RRnpc, oRRnpc, RRnpcb),
+                                                       strexd, t_strexd),
+ /* ARMv8 T32 only.  */
+#undef  ARM_VARIANT
+#define ARM_VARIANT  NULL
+ TUF("dcps1",  0,       f78f8001, 0, (),       noargs, noargs),
+ TUF("dcps2",  0,       f78f8002, 0, (),       noargs, noargs),
+ TUF("dcps3",  0,       f78f8003, 0, (),       noargs, noargs),
+
+  /* FP for ARMv8.  */
+#undef  ARM_VARIANT
+#define ARM_VARIANT   & fpu_vfp_ext_armv8xd
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT & fpu_vfp_ext_armv8xd
+
+  nUF(vseleq, _vseleq, 3, (RVSD, RVSD, RVSD),          vsel),
+  nUF(vselvs, _vselvs, 3, (RVSD, RVSD, RVSD),          vsel),
+  nUF(vselge, _vselge, 3, (RVSD, RVSD, RVSD),          vsel),
+  nUF(vselgt, _vselgt, 3, (RVSD, RVSD, RVSD),          vsel),
+  nUF(vmaxnm, _vmaxnm, 3, (RNSDQ, oRNSDQ, RNSDQ),      vmaxnm),
+  nUF(vminnm, _vminnm, 3, (RNSDQ, oRNSDQ, RNSDQ),      vmaxnm),
+  nUF(vcvta,  _vcvta,  2, (RNSDQ, oRNSDQ),             neon_cvta),
+  nUF(vcvtn,  _vcvta,  2, (RNSDQ, oRNSDQ),             neon_cvtn),
+  nUF(vcvtp,  _vcvta,  2, (RNSDQ, oRNSDQ),             neon_cvtp),
+  nUF(vcvtm,  _vcvta,  2, (RNSDQ, oRNSDQ),             neon_cvtm),
+  nCE(vrintr, _vrintr, 2, (RNSDQ, oRNSDQ),             vrintr),
+  nCE(vrintz, _vrintr, 2, (RNSDQ, oRNSDQ),             vrintz),
+  nCE(vrintx, _vrintr, 2, (RNSDQ, oRNSDQ),             vrintx),
+  nUF(vrinta, _vrinta, 2, (RNSDQ, oRNSDQ),             vrinta),
+  nUF(vrintn, _vrinta, 2, (RNSDQ, oRNSDQ),             vrintn),
+  nUF(vrintp, _vrinta, 2, (RNSDQ, oRNSDQ),             vrintp),
+  nUF(vrintm, _vrinta, 2, (RNSDQ, oRNSDQ),             vrintm),
+
+  /* Crypto v1 extensions.  */
+#undef  ARM_VARIANT
+#define ARM_VARIANT & fpu_crypto_ext_armv8
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT & fpu_crypto_ext_armv8
+
+  nUF(aese, _aes, 2, (RNQ, RNQ), aese),
+  nUF(aesd, _aes, 2, (RNQ, RNQ), aesd),
+  nUF(aesmc, _aes, 2, (RNQ, RNQ), aesmc),
+  nUF(aesimc, _aes, 2, (RNQ, RNQ), aesimc),
+  nUF(sha1c, _sha3op, 3, (RNQ, RNQ, RNQ), sha1c),
+  nUF(sha1p, _sha3op, 3, (RNQ, RNQ, RNQ), sha1p),
+  nUF(sha1m, _sha3op, 3, (RNQ, RNQ, RNQ), sha1m),
+  nUF(sha1su0, _sha3op, 3, (RNQ, RNQ, RNQ), sha1su0),
+  nUF(sha256h, _sha3op, 3, (RNQ, RNQ, RNQ), sha256h),
+  nUF(sha256h2, _sha3op, 3, (RNQ, RNQ, RNQ), sha256h2),
+  nUF(sha256su1, _sha3op, 3, (RNQ, RNQ, RNQ), sha256su1),
+  nUF(sha1h, _sha1h, 2, (RNQ, RNQ), sha1h),
+  nUF(sha1su1, _sha2op, 2, (RNQ, RNQ), sha1su1),
+  nUF(sha256su0, _sha2op, 2, (RNQ, RNQ), sha256su0),
+
+#undef  ARM_VARIANT
+#define ARM_VARIANT   & crc_ext_armv8
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT & crc_ext_armv8
+  TUEc("crc32b", 1000040, fac0f080, 3, (RR, oRR, RR), crc32b),
+  TUEc("crc32h", 1200040, fac0f090, 3, (RR, oRR, RR), crc32h),
+  TUEc("crc32w", 1400040, fac0f0a0, 3, (RR, oRR, RR), crc32w),
+  TUEc("crc32cb",1000240, fad0f080, 3, (RR, oRR, RR), crc32cb),
+  TUEc("crc32ch",1200240, fad0f090, 3, (RR, oRR, RR), crc32ch),
+  TUEc("crc32cw",1400240, fad0f0a0, 3, (RR, oRR, RR), crc32cw),
+
+ /* ARMv8.2 RAS extension.  */
+#undef  ARM_VARIANT
+#define ARM_VARIANT   & arm_ext_v8_2
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT & arm_ext_v8_2
+ TUE ("esb", 320f010, f3af8010, 0, (), noargs,  noargs),
+
 #undef  ARM_VARIANT
 #define ARM_VARIANT  & fpu_fpa_ext_v1  /* Core FPA instruction set (V1).  */
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT NULL
 
  cCE("wfs",    e200110, 1, (RR),            rd),
  cCE("rfs",    e300110, 1, (RR),            rd),
@@ -17910,8 +20157,8 @@ static const struct asm_opcode insns[] =
  cCE("fmrs",   e100a10, 2, (RR, RVS),        vfp_reg_from_sp),
  cCE("fmsr",   e000a10, 2, (RVS, RR),        vfp_sp_from_reg),
  cCE("fmstat", ef1fa10, 0, (),               noargs),
- cCE("vmrs",   ef10a10, 2, (APSR_RR, RVC),   vmrs),
- cCE("vmsr",   ee10a10, 2, (RVC, RR),        vmsr),
+ cCE("vmrs",   ef00a10, 2, (APSR_RR, RVC),   vmrs),
+ cCE("vmsr",   ee00a10, 2, (RVC, RR),        vmsr),
  cCE("fsitos", eb80ac0, 2, (RVS, RVS),       vfp_sp_monadic),
  cCE("fuitos", eb80a40, 2, (RVS, RVS),       vfp_sp_monadic),
  cCE("ftosis", ebd0a40, 2, (RVS, RVS),       vfp_sp_monadic),
@@ -18037,8 +20284,8 @@ static const struct asm_opcode insns[] =
  nCE(vnmul,     _vnmul,   3, (RVSD, RVSD, RVSD), vfp_nsyn_nmul),
  nCE(vnmla,     _vnmla,   3, (RVSD, RVSD, RVSD), vfp_nsyn_nmul),
  nCE(vnmls,     _vnmls,   3, (RVSD, RVSD, RVSD), vfp_nsyn_nmul),
- nCE(vcmp,      _vcmp,    2, (RVSD, RVSD_I0),    vfp_nsyn_cmp),
- nCE(vcmpe,     _vcmpe,   2, (RVSD, RVSD_I0),    vfp_nsyn_cmp),
+ nCE(vcmp,      _vcmp,    2, (RVSD, RSVD_FI0),    vfp_nsyn_cmp),
+ nCE(vcmpe,     _vcmpe,   2, (RVSD, RSVD_FI0),    vfp_nsyn_cmp),
  NCE(vpush,     0,       1, (VRSDLST),          vfp_nsyn_push),
  NCE(vpop,      0,       1, (VRSDLST),          vfp_nsyn_pop),
  NCE(vcvtz,     0,       2, (RVSD, RVSD),       vfp_nsyn_cvtz),
@@ -18063,16 +20310,25 @@ static const struct asm_opcode insns[] =
  NCE(vldr,      d100b00, 2, (RVSD, ADDRGLDC), neon_ldr_str),
  NCE(vstr,      d000b00, 2, (RVSD, ADDRGLDC), neon_ldr_str),
 
- nCEF(vcvt,     _vcvt,   3, (RNSDQ, RNSDQ, oI32b), neon_cvt),
+ nCEF(vcvt,     _vcvt,   3, (RNSDQ, RNSDQ, oI32z), neon_cvt),
  nCEF(vcvtr,    _vcvt,   2, (RNSDQ, RNSDQ), neon_cvtr),
nCEF(vcvtb,   _vcvt,   2, (RVS, RVS), neon_cvtb),
nCEF(vcvtt,   _vcvt,   2, (RVS, RVS), neon_cvtt),
NCEF(vcvtb,   eb20a40, 2, (RVSD, RVSD), neon_cvtb),
NCEF(vcvtt,   eb20a40, 2, (RVSD, RVSD), neon_cvtt),
 
 
   /* NOTE: All VMOV encoding is special-cased!  */
  NCE(vmov,      0,       1, (VMOV), neon_mov),
  NCE(vmovq,     0,       1, (VMOV), neon_mov),
 
+#undef  ARM_VARIANT
+#define ARM_VARIANT    & arm_ext_fp16
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT  & arm_ext_fp16
+ /* New instructions added from v8.2, allowing the extraction and insertion of
+    the upper 16 bits of a 32-bit vector register.  */
+ NCE (vmovx,     eb00a40,       2, (RVS, RVS), neon_movhf),
+ NCE (vins,      eb00ac0,       2, (RVS, RVS), neon_movhf),
+
 #undef  THUMB_VARIANT
 #define THUMB_VARIANT  & fpu_neon_ext_v1
 #undef  ARM_VARIANT
@@ -18122,7 +20378,7 @@ static const struct asm_opcode insns[] =
  NUF(vbitq,     1200110, 3, (RNQ,  RNQ,  RNQ),  neon_bitfield),
  NUF(vbif,      1300110, 3, (RNDQ, RNDQ, RNDQ), neon_bitfield),
  NUF(vbifq,     1300110, 3, (RNQ,  RNQ,  RNQ),  neon_bitfield),
-  /* Int and float variants, types S8 S16 S32 U8 U16 U32 F32.  */
+  /* Int and float variants, types S8 S16 S32 U8 U16 U32 F16 F32.  */
  nUF(vabd,      _vabd,    3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_if_su),
  nUF(vabdq,     _vabd,    3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_if_su),
  nUF(vmax,      _vmax,    3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_if_su),
@@ -18174,6 +20430,11 @@ static const struct asm_opcode insns[] =
  NUF(vrecpsq,   0000f10,  3, (RNQ,  oRNQ,  RNQ),  neon_step),
  NUF(vrsqrts,   0200f10,  3, (RNDQ, oRNDQ, RNDQ), neon_step),
  NUF(vrsqrtsq,  0200f10,  3, (RNQ,  oRNQ,  RNQ),  neon_step),
+ /* ARM v8.1 extension.  */
+ nUF (vqrdmlah,  _vqrdmlah, 3, (RNDQ, oRNDQ, RNDQ_RNSC), neon_qrdmlah),
+ nUF (vqrdmlahq, _vqrdmlah, 3, (RNQ,  oRNQ,  RNDQ_RNSC), neon_qrdmlah),
+ nUF (vqrdmlsh,  _vqrdmlsh, 3, (RNDQ, oRNDQ, RNDQ_RNSC), neon_qrdmlah),
+ nUF (vqrdmlshq, _vqrdmlsh, 3, (RNQ,  oRNQ,  RNDQ_RNSC), neon_qrdmlah),
 
   /* Two address, int/float. Types S8 S16 S32 F32.  */
  NUF(vabsq,     1b10300, 2, (RNQ,  RNQ),      neon_abs_neg),
@@ -18280,7 +20541,7 @@ static const struct asm_opcode insns[] =
  NUF(vpadalq,   1b00600, 2, (RNQ,  RNQ),      neon_pair_long),
  NUF(vpaddl,    1b00200, 2, (RNDQ, RNDQ),     neon_pair_long),
  NUF(vpaddlq,   1b00200, 2, (RNQ,  RNQ),      neon_pair_long),
-  /* Reciprocal estimates. Types U32 F32.  */
+  /* Reciprocal estimates.  Types U32 F16 F32.  */
  NUF(vrecpe,    1b30400, 2, (RNDQ, RNDQ),     neon_recip_est),
  NUF(vrecpeq,   1b30400, 2, (RNQ,  RNQ),      neon_recip_est),
  NUF(vrsqrte,   1b30480, 2, (RNDQ, RNDQ),     neon_recip_est),
@@ -18321,9 +20582,9 @@ static const struct asm_opcode insns[] =
  nUF(vst4,      _vst4,    2, (NSTRLST, ADDR),  neon_ldx_stx),
 
 #undef  THUMB_VARIANT
-#define THUMB_VARIANT &fpu_vfp_ext_v3xd
-#undef ARM_VARIANT
-#define ARM_VARIANT &fpu_vfp_ext_v3xd
+#define THUMB_VARIANT & fpu_vfp_ext_v3xd
+#undef  ARM_VARIANT
+#define ARM_VARIANT   & fpu_vfp_ext_v3xd
  cCE("fconsts",   eb00a00, 2, (RVS, I255),      vfp_sp_const),
  cCE("fshtos",    eba0a40, 2, (RVS, I16z),      vfp_sp_conv_16),
  cCE("fsltos",    eba0ac0, 2, (RVS, I32),       vfp_sp_conv_32),
@@ -18334,7 +20595,7 @@ static const struct asm_opcode insns[] =
  cCE("ftouhs",    ebf0a40, 2, (RVS, I16z),      vfp_sp_conv_16),
  cCE("ftouls",    ebf0ac0, 2, (RVS, I32),       vfp_sp_conv_32),
 
-#undef THUMB_VARIANT
+#undef  THUMB_VARIANT
 #define THUMB_VARIANT  & fpu_vfp_ext_v3
 #undef  ARM_VARIANT
 #define ARM_VARIANT    & fpu_vfp_ext_v3
@@ -18349,10 +20610,10 @@ static const struct asm_opcode insns[] =
  cCE("ftouhd",    ebf0b40, 2, (RVD, I16z),      vfp_dp_conv_16),
  cCE("ftould",    ebf0bc0, 2, (RVD, I32),       vfp_dp_conv_32),
 
-#undef ARM_VARIANT
-#define ARM_VARIANT &fpu_vfp_ext_fma
-#undef THUMB_VARIANT
-#define THUMB_VARIANT &fpu_vfp_ext_fma
+#undef  ARM_VARIANT
+#define ARM_VARIANT    & fpu_vfp_ext_fma
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT  & fpu_vfp_ext_fma
  /* Mnemonics shared by Neon and VFP.  These are included in the
     VFP FMA variant; NEON and VFP FMA always includes the NEON
     FMA instructions.  */
@@ -18392,12 +20653,12 @@ static const struct asm_opcode insns[] =
  cCE("textrcb",        e130170, 2, (RR, I7),               iwmmxt_textrc),
  cCE("textrch",        e530170, 2, (RR, I7),               iwmmxt_textrc),
  cCE("textrcw",        e930170, 2, (RR, I7),               iwmmxt_textrc),
- cCE("textrmub",       e100070, 3, (RR, RIWR, I7),         iwmmxt_textrm),
- cCE("textrmuh",       e500070, 3, (RR, RIWR, I7),         iwmmxt_textrm),
- cCE("textrmuw",       e900070, 3, (RR, RIWR, I7),         iwmmxt_textrm),
- cCE("textrmsb",       e100078, 3, (RR, RIWR, I7),         iwmmxt_textrm),
- cCE("textrmsh",       e500078, 3, (RR, RIWR, I7),         iwmmxt_textrm),
- cCE("textrmsw",       e900078, 3, (RR, RIWR, I7),         iwmmxt_textrm),
+ cCE("textrmub",e100070, 3, (RR, RIWR, I7),        iwmmxt_textrm),
+ cCE("textrmuh",e500070, 3, (RR, RIWR, I7),        iwmmxt_textrm),
+ cCE("textrmuw",e900070, 3, (RR, RIWR, I7),        iwmmxt_textrm),
+ cCE("textrmsb",e100078, 3, (RR, RIWR, I7),        iwmmxt_textrm),
+ cCE("textrmsh",e500078, 3, (RR, RIWR, I7),        iwmmxt_textrm),
+ cCE("textrmsw",e900078, 3, (RR, RIWR, I7),        iwmmxt_textrm),
  cCE("tinsrb", e600010, 3, (RIWR, RR, I7),         iwmmxt_tinsr),
  cCE("tinsrh", e600050, 3, (RIWR, RR, I7),         iwmmxt_tinsr),
  cCE("tinsrw", e600090, 3, (RIWR, RR, I7),         iwmmxt_tinsr),
@@ -18409,9 +20670,9 @@ static const struct asm_opcode insns[] =
  cCE("tmiabt", e2d0010, 3, (RIWR, RR, RR),         iwmmxt_tmia),
  cCE("tmiatb", e2e0010, 3, (RIWR, RR, RR),         iwmmxt_tmia),
  cCE("tmiatt", e2f0010, 3, (RIWR, RR, RR),         iwmmxt_tmia),
- cCE("tmovmskb",       e100030, 2, (RR, RIWR),             rd_rn),
- cCE("tmovmskh",       e500030, 2, (RR, RIWR),             rd_rn),
- cCE("tmovmskw",       e900030, 2, (RR, RIWR),             rd_rn),
+ cCE("tmovmskb",e100030, 2, (RR, RIWR),                    rd_rn),
+ cCE("tmovmskh",e500030, 2, (RR, RIWR),                    rd_rn),
+ cCE("tmovmskw",e900030, 2, (RR, RIWR),                    rd_rn),
  cCE("tmrc",   e100110, 2, (RR, RIWC_RIWG),        rd_rn),
  cCE("tmrrc",  c500000, 3, (RR, RR, RIWR),         rd_rn_rm),
  cCE("torcb",  e13f150, 1, (RR),                   iwmmxt_tandorc),
@@ -18430,10 +20691,10 @@ static const struct asm_opcode insns[] =
  cCE("waddw",  e800180, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
  cCE("waddwus",        e900180, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
  cCE("waligni",        e000020, 4, (RIWR, RIWR, RIWR, I7), iwmmxt_waligni),
- cCE("walignr0",       e800020, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
- cCE("walignr1",       e900020, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
- cCE("walignr2",       ea00020, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
- cCE("walignr3",       eb00020, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE("walignr0",e800020, 3, (RIWR, RIWR, RIWR),            rd_rn_rm),
+ cCE("walignr1",e900020, 3, (RIWR, RIWR, RIWR),            rd_rn_rm),
+ cCE("walignr2",ea00020, 3, (RIWR, RIWR, RIWR),            rd_rn_rm),
+ cCE("walignr3",eb00020, 3, (RIWR, RIWR, RIWR),            rd_rn_rm),
  cCE("wand",   e200000, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
  cCE("wandn",  e300000, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
  cCE("wavg2b", e800000, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
@@ -18443,12 +20704,12 @@ static const struct asm_opcode insns[] =
  cCE("wcmpeqb",        e000060, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
  cCE("wcmpeqh",        e400060, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
  cCE("wcmpeqw",        e800060, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
- cCE("wcmpgtub",       e100060, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
- cCE("wcmpgtuh",       e500060, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
- cCE("wcmpgtuw",       e900060, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
- cCE("wcmpgtsb",       e300060, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
- cCE("wcmpgtsh",       e700060, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
- cCE("wcmpgtsw",       eb00060, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE("wcmpgtub",e100060, 3, (RIWR, RIWR, RIWR),            rd_rn_rm),
+ cCE("wcmpgtuh",e500060, 3, (RIWR, RIWR, RIWR),            rd_rn_rm),
+ cCE("wcmpgtuw",e900060, 3, (RIWR, RIWR, RIWR),            rd_rn_rm),
+ cCE("wcmpgtsb",e300060, 3, (RIWR, RIWR, RIWR),            rd_rn_rm),
+ cCE("wcmpgtsh",e700060, 3, (RIWR, RIWR, RIWR),            rd_rn_rm),
+ cCE("wcmpgtsw",eb00060, 3, (RIWR, RIWR, RIWR),            rd_rn_rm),
  cCE("wldrb",  c100000, 2, (RIWR, ADDR),           iwmmxt_wldstbh),
  cCE("wldrh",  c500000, 2, (RIWR, ADDR),           iwmmxt_wldstbh),
  cCE("wldrw",  c100100, 2, (RIWR_RIWC, ADDR),      iwmmxt_wldstw),
@@ -18477,12 +20738,12 @@ static const struct asm_opcode insns[] =
  cCE("wmulum", e100100, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
  cCE("wmulul", e000100, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
  cCE("wor",    e000000, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
- cCE("wpackhss",       e700080, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
- cCE("wpackhus",       e500080, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
- cCE("wpackwss",       eb00080, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
- cCE("wpackwus",       e900080, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
- cCE("wpackdss",       ef00080, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
- cCE("wpackdus",       ed00080, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE("wpackhss",e700080, 3, (RIWR, RIWR, RIWR),            rd_rn_rm),
+ cCE("wpackhus",e500080, 3, (RIWR, RIWR, RIWR),            rd_rn_rm),
+ cCE("wpackwss",eb00080, 3, (RIWR, RIWR, RIWR),            rd_rn_rm),
+ cCE("wpackwus",e900080, 3, (RIWR, RIWR, RIWR),            rd_rn_rm),
+ cCE("wpackdss",ef00080, 3, (RIWR, RIWR, RIWR),            rd_rn_rm),
+ cCE("wpackdus",ed00080, 3, (RIWR, RIWR, RIWR),            rd_rn_rm),
  cCE("wrorh",  e700040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
  cCE("wrorhg", e700148, 3, (RIWR, RIWR, RIWG),     rd_rn_rm),
  cCE("wrorw",  eb00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
@@ -18624,36 +20885,36 @@ static const struct asm_opcode insns[] =
  cCE("cfmvrdl",        e100410, 2, (RR, RMD),                rd_rn),
  cCE("cfmvdhr",        e000430, 2, (RMD, RR),                rn_rd),
  cCE("cfmvrdh",        e100430, 2, (RR, RMD),                rd_rn),
- cCE("cfmv64lr",       e000510, 2, (RMDX, RR),               rn_rd),
- cCE("cfmvr64l",       e100510, 2, (RR, RMDX),               rd_rn),
- cCE("cfmv64hr",       e000530, 2, (RMDX, RR),               rn_rd),
- cCE("cfmvr64h",       e100530, 2, (RR, RMDX),               rd_rn),
- cCE("cfmval32",       e200440, 2, (RMAX, RMFX),             rd_rn),
- cCE("cfmv32al",       e100440, 2, (RMFX, RMAX),             rd_rn),
- cCE("cfmvam32",       e200460, 2, (RMAX, RMFX),             rd_rn),
- cCE("cfmv32am",       e100460, 2, (RMFX, RMAX),             rd_rn),
- cCE("cfmvah32",       e200480, 2, (RMAX, RMFX),             rd_rn),
- cCE("cfmv32ah",       e100480, 2, (RMFX, RMAX),             rd_rn),
+ cCE("cfmv64lr",e000510, 2, (RMDX, RR),                      rn_rd),
+ cCE("cfmvr64l",e100510, 2, (RR, RMDX),                      rd_rn),
+ cCE("cfmv64hr",e000530, 2, (RMDX, RR),                      rn_rd),
+ cCE("cfmvr64h",e100530, 2, (RR, RMDX),                      rd_rn),
+ cCE("cfmval32",e200440, 2, (RMAX, RMFX),            rd_rn),
+ cCE("cfmv32al",e100440, 2, (RMFX, RMAX),            rd_rn),
+ cCE("cfmvam32",e200460, 2, (RMAX, RMFX),            rd_rn),
+ cCE("cfmv32am",e100460, 2, (RMFX, RMAX),            rd_rn),
+ cCE("cfmvah32",e200480, 2, (RMAX, RMFX),            rd_rn),
+ cCE("cfmv32ah",e100480, 2, (RMFX, RMAX),            rd_rn),
  cCE("cfmva32",        e2004a0, 2, (RMAX, RMFX),             rd_rn),
  cCE("cfmv32a",        e1004a0, 2, (RMFX, RMAX),             rd_rn),
  cCE("cfmva64",        e2004c0, 2, (RMAX, RMDX),             rd_rn),
  cCE("cfmv64a",        e1004c0, 2, (RMDX, RMAX),             rd_rn),
- cCE("cfmvsc32",       e2004e0, 2, (RMDS, RMDX),             mav_dspsc),
- cCE("cfmv32sc",       e1004e0, 2, (RMDX, RMDS),             rd),
+ cCE("cfmvsc32",e2004e0, 2, (RMDS, RMDX),            mav_dspsc),
+ cCE("cfmv32sc",e1004e0, 2, (RMDX, RMDS),            rd),
  cCE("cfcpys", e000400, 2, (RMF, RMF),               rd_rn),
  cCE("cfcpyd", e000420, 2, (RMD, RMD),               rd_rn),
  cCE("cfcvtsd",        e000460, 2, (RMD, RMF),               rd_rn),
  cCE("cfcvtds",        e000440, 2, (RMF, RMD),               rd_rn),
- cCE("cfcvt32s",       e000480, 2, (RMF, RMFX),              rd_rn),
- cCE("cfcvt32d",       e0004a0, 2, (RMD, RMFX),              rd_rn),
- cCE("cfcvt64s",       e0004c0, 2, (RMF, RMDX),              rd_rn),
- cCE("cfcvt64d",       e0004e0, 2, (RMD, RMDX),              rd_rn),
- cCE("cfcvts32",       e100580, 2, (RMFX, RMF),              rd_rn),
- cCE("cfcvtd32",       e1005a0, 2, (RMFX, RMD),              rd_rn),
+ cCE("cfcvt32s",e000480, 2, (RMF, RMFX),             rd_rn),
+ cCE("cfcvt32d",e0004a0, 2, (RMD, RMFX),             rd_rn),
+ cCE("cfcvt64s",e0004c0, 2, (RMF, RMDX),             rd_rn),
+ cCE("cfcvt64d",e0004e0, 2, (RMD, RMDX),             rd_rn),
+ cCE("cfcvts32",e100580, 2, (RMFX, RMF),             rd_rn),
+ cCE("cfcvtd32",e1005a0, 2, (RMFX, RMD),             rd_rn),
  cCE("cftruncs32",e1005c0, 2, (RMFX, RMF),           rd_rn),
  cCE("cftruncd32",e1005e0, 2, (RMFX, RMD),           rd_rn),
- cCE("cfrshl32",       e000550, 3, (RMFX, RMFX, RR),         mav_triple),
- cCE("cfrshl64",       e000570, 3, (RMDX, RMDX, RR),         mav_triple),
+ cCE("cfrshl32",e000550, 3, (RMFX, RMFX, RR),        mav_triple),
+ cCE("cfrshl64",e000570, 3, (RMDX, RMDX, RR),        mav_triple),
  cCE("cfsh32", e000500, 3, (RMFX, RMFX, I63s),       mav_shift),
  cCE("cfsh64", e200500, 3, (RMDX, RMDX, I63s),       mav_shift),
  cCE("cfcmps", e100490, 3, (RR, RMF, RMF),           rd_rn_rm),
@@ -18682,15 +20943,21 @@ static const struct asm_opcode insns[] =
  cCE("cfmul64",        e100520, 3, (RMDX, RMDX, RMDX),       rd_rn_rm),
  cCE("cfmac32",        e100540, 3, (RMFX, RMFX, RMFX),       rd_rn_rm),
  cCE("cfmsc32",        e100560, 3, (RMFX, RMFX, RMFX),       rd_rn_rm),
- cCE("cfmadd32",       e000600, 4, (RMAX, RMFX, RMFX, RMFX), mav_quad),
- cCE("cfmsub32",       e100600, 4, (RMAX, RMFX, RMFX, RMFX), mav_quad),
+ cCE("cfmadd32",e000600, 4, (RMAX, RMFX, RMFX, RMFX), mav_quad),
+ cCE("cfmsub32",e100600, 4, (RMAX, RMFX, RMFX, RMFX), mav_quad),
  cCE("cfmadda32", e200600, 4, (RMAX, RMAX, RMFX, RMFX), mav_quad),
  cCE("cfmsuba32", e300600, 4, (RMAX, RMAX, RMFX, RMFX), mav_quad),
+
+#undef  ARM_VARIANT
+#define ARM_VARIANT NULL
+#undef  THUMB_VARIANT
+#define THUMB_VARIANT & arm_ext_v8m
+ TUE("tt", 0, e840f000, 2, (RRnpc, RRnpc), 0, tt),
+ TUE("ttt", 0, e840f040, 2, (RRnpc, RRnpc), 0, tt),
 };
 #undef ARM_VARIANT
 #undef THUMB_VARIANT
 #undef TCE
-#undef TCM
 #undef TUE
 #undef TUF
 #undef TCC
@@ -18761,6 +21028,26 @@ md_chars_to_number (char * buf, int n)
 
 /* MD interface: Sections.  */
 
+/* Calculate the maximum variable size (i.e., excluding fr_fix)
+   that an rs_machine_dependent frag may reach.  */
+
+unsigned int
+arm_frag_max_var (fragS *fragp)
+{
+  /* We only use rs_machine_dependent for variable-size Thumb instructions,
+     which are either THUMB_SIZE (2) or INSN_SIZE (4).
+
+     Note that we generate relaxable instructions even for cases that don't
+     really need it, like an immediate that's a trivial constant.  So we're
+     overestimating the instruction size for some of those cases.  Rather
+     than putting more intelligence here, it would probably be better to
+     avoid generating a relaxation frag in the first place when it can be
+     determined up front that a short instruction will suffice.  */
+
+  gas_assert (fragp->fr_type == rs_machine_dependent);
+  return INSN_SIZE;
+}
+
 /* Estimate the size of a frag before relaxing.  Assume everything fits in
    2 bytes.  */
 
@@ -18939,6 +21226,11 @@ md_convert_frag (bfd *abfd, segT asec ATTRIBUTE_UNUSED, fragS *fragp)
   fixp->fx_file = fragp->fr_file;
   fixp->fx_line = fragp->fr_line;
   fragp->fr_fix += fragp->fr_var;
+
+  /* Set whether we use thumb-2 ISA based on final relaxation results.  */
+  if (thumb_mode && fragp->fr_var == 4 && no_cpu_selected ()
+      && !ARM_CPU_HAS_FEATURE (thumb_arch_used, arm_arch_t2))
+    ARM_MERGE_FEATURE_SETS (arm_arch_used, thumb_arch_used, arm_ext_v6t2);
 }
 
 /* Return the size of a relaxable immediate operand instruction.
@@ -19057,6 +21349,30 @@ relax_addsub (fragS *fragp, asection *sec)
     return relax_immediate (fragp, 3, 0);
 }
 
+/* Return TRUE iff the definition of symbol S could be pre-empted
+   (overridden) at link or load time.  */
+static bfd_boolean
+symbol_preemptible (symbolS *s)
+{
+  /* Weak symbols can always be pre-empted.  */
+  if (S_IS_WEAK (s))
+    return TRUE;
+
+  /* Non-global symbols cannot be pre-empted. */
+  if (! S_IS_EXTERNAL (s))
+    return FALSE;
+
+#ifdef OBJ_ELF
+  /* In ELF, a global symbol can be marked protected, or private.  In that
+     case it can't be pre-empted (other definitions in the same link unit
+     would violate the ODR).  */
+  if (ELF_ST_VISIBILITY (S_GET_OTHER (s)) > STV_DEFAULT)
+    return FALSE;
+#endif
+
+  /* Other global symbols might be pre-empted.  */
+  return TRUE;
+}
 
 /* Return the size of a relaxable branch instruction.  BITS is the
    size of the offset field in the narrow instruction.  */
@@ -19075,16 +21391,14 @@ relax_branch (fragS *fragp, asection *sec, int bits, long stretch)
     return 4;
 
 #ifdef OBJ_ELF
+  /* A branch to a function in ARM state will require interworking.  */
   if (S_IS_DEFINED (fragp->fr_symbol)
       && ARM_IS_FUNC (fragp->fr_symbol))
       return 4;
+#endif
 
-  /* PR 12532.  Global symbols with default visibility might
-     be preempted, so do not relax relocations to them.  */
-  if ((ELF_ST_VISIBILITY (S_GET_OTHER (fragp->fr_symbol)) == STV_DEFAULT)
-      && (! S_IS_LOCAL (fragp->fr_symbol)))
+  if (symbol_preemptible (fragp->fr_symbol))
     return 4;
-#endif
 
   val = relaxed_symbol_addr (fragp, stretch);
   addr = fragp->fr_address + fragp->fr_fix + 4;
@@ -19194,7 +21508,7 @@ md_section_align (segT   segment ATTRIBUTE_UNUSED,
       int align;
 
       align = bfd_get_section_alignment (stdoutput, segment);
-      size = ((size + (1 << align) - 1) & ((valueT) -1 << align));
+      size = ((size + (1 << align) - 1) & (-((valueT) 1 << align)));
     }
 #endif
 
@@ -19207,7 +21521,7 @@ md_section_align (segT   segment ATTRIBUTE_UNUSED,
 void
 arm_handle_align (fragS * fragP)
 {
-  static char const arm_noop[2][2][4] =
+  static unsigned char const arm_noop[2][2][4] =
     {
       {  /* ARMv1 */
        {0x00, 0x00, 0xa0, 0xe1},  /* LE */
@@ -19218,7 +21532,7 @@ arm_handle_align (fragS * fragP)
        {0xe3, 0x20, 0xf0, 0x00},  /* BE */
       },
     };
-  static char const thumb_noop[2][2][2] =
+  static unsigned char const thumb_noop[2][2][2] =
     {
       {  /* Thumb-1 */
        {0xc0, 0x46},  /* LE */
@@ -19229,7 +21543,7 @@ arm_handle_align (fragS * fragP)
        {0xbf, 0x00}   /* BE */
       }
     };
-  static char const wide_thumb_noop[2][4] =
+  static unsigned char const wide_thumb_noop[2][4] =
     {  /* Wide Thumb-2 */
       {0xaf, 0xf3, 0x00, 0x80},  /* LE */
       {0xf3, 0xaf, 0x80, 0x00},  /* BE */
@@ -19237,8 +21551,8 @@ arm_handle_align (fragS * fragP)
 
   unsigned bytes, fix, noop_size;
   char * p;
-  const char * noop;
-  const char *narrow_noop = NULL;
+  const unsigned char * noop;
+  const unsigned char *narrow_noop = NULL;
 #ifdef OBJ_ELF
   enum mstate state;
 #endif
@@ -19257,7 +21571,8 @@ arm_handle_align (fragS * fragP)
 
   if (fragP->tc_frag_data.thumb_mode & (~ MODE_RECORDED))
     {
-      if (ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6t2))
+      if (ARM_CPU_HAS_FEATURE (selected_cpu_name[0]
+                              ? selected_cpu : arm_arch_none, arm_ext_v6t2))
        {
          narrow_noop = thumb_noop[1][target_big_endian];
          noop = wide_thumb_noop[target_big_endian];
@@ -19271,7 +21586,9 @@ arm_handle_align (fragS * fragP)
     }
   else
     {
-      noop = arm_noop[ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6k) != 0]
+      noop = arm_noop[ARM_CPU_HAS_FEATURE (selected_cpu_name[0]
+                                          ? selected_cpu : arm_arch_none,
+                                          arm_ext_v6k) != 0]
                     [target_big_endian];
       noop_size = 4;
 #ifdef OBJ_ELF
@@ -19332,9 +21649,9 @@ arm_frag_align_code (int n, int max)
     {
       char err_msg[128];
 
-      sprintf (err_msg, 
-        _("alignments greater than %d bytes not supported in .text sections."),
-        MAX_MEM_FOR_RS_ALIGN_CODE + 1);
+      sprintf (err_msg,
+       _("alignments greater than %d bytes not supported in .text sections."),
+       MAX_MEM_FOR_RS_ALIGN_CODE + 1);
       as_fatal ("%s", err_msg);
     }
 
@@ -19366,27 +21683,29 @@ arm_init_frag (fragS * fragP, int max_chars ATTRIBUTE_UNUSED)
 void
 arm_init_frag (fragS * fragP, int max_chars)
 {
+  int frag_thumb_mode;
+
   /* If the current ARM vs THUMB mode has not already
      been recorded into this frag then do so now.  */
   if ((fragP->tc_frag_data.thumb_mode & MODE_RECORDED) == 0)
-    {
-      fragP->tc_frag_data.thumb_mode = thumb_mode | MODE_RECORDED;
+    fragP->tc_frag_data.thumb_mode = thumb_mode | MODE_RECORDED;
 
-      /* Record a mapping symbol for alignment frags.  We will delete this
-        later if the alignment ends up empty.  */
-      switch (fragP->fr_type)
-       {
-         case rs_align:
-         case rs_align_test:
-         case rs_fill:
-           mapping_state_2 (MAP_DATA, max_chars);
-           break;
-         case rs_align_code:
-           mapping_state_2 (thumb_mode ? MAP_THUMB : MAP_ARM, max_chars);
-           break;
-         default:
-           break;
-       }
+  frag_thumb_mode = fragP->tc_frag_data.thumb_mode ^ MODE_RECORDED;
+
+  /* Record a mapping symbol for alignment frags.  We will delete this
+     later if the alignment ends up empty.  */
+  switch (fragP->fr_type)
+    {
+    case rs_align:
+    case rs_align_test:
+    case rs_fill:
+      mapping_state_2 (MAP_DATA, max_chars);
+      break;
+    case rs_align_code:
+      mapping_state_2 (frag_thumb_mode ? MAP_THUMB : MAP_ARM, max_chars);
+      break;
+    default:
+      break;
     }
 }
 
@@ -19444,10 +21763,10 @@ add_unwind_opcode (valueT op, int length)
     {
       unwind.opcode_alloc += ARM_OPCODE_CHUNK_SIZE;
       if (unwind.opcodes)
-       unwind.opcodes = (unsigned char *) xrealloc (unwind.opcodes,
-                                                     unwind.opcode_alloc);
+       unwind.opcodes = XRESIZEVEC (unsigned char, unwind.opcodes,
+                                    unwind.opcode_alloc);
       else
-       unwind.opcodes = (unsigned char *) xmalloc (unwind.opcode_alloc);
+       unwind.opcodes = XNEWVEC (unsigned char, unwind.opcode_alloc);
     }
   while (length > 0)
     {
@@ -19620,7 +21939,7 @@ start_unwind_section (const segT text_seg, int idx)
 
 /* Start an unwind table entry.         HAVE_DATA is nonzero if we have additional
    personality routine data.  Returns zero, or the index table value for
-   and inline entry.  */
+   an inline entry.  */
 
 static valueT
 create_unwind_entry (int have_data)
@@ -19690,8 +22009,17 @@ create_unwind_entry (int have_data)
        size = unwind.opcode_count - 2;
     }
   else
-    /* An extra byte is required for the opcode count. */
-    size = unwind.opcode_count + 1;
+    {
+      /* PR 16765: Missing or misplaced unwind directives can trigger this.  */
+      if (unwind.personality_index != -1)
+       {
+         as_bad (_("attempt to recreate an unwind entry"));
+         return 1;
+       }
+
+      /* An extra byte is required for the opcode count.       */
+      size = unwind.opcode_count + 1;
+    }
 
   size = (size + 3) >> 2;
   if (size > 0xff)
@@ -19703,6 +22031,8 @@ create_unwind_entry (int have_data)
 
   /* Allocate the table entry. */
   ptr = frag_more ((size << 2) + 4);
+  /* PR 13449: Zero the table entries in case some of them are not used.  */
+  memset (ptr, 0, (size << 2) + 4);
   where = frag_now_fix () - ((size << 2) + 4);
 
   switch (unwind.personality_index)
@@ -19717,7 +22047,7 @@ create_unwind_entry (int have_data)
       ptr += 4;
 
       /* Set the first byte to the number of additional words. */
-      data = size - 1;
+      data = size > 0 ? size - 1 : 0;
       n = 3;
       break;
 
@@ -19792,11 +22122,19 @@ int
 tc_arm_regname_to_dw2regnum (char *regname)
 {
   int reg = arm_reg_parse (&regname, REG_TYPE_RN);
+  if (reg != FAIL)
+    return reg;
 
-  if (reg == FAIL)
-    return -1;
+  /* PR 16694: Allow VFP registers as well.  */
+  reg = arm_reg_parse (&regname, REG_TYPE_VFS);
+  if (reg != FAIL)
+    return 64 + reg;
 
-  return reg;
+  reg = arm_reg_parse (&regname, REG_TYPE_VFD);
+  if (reg != FAIL)
+    return reg + 256;
+
+  return -1;
 }
 
 #ifdef TE_PE
@@ -19869,8 +22207,8 @@ md_pcrel_from_section (fixS * fixP, segT seg)
          && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
          && !S_FORCE_RELOC (fixP->fx_addsy, TRUE)
          && ARM_IS_FUNC (fixP->fx_addsy)
-         && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v5t))
-       base = fixP->fx_where + fixP->fx_frag->fr_address;
+         && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v5t))
+       base = fixP->fx_where + fixP->fx_frag->fr_address;
        return base + 4;
 
       /* BLX is like branches above, but forces the low two bits of PC to
@@ -19879,9 +22217,9 @@ md_pcrel_from_section (fixS * fixP, segT seg)
       if (fixP->fx_addsy
          && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
          && !S_FORCE_RELOC (fixP->fx_addsy, TRUE)
-         && THUMB_IS_FUNC (fixP->fx_addsy)
-         && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v5t))
-       base = fixP->fx_where + fixP->fx_frag->fr_address;
+         && THUMB_IS_FUNC (fixP->fx_addsy)
+         && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v5t))
+       base = fixP->fx_where + fixP->fx_frag->fr_address;
       return (base + 4) & ~3;
 
       /* ARM mode branches are offset by +8.  However, the Windows CE
@@ -19890,18 +22228,18 @@ md_pcrel_from_section (fixS * fixP, segT seg)
       if (fixP->fx_addsy
          && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
          && !S_FORCE_RELOC (fixP->fx_addsy, TRUE)
-         && ARM_IS_FUNC (fixP->fx_addsy)
-         && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v5t))
-       base = fixP->fx_where + fixP->fx_frag->fr_address;
+         && ARM_IS_FUNC (fixP->fx_addsy)
+         && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v5t))
+       base = fixP->fx_where + fixP->fx_frag->fr_address;
       return base + 8;
 
     case BFD_RELOC_ARM_PCREL_CALL:
       if (fixP->fx_addsy
          && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
          && !S_FORCE_RELOC (fixP->fx_addsy, TRUE)
-         && THUMB_IS_FUNC (fixP->fx_addsy)
-         && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v5t))
-       base = fixP->fx_where + fixP->fx_frag->fr_address;
+         && THUMB_IS_FUNC (fixP->fx_addsy)
+         && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v5t))
+       base = fixP->fx_where + fixP->fx_frag->fr_address;
       return base + 8;
 
     case BFD_RELOC_ARM_PCREL_BRANCH:
@@ -19909,11 +22247,11 @@ md_pcrel_from_section (fixS * fixP, segT seg)
     case BFD_RELOC_ARM_PLT32:
 #ifdef TE_WINCE
       /* When handling fixups immediately, because we have already
-         discovered the value of a symbol, or the address of the frag involved
+        discovered the value of a symbol, or the address of the frag involved
         we must account for the offset by +8, as the OS loader will never see the reloc.
-         see fixup_segment() in write.c
-         The S_IS_EXTERNAL test handles the case of global symbols.
-         Those need the calculated base, not just the pipe compensation the linker will need.  */
+        see fixup_segment() in write.c
+        The S_IS_EXTERNAL test handles the case of global symbols.
+        Those need the calculated base, not just the pipe compensation the linker will need.  */
       if (fixP->fx_pcrel
          && fixP->fx_addsy != NULL
          && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
@@ -19942,6 +22280,51 @@ md_pcrel_from_section (fixS * fixP, segT seg)
     }
 }
 
+static bfd_boolean flag_warn_syms = TRUE;
+
+bfd_boolean
+arm_tc_equal_in_insn (int c ATTRIBUTE_UNUSED, char * name)
+{
+  /* PR 18347 - Warn if the user attempts to create a symbol with the same
+     name as an ARM instruction.  Whilst strictly speaking it is allowed, it
+     does mean that the resulting code might be very confusing to the reader.
+     Also this warning can be triggered if the user omits an operand before
+     an immediate address, eg:
+
+       LDR =foo
+
+     GAS treats this as an assignment of the value of the symbol foo to a
+     symbol LDR, and so (without this code) it will not issue any kind of
+     warning or error message.
+
+     Note - ARM instructions are case-insensitive but the strings in the hash
+     table are all stored in lower case, so we must first ensure that name is
+     lower case too.  */
+  if (flag_warn_syms && arm_ops_hsh)
+    {
+      char * nbuf = strdup (name);
+      char * p;
+
+      for (p = nbuf; *p; p++)
+       *p = TOLOWER (*p);
+      if (hash_find (arm_ops_hsh, nbuf) != NULL)
+       {
+         static struct hash_control * already_warned = NULL;
+
+         if (already_warned == NULL)
+           already_warned = hash_new ();
+         /* Only warn about the symbol once.  To keep the code
+            simple we let hash_insert do the lookup for us.  */
+         if (hash_insert (already_warned, name, NULL) == NULL)
+           as_warn (_("[-mwarn-syms]: Assignment makes a symbol match an ARM instruction: %s"), name);
+       }
+      else
+       free (nbuf);
+    }
+
+  return FALSE;
+}
+
 /* Under ELF we need to default _GLOBAL_OFFSET_TABLE.
    Otherwise we have no need to default values of symbols.  */
 
@@ -20231,7 +22614,7 @@ encode_thumb2_b_bl_offset (char * buf, offsetT value)
   I1 = (value >> 23) & 0x01;
   I2 = (value >> 22) & 0x01;
   hi = (value >> 12) & 0x3ff;
-  lo = (value >> 1) & 0x7ff; 
+  lo = (value >> 1) & 0x7ff;
   newval   = md_chars_to_number (buf, THUMB_SIZE);
   newval2  = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
   newval  |= (S << 10) | hi;
@@ -20307,13 +22690,22 @@ md_apply_fix (fixS *  fixP,
            }
        }
 
-      newimm = encode_arm_immediate (value);
       temp = md_chars_to_number (buf, INSN_SIZE);
 
-      /* If the instruction will fail, see if we can fix things up by
-        changing the opcode.  */
-      if (newimm == (unsigned int) FAIL
-         && (newimm = negate_data_op (&temp, value)) == (unsigned int) FAIL)
+      /* If the offset is negative, we should use encoding A2 for ADR.  */
+      if ((temp & 0xfff0000) == 0x28f0000 && value < 0)
+       newimm = negate_data_op (&temp, value);
+      else
+       {
+         newimm = encode_arm_immediate (value);
+
+         /* If the instruction will fail, see if we can fix things up by
+            changing the opcode.  */
+         if (newimm == (unsigned int) FAIL)
+           newimm = negate_data_op (&temp, value);
+       }
+
+      if (newimm == (unsigned int) FAIL)
        {
          as_bad_where (fixP->fx_file, fixP->fx_line,
                        _("invalid constant (%lx) after fixup"),
@@ -20348,7 +22740,7 @@ md_apply_fix (fixS *    fixP,
                break;
              }
          }
-       
+
        newimm = encode_arm_immediate (value);
        temp = md_chars_to_number (buf, INSN_SIZE);
 
@@ -20398,7 +22790,7 @@ md_apply_fix (fixS *    fixP,
        value = 0;
 
     case BFD_RELOC_ARM_LITERAL:
-      sign = value >= 0;
+      sign = value > 0;
 
       if (value < 0)
        value = - value;
@@ -20416,14 +22808,19 @@ md_apply_fix (fixS *  fixP,
        }
 
       newval = md_chars_to_number (buf, INSN_SIZE);
-      newval &= 0xff7ff000;
-      newval |= value | (sign ? INDEX_UP : 0);
+      if (value == 0)
+       newval &= 0xfffff000;
+      else
+       {
+         newval &= 0xff7ff000;
+         newval |= value | (sign ? INDEX_UP : 0);
+       }
       md_number_to_chars (buf, newval, INSN_SIZE);
       break;
 
     case BFD_RELOC_ARM_OFFSET_IMM8:
     case BFD_RELOC_ARM_HWLITERAL:
-      sign = value >= 0;
+      sign = value > 0;
 
       if (value < 0)
        value = - value;
@@ -20434,14 +22831,20 @@ md_apply_fix (fixS *  fixP,
            as_bad_where (fixP->fx_file, fixP->fx_line,
                          _("invalid literal constant: pool needs to be closer"));
          else
-           as_bad (_("bad immediate value for 8-bit offset (%ld)"),
-                   (long) value);
+           as_bad_where (fixP->fx_file, fixP->fx_line,
+                         _("bad immediate value for 8-bit offset (%ld)"),
+                         (long) value);
          break;
        }
 
       newval = md_chars_to_number (buf, INSN_SIZE);
-      newval &= 0xff7ff0f0;
-      newval |= ((value >> 4) << 8) | (value & 0xf) | (sign ? INDEX_UP : 0);
+      if (value == 0)
+       newval &= 0xfffff0f0;
+      else
+       {
+         newval &= 0xff7ff0f0;
+         newval |= ((value >> 4) << 8) | (value & 0xf) | (sign ? INDEX_UP : 0);
+       }
       md_number_to_chars (buf, newval, INSN_SIZE);
       break;
 
@@ -20461,7 +22864,7 @@ md_apply_fix (fixS *    fixP,
         load/store instruction with immediate offset:
 
         1110 100P u1WL NNNN XXXX YYYY iiii iiii - +/-(U) pre/post(P) 8-bit,
-                                                  *4, optional writeback(W)
+                                                  *4, optional writeback(W)
                                                   (doubleword load/store)
 
         1111 100S uTTL 1111 XXXX iiii iiii iiii - +/-(U) 12-bit PC-rel
@@ -20772,7 +23175,7 @@ md_apply_fix (fixS *    fixP,
 
 #ifdef OBJ_ELF
        if (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4)
-         fixP->fx_r_type = BFD_RELOC_ARM_PCREL_CALL;
+        fixP->fx_r_type = BFD_RELOC_ARM_PCREL_CALL;
 #endif
 
     arm_branch_common:
@@ -20785,8 +23188,7 @@ md_apply_fix (fixS *    fixP,
                      _("misaligned branch destination"));
       if ((value & (offsetT)0xfe000000) != (offsetT)0
          && (value & (offsetT)0xfe000000) != (offsetT)0xfe000000)
-       as_bad_where (fixP->fx_file, fixP->fx_line,
-                     _("branch out of range"));
+       as_bad_where (fixP->fx_file, fixP->fx_line, BAD_RANGE);
 
       if (fixP->fx_done || !seg->use_rela_p)
        {
@@ -20808,8 +23210,8 @@ md_apply_fix (fixS *    fixP,
       /* CBZ can only branch forward.  */
 
       /* Attempts to use CBZ to branch to the next instruction
-         (which, strictly speaking, are prohibited) will be turned into
-         no-ops.
+        (which, strictly speaking, are prohibited) will be turned into
+        no-ops.
 
         FIXME: It may be better to remove the instruction completely and
         perform relaxation.  */
@@ -20822,10 +23224,9 @@ md_apply_fix (fixS *   fixP,
       else
        {
          if (value & ~0x7e)
-           as_bad_where (fixP->fx_file, fixP->fx_line,
-                         _("branch out of range"));
+           as_bad_where (fixP->fx_file, fixP->fx_line, BAD_RANGE);
 
-          if (fixP->fx_done || !seg->use_rela_p)
+         if (fixP->fx_done || !seg->use_rela_p)
            {
              newval = md_chars_to_number (buf, THUMB_SIZE);
              newval |= ((value & 0x3e) << 2) | ((value & 0x40) << 3);
@@ -20836,8 +23237,7 @@ md_apply_fix (fixS *    fixP,
 
     case BFD_RELOC_THUMB_PCREL_BRANCH9: /* Conditional branch. */
       if ((value & ~0xff) && ((value & ~0xff) != ~0xff))
-       as_bad_where (fixP->fx_file, fixP->fx_line,
-                     _("branch out of range"));
+       as_bad_where (fixP->fx_file, fixP->fx_line, BAD_RANGE);
 
       if (fixP->fx_done || !seg->use_rela_p)
        {
@@ -20849,8 +23249,7 @@ md_apply_fix (fixS *    fixP,
 
     case BFD_RELOC_THUMB_PCREL_BRANCH12: /* Unconditional branch.  */
       if ((value & ~0x7ff) && ((value & ~0x7ff) != ~0x7ff))
-       as_bad_where (fixP->fx_file, fixP->fx_line,
-                     _("branch out of range"));
+       as_bad_where (fixP->fx_file, fixP->fx_line, BAD_RANGE);
 
       if (fixP->fx_done || !seg->use_rela_p)
        {
@@ -20870,7 +23269,7 @@ md_apply_fix (fixS *    fixP,
          /* Force a relocation for a branch 20 bits wide.  */
          fixP->fx_done = 0;
        }
-      if ((value & ~0x1fffff) && ((value & ~0x1fffff) != ~0x1fffff))
+      if ((value & ~0x1fffff) && ((value & ~0x0fffff) != ~0x0fffff))
        as_bad_where (fixP->fx_file, fixP->fx_line,
                      _("conditional branch out of range"));
 
@@ -20895,7 +23294,6 @@ md_apply_fix (fixS *    fixP,
       break;
 
     case BFD_RELOC_THUMB_PCREL_BLX:
-
       /* If there is a blx from a thumb state function to
         another thumb function flip this to a bl and warn
         about it.  */
@@ -20920,7 +23318,6 @@ md_apply_fix (fixS *    fixP,
       goto thumb_bl_common;
 
     case BFD_RELOC_THUMB_PCREL_BRANCH23:
-
       /* A bl from Thumb state ISA to an internal ARM state function
         is converted to a blx.  */
       if (fixP->fx_addsy
@@ -20938,33 +23335,27 @@ md_apply_fix (fixS *  fixP,
 
     thumb_bl_common:
 
-#ifdef OBJ_ELF
-       if (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4 &&
-          fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX)
-        fixP->fx_r_type = BFD_RELOC_THUMB_PCREL_BRANCH23;
-#endif
-
       if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX)
        /* For a BLX instruction, make sure that the relocation is rounded up
           to a word boundary.  This follows the semantics of the instruction
           which specifies that bit 1 of the target address will come from bit
           1 of the base address.  */
-       value = (value + 1) & ~ 1;
+       value = (value + 3) & ~ 3;
 
+#ifdef OBJ_ELF
+       if (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4
+          && fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX)
+        fixP->fx_r_type = BFD_RELOC_THUMB_PCREL_BRANCH23;
+#endif
 
-       if ((value & ~0x3fffff) && ((value & ~0x3fffff) != ~0x3fffff))
+      if ((value & ~0x3fffff) && ((value & ~0x3fffff) != ~0x3fffff))
        {
-         if (!(ARM_CPU_HAS_FEATURE (cpu_variant, arm_arch_t2)))
-           {
-             as_bad_where (fixP->fx_file, fixP->fx_line,
-                           _("branch out of range"));
-           }
+         if (!(ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6t2)))
+           as_bad_where (fixP->fx_file, fixP->fx_line, BAD_RANGE);
          else if ((value & ~0x1ffffff)
                   && ((value & ~0x1ffffff) != ~0x1ffffff))
-             {
-               as_bad_where (fixP->fx_file, fixP->fx_line,
-                           _("Thumb2 branch out of range"));
-             }
+           as_bad_where (fixP->fx_file, fixP->fx_line,
+                         _("Thumb2 branch out of range"));
        }
 
       if (fixP->fx_done || !seg->use_rela_p)
@@ -20973,9 +23364,8 @@ md_apply_fix (fixS *    fixP,
       break;
 
     case BFD_RELOC_THUMB_PCREL_BRANCH25:
-      if ((value & ~0x1ffffff) && ((value & ~0x1ffffff) != ~0x1ffffff))
-       as_bad_where (fixP->fx_file, fixP->fx_line,
-                     _("branch out of range"));
+      if ((value & ~0x0ffffff) && ((value & ~0x0ffffff) != ~0x0ffffff))
+       as_bad_where (fixP->fx_file, fixP->fx_line, BAD_RANGE);
 
       if (fixP->fx_done || !seg->use_rela_p)
          encode_thumb2_b_bl_offset (buf, value);
@@ -20984,7 +23374,7 @@ md_apply_fix (fixS *    fixP,
 
     case BFD_RELOC_8:
       if (fixP->fx_done || !seg->use_rela_p)
-       md_number_to_chars (buf, value, 1);
+       *buf = value;
       break;
 
     case BFD_RELOC_16:
@@ -20997,9 +23387,6 @@ md_apply_fix (fixS *    fixP,
     case BFD_RELOC_ARM_THM_TLS_CALL:
     case BFD_RELOC_ARM_TLS_DESCSEQ:
     case BFD_RELOC_ARM_THM_TLS_DESCSEQ:
-      S_SET_THREAD_LOCAL (fixP->fx_addsy);
-      break;
-
     case BFD_RELOC_ARM_TLS_GOTDESC:
     case BFD_RELOC_ARM_TLS_GD32:
     case BFD_RELOC_ARM_TLS_LE32:
@@ -21007,23 +23394,21 @@ md_apply_fix (fixS *  fixP,
     case BFD_RELOC_ARM_TLS_LDM32:
     case BFD_RELOC_ARM_TLS_LDO32:
       S_SET_THREAD_LOCAL (fixP->fx_addsy);
-      /* fall through */
+      break;
 
     case BFD_RELOC_ARM_GOT32:
     case BFD_RELOC_ARM_GOTOFF:
-      if (fixP->fx_done || !seg->use_rela_p)
-       md_number_to_chars (buf, 0, 4);
       break;
 
     case BFD_RELOC_ARM_GOT_PREL:
       if (fixP->fx_done || !seg->use_rela_p)
-        md_number_to_chars (buf, value, 4);
+       md_number_to_chars (buf, value, 4);
       break;
 
     case BFD_RELOC_ARM_TARGET2:
       /* TARGET2 is not partial-inplace, so we need to write the
-         addend here for REL targets, because it won't be written out
-         during reloc processing later.  */
+        addend here for REL targets, because it won't be written out
+        during reloc processing later.  */
       if (fixP->fx_done || !seg->use_rela_p)
        md_number_to_chars (buf, fixP->fx_offset, 4);
       break;
@@ -21064,11 +23449,24 @@ md_apply_fix (fixS *  fixP,
 
     case BFD_RELOC_ARM_CP_OFF_IMM:
     case BFD_RELOC_ARM_T32_CP_OFF_IMM:
-      if (value < -1023 || value > 1023 || (value & 3))
+      if (fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM)
+       newval = md_chars_to_number (buf, INSN_SIZE);
+      else
+       newval = get_thumb32_insn (buf);
+      if ((newval & 0x0f200f00) == 0x0d000900)
+       {
+         /* This is a fp16 vstr/vldr.  The immediate offset in the mnemonic
+            has permitted values that are multiples of 2, in the range 0
+            to 510.  */
+         if (value < -510 || value > 510 || (value & 1))
+           as_bad_where (fixP->fx_file, fixP->fx_line,
+                         _("co-processor offset out of range"));
+       }
+      else if (value < -1023 || value > 1023 || (value & 3))
        as_bad_where (fixP->fx_file, fixP->fx_line,
                      _("co-processor offset out of range"));
     cp_off_common:
-      sign = value >= 0;
+      sign = value > 0;
       if (value < 0)
        value = -value;
       if (fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM
@@ -21076,8 +23474,24 @@ md_apply_fix (fixS *   fixP,
        newval = md_chars_to_number (buf, INSN_SIZE);
       else
        newval = get_thumb32_insn (buf);
-      newval &= 0xff7fff00;
-      newval |= (value >> 2) | (sign ? INDEX_UP : 0);
+      if (value == 0)
+       newval &= 0xffffff00;
+      else
+       {
+         newval &= 0xff7fff00;
+         if ((newval & 0x0f200f00) == 0x0d000900)
+           {
+             /* This is a fp16 vstr/vldr.
+
+                It requires the immediate offset in the instruction is shifted
+                left by 1 to be a half-word offset.
+
+                Here, left shift by 1 first, and later right shift by 2
+                should get the right offset.  */
+             value <<= 1;
+           }
+         newval |= (value >> 2) | (sign ? INDEX_UP : 0);
+       }
       if (fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM
          || fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM_S2)
        md_number_to_chars (buf, newval, INSN_SIZE);
@@ -21201,7 +23615,7 @@ md_apply_fix (fixS *    fixP,
 
        if (rd == REG_SP)
          {
-           if (value & ~0x1fc)
+           if (value & ~0x1fc)
              as_bad_where (fixP->fx_file, fixP->fx_line,
                            _("invalid immediate for stack address calculation"));
            newval = subtract ? T_OPCODE_SUB_ST : T_OPCODE_ADD_ST;
@@ -21209,10 +23623,49 @@ md_apply_fix (fixS *  fixP,
          }
        else if (rs == REG_PC || rs == REG_SP)
          {
+           /* PR gas/18541.  If the addition is for a defined symbol
+              within range of an ADR instruction then accept it.  */
+           if (subtract
+               && value == 4
+               && fixP->fx_addsy != NULL)
+             {
+               subtract = 0;
+
+               if (! S_IS_DEFINED (fixP->fx_addsy)
+                   || S_GET_SEGMENT (fixP->fx_addsy) != seg
+                   || S_IS_WEAK (fixP->fx_addsy))
+                 {
+                   as_bad_where (fixP->fx_file, fixP->fx_line,
+                                 _("address calculation needs a strongly defined nearby symbol"));
+                 }
+               else
+                 {
+                   offsetT v = fixP->fx_where + fixP->fx_frag->fr_address;
+
+                   /* Round up to the next 4-byte boundary.  */
+                   if (v & 3)
+                     v = (v + 3) & ~ 3;
+                   else
+                     v += 4;
+                   v = S_GET_VALUE (fixP->fx_addsy) - v;
+
+                   if (v & ~0x3fc)
+                     {
+                       as_bad_where (fixP->fx_file, fixP->fx_line,
+                                     _("symbol too far away"));
+                     }
+                   else
+                     {
+                       fixP->fx_done = 1;
+                       value = v;
+                     }
+                 }
+             }
+
            if (subtract || value & ~0x3fc)
              as_bad_where (fixP->fx_file, fixP->fx_line,
                            _("invalid immediate for address calculation (value = 0x%08lX)"),
-                           (unsigned long) value);
+                           (unsigned long) (subtract ? - value : value));
            newval = (rs == REG_PC ? T_OPCODE_ADD_PC : T_OPCODE_ADD_SP);
            newval |= rd << 8;
            newval |= value >> 2;
@@ -21310,6 +23763,68 @@ md_apply_fix (fixS *   fixP,
        }
       return;
 
+   case BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC:
+   case BFD_RELOC_ARM_THUMB_ALU_ABS_G1_NC:
+   case BFD_RELOC_ARM_THUMB_ALU_ABS_G2_NC:
+   case BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC:
+      gas_assert (!fixP->fx_done);
+      {
+       bfd_vma insn;
+       bfd_boolean is_mov;
+       bfd_vma encoded_addend = value;
+
+       /* Check that addend can be encoded in instruction.  */
+       if (!seg->use_rela_p && (value < 0 || value > 255))
+         as_bad_where (fixP->fx_file, fixP->fx_line,
+                       _("the offset 0x%08lX is not representable"),
+                       (unsigned long) encoded_addend);
+
+       /* Extract the instruction.  */
+       insn = md_chars_to_number (buf, THUMB_SIZE);
+       is_mov = (insn & 0xf800) == 0x2000;
+
+       /* Encode insn.  */
+       if (is_mov)
+         {
+           if (!seg->use_rela_p)
+             insn |= encoded_addend;
+         }
+       else
+         {
+           int rd, rs;
+
+           /* Extract the instruction.  */
+            /* Encoding is the following
+               0x8000  SUB
+               0x00F0  Rd
+               0x000F  Rs
+            */
+            /* The following conditions must be true :
+               - ADD
+               - Rd == Rs
+               - Rd <= 7
+            */
+           rd = (insn >> 4) & 0xf;
+           rs = insn & 0xf;
+           if ((insn & 0x8000) || (rd != rs) || rd > 7)
+             as_bad_where (fixP->fx_file, fixP->fx_line,
+                       _("Unable to process relocation for thumb opcode: %lx"),
+                       (unsigned long) insn);
+
+           /* Encode as ADD immediate8 thumb 1 code.  */
+           insn = 0x3000 | (rd << 8);
+
+           /* Place the encoded addend into the first 8 bits of the
+              instruction.  */
+           if (!seg->use_rela_p)
+             insn |= encoded_addend;
+         }
+
+       /* Update the instruction.  */
+       md_number_to_chars (buf, insn, THUMB_SIZE);
+      }
+      break;
+
    case BFD_RELOC_ARM_ALU_PC_G0_NC:
    case BFD_RELOC_ARM_ALU_PC_G0:
    case BFD_RELOC_ARM_ALU_PC_G1_NC:
@@ -21323,36 +23838,36 @@ md_apply_fix (fixS *  fixP,
      gas_assert (!fixP->fx_done);
      if (!seg->use_rela_p)
        {
-         bfd_vma insn;
-         bfd_vma encoded_addend;
-         bfd_vma addend_abs = abs (value);
-
-         /* Check that the absolute value of the addend can be
-            expressed as an 8-bit constant plus a rotation.  */
-         encoded_addend = encode_arm_immediate (addend_abs);
-         if (encoded_addend == (unsigned int) FAIL)
+        bfd_vma insn;
+        bfd_vma encoded_addend;
+        bfd_vma addend_abs = abs (value);
+
+        /* Check that the absolute value of the addend can be
+           expressed as an 8-bit constant plus a rotation.  */
+        encoded_addend = encode_arm_immediate (addend_abs);
+        if (encoded_addend == (unsigned int) FAIL)
           as_bad_where (fixP->fx_file, fixP->fx_line,
-                        _("the offset 0x%08lX is not representable"),
-                         (unsigned long) addend_abs);
-
-         /* Extract the instruction.  */
-         insn = md_chars_to_number (buf, INSN_SIZE);
-
-         /* If the addend is positive, use an ADD instruction.
-            Otherwise use a SUB.  Take care not to destroy the S bit.  */
-         insn &= 0xff1fffff;
-         if (value < 0)
-           insn |= 1 << 22;
-         else
-           insn |= 1 << 23;
-
-         /* Place the encoded addend into the first 12 bits of the
-            instruction.  */
-         insn &= 0xfffff000;
-         insn |= encoded_addend;
-
-         /* Update the instruction.  */
-         md_number_to_chars (buf, insn, INSN_SIZE);
+                        _("the offset 0x%08lX is not representable"),
+                        (unsigned long) addend_abs);
+
+        /* Extract the instruction.  */
+        insn = md_chars_to_number (buf, INSN_SIZE);
+
+        /* If the addend is positive, use an ADD instruction.
+           Otherwise use a SUB.  Take care not to destroy the S bit.  */
+        insn &= 0xff1fffff;
+        if (value < 0)
+          insn |= 1 << 22;
+        else
+          insn |= 1 << 23;
+
+        /* Place the encoded addend into the first 12 bits of the
+           instruction.  */
+        insn &= 0xfffff000;
+        insn |= encoded_addend;
+
+        /* Update the instruction.  */
+        md_number_to_chars (buf, insn, INSN_SIZE);
        }
      break;
 
@@ -21364,35 +23879,35 @@ md_apply_fix (fixS *  fixP,
     case BFD_RELOC_ARM_LDR_SB_G2:
       gas_assert (!fixP->fx_done);
       if (!seg->use_rela_p)
-        {
-          bfd_vma insn;
-          bfd_vma addend_abs = abs (value);
+       {
+         bfd_vma insn;
+         bfd_vma addend_abs = abs (value);
 
-          /* Check that the absolute value of the addend can be
-             encoded in 12 bits.  */
-          if (addend_abs >= 0x1000)
+         /* Check that the absolute value of the addend can be
+            encoded in 12 bits.  */
+         if (addend_abs >= 0x1000)
            as_bad_where (fixP->fx_file, fixP->fx_line,
-                         _("bad offset 0x%08lX (only 12 bits available for the magnitude)"),
-                          (unsigned long) addend_abs);
-
-          /* Extract the instruction.  */
-          insn = md_chars_to_number (buf, INSN_SIZE);
-
-          /* If the addend is negative, clear bit 23 of the instruction.
-             Otherwise set it.  */
-          if (value < 0)
-            insn &= ~(1 << 23);
-          else
-            insn |= 1 << 23;
-
-          /* Place the absolute value of the addend into the first 12 bits
-             of the instruction.  */
-          insn &= 0xfffff000;
-          insn |= addend_abs;
-
-          /* Update the instruction.  */
-          md_number_to_chars (buf, insn, INSN_SIZE);
-        }
+                         _("bad offset 0x%08lX (only 12 bits available for the magnitude)"),
+                         (unsigned long) addend_abs);
+
+         /* Extract the instruction.  */
+         insn = md_chars_to_number (buf, INSN_SIZE);
+
+         /* If the addend is negative, clear bit 23 of the instruction.
+            Otherwise set it.  */
+         if (value < 0)
+           insn &= ~(1 << 23);
+         else
+           insn |= 1 << 23;
+
+         /* Place the absolute value of the addend into the first 12 bits
+            of the instruction.  */
+         insn &= 0xfffff000;
+         insn |= addend_abs;
+
+         /* Update the instruction.  */
+         md_number_to_chars (buf, insn, INSN_SIZE);
+       }
       break;
 
     case BFD_RELOC_ARM_LDRS_PC_G0:
@@ -21403,36 +23918,36 @@ md_apply_fix (fixS *  fixP,
     case BFD_RELOC_ARM_LDRS_SB_G2:
       gas_assert (!fixP->fx_done);
       if (!seg->use_rela_p)
-        {
-          bfd_vma insn;
-          bfd_vma addend_abs = abs (value);
+       {
+         bfd_vma insn;
+         bfd_vma addend_abs = abs (value);
 
-          /* Check that the absolute value of the addend can be
-             encoded in 8 bits.  */
-          if (addend_abs >= 0x100)
+         /* Check that the absolute value of the addend can be
+            encoded in 8 bits.  */
+         if (addend_abs >= 0x100)
            as_bad_where (fixP->fx_file, fixP->fx_line,
-                         _("bad offset 0x%08lX (only 8 bits available for the magnitude)"),
-                          (unsigned long) addend_abs);
-
-          /* Extract the instruction.  */
-          insn = md_chars_to_number (buf, INSN_SIZE);
-
-          /* If the addend is negative, clear bit 23 of the instruction.
-             Otherwise set it.  */
-          if (value < 0)
-            insn &= ~(1 << 23);
-          else
-            insn |= 1 << 23;
-
-          /* Place the first four bits of the absolute value of the addend
-             into the first 4 bits of the instruction, and the remaining
-             four into bits 8 .. 11.  */
-          insn &= 0xfffff0f0;
-          insn |= (addend_abs & 0xf) | ((addend_abs & 0xf0) << 4);
-
-          /* Update the instruction.  */
-          md_number_to_chars (buf, insn, INSN_SIZE);
-        }
+                         _("bad offset 0x%08lX (only 8 bits available for the magnitude)"),
+                         (unsigned long) addend_abs);
+
+         /* Extract the instruction.  */
+         insn = md_chars_to_number (buf, INSN_SIZE);
+
+         /* If the addend is negative, clear bit 23 of the instruction.
+            Otherwise set it.  */
+         if (value < 0)
+           insn &= ~(1 << 23);
+         else
+           insn |= 1 << 23;
+
+         /* Place the first four bits of the absolute value of the addend
+            into the first 4 bits of the instruction, and the remaining
+            four into bits 8 .. 11.  */
+         insn &= 0xfffff0f0;
+         insn |= (addend_abs & 0xf) | ((addend_abs & 0xf0) << 4);
+
+         /* Update the instruction.  */
+         md_number_to_chars (buf, insn, INSN_SIZE);
+       }
       break;
 
     case BFD_RELOC_ARM_LDC_PC_G0:
@@ -21443,40 +23958,40 @@ md_apply_fix (fixS *  fixP,
     case BFD_RELOC_ARM_LDC_SB_G2:
       gas_assert (!fixP->fx_done);
       if (!seg->use_rela_p)
-        {
-          bfd_vma insn;
-          bfd_vma addend_abs = abs (value);
+       {
+         bfd_vma insn;
+         bfd_vma addend_abs = abs (value);
 
-          /* Check that the absolute value of the addend is a multiple of
-             four and, when divided by four, fits in 8 bits.  */
-          if (addend_abs & 0x3)
+         /* Check that the absolute value of the addend is a multiple of
+            four and, when divided by four, fits in 8 bits.  */
+         if (addend_abs & 0x3)
            as_bad_where (fixP->fx_file, fixP->fx_line,
-                         _("bad offset 0x%08lX (must be word-aligned)"),
-                          (unsigned long) addend_abs);
+                         _("bad offset 0x%08lX (must be word-aligned)"),
+                         (unsigned long) addend_abs);
 
-          if ((addend_abs >> 2) > 0xff)
+         if ((addend_abs >> 2) > 0xff)
            as_bad_where (fixP->fx_file, fixP->fx_line,
-                         _("bad offset 0x%08lX (must be an 8-bit number of words)"),
-                          (unsigned long) addend_abs);
-
-          /* Extract the instruction.  */
-          insn = md_chars_to_number (buf, INSN_SIZE);
-
-          /* If the addend is negative, clear bit 23 of the instruction.
-             Otherwise set it.  */
-          if (value < 0)
-            insn &= ~(1 << 23);
-          else
-            insn |= 1 << 23;
-
-          /* Place the addend (divided by four) into the first eight
-             bits of the instruction.  */
-          insn &= 0xfffffff0;
-          insn |= addend_abs >> 2;
-
-          /* Update the instruction.  */
-          md_number_to_chars (buf, insn, INSN_SIZE);
-        }
+                         _("bad offset 0x%08lX (must be an 8-bit number of words)"),
+                         (unsigned long) addend_abs);
+
+         /* Extract the instruction.  */
+         insn = md_chars_to_number (buf, INSN_SIZE);
+
+         /* If the addend is negative, clear bit 23 of the instruction.
+            Otherwise set it.  */
+         if (value < 0)
+           insn &= ~(1 << 23);
+         else
+           insn |= 1 << 23;
+
+         /* Place the addend (divided by four) into the first eight
+            bits of the instruction.  */
+         insn &= 0xfffffff0;
+         insn |= addend_abs >> 2;
+
+         /* Update the instruction.  */
+         md_number_to_chars (buf, insn, INSN_SIZE);
+       }
       break;
 
     case BFD_RELOC_ARM_V4BX:
@@ -21500,9 +24015,9 @@ tc_gen_reloc (asection *section, fixS *fixp)
   arelent * reloc;
   bfd_reloc_code_real_type code;
 
-  reloc = (arelent *) xmalloc (sizeof (arelent));
+  reloc = XNEW (arelent);
 
-  reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+  reloc->sym_ptr_ptr = XNEW (asymbol *);
   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
 
@@ -21615,7 +24130,6 @@ tc_gen_reloc (asection *section, fixS *fixp)
     case BFD_RELOC_ARM_SBREL32:
     case BFD_RELOC_ARM_PREL31:
     case BFD_RELOC_ARM_TARGET2:
-    case BFD_RELOC_ARM_TLS_LE32:
     case BFD_RELOC_ARM_TLS_LDO32:
     case BFD_RELOC_ARM_PCREL_CALL:
     case BFD_RELOC_ARM_PCREL_JUMP:
@@ -21648,11 +24162,16 @@ tc_gen_reloc (asection *section, fixS *fixp)
     case BFD_RELOC_ARM_LDC_SB_G1:
     case BFD_RELOC_ARM_LDC_SB_G2:
     case BFD_RELOC_ARM_V4BX:
+    case BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC:
+    case BFD_RELOC_ARM_THUMB_ALU_ABS_G1_NC:
+    case BFD_RELOC_ARM_THUMB_ALU_ABS_G2_NC:
+    case BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC:
       code = fixp->fx_r_type;
       break;
 
     case BFD_RELOC_ARM_TLS_GOTDESC:
     case BFD_RELOC_ARM_TLS_GD32:
+    case BFD_RELOC_ARM_TLS_LE32:
     case BFD_RELOC_ARM_TLS_IE32:
     case BFD_RELOC_ARM_TLS_LDM32:
       /* BFD will include the symbol's address in the addend.
@@ -21696,7 +24215,7 @@ tc_gen_reloc (asection *section, fixS *fixp)
 
     default:
       {
-       char * type;
+       const char * type;
 
        switch (fixp->fx_r_type)
          {
@@ -21756,9 +24275,9 @@ void
 cons_fix_new_arm (fragS *      frag,
                  int           where,
                  int           size,
-                 expressionS * exp)
+                 expressionS * exp,
+                 bfd_reloc_code_real_type reloc)
 {
-  bfd_reloc_code_real_type type;
   int pcrel = 0;
 
   /* Pick a reloc.
@@ -21766,17 +24285,17 @@ cons_fix_new_arm (fragS *     frag,
   switch (size)
     {
     case 1:
-      type = BFD_RELOC_8;
+      reloc = BFD_RELOC_8;
       break;
     case 2:
-      type = BFD_RELOC_16;
+      reloc = BFD_RELOC_16;
       break;
     case 4:
     default:
-      type = BFD_RELOC_32;
+      reloc = BFD_RELOC_32;
       break;
     case 8:
-      type = BFD_RELOC_64;
+      reloc = BFD_RELOC_64;
       break;
     }
 
@@ -21784,11 +24303,11 @@ cons_fix_new_arm (fragS *     frag,
   if (exp->X_op == O_secrel)
   {
     exp->X_op = O_symbol;
-    type = BFD_RELOC_32_SECREL;
+    reloc = BFD_RELOC_32_SECREL;
   }
 #endif
 
-  fix_new_exp (frag, where, (int) size, exp, pcrel, type);
+  fix_new_exp (frag, where, size, exp, pcrel, reloc);
 }
 
 #if defined (OBJ_COFF)
@@ -21846,14 +24365,25 @@ arm_force_relocation (struct fix * fixp)
     }
 #endif
 
-  /* Resolve these relocations even if the symbol is extern or weak.  */
+  /* Resolve these relocations even if the symbol is extern or weak.
+     Technically this is probably wrong due to symbol preemption.
+     In practice these relocations do not have enough range to be useful
+     at dynamic link time, and some code (e.g. in the Linux kernel)
+     expects these references to be resolved.  */
   if (fixp->fx_r_type == BFD_RELOC_ARM_IMMEDIATE
       || fixp->fx_r_type == BFD_RELOC_ARM_OFFSET_IMM
+      || fixp->fx_r_type == BFD_RELOC_ARM_OFFSET_IMM8
       || fixp->fx_r_type == BFD_RELOC_ARM_ADRL_IMMEDIATE
+      || fixp->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM
+      || fixp->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM_S2
+      || fixp->fx_r_type == BFD_RELOC_ARM_THUMB_OFFSET
       || fixp->fx_r_type == BFD_RELOC_ARM_T32_ADD_IMM
       || fixp->fx_r_type == BFD_RELOC_ARM_T32_IMMEDIATE
       || fixp->fx_r_type == BFD_RELOC_ARM_T32_IMM12
-      || fixp->fx_r_type == BFD_RELOC_ARM_T32_ADD_PC12)
+      || fixp->fx_r_type == BFD_RELOC_ARM_T32_OFFSET_IMM
+      || fixp->fx_r_type == BFD_RELOC_ARM_T32_ADD_PC12
+      || fixp->fx_r_type == BFD_RELOC_ARM_T32_CP_OFF_IMM
+      || fixp->fx_r_type == BFD_RELOC_ARM_T32_CP_OFF_IMM_S2)
     return 0;
 
   /* Always leave these relocations for the linker.  */
@@ -21938,12 +24468,17 @@ arm_fix_adjustable (fixS * fixP)
       || fixP->fx_r_type == BFD_RELOC_ARM_THUMB_MOVT_PCREL)
     return FALSE;
 
+  /* BFD_RELOC_ARM_THUMB_ALU_ABS_Gx_NC relocations have VERY limited
+     offsets, so keep these symbols.  */
+  if (fixP->fx_r_type >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC
+      && fixP->fx_r_type <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC)
+    return FALSE;
+
   return TRUE;
 }
 #endif /* defined (OBJ_ELF) || defined (OBJ_COFF) */
 
 #ifdef OBJ_ELF
-
 const char *
 elf32_arm_target_format (void)
 {
@@ -21955,6 +24490,10 @@ elf32_arm_target_format (void)
   return (target_big_endian
          ? "elf32-bigarm-vxworks"
          : "elf32-littlearm-vxworks");
+#elif defined (TE_NACL)
+  return (target_big_endian
+         ? "elf32-bigarm-nacl"
+         : "elf32-littlearm-nacl");
 #else
   if (target_big_endian)
     return "elf32-bigarm";
@@ -22189,7 +24728,7 @@ md_begin (void)
     hash_insert (arm_psr_hsh, psrs[i].template_name, (void *) (psrs + i));
   for (i = 0; i < sizeof (v7m_psrs) / sizeof (struct asm_psr); i++)
     hash_insert (arm_v7m_psr_hsh, v7m_psrs[i].template_name,
-                 (void *) (v7m_psrs + i));
+                (void *) (v7m_psrs + i));
   for (i = 0; i < sizeof (reg_names) / sizeof (struct reg_entry); i++)
     hash_insert (arm_reg_hsh, reg_names[i].name, (void *) (reg_names + i));
   for (i = 0;
@@ -22198,8 +24737,16 @@ md_begin (void)
     hash_insert (arm_barrier_opt_hsh, barrier_opt_names[i].template_name,
                 (void *) (barrier_opt_names + i));
 #ifdef OBJ_ELF
-  for (i = 0; i < sizeof (reloc_names) / sizeof (struct reloc_entry); i++)
-    hash_insert (arm_reloc_hsh, reloc_names[i].name, (void *) (reloc_names + i));
+  for (i = 0; i < ARRAY_SIZE (reloc_names); i++)
+    {
+      struct reloc_entry * entry = reloc_names + i;
+
+      if (arm_is_eabi() && entry->reloc == BFD_RELOC_ARM_PLT32)
+       /* This makes encode_branch() use the EABI versions of this relocation.  */
+       entry->reloc = BFD_RELOC_UNUSED;
+
+      hash_insert (arm_reloc_hsh, entry->name, (void *) entry);
+    }
 #endif
 
   set_constant_flonums ();
@@ -22256,6 +24803,8 @@ md_begin (void)
       mcpu_cpu_opt = &cpu_default;
       selected_cpu = cpu_default;
     }
+  else if (no_cpu_selected ())
+    selected_cpu = cpu_default;
 #else
   if (mcpu_cpu_opt)
     selected_cpu = *mcpu_cpu_opt;
@@ -22403,6 +24952,7 @@ md_begin (void)
              -mthumb-interwork          Code supports ARM/Thumb interworking
 
              -m[no-]warn-deprecated     Warn about deprecated features
+             -m[no-]warn-syms           Warn when symbols match instructions
 
       For now we will also provide support for:
 
@@ -22471,15 +25021,16 @@ struct option md_longopts[] =
   {NULL, no_argument, NULL, 0}
 };
 
+
 size_t md_longopts_size = sizeof (md_longopts);
 
 struct arm_option_table
 {
-  char *option;                /* Option name to match.  */
-  char *help;          /* Help information.  */
+  const char *option;          /* Option name to match.  */
+  const char *help;            /* Help information.  */
   int  *var;           /* Variable to change.  */
   int  value;          /* What to change it to.  */
-  char *deprecated;    /* If non-null, print this message.  */
+  const char *deprecated;      /* If non-null, print this message.  */
 };
 
 struct arm_option_table arm_opts[] =
@@ -22505,15 +25056,17 @@ struct arm_option_table arm_opts[] =
   {"mwarn-deprecated", NULL, &warn_on_deprecated, 1, NULL},
   {"mno-warn-deprecated", N_("do not warn on use of deprecated feature"),
    &warn_on_deprecated, 0, NULL},
+  {"mwarn-syms", N_("warn about symbols that match instruction names [default]"), (int *) (& flag_warn_syms), TRUE, NULL},
+  {"mno-warn-syms", N_("disable warnings about symobls that match instructions"), (int *) (& flag_warn_syms), FALSE, NULL},
   {NULL, NULL, NULL, 0, NULL}
 };
 
 struct arm_legacy_option_table
 {
-  char *option;                                /* Option name to match.  */
+  const char *option;                          /* Option name to match.  */
   const arm_feature_set        **var;          /* Variable to change.  */
   const arm_feature_set        value;          /* What to change it to.  */
-  char *deprecated;                    /* If non-null, print this message.  */
+  const char *deprecated;                      /* If non-null, print this message.  */
 };
 
 const struct arm_legacy_option_table arm_legacy_opts[] =
@@ -22631,7 +25184,8 @@ const struct arm_legacy_option_table arm_legacy_opts[] =
 
 struct arm_cpu_option_table
 {
-  char *name;
+  const char *name;
+  size_t name_len;
   const arm_feature_set        value;
   /* For some CPUs we assume an FPU unless the user explicitly sets
      -mfpu=... */
@@ -22643,211 +25197,311 @@ struct arm_cpu_option_table
 
 /* This list should, at a minimum, contain all the cpu names
    recognized by GCC.  */
+#define ARM_CPU_OPT(N, V, DF, CN) { N, sizeof (N) - 1, V, DF, CN }
 static const struct arm_cpu_option_table arm_cpus[] =
 {
-  {"all",              ARM_ANY,         FPU_ARCH_FPA,    NULL},
-  {"arm1",             ARM_ARCH_V1,     FPU_ARCH_FPA,    NULL},
-  {"arm2",             ARM_ARCH_V2,     FPU_ARCH_FPA,    NULL},
-  {"arm250",           ARM_ARCH_V2S,    FPU_ARCH_FPA,    NULL},
-  {"arm3",             ARM_ARCH_V2S,    FPU_ARCH_FPA,    NULL},
-  {"arm6",             ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm60",            ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm600",           ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm610",           ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm620",           ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm7",             ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm7m",            ARM_ARCH_V3M,    FPU_ARCH_FPA,    NULL},
-  {"arm7d",            ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm7dm",           ARM_ARCH_V3M,    FPU_ARCH_FPA,    NULL},
-  {"arm7di",           ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm7dmi",          ARM_ARCH_V3M,    FPU_ARCH_FPA,    NULL},
-  {"arm70",            ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm700",           ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm700i",          ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm710",           ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm710t",          ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL},
-  {"arm720",           ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm720t",          ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL},
-  {"arm740t",          ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL},
-  {"arm710c",          ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm7100",          ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm7500",          ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm7500fe",                ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL},
-  {"arm7t",            ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL},
-  {"arm7tdmi",         ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL},
-  {"arm7tdmi-s",       ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL},
-  {"arm8",             ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL},
-  {"arm810",           ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL},
-  {"strongarm",                ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL},
-  {"strongarm1",       ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL},
-  {"strongarm110",     ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL},
-  {"strongarm1100",    ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL},
-  {"strongarm1110",    ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL},
-  {"arm9",             ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL},
-  {"arm920",           ARM_ARCH_V4T,    FPU_ARCH_FPA,    "ARM920T"},
-  {"arm920t",          ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL},
-  {"arm922t",          ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL},
-  {"arm940t",          ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL},
-  {"arm9tdmi",         ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL},
-  {"fa526",            ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL},
-  {"fa626",            ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL},
+  ARM_CPU_OPT ("all",          ARM_ANY,         FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm1",         ARM_ARCH_V1,     FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm2",         ARM_ARCH_V2,     FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm250",       ARM_ARCH_V2S,    FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm3",         ARM_ARCH_V2S,    FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm6",         ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm60",                ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm600",       ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm610",       ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm620",       ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm7",         ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm7m",                ARM_ARCH_V3M,    FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm7d",                ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm7dm",       ARM_ARCH_V3M,    FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm7di",       ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm7dmi",      ARM_ARCH_V3M,    FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm70",                ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm700",       ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm700i",      ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm710",       ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm710t",      ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm720",       ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm720t",      ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm740t",      ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm710c",      ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm7100",      ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm7500",      ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm7500fe",    ARM_ARCH_V3,     FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm7t",                ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm7tdmi",     ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm7tdmi-s",   ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm8",         ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm810",       ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("strongarm",    ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("strongarm1",   ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("strongarm110", ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("strongarm1100",        ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("strongarm1110",        ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm9",         ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm920",       ARM_ARCH_V4T,    FPU_ARCH_FPA,    "ARM920T"),
+  ARM_CPU_OPT ("arm920t",      ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm922t",      ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm940t",      ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("arm9tdmi",     ARM_ARCH_V4T,    FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("fa526",                ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL),
+  ARM_CPU_OPT ("fa626",                ARM_ARCH_V4,     FPU_ARCH_FPA,    NULL),
   /* For V5 or later processors we default to using VFP; but the user
      should really set the FPU type explicitly.         */
-  {"arm9e-r0",         ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL},
-  {"arm9e",            ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL},
-  {"arm926ej",         ARM_ARCH_V5TEJ,  FPU_ARCH_VFP_V2, "ARM926EJ-S"},
-  {"arm926ejs",                ARM_ARCH_V5TEJ,  FPU_ARCH_VFP_V2, "ARM926EJ-S"},
-  {"arm926ej-s",       ARM_ARCH_V5TEJ,  FPU_ARCH_VFP_V2, NULL},
-  {"arm946e-r0",       ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL},
-  {"arm946e",          ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, "ARM946E-S"},
-  {"arm946e-s",                ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL},
-  {"arm966e-r0",       ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL},
-  {"arm966e",          ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, "ARM966E-S"},
-  {"arm966e-s",                ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL},
-  {"arm968e-s",                ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL},
-  {"arm10t",           ARM_ARCH_V5T,    FPU_ARCH_VFP_V1, NULL},
-  {"arm10tdmi",                ARM_ARCH_V5T,    FPU_ARCH_VFP_V1, NULL},
-  {"arm10e",           ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL},
-  {"arm1020",          ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, "ARM1020E"},
-  {"arm1020t",         ARM_ARCH_V5T,    FPU_ARCH_VFP_V1, NULL},
-  {"arm1020e",         ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL},
-  {"arm1022e",         ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL},
-  {"arm1026ejs",       ARM_ARCH_V5TEJ,  FPU_ARCH_VFP_V2, "ARM1026EJ-S"},
-  {"arm1026ej-s",      ARM_ARCH_V5TEJ,  FPU_ARCH_VFP_V2, NULL},
-  {"fa606te",          ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL},
-  {"fa616te",          ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL},
-  {"fa626te",          ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL},
-  {"fmp626",           ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL},
-  {"fa726te",          ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL},
-  {"arm1136js",                ARM_ARCH_V6,     FPU_NONE,        "ARM1136J-S"},
-  {"arm1136j-s",       ARM_ARCH_V6,     FPU_NONE,        NULL},
-  {"arm1136jfs",       ARM_ARCH_V6,     FPU_ARCH_VFP_V2, "ARM1136JF-S"},
-  {"arm1136jf-s",      ARM_ARCH_V6,     FPU_ARCH_VFP_V2, NULL},
-  {"mpcore",           ARM_ARCH_V6K,    FPU_ARCH_VFP_V2, "MPCore"},
-  {"mpcorenovfp",      ARM_ARCH_V6K,    FPU_NONE,        "MPCore"},
-  {"arm1156t2-s",      ARM_ARCH_V6T2,   FPU_NONE,        NULL},
-  {"arm1156t2f-s",     ARM_ARCH_V6T2,   FPU_ARCH_VFP_V2, NULL},
-  {"arm1176jz-s",      ARM_ARCH_V6ZK,   FPU_NONE,        NULL},
-  {"arm1176jzf-s",     ARM_ARCH_V6ZK,   FPU_ARCH_VFP_V2, NULL},
-  {"cortex-a5",                ARM_ARCH_V7A_MP_SEC, 
-                                        FPU_NONE,        "Cortex-A5"},
-  {"cortex-a8",                ARM_ARCH_V7A_SEC,
-                                        ARM_FEATURE (0, FPU_VFP_V3
-                                                        | FPU_NEON_EXT_V1),
-                                                          "Cortex-A8"},
-  {"cortex-a9",                ARM_ARCH_V7A_MP_SEC,
-                                        ARM_FEATURE (0, FPU_VFP_V3
-                                                        | FPU_NEON_EXT_V1),
-                                                          "Cortex-A9"},
-  {"cortex-a15",       ARM_ARCH_V7A_IDIV_MP_SEC_VIRT,
-                                        FPU_ARCH_NEON_VFP_V4,
-                                                          "Cortex-A15"},
-  {"cortex-r4",                ARM_ARCH_V7R,    FPU_NONE,        "Cortex-R4"},
-  {"cortex-r4f",       ARM_ARCH_V7R,    FPU_ARCH_VFP_V3D16,
-                                                         "Cortex-R4F"},
-  {"cortex-m4",                ARM_ARCH_V7EM,   FPU_NONE,        "Cortex-M4"},
-  {"cortex-m3",                ARM_ARCH_V7M,    FPU_NONE,        "Cortex-M3"},
-  {"cortex-m1",                ARM_ARCH_V6SM,   FPU_NONE,        "Cortex-M1"},
-  {"cortex-m0",                ARM_ARCH_V6SM,   FPU_NONE,        "Cortex-M0"},
+  ARM_CPU_OPT ("arm9e-r0",     ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL),
+  ARM_CPU_OPT ("arm9e",                ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL),
+  ARM_CPU_OPT ("arm926ej",     ARM_ARCH_V5TEJ,  FPU_ARCH_VFP_V2, "ARM926EJ-S"),
+  ARM_CPU_OPT ("arm926ejs",    ARM_ARCH_V5TEJ,  FPU_ARCH_VFP_V2, "ARM926EJ-S"),
+  ARM_CPU_OPT ("arm926ej-s",   ARM_ARCH_V5TEJ,  FPU_ARCH_VFP_V2, NULL),
+  ARM_CPU_OPT ("arm946e-r0",   ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL),
+  ARM_CPU_OPT ("arm946e",      ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, "ARM946E-S"),
+  ARM_CPU_OPT ("arm946e-s",    ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL),
+  ARM_CPU_OPT ("arm966e-r0",   ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL),
+  ARM_CPU_OPT ("arm966e",      ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, "ARM966E-S"),
+  ARM_CPU_OPT ("arm966e-s",    ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL),
+  ARM_CPU_OPT ("arm968e-s",    ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL),
+  ARM_CPU_OPT ("arm10t",       ARM_ARCH_V5T,    FPU_ARCH_VFP_V1, NULL),
+  ARM_CPU_OPT ("arm10tdmi",    ARM_ARCH_V5T,    FPU_ARCH_VFP_V1, NULL),
+  ARM_CPU_OPT ("arm10e",       ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL),
+  ARM_CPU_OPT ("arm1020",      ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, "ARM1020E"),
+  ARM_CPU_OPT ("arm1020t",     ARM_ARCH_V5T,    FPU_ARCH_VFP_V1, NULL),
+  ARM_CPU_OPT ("arm1020e",     ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL),
+  ARM_CPU_OPT ("arm1022e",     ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL),
+  ARM_CPU_OPT ("arm1026ejs",   ARM_ARCH_V5TEJ,  FPU_ARCH_VFP_V2,
+                                                                "ARM1026EJ-S"),
+  ARM_CPU_OPT ("arm1026ej-s",  ARM_ARCH_V5TEJ,  FPU_ARCH_VFP_V2, NULL),
+  ARM_CPU_OPT ("fa606te",      ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL),
+  ARM_CPU_OPT ("fa616te",      ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL),
+  ARM_CPU_OPT ("fa626te",      ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL),
+  ARM_CPU_OPT ("fmp626",       ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL),
+  ARM_CPU_OPT ("fa726te",      ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2, NULL),
+  ARM_CPU_OPT ("arm1136js",    ARM_ARCH_V6,     FPU_NONE,        "ARM1136J-S"),
+  ARM_CPU_OPT ("arm1136j-s",   ARM_ARCH_V6,     FPU_NONE,        NULL),
+  ARM_CPU_OPT ("arm1136jfs",   ARM_ARCH_V6,     FPU_ARCH_VFP_V2,
+                                                                "ARM1136JF-S"),
+  ARM_CPU_OPT ("arm1136jf-s",  ARM_ARCH_V6,     FPU_ARCH_VFP_V2, NULL),
+  ARM_CPU_OPT ("mpcore",       ARM_ARCH_V6K,    FPU_ARCH_VFP_V2, "MPCore"),
+  ARM_CPU_OPT ("mpcorenovfp",  ARM_ARCH_V6K,    FPU_NONE,        "MPCore"),
+  ARM_CPU_OPT ("arm1156t2-s",  ARM_ARCH_V6T2,   FPU_NONE,        NULL),
+  ARM_CPU_OPT ("arm1156t2f-s", ARM_ARCH_V6T2,   FPU_ARCH_VFP_V2, NULL),
+  ARM_CPU_OPT ("arm1176jz-s",  ARM_ARCH_V6KZ,   FPU_NONE,        NULL),
+  ARM_CPU_OPT ("arm1176jzf-s", ARM_ARCH_V6KZ,   FPU_ARCH_VFP_V2, NULL),
+  ARM_CPU_OPT ("cortex-a5",    ARM_ARCH_V7A_MP_SEC,
+                                                FPU_NONE,        "Cortex-A5"),
+  ARM_CPU_OPT ("cortex-a7",    ARM_ARCH_V7VE,   FPU_ARCH_NEON_VFP_V4,
+                                                                 "Cortex-A7"),
+  ARM_CPU_OPT ("cortex-a8",    ARM_ARCH_V7A_SEC,
+                                                ARM_FEATURE_COPROC (FPU_VFP_V3
+                                                       | FPU_NEON_EXT_V1),
+                                                                 "Cortex-A8"),
+  ARM_CPU_OPT ("cortex-a9",    ARM_ARCH_V7A_MP_SEC,
+                                                ARM_FEATURE_COPROC (FPU_VFP_V3
+                                                       | FPU_NEON_EXT_V1),
+                                                                 "Cortex-A9"),
+  ARM_CPU_OPT ("cortex-a12",   ARM_ARCH_V7VE,   FPU_ARCH_NEON_VFP_V4,
+                                                                 "Cortex-A12"),
+  ARM_CPU_OPT ("cortex-a15",   ARM_ARCH_V7VE,   FPU_ARCH_NEON_VFP_V4,
+                                                                 "Cortex-A15"),
+  ARM_CPU_OPT ("cortex-a17",   ARM_ARCH_V7VE,   FPU_ARCH_NEON_VFP_V4,
+                                                                 "Cortex-A17"),
+  ARM_CPU_OPT ("cortex-a32",    ARM_ARCH_V8A,    FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+                                                                 "Cortex-A32"),
+  ARM_CPU_OPT ("cortex-a35",    ARM_ARCH_V8A,    FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+                                                                 "Cortex-A35"),
+  ARM_CPU_OPT ("cortex-a53",    ARM_ARCH_V8A,    FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+                                                                 "Cortex-A53"),
+  ARM_CPU_OPT ("cortex-a57",    ARM_ARCH_V8A,    FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+                                                                 "Cortex-A57"),
+  ARM_CPU_OPT ("cortex-a72",    ARM_ARCH_V8A,    FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+                                                                 "Cortex-A72"),
+  ARM_CPU_OPT ("cortex-r4",    ARM_ARCH_V7R,    FPU_NONE,        "Cortex-R4"),
+  ARM_CPU_OPT ("cortex-r4f",   ARM_ARCH_V7R,    FPU_ARCH_VFP_V3D16,
+                                                                 "Cortex-R4F"),
+  ARM_CPU_OPT ("cortex-r5",    ARM_ARCH_V7R_IDIV,
+                                                FPU_NONE,        "Cortex-R5"),
+  ARM_CPU_OPT ("cortex-r7",    ARM_ARCH_V7R_IDIV,
+                                                FPU_ARCH_VFP_V3D16,
+                                                                 "Cortex-R7"),
+  ARM_CPU_OPT ("cortex-r8",    ARM_ARCH_V7R_IDIV,
+                                                FPU_ARCH_VFP_V3D16,
+                                                                 "Cortex-R8"),
+  ARM_CPU_OPT ("cortex-m7",    ARM_ARCH_V7EM,   FPU_NONE,        "Cortex-M7"),
+  ARM_CPU_OPT ("cortex-m4",    ARM_ARCH_V7EM,   FPU_NONE,        "Cortex-M4"),
+  ARM_CPU_OPT ("cortex-m3",    ARM_ARCH_V7M,    FPU_NONE,        "Cortex-M3"),
+  ARM_CPU_OPT ("cortex-m1",    ARM_ARCH_V6SM,   FPU_NONE,        "Cortex-M1"),
+  ARM_CPU_OPT ("cortex-m0",    ARM_ARCH_V6SM,   FPU_NONE,        "Cortex-M0"),
+  ARM_CPU_OPT ("cortex-m0plus",        ARM_ARCH_V6SM,   FPU_NONE,        "Cortex-M0+"),
+  ARM_CPU_OPT ("exynos-m1",    ARM_ARCH_V8A,    FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+                                                                 "Samsung " \
+                                                                 "Exynos M1"),
+  ARM_CPU_OPT ("qdf24xx",      ARM_ARCH_V8A,    FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+                                                                 "Qualcomm "
+                                                                 "QDF24XX"),
+
   /* ??? XSCALE is really an architecture.  */
-  {"xscale",           ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL},
+  ARM_CPU_OPT ("xscale",       ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL),
   /* ??? iwmmxt is not a processor.  */
-  {"iwmmxt",           ARM_ARCH_IWMMXT, FPU_ARCH_VFP_V2, NULL},
-  {"iwmmxt2",          ARM_ARCH_IWMMXT2,FPU_ARCH_VFP_V2, NULL},
-  {"i80200",           ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL},
+  ARM_CPU_OPT ("iwmmxt",       ARM_ARCH_IWMMXT, FPU_ARCH_VFP_V2, NULL),
+  ARM_CPU_OPT ("iwmmxt2",      ARM_ARCH_IWMMXT2,FPU_ARCH_VFP_V2, NULL),
+  ARM_CPU_OPT ("i80200",       ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL),
   /* Maverick */
-  {"ep9312",   ARM_FEATURE (ARM_AEXT_V4T, ARM_CEXT_MAVERICK), FPU_ARCH_MAVERICK, "ARM920T"},
-  {NULL,               ARM_ARCH_NONE,   ARM_ARCH_NONE, NULL}
+  ARM_CPU_OPT ("ep9312",       ARM_FEATURE_LOW (ARM_AEXT_V4T, ARM_CEXT_MAVERICK),
+                                                FPU_ARCH_MAVERICK, "ARM920T"),
+  /* Marvell processors.  */
+  ARM_CPU_OPT ("marvell-pj4",   ARM_FEATURE_CORE (ARM_AEXT_V7A | ARM_EXT_MP
+                                                 | ARM_EXT_SEC,
+                                                 ARM_EXT2_V6T2_V8M),
+                                               FPU_ARCH_VFP_V3D16, NULL),
+  ARM_CPU_OPT ("marvell-whitney", ARM_FEATURE_CORE (ARM_AEXT_V7A | ARM_EXT_MP
+                                                   | ARM_EXT_SEC,
+                                                   ARM_EXT2_V6T2_V8M),
+                                              FPU_ARCH_NEON_VFP_V4, NULL),
+  /* APM X-Gene family.  */
+  ARM_CPU_OPT ("xgene1",        ARM_ARCH_V8A,    FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+                                                                 "APM X-Gene 1"),
+  ARM_CPU_OPT ("xgene2",        ARM_ARCH_V8A,    FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+                                                                 "APM X-Gene 2"),
+
+  { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE, NULL }
 };
+#undef ARM_CPU_OPT
 
 struct arm_arch_option_table
 {
-  char *name;
+  const char *name;
+  size_t name_len;
   const arm_feature_set        value;
   const arm_feature_set        default_fpu;
 };
 
 /* This list should, at a minimum, contain all the architecture names
    recognized by GCC.  */
+#define ARM_ARCH_OPT(N, V, DF) { N, sizeof (N) - 1, V, DF }
 static const struct arm_arch_option_table arm_archs[] =
 {
-  {"all",              ARM_ANY,         FPU_ARCH_FPA},
-  {"armv1",            ARM_ARCH_V1,     FPU_ARCH_FPA},
-  {"armv2",            ARM_ARCH_V2,     FPU_ARCH_FPA},
-  {"armv2a",           ARM_ARCH_V2S,    FPU_ARCH_FPA},
-  {"armv2s",           ARM_ARCH_V2S,    FPU_ARCH_FPA},
-  {"armv3",            ARM_ARCH_V3,     FPU_ARCH_FPA},
-  {"armv3m",           ARM_ARCH_V3M,    FPU_ARCH_FPA},
-  {"armv4",            ARM_ARCH_V4,     FPU_ARCH_FPA},
-  {"armv4xm",          ARM_ARCH_V4xM,   FPU_ARCH_FPA},
-  {"armv4t",           ARM_ARCH_V4T,    FPU_ARCH_FPA},
-  {"armv4txm",         ARM_ARCH_V4TxM,  FPU_ARCH_FPA},
-  {"armv5",            ARM_ARCH_V5,     FPU_ARCH_VFP},
-  {"armv5t",           ARM_ARCH_V5T,    FPU_ARCH_VFP},
-  {"armv5txm",         ARM_ARCH_V5TxM,  FPU_ARCH_VFP},
-  {"armv5te",          ARM_ARCH_V5TE,   FPU_ARCH_VFP},
-  {"armv5texp",                ARM_ARCH_V5TExP, FPU_ARCH_VFP},
-  {"armv5tej",         ARM_ARCH_V5TEJ,  FPU_ARCH_VFP},
-  {"armv6",            ARM_ARCH_V6,     FPU_ARCH_VFP},
-  {"armv6j",           ARM_ARCH_V6,     FPU_ARCH_VFP},
-  {"armv6k",           ARM_ARCH_V6K,    FPU_ARCH_VFP},
-  {"armv6z",           ARM_ARCH_V6Z,    FPU_ARCH_VFP},
-  {"armv6zk",          ARM_ARCH_V6ZK,   FPU_ARCH_VFP},
-  {"armv6t2",          ARM_ARCH_V6T2,   FPU_ARCH_VFP},
-  {"armv6kt2",         ARM_ARCH_V6KT2,  FPU_ARCH_VFP},
-  {"armv6zt2",         ARM_ARCH_V6ZT2,  FPU_ARCH_VFP},
-  {"armv6zkt2",                ARM_ARCH_V6ZKT2, FPU_ARCH_VFP},
-  {"armv6-m",          ARM_ARCH_V6M,    FPU_ARCH_VFP},
-  {"armv6s-m",         ARM_ARCH_V6SM,   FPU_ARCH_VFP},
-  {"armv7",            ARM_ARCH_V7,     FPU_ARCH_VFP},
+  ARM_ARCH_OPT ("all",         ARM_ANY,         FPU_ARCH_FPA),
+  ARM_ARCH_OPT ("armv1",       ARM_ARCH_V1,     FPU_ARCH_FPA),
+  ARM_ARCH_OPT ("armv2",       ARM_ARCH_V2,     FPU_ARCH_FPA),
+  ARM_ARCH_OPT ("armv2a",      ARM_ARCH_V2S,    FPU_ARCH_FPA),
+  ARM_ARCH_OPT ("armv2s",      ARM_ARCH_V2S,    FPU_ARCH_FPA),
+  ARM_ARCH_OPT ("armv3",       ARM_ARCH_V3,     FPU_ARCH_FPA),
+  ARM_ARCH_OPT ("armv3m",      ARM_ARCH_V3M,    FPU_ARCH_FPA),
+  ARM_ARCH_OPT ("armv4",       ARM_ARCH_V4,     FPU_ARCH_FPA),
+  ARM_ARCH_OPT ("armv4xm",     ARM_ARCH_V4xM,   FPU_ARCH_FPA),
+  ARM_ARCH_OPT ("armv4t",      ARM_ARCH_V4T,    FPU_ARCH_FPA),
+  ARM_ARCH_OPT ("armv4txm",    ARM_ARCH_V4TxM,  FPU_ARCH_FPA),
+  ARM_ARCH_OPT ("armv5",       ARM_ARCH_V5,     FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv5t",      ARM_ARCH_V5T,    FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv5txm",    ARM_ARCH_V5TxM,  FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv5te",     ARM_ARCH_V5TE,   FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv5texp",   ARM_ARCH_V5TExP, FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv5tej",    ARM_ARCH_V5TEJ,  FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv6",       ARM_ARCH_V6,     FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv6j",      ARM_ARCH_V6,     FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv6k",      ARM_ARCH_V6K,    FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv6z",      ARM_ARCH_V6Z,    FPU_ARCH_VFP),
+  /* The official spelling of this variant is ARMv6KZ, the name "armv6zk" is
+     kept to preserve existing behaviour.  */
+  ARM_ARCH_OPT ("armv6kz",     ARM_ARCH_V6KZ,   FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv6zk",     ARM_ARCH_V6KZ,   FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv6t2",     ARM_ARCH_V6T2,   FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv6kt2",    ARM_ARCH_V6KT2,  FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv6zt2",    ARM_ARCH_V6ZT2,  FPU_ARCH_VFP),
+  /* The official spelling of this variant is ARMv6KZ, the name "armv6zkt2" is
+     kept to preserve existing behaviour.  */
+  ARM_ARCH_OPT ("armv6kzt2",   ARM_ARCH_V6KZT2, FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv6zkt2",   ARM_ARCH_V6KZT2, FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv6-m",     ARM_ARCH_V6M,    FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv6s-m",    ARM_ARCH_V6SM,   FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv7",       ARM_ARCH_V7,     FPU_ARCH_VFP),
   /* The official spelling of the ARMv7 profile variants is the dashed form.
      Accept the non-dashed form for compatibility with old toolchains.  */
-  {"armv7a",           ARM_ARCH_V7A,    FPU_ARCH_VFP},
-  {"armv7r",           ARM_ARCH_V7R,    FPU_ARCH_VFP},
-  {"armv7m",           ARM_ARCH_V7M,    FPU_ARCH_VFP},
-  {"armv7-a",          ARM_ARCH_V7A,    FPU_ARCH_VFP},
-  {"armv7-r",          ARM_ARCH_V7R,    FPU_ARCH_VFP},
-  {"armv7-m",          ARM_ARCH_V7M,    FPU_ARCH_VFP},
-  {"armv7e-m",         ARM_ARCH_V7EM,   FPU_ARCH_VFP},
-  {"xscale",           ARM_ARCH_XSCALE, FPU_ARCH_VFP},
-  {"iwmmxt",           ARM_ARCH_IWMMXT, FPU_ARCH_VFP},
-  {"iwmmxt2",          ARM_ARCH_IWMMXT2,FPU_ARCH_VFP},
-  {NULL,               ARM_ARCH_NONE,   ARM_ARCH_NONE}
+  ARM_ARCH_OPT ("armv7a",      ARM_ARCH_V7A,    FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv7ve",     ARM_ARCH_V7VE,   FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv7r",      ARM_ARCH_V7R,    FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv7m",      ARM_ARCH_V7M,    FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv7-a",     ARM_ARCH_V7A,    FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv7-r",     ARM_ARCH_V7R,    FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv7-m",     ARM_ARCH_V7M,    FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv7e-m",    ARM_ARCH_V7EM,   FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv8-m.base",        ARM_ARCH_V8M_BASE, FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv8-m.main",        ARM_ARCH_V8M_MAIN, FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv8-a",     ARM_ARCH_V8A,    FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv8.1-a",   ARM_ARCH_V8_1A,  FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("armv8.2-a",   ARM_ARCH_V8_2A,  FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("xscale",      ARM_ARCH_XSCALE, FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("iwmmxt",      ARM_ARCH_IWMMXT, FPU_ARCH_VFP),
+  ARM_ARCH_OPT ("iwmmxt2",     ARM_ARCH_IWMMXT2,FPU_ARCH_VFP),
+  { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
 };
+#undef ARM_ARCH_OPT
 
 /* ISA extensions in the co-processor and main instruction set space.  */
 struct arm_option_extension_value_table
 {
-  char *name;
-  const arm_feature_set value;
+  const char *name;
+  size_t name_len;
+  const arm_feature_set merge_value;
+  const arm_feature_set clear_value;
   const arm_feature_set allowed_archs;
 };
 
 /* The following table must be in alphabetical order with a NULL last entry.
    */
+#define ARM_EXT_OPT(N, M, C, AA) { N, sizeof (N) - 1, M, C, AA }
 static const struct arm_option_extension_value_table arm_extensions[] =
 {
-  {"idiv",     ARM_FEATURE (ARM_EXT_ADIV | ARM_EXT_DIV, 0),
-                                  ARM_FEATURE (ARM_EXT_V7A, 0)},
-  {"iwmmxt",   ARM_FEATURE (0, ARM_CEXT_IWMMXT),       ARM_ANY},
-  {"iwmmxt2",  ARM_FEATURE (0, ARM_CEXT_IWMMXT2),      ARM_ANY},
-  {"maverick", ARM_FEATURE (0, ARM_CEXT_MAVERICK),     ARM_ANY},
-  {"mp",       ARM_FEATURE (ARM_EXT_MP, 0),
-                    ARM_FEATURE (ARM_EXT_V7A | ARM_EXT_V7R, 0)},
-  {"os",       ARM_FEATURE (ARM_EXT_OS, 0),
-                                  ARM_FEATURE (ARM_EXT_V6M, 0)},
-  {"sec",      ARM_FEATURE (ARM_EXT_SEC, 0),
-                    ARM_FEATURE (ARM_EXT_V6K | ARM_EXT_V7A, 0)},
-  {"virt",     ARM_FEATURE (ARM_EXT_VIRT | ARM_EXT_ADIV | ARM_EXT_DIV, 0),
-                                  ARM_FEATURE (ARM_EXT_V7A, 0)},
-  {"xscale",   ARM_FEATURE (0, ARM_CEXT_XSCALE),       ARM_ANY},
-  {NULL,       ARM_ARCH_NONE,                    ARM_ARCH_NONE}
+  ARM_EXT_OPT ("crc",  ARCH_CRC_ARMV8, ARM_FEATURE_COPROC (CRC_EXT_ARMV8),
+                        ARM_FEATURE_CORE_LOW (ARM_EXT_V8)),
+  ARM_EXT_OPT ("crypto", FPU_ARCH_CRYPTO_NEON_VFP_ARMV8,
+                        ARM_FEATURE_COPROC (FPU_CRYPTO_ARMV8),
+                                  ARM_FEATURE_CORE_LOW (ARM_EXT_V8)),
+  ARM_EXT_OPT ("fp",     FPU_ARCH_VFP_ARMV8, ARM_FEATURE_COPROC (FPU_VFP_ARMV8),
+                                  ARM_FEATURE_CORE_LOW (ARM_EXT_V8)),
+  ARM_EXT_OPT ("fp16",  ARM_FEATURE_CORE_HIGH (ARM_EXT2_FP16_INST),
+                       ARM_FEATURE_CORE_HIGH (ARM_EXT2_FP16_INST),
+                       ARM_ARCH_V8_2A),
+  ARM_EXT_OPT ("idiv", ARM_FEATURE_CORE_LOW (ARM_EXT_ADIV | ARM_EXT_DIV),
+                       ARM_FEATURE_CORE_LOW (ARM_EXT_ADIV | ARM_EXT_DIV),
+                                  ARM_FEATURE_CORE_LOW (ARM_EXT_V7A | ARM_EXT_V7R)),
+  ARM_EXT_OPT ("iwmmxt",ARM_FEATURE_COPROC (ARM_CEXT_IWMMXT),
+                       ARM_FEATURE_COPROC (ARM_CEXT_IWMMXT), ARM_ANY),
+  ARM_EXT_OPT ("iwmmxt2", ARM_FEATURE_COPROC (ARM_CEXT_IWMMXT2),
+                       ARM_FEATURE_COPROC (ARM_CEXT_IWMMXT2), ARM_ANY),
+  ARM_EXT_OPT ("maverick", ARM_FEATURE_COPROC (ARM_CEXT_MAVERICK),
+                       ARM_FEATURE_COPROC (ARM_CEXT_MAVERICK), ARM_ANY),
+  ARM_EXT_OPT ("mp",   ARM_FEATURE_CORE_LOW (ARM_EXT_MP),
+                       ARM_FEATURE_CORE_LOW (ARM_EXT_MP),
+                                  ARM_FEATURE_CORE_LOW (ARM_EXT_V7A | ARM_EXT_V7R)),
+  ARM_EXT_OPT ("os",   ARM_FEATURE_CORE_LOW (ARM_EXT_OS),
+                       ARM_FEATURE_CORE_LOW (ARM_EXT_OS),
+                                  ARM_FEATURE_CORE_LOW (ARM_EXT_V6M)),
+  ARM_EXT_OPT ("pan",  ARM_FEATURE_CORE_HIGH (ARM_EXT2_PAN),
+                       ARM_FEATURE (ARM_EXT_V8, ARM_EXT2_PAN, 0),
+                       ARM_FEATURE_CORE_LOW (ARM_EXT_V8)),
+  ARM_EXT_OPT ("rdma",  FPU_ARCH_NEON_VFP_ARMV8_1,
+                       ARM_FEATURE_COPROC (FPU_NEON_ARMV8 | FPU_NEON_EXT_RDMA),
+                       ARM_FEATURE_CORE_LOW (ARM_EXT_V8)),
+  ARM_EXT_OPT ("sec",  ARM_FEATURE_CORE_LOW (ARM_EXT_SEC),
+                       ARM_FEATURE_CORE_LOW (ARM_EXT_SEC),
+                                  ARM_FEATURE_CORE_LOW (ARM_EXT_V6K | ARM_EXT_V7A)),
+  ARM_EXT_OPT ("simd",  FPU_ARCH_NEON_VFP_ARMV8,
+                       ARM_FEATURE_COPROC (FPU_NEON_ARMV8),
+                       ARM_FEATURE_CORE_LOW (ARM_EXT_V8)),
+  ARM_EXT_OPT ("virt", ARM_FEATURE_CORE_LOW (ARM_EXT_VIRT | ARM_EXT_ADIV
+                                    | ARM_EXT_DIV),
+                       ARM_FEATURE_CORE_LOW (ARM_EXT_VIRT),
+                                  ARM_FEATURE_CORE_LOW (ARM_EXT_V7A)),
+  ARM_EXT_OPT ("xscale",ARM_FEATURE_COPROC (ARM_CEXT_XSCALE),
+                       ARM_FEATURE_COPROC (ARM_CEXT_XSCALE), ARM_ANY),
+  { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE, ARM_ARCH_NONE }
 };
+#undef ARM_EXT_OPT
 
 /* ISA floating-point and Advanced SIMD extensions.  */
 struct arm_option_fpu_value_table
 {
-  char *name;
+  const char *name;
   const arm_feature_set value;
 };
 
@@ -22888,13 +25542,22 @@ static const struct arm_option_fpu_value_table arm_fpus[] =
   {"vfpv4",            FPU_ARCH_VFP_V4},
   {"vfpv4-d16",                FPU_ARCH_VFP_V4D16},
   {"fpv4-sp-d16",      FPU_ARCH_VFP_V4_SP_D16},
+  {"fpv5-d16",         FPU_ARCH_VFP_V5D16},
+  {"fpv5-sp-d16",      FPU_ARCH_VFP_V5_SP_D16},
   {"neon-vfpv4",       FPU_ARCH_NEON_VFP_V4},
+  {"fp-armv8",         FPU_ARCH_VFP_ARMV8},
+  {"neon-fp-armv8",    FPU_ARCH_NEON_VFP_ARMV8},
+  {"crypto-neon-fp-armv8",
+                       FPU_ARCH_CRYPTO_NEON_VFP_ARMV8},
+  {"neon-fp-armv8.1",  FPU_ARCH_NEON_VFP_ARMV8_1},
+  {"crypto-neon-fp-armv8.1",
+                       FPU_ARCH_CRYPTO_NEON_VFP_ARMV8_1},
   {NULL,               ARM_ARCH_NONE}
 };
 
 struct arm_option_value_table
 {
-  char *name;
+  const char *name;
   long value;
 };
 
@@ -22919,23 +25582,22 @@ static const struct arm_option_value_table arm_eabis[] =
 
 struct arm_long_option_table
 {
-  char * option;               /* Substring to match.  */
-  char * help;                 /* Help information.  */
-  int (* func) (char * subopt);        /* Function to decode sub-option.  */
-  char * deprecated;           /* If non-null, print this message.  */
+  const char * option;         /* Substring to match.  */
+  const char * help;                   /* Help information.  */
+  int (* func) (const char * subopt);  /* Function to decode sub-option.  */
+  const char * deprecated;             /* If non-null, print this message.  */
 };
 
 static bfd_boolean
-arm_parse_extension (char * str, const arm_feature_set **opt_p)
+arm_parse_extension (const char *str, const arm_feature_set **opt_p)
 {
-  arm_feature_set *ext_set = (arm_feature_set *)
-      xmalloc (sizeof (arm_feature_set));
+  arm_feature_set *ext_set = XNEW (arm_feature_set);
 
   /* We insist on extensions being specified in alphabetical order, and with
-     extensions being added before being removed.  We achieve this by having 
-     the global ARM_EXTENSIONS table in alphabetical order, and using the 
+     extensions being added before being removed.  We achieve this by having
+     the global ARM_EXTENSIONS table in alphabetical order, and using the
      ADDING_VALUE variable to indicate whether we are adding an extension (1)
-     or removing it (0) and only allowing it to change in the order 
+     or removing it (0) and only allowing it to change in the order
      -1 -> 1 -> 0.  */
   const struct arm_option_extension_value_table * opt = NULL;
   int adding_value = -1;
@@ -22946,8 +25608,8 @@ arm_parse_extension (char * str, const arm_feature_set **opt_p)
 
   while (str != NULL && *str != 0)
     {
-      char * ext;
-      size_t optlen;
+      const char *ext;
+      size_t len;
 
       if (*str != '+')
        {
@@ -22959,12 +25621,11 @@ arm_parse_extension (char * str, const arm_feature_set **opt_p)
       ext = strchr (str, '+');
 
       if (ext != NULL)
-       optlen = ext - str;
+       len = ext - str;
       else
-       optlen = strlen (str);
+       len = strlen (str);
 
-      if (optlen >= 2
-         && strncmp (str, "no", 2) == 0)
+      if (len >= 2 && strncmp (str, "no", 2) == 0)
        {
          if (adding_value != 0)
            {
@@ -22972,10 +25633,10 @@ arm_parse_extension (char * str, const arm_feature_set **opt_p)
              opt = arm_extensions;
            }
 
-         optlen -= 2;
+         len -= 2;
          str += 2;
        }
-      else if (optlen > 0)
+      else if (len > 0)
        {
          if (adding_value == -1)
            {
@@ -22990,7 +25651,7 @@ arm_parse_extension (char * str, const arm_feature_set **opt_p)
            }
        }
 
-      if (optlen == 0)
+      if (len == 0)
        {
          as_bad (_("missing architectural extension"));
          return FALSE;
@@ -23001,8 +25662,7 @@ arm_parse_extension (char * str, const arm_feature_set **opt_p)
 
       /* Scan over the options table trying to find an exact match. */
       for (; opt->name != NULL; opt++)
-       if (strncmp (opt->name, str, optlen) == 0
-           && strlen (opt->name) == optlen)
+       if (opt->name_len == len && strncmp (opt->name, str, len) == 0)
          {
            /* Check we can apply the extension to this architecture.  */
            if (!ARM_CPU_HAS_FEATURE (*ext_set, opt->allowed_archs))
@@ -23013,9 +25673,9 @@ arm_parse_extension (char * str, const arm_feature_set **opt_p)
 
            /* Add or remove the extension.  */
            if (adding_value)
-             ARM_MERGE_FEATURE_SETS (*ext_set, *ext_set, opt->value);
+             ARM_MERGE_FEATURE_SETS (*ext_set, *ext_set, opt->merge_value);
            else
-             ARM_CLEAR_FEATURE (*ext_set, *ext_set, opt->value);
+             ARM_CLEAR_FEATURE (*ext_set, *ext_set, opt->clear_value);
 
            break;
          }
@@ -23026,7 +25686,7 @@ arm_parse_extension (char * str, const arm_feature_set **opt_p)
             alphabetical order, or because it does not exist?  */
 
          for (opt = arm_extensions; opt->name != NULL; opt++)
-           if (strncmp (opt->name, str, optlen) == 0)
+           if (opt->name_len == len && strncmp (opt->name, str, len) == 0)
              break;
 
          if (opt->name == NULL)
@@ -23051,35 +25711,41 @@ arm_parse_extension (char * str, const arm_feature_set **opt_p)
 }
 
 static bfd_boolean
-arm_parse_cpu (char * str)
+arm_parse_cpu (const char *str)
 {
-  const struct arm_cpu_option_table * opt;
-  char * ext = strchr (str, '+');
-  int optlen;
+  const struct arm_cpu_option_table *opt;
+  const char *ext = strchr (str, '+');
+  size_t len;
 
   if (ext != NULL)
-    optlen = ext - str;
+    len = ext - str;
   else
-    optlen = strlen (str);
+    len = strlen (str);
 
-  if (optlen == 0)
+  if (len == 0)
     {
       as_bad (_("missing cpu name `%s'"), str);
       return FALSE;
     }
 
   for (opt = arm_cpus; opt->name != NULL; opt++)
-    if (strncmp (opt->name, str, optlen) == 0)
+    if (opt->name_len == len && strncmp (opt->name, str, len) == 0)
       {
        mcpu_cpu_opt = &opt->value;
        mcpu_fpu_opt = &opt->default_fpu;
        if (opt->canonical_name)
-         strcpy (selected_cpu_name, opt->canonical_name);
+         {
+           gas_assert (sizeof selected_cpu_name > strlen (opt->canonical_name));
+           strcpy (selected_cpu_name, opt->canonical_name);
+         }
        else
          {
-           int i;
+           size_t i;
+
+           if (len >= sizeof selected_cpu_name)
+             len = (sizeof selected_cpu_name) - 1;
 
-           for (i = 0; i < optlen; i++)
+           for (i = 0; i < len; i++)
              selected_cpu_name[i] = TOUPPER (opt->name[i]);
            selected_cpu_name[i] = 0;
          }
@@ -23095,25 +25761,25 @@ arm_parse_cpu (char * str)
 }
 
 static bfd_boolean
-arm_parse_arch (char * str)
+arm_parse_arch (const char *str)
 {
   const struct arm_arch_option_table *opt;
-  char *ext = strchr (str, '+');
-  int optlen;
+  const char *ext = strchr (str, '+');
+  size_t len;
 
   if (ext != NULL)
-    optlen = ext - str;
+    len = ext - str;
   else
-    optlen = strlen (str);
+    len = strlen (str);
 
-  if (optlen == 0)
+  if (len == 0)
     {
       as_bad (_("missing architecture name `%s'"), str);
       return FALSE;
     }
 
   for (opt = arm_archs; opt->name != NULL; opt++)
-    if (strncmp (opt->name, str, optlen) == 0)
+    if (opt->name_len == len && strncmp (opt->name, str, len) == 0)
       {
        march_cpu_opt = &opt->value;
        march_fpu_opt = &opt->default_fpu;
@@ -23130,7 +25796,7 @@ arm_parse_arch (char * str)
 }
 
 static bfd_boolean
-arm_parse_fpu (char * str)
+arm_parse_fpu (const char * str)
 {
   const struct arm_option_fpu_value_table * opt;
 
@@ -23146,7 +25812,7 @@ arm_parse_fpu (char * str)
 }
 
 static bfd_boolean
-arm_parse_float_abi (char * str)
+arm_parse_float_abi (const char * str)
 {
   const struct arm_option_value_table * opt;
 
@@ -23163,7 +25829,7 @@ arm_parse_float_abi (char * str)
 
 #ifdef OBJ_ELF
 static bfd_boolean
-arm_parse_eabi (char * str)
+arm_parse_eabi (const char * str)
 {
   const struct arm_option_value_table *opt;
 
@@ -23179,7 +25845,7 @@ arm_parse_eabi (char * str)
 #endif
 
 static bfd_boolean
-arm_parse_it_mode (char * str)
+arm_parse_it_mode (const char * str)
 {
   bfd_boolean ret = TRUE;
 
@@ -23194,13 +25860,22 @@ arm_parse_it_mode (char * str)
   else
     {
       as_bad (_("unknown implicit IT mode `%s', should be "\
-                "arm, thumb, always, or never."), str);
+               "arm, thumb, always, or never."), str);
       ret = FALSE;
     }
 
   return ret;
 }
 
+static bfd_boolean
+arm_ccs_mode (const char * unused ATTRIBUTE_UNUSED)
+{
+  codecomposer_syntax = TRUE;
+  arm_comment_chars[0] = ';';
+  arm_line_separator_chars[0] = 0;
+  return TRUE;
+}
+
 struct arm_long_option_table arm_long_opts[] =
 {
   {"mcpu=", N_("<cpu name>\t  assemble for CPU <cpu name>"),
@@ -23217,11 +25892,13 @@ struct arm_long_option_table arm_long_opts[] =
 #endif
   {"mimplicit-it=", N_("<mode>\t  controls implicit insertion of IT instructions"),
    arm_parse_it_mode, NULL},
+  {"mccs", N_("\t\t\t  TI CodeComposer Studio syntax compatibility mode"),
+   arm_ccs_mode, NULL},
   {NULL, NULL, 0, NULL}
 };
 
 int
-md_parse_option (int c, char * arg)
+md_parse_option (int c, const char * arg)
 {
   struct arm_option_table *opt;
   const struct arm_legacy_option_table *fopt;
@@ -23349,8 +26026,9 @@ typedef struct
   arm_feature_set flags;
 } cpu_arch_ver_table;
 
-/* Mapping from CPU features to EABI CPU arch values.  Table must be sorted
-   least features first.  */
+/* Mapping from CPU features to EABI CPU arch values.  As a general rule, table
+   must be sorted least features first but some reordering is needed, eg. for
+   Thumb-2 instructions to be detected as coming from ARMv6T2.  */
 static const cpu_arch_ver_table cpu_arch_ver[] =
 {
     {1, ARM_ARCH_V4},
@@ -23365,9 +26043,12 @@ static const cpu_arch_ver_table cpu_arch_ver[] =
     {11, ARM_ARCH_V6M},
     {12, ARM_ARCH_V6SM},
     {8, ARM_ARCH_V6T2},
-    {10, ARM_ARCH_V7A},
+    {10, ARM_ARCH_V7VE},
     {10, ARM_ARCH_V7R},
     {10, ARM_ARCH_V7M},
+    {14, ARM_ARCH_V8A},
+    {16, ARM_ARCH_V8M_BASE},
+    {17, ARM_ARCH_V8M_MAIN},
     {0, ARM_ARCH_NONE}
 };
 
@@ -23391,13 +26072,16 @@ aeabi_set_attribute_string (int tag, const char *value)
 }
 
 /* Set the public EABI object attributes.  */
-static void
+void
 aeabi_set_public_attributes (void)
 {
   int arch;
+  char profile;
   int virt_sec = 0;
+  int fp16_optional = 0;
   arm_feature_set flags;
   arm_feature_set tmp;
+  arm_feature_set arm_arch_v8m_base = ARM_ARCH_V8M_BASE;
   const cpu_arch_ver_table *p;
 
   /* Choose the architecture based on the capabilities of the requested cpu
@@ -23405,7 +26089,16 @@ aeabi_set_public_attributes (void)
   ARM_MERGE_FEATURE_SETS (flags, arm_arch_used, thumb_arch_used);
   ARM_MERGE_FEATURE_SETS (flags, flags, *mfpu_opt);
   ARM_MERGE_FEATURE_SETS (flags, flags, selected_cpu);
-  /*Allow the user to override the reported architecture.  */
+
+  if (ARM_CPU_HAS_FEATURE (arm_arch_used, arm_arch_any))
+    ARM_MERGE_FEATURE_SETS (flags, flags, arm_ext_v1);
+
+  if (ARM_CPU_HAS_FEATURE (thumb_arch_used, arm_arch_any))
+    ARM_MERGE_FEATURE_SETS (flags, flags, arm_ext_v4t);
+
+  selected_cpu = flags;
+
+  /* Allow the user to override the reported architecture.  */
   if (object_arch)
     {
       ARM_CLEAR_FEATURE (flags, flags, arm_arch_any);
@@ -23416,7 +26109,7 @@ aeabi_set_public_attributes (void)
      when the only v6S-M feature in use is the Operating System Extensions.  */
   if (ARM_CPU_HAS_FEATURE (flags, arm_ext_os))
       if (!ARM_CPU_HAS_FEATURE (flags, arm_arch_v6m_only))
-        ARM_CLEAR_FEATURE (flags, flags, arm_ext_os);
+       ARM_CLEAR_FEATURE (flags, flags, arm_ext_os);
 
   tmp = flags;
   arch = 0;
@@ -23437,11 +26130,22 @@ aeabi_set_public_attributes (void)
      actually used.  Perhaps we should separate out the specified
      and implicit cases.  Avoid taking this path for -march=all by
      checking for contradictory v7-A / v7-M features.  */
-  if (arch == 10
+  if (arch == TAG_CPU_ARCH_V7
       && !ARM_CPU_HAS_FEATURE (flags, arm_ext_v7a)
       && ARM_CPU_HAS_FEATURE (flags, arm_ext_v7m)
       && ARM_CPU_HAS_FEATURE (flags, arm_ext_v6_dsp))
-    arch = 13;
+    arch = TAG_CPU_ARCH_V7E_M;
+
+  ARM_CLEAR_FEATURE (tmp, flags, arm_arch_v8m_base);
+  if (arch == TAG_CPU_ARCH_V8M_BASE && ARM_CPU_HAS_FEATURE (tmp, arm_arch_any))
+    arch = TAG_CPU_ARCH_V8M_MAIN;
+
+  /* In cpu_arch_ver ARMv8-A is before ARMv8-M for atomics to be detected as
+     coming from ARMv8-A.  However, since ARMv8-A has more instructions than
+     ARMv8-M, -march=all must be detected as ARMv8-A.  */
+  if (arch == TAG_CPU_ARCH_V8M_MAIN
+      && ARM_FEATURE_CORE_EQUAL (selected_cpu, arm_arch_any))
+    arch = TAG_CPU_ARCH_V8;
 
   /* Tag_CPU_name.  */
   if (selected_cpu_name[0])
@@ -23464,12 +26168,20 @@ aeabi_set_public_attributes (void)
   aeabi_set_attribute_int (Tag_CPU_arch, arch);
 
   /* Tag_CPU_arch_profile.  */
-  if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7a))
-    aeabi_set_attribute_int (Tag_CPU_arch_profile, 'A');
+  if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7a)
+      || ARM_CPU_HAS_FEATURE (flags, arm_ext_v8)
+      || (ARM_CPU_HAS_FEATURE (flags, arm_ext_atomics)
+         && !ARM_CPU_HAS_FEATURE (flags, arm_ext_v8m)))
+    profile = 'A';
   else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7r))
-    aeabi_set_attribute_int (Tag_CPU_arch_profile, 'R');
+    profile = 'R';
   else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_m))
-    aeabi_set_attribute_int (Tag_CPU_arch_profile, 'M');
+    profile = 'M';
+  else
+    profile = '\0';
+
+  if (profile != '\0')
+    aeabi_set_attribute_int (Tag_CPU_arch_profile, profile);
 
   /* Tag_ARM_ISA_use.  */
   if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v1)
@@ -23479,22 +26191,42 @@ aeabi_set_public_attributes (void)
   /* Tag_THUMB_ISA_use.  */
   if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v4t)
       || arch == 0)
-    aeabi_set_attribute_int (Tag_THUMB_ISA_use,
-       ARM_CPU_HAS_FEATURE (flags, arm_arch_t2) ? 2 : 1);
+    {
+      int thumb_isa_use;
+
+      if (!ARM_CPU_HAS_FEATURE (flags, arm_ext_v8)
+         && ARM_CPU_HAS_FEATURE (flags, arm_ext_v8m))
+       thumb_isa_use = 3;
+      else if (ARM_CPU_HAS_FEATURE (flags, arm_arch_t2))
+       thumb_isa_use = 2;
+      else
+       thumb_isa_use = 1;
+      aeabi_set_attribute_int (Tag_THUMB_ISA_use, thumb_isa_use);
+    }
 
   /* Tag_VFP_arch.  */
-  if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_fma))
+  if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_armv8xd))
+    aeabi_set_attribute_int (Tag_VFP_arch,
+                            ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_d32)
+                            ? 7 : 8);
+  else if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_fma))
     aeabi_set_attribute_int (Tag_VFP_arch,
                             ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_d32)
                             ? 5 : 6);
   else if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_d32))
-    aeabi_set_attribute_int (Tag_VFP_arch, 3);
+    {
+      fp16_optional = 1;
+      aeabi_set_attribute_int (Tag_VFP_arch, 3);
+    }
   else if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_v3xd))
-    aeabi_set_attribute_int (Tag_VFP_arch, 4);
+    {
+      aeabi_set_attribute_int (Tag_VFP_arch, 4);
+      fp16_optional = 1;
+    }
   else if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_v2))
     aeabi_set_attribute_int (Tag_VFP_arch, 2);
   else if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_v1)
-           || ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_v1xd))
+          || ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_v1xd))
     aeabi_set_attribute_int (Tag_VFP_arch, 1);
 
   /* Tag_ABI_HardFP_use.  */
@@ -23509,22 +26241,48 @@ aeabi_set_public_attributes (void)
     aeabi_set_attribute_int (Tag_WMMX_arch, 1);
 
   /* Tag_Advanced_SIMD_arch (formerly Tag_NEON_arch).  */
-  if (ARM_CPU_HAS_FEATURE (flags, fpu_neon_ext_v1))
-    aeabi_set_attribute_int
-      (Tag_Advanced_SIMD_arch, (ARM_CPU_HAS_FEATURE (flags, fpu_neon_ext_fma)
-                               ? 2 : 1));
-  
+  if (ARM_CPU_HAS_FEATURE (flags, fpu_neon_ext_v8_1))
+    aeabi_set_attribute_int (Tag_Advanced_SIMD_arch, 4);
+  else if (ARM_CPU_HAS_FEATURE (flags, fpu_neon_ext_armv8))
+    aeabi_set_attribute_int (Tag_Advanced_SIMD_arch, 3);
+  else if (ARM_CPU_HAS_FEATURE (flags, fpu_neon_ext_v1))
+    {
+      if (ARM_CPU_HAS_FEATURE (flags, fpu_neon_ext_fma))
+       {
+         aeabi_set_attribute_int (Tag_Advanced_SIMD_arch, 2);
+       }
+      else
+       {
+         aeabi_set_attribute_int (Tag_Advanced_SIMD_arch, 1);
+         fp16_optional = 1;
+       }
+    }
+
   /* Tag_VFP_HP_extension (formerly Tag_NEON_FP16_arch).  */
-  if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_fp16))
+  if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_fp16) && fp16_optional)
     aeabi_set_attribute_int (Tag_VFP_HP_extension, 1);
 
-  /* Tag_DIV_use.  */
-  if (ARM_CPU_HAS_FEATURE (flags, arm_ext_adiv))
-    aeabi_set_attribute_int (Tag_DIV_use, 2);
-  else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_div))
+  /* Tag_DIV_use.
+
+     We set Tag_DIV_use to two when integer divide instructions have been used
+     in ARM state, or when Thumb integer divide instructions have been used,
+     but we have no architecture profile set, nor have we any ARM instructions.
+
+     For ARMv8-A and ARMv8-M we set the tag to 0 as integer divide is implied
+     by the base architecture.
+
+     For new architectures we will have to check these tests.  */
+  gas_assert (arch <= TAG_CPU_ARCH_V8
+             || (arch >= TAG_CPU_ARCH_V8M_BASE
+                 && arch <= TAG_CPU_ARCH_V8M_MAIN));
+  if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v8)
+      || ARM_CPU_HAS_FEATURE (flags, arm_ext_v8m))
     aeabi_set_attribute_int (Tag_DIV_use, 0);
-  else
-    aeabi_set_attribute_int (Tag_DIV_use, 1);
+  else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_adiv)
+          || (profile == '\0'
+              && ARM_CPU_HAS_FEATURE (flags, arm_ext_div)
+              && !ARM_CPU_HAS_FEATURE (arm_arch_used, arm_arch_any)))
+    aeabi_set_attribute_int (Tag_DIV_use, 2);
 
   /* Tag_MP_extension_use.  */
   if (ARM_CPU_HAS_FEATURE (flags, arm_ext_mp))
@@ -23579,6 +26337,7 @@ s_arm_cpu (int ignored ATTRIBUTE_UNUSED)
            int i;
            for (i = 0; opt->name[i]; i++)
              selected_cpu_name[i] = TOUPPER (opt->name[i]);
+
            selected_cpu_name[i] = 0;
          }
        ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
@@ -23690,9 +26449,10 @@ s_arm_arch_extension (int ignored ATTRIBUTE_UNUSED)
          }
 
        if (adding_value)
-         ARM_MERGE_FEATURE_SETS (selected_cpu, selected_cpu, opt->value);
+         ARM_MERGE_FEATURE_SETS (selected_cpu, selected_cpu,
+                                 opt->merge_value);
        else
-         ARM_CLEAR_FEATURE (selected_cpu, selected_cpu, opt->value);
+         ARM_CLEAR_FEATURE (selected_cpu, selected_cpu, opt->clear_value);
 
        mcpu_cpu_opt = &selected_cpu;
        ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
@@ -23702,7 +26462,7 @@ s_arm_arch_extension (int ignored ATTRIBUTE_UNUSED)
       }
 
   if (opt->name == NULL)
-    as_bad (_("unknown architecture `%s'\n"), name);
+    as_bad (_("unknown architecture extension `%s'\n"), name);
 
   *input_line_pointer = saved_char;
   ignore_rest_of_line ();
@@ -23822,14 +26582,18 @@ arm_convert_symbolic_attribute (const char *name)
 }
 
 
-/* Apply sym value for relocations only in the case that
-   they are for local symbols and you have the respective
-   architectural feature for blx and simple switches.  */
+/* Apply sym value for relocations only in the case that they are for
+   local symbols in the same segment as the fixup and you have the
+   respective architectural feature for blx and simple switches.  */
 int
-arm_apply_sym_value (struct fix * fixP)
+arm_apply_sym_value (struct fix * fixP, segT this_seg)
 {
   if (fixP->fx_addsy
       && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v5t)
+      /* PR 17444: If the local symbol is in a different section then a reloc
+        will always be generated for it, so applying the symbol value now
+        will result in a double offset being stored in the relocation.  */
+      && (S_GET_SEGMENT (fixP->fx_addsy) == this_seg)
       && !S_FORCE_RELOC (fixP->fx_addsy, TRUE))
     {
       switch (fixP->fx_r_type)
@@ -23843,7 +26607,7 @@ arm_apply_sym_value (struct fix * fixP)
        case BFD_RELOC_ARM_PCREL_CALL:
        case BFD_RELOC_THUMB_PCREL_BLX:
          if (THUMB_IS_FUNC (fixP->fx_addsy))
-             return 1;
+           return 1;
          break;
 
        default:
This page took 0.337212 seconds and 4 git commands to generate.