Switch to GPLv3
[deliverable/binutils-gdb.git] / gas / config / tc-arm.c
index c77952278e9c57689f386fd760d776c24da5065e..fbb7ae2cb4ee7296c8c91c40c123c62db4ebc57b 100644 (file)
@@ -1,6 +1,6 @@
 /* tc-arm.c -- Assemble for the ARM
    Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
-   2004, 2005, 2006
+   2004, 2005, 2006, 2007
    Free Software Foundation, Inc.
    Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
        Modified by David Taylor (dtaylor@armltd.co.uk)
@@ -12,7 +12,7 @@
 
    GAS is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GAS is distributed in the hope that it will be useful,
@@ -155,6 +155,7 @@ static const arm_feature_set *mcpu_fpu_opt = NULL;
 static const arm_feature_set *march_cpu_opt = NULL;
 static const arm_feature_set *march_fpu_opt = NULL;
 static const arm_feature_set *mfpu_opt = NULL;
+static const arm_feature_set *object_arch = NULL;
 
 /* Constants for known architecture features.  */
 static const arm_feature_set fpu_default = FPU_DEFAULT;
@@ -201,6 +202,8 @@ static const arm_feature_set arm_arch_full = ARM_FEATURE (-1, -1);
 static const arm_feature_set arm_arch_t2 = ARM_ARCH_THUMB2;
 static const arm_feature_set arm_arch_none = ARM_ARCH_NONE;
 
+static const arm_feature_set arm_cext_iwmmxt2 =
+  ARM_FEATURE (0, ARM_CEXT_IWMMXT2);
 static const arm_feature_set arm_cext_iwmmxt =
   ARM_FEATURE (0, ARM_CEXT_IWMMXT);
 static const arm_feature_set arm_cext_xscale =
@@ -229,6 +232,12 @@ static int meabi_flags = EABI_DEFAULT;
 # else
 static int meabi_flags = EF_ARM_EABI_UNKNOWN;
 # endif
+
+bfd_boolean
+arm_is_eabi(void)
+{
+  return (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4);
+}
 #endif
 
 #ifdef OBJ_ELF
@@ -324,6 +333,7 @@ struct arm_it
     unsigned immisreg  : 1;  /* .imm field is a second register.  */
     unsigned isscalar   : 1;  /* Operand is a (Neon) scalar.  */
     unsigned immisalign : 1;  /* Immediate is an alignment specifier.  */
+    unsigned immisfloat : 1;  /* Immediate was parsed as a float.  */
     /* Note: we abuse "regisimm" to mean "is Neon register" in VMOV
        instructions. This allows us to disambiguate ARM <-> vector insns.  */
     unsigned regisimm   : 1;  /* 64-bit immediate, reg forms high 32 bits.  */
@@ -539,11 +549,14 @@ struct asm_opcode
 #define INDEX_UP       0x00800000
 #define WRITE_BACK     0x00200000
 #define LDM_TYPE_2_OR_3        0x00400000
+#define CPSI_MMOD      0x00020000
 
 #define LITERAL_MASK   0xf000f000
 #define OPCODE_MASK    0xfe1fffff
 #define V4_STR_BIT     0x00000020
 
+#define T2_SUBS_PC_LR  0xf3de8f00
+
 #define DATA_OP_SHIFT  21
 
 #define T2_OPCODE_MASK 0xfe1fffff
@@ -1261,7 +1274,9 @@ parse_typed_reg_or_scalar (char **ccp, enum arm_reg_type type,
           && (reg->type == REG_TYPE_VFS || reg->type == REG_TYPE_VFD))
       || (type == REG_TYPE_NSDQ
           && (reg->type == REG_TYPE_VFS || reg->type == REG_TYPE_VFD
-              || reg->type == REG_TYPE_NQ)))
+              || reg->type == REG_TYPE_NQ))
+      || (type == REG_TYPE_MMXWC
+         && (reg->type == REG_TYPE_MMXWCG)))
     type = reg->type;
 
   if (type != reg->type)
@@ -2277,7 +2292,7 @@ s_unreq (int a ATTRIBUTE_UNUSED)
 
 static enum mstate mapstate = MAP_UNDEFINED;
 
-static void
+void
 mapping_state (enum mstate state)
 {
   symbolS * symbolP;
@@ -2598,6 +2613,7 @@ static void
 s_align (int unused ATTRIBUTE_UNUSED)
 {
   int temp;
+  bfd_boolean fill_p;
   long temp_fill;
   long max_alignment = 15;
 
@@ -2614,16 +2630,25 @@ s_align (int unused ATTRIBUTE_UNUSED)
     {
       input_line_pointer++;
       temp_fill = get_absolute_expression ();
+      fill_p = TRUE;
     }
   else
-    temp_fill = 0;
+    {
+      fill_p = FALSE;
+      temp_fill = 0;
+    }
 
   if (!temp)
     temp = 2;
 
   /* Only make a frag if we HAVE to.  */
   if (temp && !need_pass_2)
-    frag_align (temp, (int) temp_fill, 0);
+    {
+      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);
@@ -3448,7 +3473,7 @@ s_arm_unwind_save_mmxwr (void)
 
              op = 0xffff << (reg - 1);
              if (reg > 0
-                 || ((mask & op) == (1u << (reg - 1))))
+                 && ((mask & op) == (1u << (reg - 1))))
                {
                  op = (1 << (reg + i + 1)) - 1;
                  op &= ~((1 << reg) - 1);
@@ -3626,6 +3651,7 @@ s_arm_unwind_movsp (int ignored ATTRIBUTE_UNUSED)
 {
   int reg;
   valueT op;
+  int offset;
 
   reg = arm_reg_parse (&input_line_pointer, REG_TYPE_RN);
   if (reg == FAIL)
@@ -3634,6 +3660,16 @@ s_arm_unwind_movsp (int ignored ATTRIBUTE_UNUSED)
       ignore_rest_of_line ();
       return;
     }
+
+  /* Optional constant.         */
+  if (skip_past_comma (&input_line_pointer) != FAIL)
+    {
+      if (immediate_for_directive (&offset) == FAIL)
+       return;
+    }
+  else
+    offset = 0;
+
   demand_empty_rest_of_line ();
 
   if (reg == REG_SP || reg == REG_PC)
@@ -3651,7 +3687,7 @@ s_arm_unwind_movsp (int ignored ATTRIBUTE_UNUSED)
 
   /* Record the information for later. */
   unwind.fp_reg = reg;
-  unwind.fp_offset = unwind.frame_size;
+  unwind.fp_offset = unwind.frame_size - offset;
   unwind.sp_restored = 1;
 }
 
@@ -3793,88 +3829,12 @@ s_arm_unwind_raw (int ignored ATTRIBUTE_UNUSED)
 static void
 s_arm_eabi_attribute (int ignored ATTRIBUTE_UNUSED)
 {
-  expressionS exp;
-  bfd_boolean is_string;
-  int tag;
-  unsigned int i = 0;
-  char *s = NULL;
-  char saved_char;
-
-  expression (& exp);
-  if (exp.X_op != O_constant)
-    goto bad;
-
-  tag = exp.X_add_number;
-  if (tag == 4 || tag == 5 || tag == 32 || (tag > 32 && (tag & 1) != 0))
-    is_string = 1;
-  else
-    is_string = 0;
-
-  if (skip_past_comma (&input_line_pointer) == FAIL)
-    goto bad;
-  if (tag == 32 || !is_string)
-    {
-      expression (& exp);
-      if (exp.X_op != O_constant)
-       {
-         as_bad (_("expected numeric constant"));
-         ignore_rest_of_line ();
-         return;
-       }
-      i = exp.X_add_number;
-    }
-  if (tag == Tag_compatibility
-      && skip_past_comma (&input_line_pointer) == FAIL)
-    {
-      as_bad (_("expected comma"));
-      ignore_rest_of_line ();
-      return;
-    }
-  if (is_string)
-    {
-      skip_whitespace(input_line_pointer);
-      if (*input_line_pointer != '"')
-       goto bad_string;
-      input_line_pointer++;
-      s = input_line_pointer;
-      while (*input_line_pointer && *input_line_pointer != '"')
-       input_line_pointer++;
-      if (*input_line_pointer != '"')
-       goto bad_string;
-      saved_char = *input_line_pointer;
-      *input_line_pointer = 0;
-    }
-  else
-    {
-      s = NULL;
-      saved_char = 0;
-    }
-  
-  if (tag == Tag_compatibility)
-    elf32_arm_add_eabi_attr_compat (stdoutput, i, s);
-  else if (is_string)
-    elf32_arm_add_eabi_attr_string (stdoutput, tag, s);
-  else
-    elf32_arm_add_eabi_attr_int (stdoutput, tag, i);
-
-  if (s)
-    {
-      *input_line_pointer = saved_char;
-      input_line_pointer++;
-    }
-  demand_empty_rest_of_line ();
-  return;
-bad_string:
-  as_bad (_("bad string constant"));
-  ignore_rest_of_line ();
-  return;
-bad:
-  as_bad (_("expected <tag> , <value>"));
-  ignore_rest_of_line ();
+  s_vendor_attribute (OBJ_ATTR_PROC);
 }
 #endif /* OBJ_ELF */
 
 static void s_arm_arch (int);
+static void s_arm_object_arch (int);
 static void s_arm_cpu (int);
 static void s_arm_fpu (int);
 
@@ -3928,6 +3888,7 @@ const pseudo_typeS md_pseudo_table[] =
   { "syntax",     s_syntax,      0 },
   { "cpu",        s_arm_cpu,     0 },
   { "arch",       s_arm_arch,    0 },
+  { "object_arch", s_arm_object_arch,  0 },
   { "fpu",        s_arm_fpu,     0 },
 #ifdef OBJ_ELF
   { "word",       s_arm_elf_cons, 4 },
@@ -3998,7 +3959,7 @@ parse_immediate (char **str, int *val, int min, int max,
 }
 
 /* Less-generic immediate-value read function with the possibility of loading a
-   big (64-bit) immediate, as required by Neon VMOV and VMVN immediate
+   big (64-bit) immediate, as required by Neon VMOV, VMVN and logic immediate
    instructions. Puts the result directly in inst.operands[i].  */
 
 static int
@@ -4010,7 +3971,18 @@ parse_big_immediate (char **str, int i)
   my_get_expression (&exp, &ptr, GE_OPT_PREFIX_BIG);
 
   if (exp.X_op == O_constant)
-    inst.operands[i].imm = exp.X_add_number;
+    {
+      inst.operands[i].imm = exp.X_add_number & 0xffffffff;
+      /* If we're on a 64-bit host, then a 64-bit number can be returned using
+        O_constant.  We have to be careful not to break compilation for
+        32-bit X_add_number, though.  */
+      if ((exp.X_add_number & ~0xffffffffl) != 0)
+       {
+          /* X >> 32 is illegal if sizeof (exp.X_add_number) == 4.  */
+         inst.operands[i].reg = ((exp.X_add_number >> 16) >> 16) & 0xffffffff;
+         inst.operands[i].regisimm = 1;
+       }
+    }
   else if (exp.X_op == O_big
            && LITTLENUM_NUMBER_OF_BITS * exp.X_add_number > 32
            && LITTLENUM_NUMBER_OF_BITS * exp.X_add_number <= 64)
@@ -4141,18 +4113,43 @@ is_quarter_float (unsigned imm)
 
 /* Parse an 8-bit "quarter-precision" floating point number of the form:
    0baBbbbbbc defgh000 00000000 00000000.
-   The minus-zero case needs special handling, since it can't be encoded in the
-   "quarter-precision" float format, but can nonetheless be loaded as an integer
-   constant.  */
+   The zero and minus-zero cases need special handling, since they can't be
+   encoded in the "quarter-precision" float format, but can nonetheless be
+   loaded as integer constants.  */
 
 static unsigned
 parse_qfloat_immediate (char **ccp, int *immed)
 {
   char *str = *ccp;
+  char *fpnum;
   LITTLENUM_TYPE words[MAX_LITTLENUMS];
+  int found_fpchar = 0;
   
   skip_past_char (&str, '#');
   
+  /* We must not accidentally parse an integer as a floating-point number. Make
+     sure that the value we parse is not an integer by checking for special
+     characters '.' or 'e'.
+     FIXME: This is a horrible hack, but doing better is tricky because type
+     information isn't in a very usable state at parse time.  */
+  fpnum = str;
+  skip_whitespace (fpnum);
+
+  if (strncmp (fpnum, "0x", 2) == 0)
+    return FAIL;
+  else
+    {
+      for (; *fpnum != '\0' && *fpnum != ' ' && *fpnum != '\n'; fpnum++)
+        if (*fpnum == '.' || *fpnum == 'e' || *fpnum == 'E')
+          {
+            found_fpchar = 1;
+            break;
+          }
+
+      if (!found_fpchar)
+        return FAIL;
+    }
+  
   if ((str = atof_ieee (str, 's', words)) != NULL)
     {
       unsigned fpword = 0;
@@ -4165,7 +4162,7 @@ parse_qfloat_immediate (char **ccp, int *immed)
           fpword |= words[i];
         }
       
-      if (is_quarter_float (fpword) || fpword == 0x80000000)
+      if (is_quarter_float (fpword) || (fpword & 0x7fffffff) == 0)
         *immed = fpword;
       else
         return FAIL;
@@ -5165,7 +5162,7 @@ parse_neon_mov (char **str, int *which_operand)
              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>  */
@@ -5358,6 +5355,7 @@ enum operand_parse_code
   OP_VMOV,      /* Neon VMOV operands.  */
   OP_RNDQ_IMVNb,/* Neon D or Q reg, or immediate good for VMVN.  */
   OP_RNDQ_I63b, /* Neon D or Q reg, or immediate for shift.  */
+  OP_RIWR_I32z, /* iWMMXt wR register, or immediate 0 .. 32 for iWMMXt2.  */
 
   OP_I0,        /* immediate zero */
   OP_I7,       /* immediate value 0 .. 7 */
@@ -5415,6 +5413,7 @@ enum operand_parse_code
 
   OP_oRR,       /* ARM register */
   OP_oRRnpc,    /* ARM register, not the PC */
+  OP_oRRw,      /* ARM register, not r15, optional trailing ! */
   OP_oRND,       /* Optional Neon double precision register */
   OP_oRNQ,       /* Optional Neon quad precision register */
   OP_oRNDQ,      /* Optional Neon double or quad precision register */
@@ -5519,7 +5518,7 @@ parse_operands (char *str, const unsigned char *pattern)
          backtrack_index = i;
        }
 
-      if (i > 0)
+      if (i > 0 && (i > 1 || inst.operands[0].present))
        po_char_or_fail (',');
 
       switch (upat[i])
@@ -5536,7 +5535,13 @@ parse_operands (char *str, const unsigned char *pattern)
        case OP_RVD:   po_reg_or_fail (REG_TYPE_VFD);     break;
         case OP_oRND:
        case OP_RND:   po_reg_or_fail (REG_TYPE_VFD);     break;
-       case OP_RVC:   po_reg_or_fail (REG_TYPE_VFC);     break;
+       case OP_RVC:
+         po_reg_or_goto (REG_TYPE_VFC, coproc_reg);
+         break;
+         /* Also accept generic coprocessor regs for unknown registers.  */
+         coproc_reg:
+         po_reg_or_fail (REG_TYPE_CN);
+         break;
        case OP_RMF:   po_reg_or_fail (REG_TYPE_MVF);     break;
        case OP_RMD:   po_reg_or_fail (REG_TYPE_MVD);     break;
        case OP_RMFX:  po_reg_or_fail (REG_TYPE_MVFX);    break;
@@ -5566,6 +5571,7 @@ parse_operands (char *str, const unsigned char *pattern)
         case OP_NILO:
           {
             po_reg_or_goto (REG_TYPE_NDQ, try_imm);
+           inst.operands[i].present = 1;
             i++;
             skip_past_comma (&str);
             po_reg_or_goto (REG_TYPE_NDQ, one_reg_only);
@@ -5578,8 +5584,13 @@ parse_operands (char *str, const unsigned char *pattern)
             inst.operands[i-1].present = 0;
             break;
             try_imm:
-            /* Immediate gets verified properly later, so accept any now.  */
-            po_imm_or_fail (INT_MIN, INT_MAX, TRUE);
+           /* There's a possibility of getting a 64-bit immediate here, so
+              we need special handling.  */
+           if (parse_big_immediate (&str, i) == FAIL)
+             {
+               inst.error = _("immediate value is out of range");
+               goto failure;
+             }
           }
           break;
 
@@ -5669,6 +5680,7 @@ parse_operands (char *str, const unsigned char *pattern)
          break;
 
        case OP_RRw:
+       case OP_oRRw:
          po_reg_or_fail (REG_TYPE_RN);
          if (skip_past_char (&str, '!') == SUCCESS)
            inst.operands[i].writeback = 1;
@@ -5779,6 +5791,9 @@ parse_operands (char *str, const unsigned char *pattern)
          inst.operands[i].isreg = 1;
          break;
 
+       case OP_RIWR_I32z: po_reg_or_goto (REG_TYPE_MMXWR, I32z); break;
+       I32z:             po_imm_or_fail (0, 32, FALSE);          break;
+
          /* Two kinds of register */
        case OP_RIWR_RIWC:
          {
@@ -5953,6 +5968,7 @@ parse_operands (char *str, const unsigned char *pattern)
        case OP_RRnpc:
        case OP_RRnpcb:
        case OP_RRw:
+       case OP_oRRw:
        case OP_RRnpc_I0:
          if (inst.operands[i].isreg && inst.operands[i].reg == REG_PC)
            inst.error = BAD_PC;
@@ -6783,7 +6799,11 @@ static void
 do_cpsi (void)
 {
   inst.instruction |= inst.operands[0].imm << 6;
-  inst.instruction |= inst.operands[1].imm;
+  if (inst.operands[1].present)
+    {
+      inst.instruction |= CPSI_MMOD;
+      inst.instruction |= inst.operands[1].imm;
+    }
 }
 
 static void
@@ -7001,17 +7021,16 @@ do_lstc (void)
 static void
 do_mlas (void)
 {
-  /* This restriction does not apply to mls (nor to mla in v6, but
-     that's hard to detect at present).         */
+  /* 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"));
+    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
@@ -7119,8 +7138,9 @@ do_mul (void)
   inst.instruction |= inst.operands[1].reg;
   inst.instruction |= inst.operands[2].reg << 8;
 
-  if (inst.operands[0].reg == inst.operands[1].reg)
-    as_tsktsk (_("rd and rm should be different in mul"));
+  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
@@ -7386,13 +7406,25 @@ do_smul (void)
   inst.instruction |= inst.operands[2].reg << 8;
 }
 
-/* ARM V6 srs (argument parse).         */
+/* ARM V6 srs (argument parse).  The variable fields in the encoding are
+   the same for both ARM and Thumb-2.  */
 
 static void
 do_srs (void)
 {
-  inst.instruction |= inst.operands[0].imm;
-  if (inst.operands[0].writeback)
+  int reg;
+
+  if (inst.operands[0].present)
+    {
+      reg = inst.operands[0].reg;
+      constraint (reg != 13, _("SRS base register must be r13"));
+    }
+  else
+    reg = 13;
+
+  inst.instruction |= reg << 16;
+  inst.instruction |= inst.operands[1].imm;
+  if (inst.operands[0].writeback || inst.operands[1].writeback)
     inst.instruction |= WRITE_BACK;
 }
 
@@ -7680,16 +7712,16 @@ static void
 do_vfp_sp_const (void)
 {
   encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
-  inst.instruction |= (inst.operands[1].imm & 15) << 16;
-  inst.instruction |= (inst.operands[1].imm >> 4);
+  inst.instruction |= (inst.operands[1].imm & 0xf0) << 12;
+  inst.instruction |= (inst.operands[1].imm & 0x0f);
 }
 
 static void
 do_vfp_dp_const (void)
 {
   encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
-  inst.instruction |= (inst.operands[1].imm & 15) << 16;
-  inst.instruction |= (inst.operands[1].imm >> 4);
+  inst.instruction |= (inst.operands[1].imm & 0xf0) << 12;
+  inst.instruction |= (inst.operands[1].imm & 0x0f);
 }
 
 static void
@@ -7826,6 +7858,15 @@ do_iwmmxt_waligni (void)
   inst.instruction |= inst.operands[3].imm << 20;
 }
 
+static void
+do_iwmmxt_wmerge (void)
+{
+  inst.instruction |= inst.operands[0].reg << 12;
+  inst.instruction |= inst.operands[1].reg << 16;
+  inst.instruction |= inst.operands[2].reg;
+  inst.instruction |= inst.operands[3].imm << 21;
+}
+
 static void
 do_iwmmxt_wmov (void)
 {
@@ -7865,7 +7906,23 @@ static void
 do_iwmmxt_wldstd (void)
 {
   inst.instruction |= inst.operands[0].reg << 12;
-  encode_arm_cp_address (1, TRUE, FALSE, 0);
+  if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt2)
+      && inst.operands[1].immisreg)
+    {
+      inst.instruction &= ~0x1a000ff;
+      inst.instruction |= (0xf << 28);
+      if (inst.operands[1].preind)
+       inst.instruction |= PRE_INDEX;
+      if (!inst.operands[1].negative)
+       inst.instruction |= INDEX_UP;
+      if (inst.operands[1].writeback)
+       inst.instruction |= WRITE_BACK;
+      inst.instruction |= inst.operands[1].reg << 16;
+      inst.instruction |= inst.reloc.exp.X_add_number << 4;
+      inst.instruction |= inst.operands[1].imm;
+    }
+  else
+    encode_arm_cp_address (1, TRUE, FALSE, 0);
 }
 
 static void
@@ -7885,6 +7942,56 @@ do_iwmmxt_wzero (void)
   inst.instruction |= inst.operands[0].reg << 12;
   inst.instruction |= inst.operands[0].reg << 16;
 }
+
+static void
+do_iwmmxt_wrwrwr_or_imm5 (void)
+{
+  if (inst.operands[2].isreg)
+    do_rd_rn_rm ();
+  else {
+    constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt2),
+               _("immediate operand requires iWMMXt2"));
+    do_rd_rn ();
+    if (inst.operands[2].imm == 0)
+      {
+       switch ((inst.instruction >> 20) & 0xf)
+         {
+         case 4:
+         case 5:
+         case 6:
+         case 7: 
+           /* w...h wrd, wrn, #0 -> wrorh wrd, wrn, #16.  */
+           inst.operands[2].imm = 16;
+           inst.instruction = (inst.instruction & 0xff0fffff) | (0x7 << 20);
+           break;
+         case 8:
+         case 9:
+         case 10:
+         case 11:
+           /* w...w wrd, wrn, #0 -> wrorw wrd, wrn, #32.  */
+           inst.operands[2].imm = 32;
+           inst.instruction = (inst.instruction & 0xff0fffff) | (0xb << 20);
+           break;
+         case 12:
+         case 13:
+         case 14:
+         case 15:
+           {
+             /* w...d wrd, wrn, #0 -> wor wrd, wrn, wrn.  */
+             unsigned long wrn;
+             wrn = (inst.instruction >> 16) & 0xf;
+             inst.instruction &= 0xff0fff0f;
+             inst.instruction |= wrn;
+             /* Bail out here; the instruction is now assembled.  */
+             return;
+           }
+         }
+      }
+    /* Map 32 -> 0, etc.  */
+    inst.operands[2].imm &= 0x1f;
+    inst.instruction |= (0xf << 28) | ((inst.operands[2].imm & 0x10) << 4) | (inst.operands[2].imm & 0xf);
+  }
+}
 \f
 /* Cirrus Maverick instructions.  Simple 2-, 3-, and 4-register
    operations first, then control, shift, and load/store.  */
@@ -8119,7 +8226,7 @@ encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d)
   X(cpsie, b660, f3af8400),                    \
   X(cpsid, b670, f3af8600),                    \
   X(cpy,   4600, ea4f0000),                    \
-  X(dec_sp,80dd, f1bd0d00),                    \
+  X(dec_sp,80dd, f1ad0d00),                    \
   X(eor,   4040, ea800000),                    \
   X(eors,  4040, ea900000),                    \
   X(inc_sp,00dd, f10d0d00),                    \
@@ -8273,7 +8380,21 @@ do_t_add_sub (void)
          if (inst.size_req == 4
              || (inst.size_req != 2 && !opcode))
            {
-             if (Rs == REG_PC)
+             if (Rd == REG_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;
@@ -8289,8 +8410,8 @@ do_t_add_sub (void)
                  else
                    inst.reloc.type = BFD_RELOC_ARM_T32_ADD_IMM;
                }
-             inst.instruction |= inst.operands[0].reg << 8;
-             inst.instruction |= inst.operands[1].reg << 16;
+             inst.instruction |= Rd << 8;
+             inst.instruction |= Rs << 16;
            }
        }
       else
@@ -8856,7 +8977,7 @@ do_t_cpy (void)
 }
 
 static void
-do_t_czb (void)
+do_t_cbz (void)
 {
   constraint (current_it_mask, BAD_NOT_IT);
   constraint (inst.operands[0].reg > 7, BAD_HIREG);
@@ -8920,6 +9041,68 @@ do_t_it (void)
   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 (load)
+    {
+      if (mask & (1 << 14)
+         && mask & (1 << 15))
+       inst.error = _("LR and PC should not both be in register list");
+
+      if ((mask & (1 << base)) != 0
+         && writeback)
+       as_warn (_("base register should not be in register list "
+                  "when written back"));
+    }
+  else
+    {
+      if (mask & (1 << 15))
+       inst.error = _("PC not allowed in register list");
+
+      if (mask & (1 << base))
+       as_warn (_("value stored for r%d is UNPREDICTABLE"), base);
+    }
+
+  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)
 {
@@ -8931,60 +9114,60 @@ do_t_ldmstm (void)
 
   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[0].reg <= 7
-         && !(inst.operands[1].imm & ~0xff)
-         && (inst.instruction == T_MNEM_stmia
-             ? inst.operands[0].writeback
-             : (inst.operands[0].writeback
-                == !(inst.operands[1].imm & (1 << inst.operands[0].reg)))))
+         && !(inst.operands[1].imm & ~0xff))
        {
-         if (inst.instruction == T_MNEM_stmia
-             && (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 UNPREDICTABLE"),
-                    inst.operands[0].reg);
+         mask = 1 << inst.operands[0].reg;
 
-         inst.instruction = THUMB_OP16 (inst.instruction);
-         inst.instruction |= inst.operands[0].reg << 8;
-         inst.instruction |= inst.operands[1].imm;
-       }
-      else
-       {
-         if (inst.operands[1].imm & (1 << 13))
-           as_warn (_("SP should not be in register list"));
-         if (inst.instruction == T_MNEM_stmia)
+         if (inst.operands[0].reg <= 7
+             && (inst.instruction == T_MNEM_stmia
+                 ? inst.operands[0].writeback
+                 : (inst.operands[0].writeback
+                    == !(inst.operands[1].imm & mask))))
            {
-             if (inst.operands[1].imm & (1 << 15))
-               as_warn (_("PC should not be in register list"));
-             if (inst.operands[1].imm & (1 << inst.operands[0].reg))
+             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 UNPREDICTABLE"),
                         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
+         else if (inst.operands[0] .reg == REG_SP
+                  && inst.operands[0].writeback)
            {
-             if (inst.operands[1].imm & (1 << 14)
-                 && inst.operands[1].imm & (1 << 15))
-               as_warn (_("LR and PC should not both be in register list"));
-             if ((inst.operands[1].imm & (1 << inst.operands[0].reg))
-                 && inst.operands[0].writeback)
-               as_warn (_("base register should not be in register list "
-                          "when written back"));
+             inst.instruction = THUMB_OP16 (inst.instruction == T_MNEM_stmia
+                                            ? T_MNEM_push : T_MNEM_pop);
+             inst.instruction |= inst.operands[1].imm;
+             narrow = TRUE;
            }
+       }
+
+      if (!narrow)
+       {
          if (inst.instruction < 0xffff)
            inst.instruction = THUMB_OP32 (inst.instruction);
-         inst.instruction |= inst.operands[0].reg << 16;
-         inst.instruction |= inst.operands[1].imm;
-         if (inst.operands[0].writeback)
-           inst.instruction |= WRITE_BACK;
+
+         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)
@@ -9258,6 +9441,16 @@ do_t_mov_cmp (void)
          || 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
+         && inst.operands[0].reg == REG_PC
+         && inst.operands[1].reg == REG_LR)
+       {
+         inst.instruction = T2_SUBS_PC_LR;
+         return;
+       }
+
       if (!inst.operands[1].isreg)
        {
          /* Immediate operand.  */
@@ -9280,11 +9473,98 @@ do_t_mov_cmp (void)
              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 (current_it_mask)
+           narrow = !flags;
+         else
+           narrow = flags;
+
+         if (inst.size_req == 4)
+           narrow = FALSE;
+
+         if (!low_regs || inst.operands[1].imm > 7)
+           narrow = FALSE;
+
+         if (inst.operands[0].reg != inst.operands[1].reg)
+           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 |= inst.operands[0].reg;
+             inst.instruction |= inst.operands[1].imm << 3;
+           }
+         else
+           {
+             if (flags)
+               inst.instruction |= CONDS_BIT;
+
+             inst.instruction |= inst.operands[0].reg << 8;
+             inst.instruction |= inst.operands[1].reg << 16;
+             inst.instruction |= inst.operands[1].imm;
+           }
+       }
       else if (!narrow)
        {
-         inst.instruction = THUMB_OP32 (inst.instruction);
-         inst.instruction |= inst.operands[0].reg << r0off;
-         encode_thumb32_shifted_operand (1);
+         /* 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 (current_it_mask)
+               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 |= inst.operands[0].reg;
+             inst.instruction |= inst.operands[1].reg << 3;
+             inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
+           }
+         else
+           {
+             inst.instruction = THUMB_OP32 (inst.instruction);
+             inst.instruction |= inst.operands[0].reg << r0off;
+             encode_thumb32_shifted_operand (1);
+           }
        }
       else
        switch (inst.instruction)
@@ -9664,7 +9944,7 @@ do_t_push_pop (void)
 
   mask = inst.operands[0].imm;
   if ((mask & ~0xff) == 0)
-    inst.instruction = THUMB_OP16 (inst.instruction);
+    inst.instruction = THUMB_OP16 (inst.instruction) | mask;
   else if ((inst.instruction == T_MNEM_push
            && (mask & ~0xff) == 1 << REG_LR)
           || (inst.instruction == T_MNEM_pop
@@ -9672,43 +9952,18 @@ do_t_push_pop (void)
     {
       inst.instruction = THUMB_OP16 (inst.instruction);
       inst.instruction |= THUMB_PP_PC_LR;
-      mask &= 0xff;
+      inst.instruction |= mask & 0xff;
     }
   else if (unified_syntax)
     {
-      if (mask & (1 << 13))
-       inst.error =  _("SP not allowed in register list");
-      if (inst.instruction == T_MNEM_push)
-       {
-         if (mask & (1 << 15))
-           inst.error = _("PC not allowed in register list");
-       }
-      else
-       {
-         if (mask & (1 << 14)
-             && mask & (1 << 15))
-           inst.error = _("LR and PC should not both be in register list");
-       }
-      if ((mask & (mask - 1)) == 0)
-       {
-         /* Single register push/pop implemented as str/ldr.  */
-         if (inst.instruction == T_MNEM_push)
-           inst.instruction = 0xf84d0d04; /* str reg, [sp, #-4]! */
-         else
-           inst.instruction = 0xf85d0b04; /* ldr reg, [sp], #4 */
-         mask = ffs(mask) - 1;
-         mask <<= 12;
-       }
-      else
-       inst.instruction = THUMB_OP32 (inst.instruction);
+      inst.instruction = THUMB_OP32 (inst.instruction);
+      encode_thumb2_ldmstm(13, mask, TRUE);
     }
   else
     {
       inst.error = _("invalid register list to push/pop instruction");
       return;
     }
-
-  inst.instruction |= mask;
 }
 
 static void
@@ -9753,8 +10008,37 @@ do_t_rsb (void)
   inst.instruction |= Rs << 16;
   if (!inst.operands[2].isreg)
     {
-      inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
-      inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
+      bfd_boolean narrow;
+
+      if ((inst.instruction & 0x00100000) != 0)
+       narrow = (current_it_mask == 0);
+      else
+       narrow = (current_it_mask != 0);
+
+      if (Rd > 7 || Rs > 7)
+       narrow = FALSE;
+
+      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);
@@ -10102,8 +10386,8 @@ struct neon_tab_entry
   X(vcgt,      0x0000300, 0x1200e00, 0x1b10000),       \
   /* Register variants of the following two instructions are encoded as
      vcge / vcgt with the operands reversed. */        \
-  X(vclt,      0x0000310, 0x1000e00, 0x1b10200),       \
-  X(vcle,      0x0000300, 0x1200e00, 0x1b10180),       \
+  X(vclt,      0x0000300, 0x1200e00, 0x1b10200),       \
+  X(vcle,      0x0000310, 0x1000e00, 0x1b10180),       \
   X(vmla,      0x0000900, 0x0000d10, 0x0800040),       \
   X(vmls,      0x1000900, 0x0200d10, 0x0800440),       \
   X(vmul,      0x0000910, 0x1000d10, 0x0800840),       \
@@ -11132,9 +11416,9 @@ do_vfp_nsyn_pop (void)
 {
   nsyn_insert_sp ();
   if (inst.operands[1].issingle)
-    do_vfp_nsyn_opcode ("fldmdbs");
+    do_vfp_nsyn_opcode ("fldmias");
   else
-    do_vfp_nsyn_opcode ("fldmdbd");
+    do_vfp_nsyn_opcode ("fldmiad");
 }
 
 /* Fix up Neon data-processing instructions, ORing in the correct bits for
@@ -11273,6 +11557,18 @@ do_neon_shl_imm (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_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;
       inst.instruction = NEON_ENC_INTEGER (inst.instruction);
       neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
     }
@@ -11285,6 +11581,7 @@ do_neon_qshl_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_SU_ALL | N_KEY);
+
       inst.instruction = NEON_ENC_IMMED (inst.instruction);
       neon_imm_shift (TRUE, et.type == NT_unsigned, neon_quad (rs), et,
                       inst.operands[2].imm);
@@ -11294,53 +11591,80 @@ do_neon_qshl_imm (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_SU_ALL | N_KEY, N_EQK | N_SGN);
+      unsigned int tmp;
+
+      /* 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;
       inst.instruction = NEON_ENC_INTEGER (inst.instruction);
       neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
     }
 }
 
+static void
+do_neon_rshl (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);
+}
+
 static int
 neon_cmode_for_logic_imm (unsigned immediate, unsigned *immbits, int size)
 {
-  /* Handle .I8 and .I64 as pseudo-instructions.  */
-  switch (size)
+  /* Handle .I8 pseudo-instructions.  */
+  if (size == 8)
     {
-    case 8:
       /* Unfortunately, this will make everything apart from zero out-of-range.
          FIXME is this the intended semantics? There doesn't seem much point in
          accepting .I8 if so.  */
       immediate |= immediate << 8;
       size = 16;
-      break;
-    case 64:
-      /* Similarly, anything other than zero will be replicated in bits [63:32],
-         which probably isn't want we want if we specified .I64.  */
-      if (immediate != 0)
-        goto bad_immediate;
-      size = 32;
-      break;
-    default: ;
+    }
+
+  if (size >= 32)
+    {
+      if (immediate == (immediate & 0x000000ff))
+       {
+         *immbits = immediate;
+         return 0x1;
+       }
+      else if (immediate == (immediate & 0x0000ff00))
+       {
+         *immbits = immediate >> 8;
+         return 0x3;
+       }
+      else if (immediate == (immediate & 0x00ff0000))
+       {
+         *immbits = immediate >> 16;
+         return 0x5;
+       }
+      else if (immediate == (immediate & 0xff000000))
+       {
+         *immbits = immediate >> 24;
+         return 0x7;
+       }
+      if ((immediate & 0xffff) != (immediate >> 16))
+       goto bad_immediate;
+      immediate &= 0xffff;
     }
 
   if (immediate == (immediate & 0x000000ff))
     {
       *immbits = immediate;
-      return (size == 16) ? 0x9 : 0x1;
+      return 0x9;
     }
   else if (immediate == (immediate & 0x0000ff00))
     {
       *immbits = immediate >> 8;
-      return (size == 16) ? 0xb : 0x3;
-    }
-  else if (immediate == (immediate & 0x00ff0000))
-    {
-      *immbits = immediate >> 16;
-      return 0x5;
-    }
-  else if (immediate == (immediate & 0xff000000))
-    {
-      *immbits = immediate >> 24;
-      return 0x7;
+      return 0xb;
     }
 
   bad_immediate:
@@ -11381,12 +11705,19 @@ neon_qfloat_bits (unsigned imm)
    the instruction. *OP is passed as the initial value of the op field, and
    may be set to a different value depending on the constant (i.e.
    "MOV I64, 0bAAAAAAAABBBB..." which uses OP = 1 despite being MOV not
-   MVN).  */
+   MVN).  If the immediate looks like a repeated parttern then also
+   try smaller element sizes.  */
 
 static int
-neon_cmode_for_move_imm (unsigned immlo, unsigned immhi, unsigned *immbits,
-                         int *op, int size, enum neon_el_type type)
+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)
@@ -11394,63 +11725,87 @@ neon_cmode_for_move_imm (unsigned immlo, unsigned immhi, unsigned *immbits,
       *immbits = neon_qfloat_bits (immlo);
       return 0xf;
     }
-  else if (size == 64 && neon_bits_same_in_bytes (immhi)
-      && neon_bits_same_in_bytes (immlo))
-    {
-      /* Check this one first so we don't have to bother with immhi in later
-         tests.  */
-      if (*op == 1)
-        return FAIL;
-      *immbits = (neon_squash_bits (immhi) << 4) | neon_squash_bits (immlo);
-      *op = 1;
-      return 0xe;
-    }
-  else if (immhi != 0)
-    return FAIL;
-  else if (immlo == (immlo & 0x000000ff))
-    {
-      /* 64-bit case was already handled. Don't allow MVN with 8-bit
-         immediate.  */
-      if ((size != 8 && size != 16 && size != 32)
-          || (size == 8 && *op == 1))
-        return FAIL;
-      *immbits = immlo;
-      return (size == 8) ? 0xe : (size == 16) ? 0x8 : 0x0;
-    }
-  else if (immlo == (immlo & 0x0000ff00))
-    {
-      if (size != 16 && size != 32)
-        return FAIL;
-      *immbits = immlo >> 8;
-      return (size == 16) ? 0xa : 0x2;
-    }
-  else if (immlo == (immlo & 0x00ff0000))
+
+  if (size == 64)
     {
-      if (size != 32)
-        return FAIL;
-      *immbits = immlo >> 16;
-      return 0x4;
+      if (neon_bits_same_in_bytes (immhi)
+         && neon_bits_same_in_bytes (immlo))
+       {
+         if (*op == 1)
+           return FAIL;
+         *immbits = (neon_squash_bits (immhi) << 4)
+                    | neon_squash_bits (immlo);
+         *op = 1;
+         return 0xe;
+       }
+
+      if (immhi != immlo)
+       return FAIL;
     }
-  else if (immlo == (immlo & 0xff000000))
+
+  if (size >= 32)
     {
-      if (size != 32)
-        return FAIL;
-      *immbits = immlo >> 24;
-      return 0x6;
+      if (immlo == (immlo & 0x000000ff))
+       {
+         *immbits = immlo;
+         return 0x0;
+       }
+      else if (immlo == (immlo & 0x0000ff00))
+       {
+         *immbits = immlo >> 8;
+         return 0x2;
+       }
+      else if (immlo == (immlo & 0x00ff0000))
+       {
+         *immbits = immlo >> 16;
+         return 0x4;
+       }
+      else if (immlo == (immlo & 0xff000000))
+       {
+         *immbits = immlo >> 24;
+         return 0x6;
+       }
+      else if (immlo == ((immlo & 0x0000ff00) | 0x000000ff))
+       {
+         *immbits = (immlo >> 8) & 0xff;
+         return 0xc;
+       }
+      else if (immlo == ((immlo & 0x00ff0000) | 0x0000ffff))
+       {
+         *immbits = (immlo >> 16) & 0xff;
+         return 0xd;
+       }
+
+      if ((immlo & 0xffff) != (immlo >> 16))
+       return FAIL;
+      immlo &= 0xffff;
     }
-  else if (immlo == ((immlo & 0x0000ff00) | 0x000000ff))
+
+  if (size >= 16)
     {
-      if (size != 32)
-        return FAIL;
-      *immbits = (immlo >> 8) & 0xff;
-      return 0xc;
+      if (immlo == (immlo & 0x000000ff))
+       {
+         *immbits = immlo;
+         return 0x8;
+       }
+      else if (immlo == (immlo & 0x0000ff00))
+       {
+         *immbits = immlo >> 8;
+         return 0xa;
+       }
+
+      if ((immlo & 0xff) != (immlo >> 8))
+       return FAIL;
+      immlo &= 0xff;
     }
-  else if (immlo == ((immlo & 0x00ff0000) | 0x0000ffff))
+
+  if (immlo == (immlo & 0x000000ff))
     {
-      if (size != 32)
-        return FAIL;
-      *immbits = (immlo >> 16) & 0xff;
-      return 0xd;
+      /* Don't allow MVN with 8-bit immediate.  */
+      if (*op == 1)
+       return FAIL;
+      *immbits = immlo;
+      return 0xe;
     }
 
   return FAIL;
@@ -11533,28 +11888,37 @@ do_neon_logic (void)
       
       inst.instruction = NEON_ENC_IMMED (inst.instruction);
 
+      immbits = inst.operands[1].imm;
+      if (et.size == 64)
+       {
+         /* .i64 is a pseudo-op, so the immediate must be a repeating
+            pattern.  */
+         if (immbits != (inst.operands[1].regisimm ?
+                         inst.operands[1].reg : 0))
+           {
+             /* Set immbits to an invalid constant.  */
+             immbits = 0xdeadbeef;
+           }
+       }
+
       switch (opcode)
         {
         case N_MNEM_vbic:
-          cmode = neon_cmode_for_logic_imm (inst.operands[1].imm, &immbits,
-                                            et.size);
+          cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size);
           break;
         
         case N_MNEM_vorr:
-          cmode = neon_cmode_for_logic_imm (inst.operands[1].imm, &immbits,
-                                            et.size);
+          cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size);
           break;
         
         case N_MNEM_vand:
           /* Pseudo-instruction for VBIC.  */
-          immbits = inst.operands[1].imm;
           neon_invert_size (&immbits, 0, et.size);
           cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size);
           break;
         
         case N_MNEM_vorn:
           /* Pseudo-instruction for VORR.  */
-          immbits = inst.operands[1].imm;
           neon_invert_size (&immbits, 0, et.size);
           cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size);
           break;
@@ -11617,16 +11981,12 @@ do_neon_dyadic_if_su_d (void)
   neon_dyadic_misc (NT_unsigned, N_SUF_32, 0);
 }
 
-static void
-do_neon_dyadic_if_i (void)
-{
-  neon_dyadic_misc (NT_unsigned, N_IF_32, 0);
-}
-
 static void
 do_neon_dyadic_if_i_d (void)
 {
-  neon_dyadic_misc (NT_unsigned, N_IF_32, 0);
+  /* The "untyped" case can't happen. Do this to stop the "U" bit being
+     affected if we specify unsigned args.  */
+  neon_dyadic_misc (NT_untyped, N_IF_32, 0);
 }
 
 enum vfp_or_neon_is_neon_bits
@@ -11841,7 +12201,11 @@ do_neon_mac_maybe_scalar (void)
       neon_mul_mac (et, neon_quad (rs));
     }
   else
-    do_neon_dyadic_if_i ();
+    {
+      /* The "untyped" case can't happen.  Do this to stop the "U" bit being
+        affected if we specify unsigned args.  */
+      neon_dyadic_misc (NT_untyped, N_IF_32, 0);
+    }
 }
 
 static void
@@ -12349,7 +12713,7 @@ neon_move_immediate (void)
   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;
+  int op, cmode, float_p;
 
   constraint (et.type == NT_invtype,
               _("operand size must be specified for immediate VMOV"));
@@ -12364,7 +12728,9 @@ neon_move_immediate (void)
   constraint (et.size < 32 && (immlo & ~((1 << et.size) - 1)) != 0,
               _("immediate has bits set outside the operand size"));
 
-  if ((cmode = neon_cmode_for_move_imm (immlo, immhi, &immbits, &op,
+  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.  */
@@ -12373,8 +12739,8 @@ neon_move_immediate (void)
          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, &immbits, &op,
-                                            et.size, et.type)) == FAIL)
+      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;
@@ -12492,6 +12858,9 @@ do_neon_dyadic_narrow (void)
 {
   struct neon_type_el et = neon_check_type (3, NS_QDD,
     N_EQK | N_DBL, N_EQK, N_I16 | N_I32 | N_I64 | N_KEY);
+  /* Operand sign is unimportant, and the U bit is part of the opcode,
+     so force the operand type to integer.  */
+  et.type = NT_integer;
   neon_mixed_length (et, et.size / 2);
 }
 
@@ -12527,6 +12896,7 @@ do_neon_ext (void)
   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;
+  constraint (imm >= (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;
@@ -13582,11 +13952,14 @@ opcode_lookup (char **str)
   const struct asm_opcode *opcode;
   const struct asm_cond *cond;
   char save[2];
+  bfd_boolean neon_supported;
+  
+  neon_supported = ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_v1);
 
   /* Scan up to the end of the mnemonic, which must end in white space,
-     '.' (in unified mode only), or end of string.  */
+     '.' (in unified mode, or for Neon instructions), or end of string.  */
   for (base = end = *str; *end != '\0'; end++)
-    if (*end == ' ' || (unified_syntax && *end == '.'))
+    if (*end == ' ' || ((unified_syntax || neon_supported) && *end == '.'))
       break;
 
   if (end == base)
@@ -13597,9 +13970,11 @@ opcode_lookup (char **str)
     {
       int offset = 2;
       
-      if (end[1] == 'w')
+      /* The .w and .n suffixes are only valid if the unified syntax is in
+         use.  */
+      if (unified_syntax && end[1] == 'w')
        inst.size_req = 4;
-      else if (end[1] == 'n')
+      else if (unified_syntax && end[1] == 'n')
        inst.size_req = 2;
       else
         offset = 0;
@@ -13610,7 +13985,8 @@ opcode_lookup (char **str)
 
       if (end[offset] == '.')      
        {
-         /* See if we have a Neon type suffix.  */
+         /* See if we have a Neon type suffix (possible in either unified or
+             non-unified ARM syntax mode).  */
           if (parse_neon_type (&inst.vectype, str) == FAIL)
            return 0;
         }
@@ -13786,6 +14162,14 @@ md_assemble (char *str)
          return;
        }
 
+      if (!ARM_CPU_HAS_FEATURE (variant, arm_ext_v6t2) && !inst.size_req)
+       {
+         /* Implicit require narrow instructions on Thumb-1.  This avoids
+            relaxation accidentally introducing Thumb-2 instructions.  */
+         if (opcode->tencode != do_t_blx && opcode->tencode != do_t_branch23)
+           inst.size_req = 2;
+       }
+
       /* Check conditional suffixes.  */
       if (current_it_mask)
        {
@@ -13827,6 +14211,11 @@ md_assemble (char *str)
              return;
            }
        }
+
+      /* Something has gone badly wrong if we try to relax a fixed size
+         instruction.  */
+      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
@@ -13838,7 +14227,7 @@ md_assemble (char *str)
        ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
                                arm_ext_v6t2);
     }
-  else
+  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1))
     {
       /* Check that this instruction is supported for this CPU.  */
       if (!opcode->avariant ||
@@ -13871,6 +14260,12 @@ md_assemble (char *str)
        ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used,
                                *opcode->avariant);
     }
+  else
+    {
+      as_bad (_("attempt to use an ARM instruction on a Thumb-only processor "
+               "-- `%s'"), str);
+      return;
+    }
   output_inst (str);
 }
 
@@ -14040,6 +14435,10 @@ static const struct reg_entry reg_names[] =
   /* VFP control registers.  */
   REGDEF(fpsid,0,VFC), REGDEF(fpscr,1,VFC), REGDEF(fpexc,8,VFC),
   REGDEF(FPSID,0,VFC), REGDEF(FPSCR,1,VFC), REGDEF(FPEXC,8,VFC),
+  REGDEF(fpinst,9,VFC), REGDEF(fpinst2,10,VFC),
+  REGDEF(FPINST,9,VFC), REGDEF(FPINST2,10,VFC),
+  REGDEF(mvfr0,7,VFC), REGDEF(mvfr1,6,VFC),
+  REGDEF(MVFR0,7,VFC), REGDEF(MVFR1,6,VFC),
 
   /* Maverick DSP coprocessor registers.  */
   REGSET(mvf,MVF),  REGSET(mvd,MVD),  REGSET(mvfx,MVFX),  REGSET(mvdx,MVDX),
@@ -14156,20 +14555,21 @@ static const struct asm_psr psrs[] =
 /* Table of V7M psr names.  */
 static const struct asm_psr v7m_psrs[] =
 {
-  {"apsr",     0 },
-  {"iapsr",    1 },
-  {"eapsr",    2 },
-  {"psr",      3 },
-  {"ipsr",     5 },
-  {"epsr",     6 },
-  {"iepsr",    7 },
-  {"msp",      8 },
-  {"psp",      9 },
-  {"primask",  16},
-  {"basepri",  17},
-  {"basepri_max", 18},
-  {"faultmask",        19},
-  {"control",  20}
+  {"apsr",       0 }, {"APSR",         0 },
+  {"iapsr",      1 }, {"IAPSR",        1 },
+  {"eapsr",      2 }, {"EAPSR",        2 },
+  {"psr",        3 }, {"PSR",          3 },
+  {"xpsr",       3 }, {"XPSR",         3 }, {"xPSR",     3 },
+  {"ipsr",       5 }, {"IPSR",         5 },
+  {"epsr",       6 }, {"EPSR",         6 },
+  {"iepsr",      7 }, {"IEPSR",        7 },
+  {"msp",        8 }, {"MSP",          8 },
+  {"psp",        9 }, {"PSP",          9 },
+  {"primask",    16}, {"PRIMASK",      16},
+  {"basepri",    17}, {"BASEPRI",      17},
+  {"basepri_max", 18}, {"BASEPRI_MAX", 18},
+  {"faultmask",          19}, {"FAULTMASK",    19},
+  {"control",    20}, {"CONTROL",      20}
 };
 
 /* Table of all shift-in-operand names.         */
@@ -14497,6 +14897,10 @@ static const struct asm_opcode insns[] =
  tCE(push,     92d0000, push,     1, (REGLST),      push_pop, t_push_pop),
  tCE(pop,      8bd0000, pop,      1, (REGLST),      push_pop, t_push_pop),
 
+ /* These may simplify to neg.  */
+ TCE(rsb,      0600000, ebc00000, 3, (RR, oRR, SH), arit, t_rsb),
+ TC3(rsbs,     0700000, ebd00000, 3, (RR, oRR, SH), arit, t_rsb),
+
 #undef THUMB_VARIANT
 #define THUMB_VARIANT &arm_ext_v6
  TCE(cpy,       1a00000, 4600,     2, (RR, RR),      rd_rm, t_cpy),
@@ -14504,8 +14908,6 @@ static const struct asm_opcode insns[] =
  /* V1 instructions with no Thumb analogue prior to V6T2.  */
 #undef THUMB_VARIANT
 #define THUMB_VARIANT &arm_ext_v6t2
- TCE(rsb,      0600000, ebc00000, 3, (RR, oRR, SH), arit, t_rsb),
- TC3(rsbs,     0700000, ebd00000, 3, (RR, oRR, SH), arit, t_rsb),
  TCE(teq,      1300000, ea900f00, 2, (RR, SH),      cmp,  t_mvn_tst),
  TC3w(teqs,    1300000, ea900f00, 2, (RR, SH),      cmp,  t_mvn_tst),
   CL(teqp,     130f000,           2, (RR, SH),      cmp),
@@ -14645,8 +15047,8 @@ static const struct asm_opcode insns[] =
 #undef ARM_VARIANT
 #define ARM_VARIANT &arm_ext_v5e /*  ARM Architecture 5TE.  */
  TUF(pld,      450f000, f810f000, 1, (ADDR),                pld,  t_pld),
- TC3(ldrd,     00000d0, e9500000, 3, (RRnpc, oRRnpc, ADDRGLDRS), ldrd, t_ldstd),
- TC3(strd,     00000f0, e9400000, 3, (RRnpc, oRRnpc, ADDRGLDRS), ldrd, t_ldstd),
+ TC3(ldrd,     00000d0, e8500000, 3, (RRnpc, oRRnpc, ADDRGLDRS), ldrd, t_ldstd),
+ TC3(strd,     00000f0, e8400000, 3, (RRnpc, oRRnpc, ADDRGLDRS), ldrd, t_ldstd),
 
  TCE(mcrr,     c400000, ec400000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c),
  TCE(mrrc,     c500000, ec500000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c),
@@ -14673,6 +15075,7 @@ static const struct asm_opcode insns[] =
 #undef THUMB_VARIANT
 #define THUMB_VARIANT &arm_ext_v6t2
  TCE(ldrex,    1900f9f, e8500f00, 2, (RRnpc, ADDR),              ldrex, t_ldrex),
+ TCE(strex,    1800f90, e8400000, 3, (RRnpc, RRnpc, ADDR),        strex,  t_strex),
  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),
 
@@ -14756,12 +15159,11 @@ static const struct asm_opcode insns[] =
  TCE(smuadx,   700f030, fb20f010, 3, (RRnpc, RRnpc, RRnpc),       smul, t_simd),
  TCE(smusd,    700f050, fb40f000, 3, (RRnpc, RRnpc, RRnpc),       smul, t_simd),
  TCE(smusdx,   700f070, fb40f010, 3, (RRnpc, RRnpc, RRnpc),       smul, t_simd),
- TUF(srsia,    8cd0500, e980c000, 1, (I31w),                      srs,  srs),
-  UF(srsib,    9cd0500,           1, (I31w),                      srs),
-  UF(srsda,    84d0500,           1, (I31w),                      srs),
- TUF(srsdb,    94d0500, e800c000, 1, (I31w),                      srs,  srs),
+ TUF(srsia,    8c00500, e980c000, 2, (oRRw, I31w),                srs,  srs),
+  UF(srsib,    9c00500,           2, (oRRw, I31w),                srs),
+  UF(srsda,    8400500,           2, (oRRw, I31w),                srs),
+ TUF(srsdb,    9400500, e800c000, 2, (oRRw, I31w),                srs,  srs),
  TCE(ssat16,   6a00f30, f3200000, 3, (RRnpc, I16, RRnpc),         ssat16, t_ssat16),
- TCE(strex,    1800f90, e8400000, 3, (RRnpc, RRnpc, ADDR),        strex,  t_strex),
  TCE(umaal,    0400090, fbe00060, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smlal,  t_mlal),
  TCE(usad8,    780f010, fb70f000, 3, (RRnpc, RRnpc, RRnpc),       smul,   t_simd),
  TCE(usada8,   7800010, fb700000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla,   t_mla),
@@ -14810,9 +15212,11 @@ static const struct asm_opcode insns[] =
  TC3(ldrsbt,   03000d0, f9100e00, 2, (RR, ADDR), ldsttv4, t_ldstt),
  TC3(strht,    02000b0, f8200e00, 2, (RR, ADDR), ldsttv4, t_ldstt),
 
-  UT(cbnz,      b900,    2, (RR, EXP), t_czb),
-  UT(cbz,       b100,    2, (RR, EXP), t_czb),
- /* ARM does not really have an IT instruction.  */
+  UT(cbnz,      b900,    2, (RR, EXP), t_cbz),
+  UT(cbz,       b100,    2, (RR, EXP), t_cbz),
+ /* ARM does not really have an IT instruction, so always allow it.  */
+#undef ARM_VARIANT
+#define ARM_VARIANT &arm_ext_v1
  TUE(it,        0, bf08, 1, (COND),    it, t_it),
  TUE(itt,       0, bf0c, 1, (COND),    it, t_it),
  TUE(ite,       0, bf04, 1, (COND),    it, t_it),
@@ -15475,10 +15879,10 @@ static const struct asm_opcode insns[] =
  NUF(vqaddq,    0000010, 3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_i64_su),
  NUF(vqsub,     0000210, 3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_i64_su),
  NUF(vqsubq,    0000210, 3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_i64_su),
- NUF(vrshl,     0000500, 3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_i64_su),
- NUF(vrshlq,    0000500, 3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_i64_su),
- NUF(vqrshl,    0000510, 3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_i64_su),
- NUF(vqrshlq,   0000510, 3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_i64_su),
+ NUF(vrshl,     0000500, 3, (RNDQ, oRNDQ, RNDQ), neon_rshl),
+ NUF(vrshlq,    0000500, 3, (RNQ,  oRNQ,  RNQ),  neon_rshl),
+ NUF(vqrshl,    0000510, 3, (RNDQ, oRNDQ, RNDQ), neon_rshl),
+ NUF(vqrshlq,   0000510, 3, (RNQ,  oRNQ,  RNQ),  neon_rshl),
   /* If not immediate, fall back to neon_dyadic_i64_su.
      shl_imm should accept I8 I16 I32 I64,
      qshl_imm should accept S8 S16 S32 S64 U8 U16 U32 U64.  */
@@ -15521,14 +15925,13 @@ static const struct asm_opcode insns[] =
  nUF(vcltq,     vclt,    3, (RNQ,  oRNQ,  RNDQ_I0), neon_cmp_inv),
  nUF(vcle,      vcle,    3, (RNDQ, oRNDQ, RNDQ_I0), neon_cmp_inv),
  nUF(vcleq,     vcle,    3, (RNQ,  oRNQ,  RNDQ_I0), neon_cmp_inv),
-  /* Comparison. Type I8 I16 I32 F32. Non-immediate -> neon_dyadic_if_i.  */
+  /* Comparison. Type I8 I16 I32 F32.  */
  nUF(vceq,      vceq,    3, (RNDQ, oRNDQ, RNDQ_I0), neon_ceq),
  nUF(vceqq,     vceq,    3, (RNQ,  oRNQ,  RNDQ_I0), neon_ceq),
   /* As above, D registers only.  */
  nUF(vpmax,     vpmax,   3, (RND, oRND, RND), neon_dyadic_if_su_d),
  nUF(vpmin,     vpmin,   3, (RND, oRND, RND), neon_dyadic_if_su_d),
   /* Int and float variants, signedness unimportant.  */
-  /* If not scalar, fall back to neon_dyadic_if_i.  */
  nUF(vmlaq,     vmla,    3, (RNQ,  oRNQ,  RNDQ_RNSC), neon_mac_maybe_scalar),
  nUF(vmlsq,     vmls,    3, (RNQ,  oRNQ,  RNDQ_RNSC), neon_mac_maybe_scalar),
  nUF(vpadd,     vpadd,   3, (RND,  oRND,  RND),       neon_dyadic_if_i_d),
@@ -15549,10 +15952,10 @@ static const struct asm_opcode insns[] =
  NUF(vacgeq,    0000e10,  3, (RNQ,  oRNQ,  RNQ),  neon_fcmp_absolute),
  NUF(vacgt,     0200e10,  3, (RNDQ, oRNDQ, RNDQ), neon_fcmp_absolute),
  NUF(vacgtq,    0200e10,  3, (RNQ,  oRNQ,  RNQ),  neon_fcmp_absolute),
- NUF(vaclt,     0000e10,  3, (RNDQ, oRNDQ, RNDQ), neon_fcmp_absolute_inv),
- NUF(vacltq,    0000e10,  3, (RNQ,  oRNQ,  RNQ),  neon_fcmp_absolute_inv),
- NUF(vacle,     0200e10,  3, (RNDQ, oRNDQ, RNDQ), neon_fcmp_absolute_inv),
- NUF(vacleq,    0200e10,  3, (RNQ,  oRNQ,  RNQ),  neon_fcmp_absolute_inv),
+ NUF(vaclt,     0200e10,  3, (RNDQ, oRNDQ, RNDQ), neon_fcmp_absolute_inv),
+ NUF(vacltq,    0200e10,  3, (RNQ,  oRNQ,  RNQ),  neon_fcmp_absolute_inv),
+ NUF(vacle,     0000e10,  3, (RNDQ, oRNDQ, RNDQ), neon_fcmp_absolute_inv),
+ NUF(vacleq,    0000e10,  3, (RNQ,  oRNQ,  RNQ),  neon_fcmp_absolute_inv),
  NUF(vrecps,    0000f10,  3, (RNDQ, oRNDQ, RNDQ), neon_step),
  NUF(vrecpsq,   0000f10,  3, (RNQ,  oRNQ,  RNQ),  neon_step),
  NUF(vrsqrts,   0200f10,  3, (RNDQ, oRNDQ, RNDQ), neon_step),
@@ -15626,8 +16029,8 @@ static const struct asm_opcode insns[] =
  nUF(vmull,     vmull,   3, (RNQ, RND, RND_RNSC), neon_vmull),
 
   /* Extract. Size 8.  */
- NUF(vext,      0b00000, 4, (RNDQ, oRNDQ, RNDQ, I7), neon_ext),
- NUF(vextq,     0b00000, 4, (RNQ,  oRNQ,  RNQ,  I7), neon_ext),
+ NUF(vext,      0b00000, 4, (RNDQ, oRNDQ, RNDQ, I15), neon_ext),
+ NUF(vextq,     0b00000, 4, (RNQ,  oRNQ,  RNQ,  I15), neon_ext),
 
   /* Two registers, miscellaneous.  */
   /* Reverse. Sizes 8 16 32 (must be < size in opcode).  */
@@ -15839,34 +16242,34 @@ static const struct asm_opcode insns[] =
  cCE(wpackwus, e900080, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
  cCE(wpackdss, ef00080, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
  cCE(wpackdus, ed00080, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
- cCE(wrorh,    e700040, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wrorh,    e700040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
  cCE(wrorhg,   e700148, 3, (RIWR, RIWR, RIWG),     rd_rn_rm),
- cCE(wrorw,    eb00040, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wrorw,    eb00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
  cCE(wrorwg,   eb00148, 3, (RIWR, RIWR, RIWG),     rd_rn_rm),
- cCE(wrord,    ef00040, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wrord,    ef00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
  cCE(wrordg,   ef00148, 3, (RIWR, RIWR, RIWG),     rd_rn_rm),
  cCE(wsadb,    e000120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
  cCE(wsadbz,   e100120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
  cCE(wsadh,    e400120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
  cCE(wsadhz,   e500120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
  cCE(wshufh,   e0001e0, 3, (RIWR, RIWR, I255),     iwmmxt_wshufh),
- cCE(wsllh,    e500040, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wsllh,    e500040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
  cCE(wsllhg,   e500148, 3, (RIWR, RIWR, RIWG),     rd_rn_rm),
- cCE(wsllw,    e900040, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wsllw,    e900040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
  cCE(wsllwg,   e900148, 3, (RIWR, RIWR, RIWG),     rd_rn_rm),
- cCE(wslld,    ed00040, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wslld,    ed00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
  cCE(wslldg,   ed00148, 3, (RIWR, RIWR, RIWG),     rd_rn_rm),
- cCE(wsrah,    e400040, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wsrah,    e400040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
  cCE(wsrahg,   e400148, 3, (RIWR, RIWR, RIWG),     rd_rn_rm),
- cCE(wsraw,    e800040, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wsraw,    e800040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
  cCE(wsrawg,   e800148, 3, (RIWR, RIWR, RIWG),     rd_rn_rm),
- cCE(wsrad,    ec00040, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wsrad,    ec00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
  cCE(wsradg,   ec00148, 3, (RIWR, RIWR, RIWG),     rd_rn_rm),
- cCE(wsrlh,    e600040, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wsrlh,    e600040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
  cCE(wsrlhg,   e600148, 3, (RIWR, RIWR, RIWG),     rd_rn_rm),
- cCE(wsrlw,    ea00040, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wsrlw,    ea00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
  cCE(wsrlwg,   ea00148, 3, (RIWR, RIWR, RIWG),     rd_rn_rm),
- cCE(wsrld,    ee00040, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wsrld,    ee00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
  cCE(wsrldg,   ee00148, 3, (RIWR, RIWR, RIWG),     rd_rn_rm),
  cCE(wstrb,    c000000, 2, (RIWR, ADDR),           iwmmxt_wldstbh),
  cCE(wstrh,    c400000, 2, (RIWR, ADDR),           iwmmxt_wldstbh),
@@ -15902,6 +16305,66 @@ static const struct asm_opcode insns[] =
  cCE(wxor,     e100000, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
  cCE(wzero,    e300000, 1, (RIWR),                 iwmmxt_wzero),
 
+#undef ARM_VARIANT
+#define ARM_VARIANT &arm_cext_iwmmxt2 /* Intel Wireless MMX technology, version 2.  */
+ cCE(torvscb,   e13f190, 1, (RR),                  iwmmxt_tandorc),
+ cCE(torvsch,   e53f190, 1, (RR),                  iwmmxt_tandorc),
+ cCE(torvscw,   e93f190, 1, (RR),                  iwmmxt_tandorc),
+ cCE(wabsb,     e2001c0, 2, (RIWR, RIWR),           rd_rn),
+ cCE(wabsh,     e6001c0, 2, (RIWR, RIWR),           rd_rn),
+ cCE(wabsw,     ea001c0, 2, (RIWR, RIWR),           rd_rn),
+ cCE(wabsdiffb, e1001c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wabsdiffh, e5001c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wabsdiffw, e9001c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(waddbhusl, e2001a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(waddbhusm, e6001a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(waddhc,    e600180, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(waddwc,    ea00180, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(waddsubhx, ea001a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wavg4,    e400000, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wavg4r,    e500000, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wmaddsn,   ee00100, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wmaddsx,   eb00100, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wmaddun,   ec00100, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wmaddux,   e900100, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wmerge,    e000080, 4, (RIWR, RIWR, RIWR, I7), iwmmxt_wmerge),
+ cCE(wmiabb,    e0000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wmiabt,    e1000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wmiatb,    e2000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wmiatt,    e3000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wmiabbn,   e4000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wmiabtn,   e5000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wmiatbn,   e6000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wmiattn,   e7000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wmiawbb,   e800120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wmiawbt,   e900120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wmiawtb,   ea00120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wmiawtt,   eb00120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wmiawbbn,  ec00120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wmiawbtn,  ed00120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wmiawtbn,  ee00120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wmiawttn,  ef00120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wmulsmr,   ef00100, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wmulumr,   ed00100, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wmulwumr,  ec000c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wmulwsmr,  ee000c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wmulwum,   ed000c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wmulwsm,   ef000c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wmulwl,    eb000c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wqmiabb,   e8000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wqmiabt,   e9000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wqmiatb,   ea000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wqmiatt,   eb000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wqmiabbn,  ec000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wqmiabtn,  ed000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wqmiatbn,  ee000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wqmiattn,  ef000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wqmulm,    e100080, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wqmulmr,   e300080, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wqmulwm,   ec000e0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wqmulwmr,  ee000e0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+ cCE(wsubaddhx, ed001c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
+
 #undef ARM_VARIANT
 #define ARM_VARIANT &arm_cext_maverick /* Cirrus Maverick instructions.        */
  cCE(cfldrs,   c100400, 2, (RMF, ADDRGLDC),          rd_cpaddr),
@@ -16250,16 +16713,42 @@ relax_immediate (fragS *fragp, int size, int shift)
   offset = fragp->fr_offset;
   /* Force misaligned offsets to 32-bit variant.  */
   if (offset & low)
-    return -4;
+    return 4;
   if (offset & ~mask)
     return 4;
   return 2;
 }
 
+/* Get the address of a symbol during relaxation.  */
+static addressT
+relaxed_symbol_addr(fragS *fragp, long stretch)
+{
+  fragS *sym_frag;
+  addressT addr;
+  symbolS *sym;
+
+  sym = fragp->fr_symbol;
+  sym_frag = symbol_get_frag (sym);
+  know (S_GET_SEGMENT (sym) != absolute_section
+       || sym_frag == &zero_address_frag);
+  addr = S_GET_VALUE (sym) + fragp->fr_offset;
+
+  /* If frag has yet to be reached on this pass, assume it will
+     move by STRETCH just as we did.  If this is not so, it will
+     be because some frag between grows, and that will force
+     another pass.  */
+
+  if (stretch != 0
+      && sym_frag->relax_marker != fragp->relax_marker)
+    addr += stretch;
+
+  return addr;
+}
+
 /* Return the size of a relaxable adr pseudo-instruction or PC-relative
    load.  */
 static int
-relax_adr (fragS *fragp, asection *sec)
+relax_adr (fragS *fragp, asection *sec, long stretch)
 {
   addressT addr;
   offsetT val;
@@ -16269,14 +16758,12 @@ relax_adr (fragS *fragp, asection *sec)
       || sec != S_GET_SEGMENT (fragp->fr_symbol))
     return 4;
 
-  val = S_GET_VALUE(fragp->fr_symbol) + fragp->fr_offset;
+  val = relaxed_symbol_addr(fragp, stretch);
   addr = fragp->fr_address + fragp->fr_fix;
   addr = (addr + 4) & ~3;
-  /* Fix the insn as the 4-byte version if the target address is not
-     sufficiently aligned.  This is prevents an infinite loop when two
-     instructions have contradictory range/alignment requirements.  */
+  /* Force misaligned targets to 32-bit variant.  */
   if (val & 3)
-    return -4;
+    return 4;
   val -= addr;
   if (val < 0 || val > 1020)
     return 4;
@@ -16303,7 +16790,7 @@ relax_addsub (fragS *fragp, asection *sec)
    size of the offset field in the narrow instruction.  */
 
 static int
-relax_branch (fragS *fragp, asection *sec, int bits)
+relax_branch (fragS *fragp, asection *sec, int bits, long stretch)
 {
   addressT addr;
   offsetT val;
@@ -16314,7 +16801,7 @@ relax_branch (fragS *fragp, asection *sec, int bits)
       || sec != S_GET_SEGMENT (fragp->fr_symbol))
     return 4;
 
-  val = S_GET_VALUE(fragp->fr_symbol) + fragp->fr_offset;
+  val = relaxed_symbol_addr(fragp, stretch);
   addr = fragp->fr_address + fragp->fr_fix + 4;
   val -= addr;
 
@@ -16330,7 +16817,7 @@ relax_branch (fragS *fragp, asection *sec, int bits)
    the current size of the frag should change.  */
 
 int
-arm_relax_frag (asection *sec, fragS *fragp, long stretch ATTRIBUTE_UNUSED)
+arm_relax_frag (asection *sec, fragS *fragp, long stretch)
 {
   int oldsize;
   int newsize;
@@ -16339,7 +16826,7 @@ arm_relax_frag (asection *sec, fragS *fragp, long stretch ATTRIBUTE_UNUSED)
   switch (fragp->fr_subtype)
     {
     case T_MNEM_ldr_pc2:
-      newsize = relax_adr(fragp, sec);
+      newsize = relax_adr(fragp, sec, stretch);
       break;
     case T_MNEM_ldr_pc:
     case T_MNEM_ldr_sp:
@@ -16359,7 +16846,7 @@ arm_relax_frag (asection *sec, fragS *fragp, long stretch ATTRIBUTE_UNUSED)
       newsize = relax_immediate(fragp, 5, 0);
       break;
     case T_MNEM_adr:
-      newsize = relax_adr(fragp, sec);
+      newsize = relax_adr(fragp, sec, stretch);
       break;
     case T_MNEM_mov:
     case T_MNEM_movs:
@@ -16368,10 +16855,10 @@ arm_relax_frag (asection *sec, fragS *fragp, long stretch ATTRIBUTE_UNUSED)
       newsize = relax_immediate(fragp, 8, 0);
       break;
     case T_MNEM_b:
-      newsize = relax_branch(fragp, sec, 11);
+      newsize = relax_branch(fragp, sec, 11, stretch);
       break;
     case T_MNEM_bcond:
-      newsize = relax_branch(fragp, sec, 8);
+      newsize = relax_branch(fragp, sec, 8, stretch);
       break;
     case T_MNEM_add_sp:
     case T_MNEM_add_pc:
@@ -16390,14 +16877,18 @@ arm_relax_frag (asection *sec, fragS *fragp, long stretch ATTRIBUTE_UNUSED)
     default:
       abort();
     }
-  if (newsize < 0)
+
+  fragp->fr_var = newsize;
+  /* Freeze wide instructions that are at or before the same location as
+     in the previous pass.  This avoids infinite loops.
+     Don't freeze them unconditionally because targets may be artificialy
+     misaligned by the expansion of preceeding frags.  */
+  if (stretch <= 0 && newsize > 2)
     {
-      fragp->fr_var = -newsize;
       md_convert_frag (sec->owner, sec, fragp);
       frag_wane(fragp);
-      return -(newsize + oldsize);
     }
-  fragp->fr_var = newsize;
+
   return newsize - oldsize;
 }
 
@@ -17217,11 +17708,11 @@ negate_data_op (unsigned long * instruction,
 /* Like negate_data_op, but for Thumb-2.   */
 
 static unsigned int
-thumb32_negate_data_op (offsetT *instruction, offsetT value)
+thumb32_negate_data_op (offsetT *instruction, unsigned int value)
 {
   int op, new_inst;
   int rd;
-  offsetT negated, inverted;
+  unsigned int negated, inverted;
 
   negated = encode_thumb32_immediate (-value);
   inverted = encode_thumb32_immediate (~value);
@@ -17282,7 +17773,7 @@ thumb32_negate_data_op (offsetT *instruction, offsetT value)
       return FAIL;
     }
 
-  if (value == FAIL)
+  if (value == (unsigned int)FAIL)
     return FAIL;
 
   *instruction &= T2_OPCODE_MASK;
@@ -17488,7 +17979,7 @@ 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 half-word offset (%ld)"),
+           as_bad (_("bad immediate value for 8-bit offset (%ld)"),
                    (long) value);
          break;
        }
@@ -17796,18 +18287,34 @@ md_apply_fix (fixS *  fixP,
        }
       break;
 
-    case BFD_RELOC_THUMB_PCREL_BRANCH7: /* CZB */
-      /* CZB can only branch forward.  */
-      if (value & ~0x7e)
-       as_bad_where (fixP->fx_file, fixP->fx_line,
-                     _("branch out of range"));
+    case BFD_RELOC_THUMB_PCREL_BRANCH7: /* CBZ */
+      /* CBZ can only branch forward.  */
 
-      if (fixP->fx_done || !seg->use_rela_p)
+      /* Attempts to use CBZ to branch to the next instruction
+         (which, strictly speaking, are prohibited) will be turned into
+         no-ops.
+
+        FIXME: It may be better to remove the instruction completely and
+        perform relaxation.  */
+      if (value == -2)
        {
          newval = md_chars_to_number (buf, THUMB_SIZE);
-         newval |= ((value & 0x3e) << 2) | ((value & 0x40) << 3);
+         newval = 0xbf00; /* NOP encoding T1 */
          md_number_to_chars (buf, newval, THUMB_SIZE);
        }
+      else
+       {
+         if (value & ~0x7e)
+           as_bad_where (fixP->fx_file, fixP->fx_line,
+                         _("branch out of range"));
+
+          if (fixP->fx_done || !seg->use_rela_p)
+           {
+             newval = md_chars_to_number (buf, THUMB_SIZE);
+             newval |= ((value & 0x3e) << 2) | ((value & 0x40) << 3);
+             md_number_to_chars (buf, newval, THUMB_SIZE);
+           }
+       }
       break;
 
     case BFD_RELOC_THUMB_PCREL_BRANCH9: /* Conditional branch. */
@@ -17991,8 +18498,6 @@ md_apply_fix (fixS *    fixP,
        newval = get_thumb32_insn (buf);
       newval &= 0xff7fff00;
       newval |= (value >> 2) | (sign ? INDEX_UP : 0);
-      if (value == 0)
-       newval &= ~WRITE_BACK;
       if (fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM
          || fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM_S2)
        md_number_to_chars (buf, newval, INSN_SIZE);
@@ -18727,39 +19232,16 @@ arm_force_relocation (struct fix * fixp)
       || fixp->fx_r_type == BFD_RELOC_ARM_LDR_PC_G0)
     return 1;
 
-  return generic_force_reloc (fixp);
-}
-
-#ifdef OBJ_COFF
-bfd_boolean
-arm_fix_adjustable (fixS * fixP)
-{
-  /* This is a little hack to help the gas/arm/adrl.s test.  It prevents
-     local labels from being added to the output symbol table when they
-     are used with the ADRL pseudo op.  The ADRL relocation should always
-     be resolved before the binbary is emitted, so it is safe to say that
-     it is adjustable.  */
-  if (fixP->fx_r_type == BFD_RELOC_ARM_ADRL_IMMEDIATE)
+  /* Always generate relocations against function symbols.  */
+  if (fixp->fx_r_type == BFD_RELOC_32
+      && fixp->fx_addsy
+      && (symbol_get_bfdsym (fixp->fx_addsy)->flags & BSF_FUNCTION))
     return 1;
 
-  /* This is a hack for the gas/all/redef2.s test.  This test causes symbols
-     to be cloned, and without this test relocs would still be generated
-     against the original, pre-cloned symbol.  Such symbols would not appear
-     in the symbol table however, and so a valid reloc could not be
-     generated.  So check to see if the fixup is against a symbol which has
-     been removed from the symbol chain, and if it is, then allow it to be
-     adjusted into a reloc against a section symbol. */
-  if (fixP->fx_addsy != NULL
-      && ! S_IS_LOCAL (fixP->fx_addsy)
-      && symbol_next (fixP->fx_addsy) == NULL
-      && symbol_next (fixP->fx_addsy) == symbol_previous (fixP->fx_addsy))
-    return 1;
-  
-  return 0;
+  return generic_force_reloc (fixp);
 }
-#endif
 
-#ifdef OBJ_ELF
+#if defined (OBJ_ELF) || defined (OBJ_COFF)
 /* Relocations against function names must be left unadjusted,
    so that the linker can use this information to generate interworking
    stubs.  The MIPS version of this function
@@ -18812,6 +19294,9 @@ arm_fix_adjustable (fixS * fixP)
 
   return 1;
 }
+#endif /* defined (OBJ_ELF) || defined (OBJ_COFF) */
+
+#ifdef OBJ_ELF
 
 const char *
 elf32_arm_target_format (void)
@@ -18930,7 +19415,7 @@ arm_adjust_symtab (void)
              if (THUMB_IS_FUNC (sym))
                elf_sym->internal_elf_sym.st_info =
                  ELF_ST_INFO (bind, STT_ARM_TFUNC);
-             else
+             else if (EF_ARM_EABI_VERSION (meabi_flags) < EF_ARM_EABI_VER4)
                elf_sym->internal_elf_sym.st_info =
                  ELF_ST_INFO (bind, STT_ARM_16BIT);
            }
@@ -18951,6 +19436,16 @@ set_constant_flonums (void)
       abort ();
 }
 
+/* Auto-select Thumb mode if it's the only available instruction set for the
+   given architecture.  */
+
+static void
+autoselect_thumb_from_cpu_variant (void)
+{
+  if (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1))
+    opcode_select (16);
+}
+
 void
 md_begin (void)
 {
@@ -19028,9 +19523,9 @@ md_begin (void)
 
   if (!mfpu_opt)
     {
-      if (!mcpu_cpu_opt)
+      if (mcpu_cpu_opt != NULL)
        mfpu_opt = &fpu_default;
-      else if (ARM_CPU_HAS_FEATURE (*mcpu_fpu_opt, arm_ext_v5))
+      else if (mcpu_fpu_opt != NULL && ARM_CPU_HAS_FEATURE (*mcpu_fpu_opt, arm_ext_v5))
        mfpu_opt = &fpu_arch_vfp_v2;
       else
        mfpu_opt = &fpu_arch_fpa;
@@ -19051,6 +19546,8 @@ md_begin (void)
 
   ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
 
+  autoselect_thumb_from_cpu_variant ();
+
   arm_arch_used = thumb_arch_used = arm_arch_none;
 
 #if defined OBJ_COFF || defined OBJ_ELF
@@ -19126,7 +19623,9 @@ md_begin (void)
 #endif
 
   /* Record the CPU type as well.  */
-  if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt))
+  if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt2))
+    mach = bfd_mach_arm_iWMMXt2;
+  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt))
     mach = bfd_mach_arm_iWMMXt;
   else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_xscale))
     mach = bfd_mach_arm_XScale;
@@ -19505,6 +20004,7 @@ static const struct arm_cpu_option_table arm_cpus[] =
   {"xscale",           ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL},
   /* ??? iwmmxt is not a processor.  */
   {"iwmmxt",           ARM_ARCH_IWMMXT, FPU_ARCH_VFP_V2, NULL},
+  {"iwmmxt2",          ARM_ARCH_IWMMXT2,FPU_ARCH_VFP_V2, NULL},
   {"i80200",           ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL},
   /* Maverick */
   {"ep9312",   ARM_FEATURE(ARM_AEXT_V4T, ARM_CEXT_MAVERICK), FPU_ARCH_MAVERICK, "ARM920T"},
@@ -19549,11 +20049,17 @@ static const struct arm_arch_option_table arm_archs[] =
   {"armv6zt2",         ARM_ARCH_V6ZT2,  FPU_ARCH_VFP},
   {"armv6zkt2",                ARM_ARCH_V6ZKT2, FPU_ARCH_VFP},
   {"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},
   {"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}
 };
 
@@ -19569,6 +20075,7 @@ static const struct arm_option_cpu_value_table arm_extensions[] =
   {"maverick",         ARM_FEATURE (0, ARM_CEXT_MAVERICK)},
   {"xscale",           ARM_FEATURE (0, ARM_CEXT_XSCALE)},
   {"iwmmxt",           ARM_FEATURE (0, ARM_CEXT_IWMMXT)},
+  {"iwmmxt2",          ARM_FEATURE (0, ARM_CEXT_IWMMXT2)},
   {NULL,               ARM_ARCH_NONE}
 };
 
@@ -19993,7 +20500,13 @@ aeabi_set_public_attributes (void)
   ARM_MERGE_FEATURE_SETS (flags, arm_arch_used, thumb_arch_used);
   ARM_MERGE_FEATURE_SETS (flags, flags, *mfpu_opt);
   ARM_MERGE_FEATURE_SETS (flags, flags, selected_cpu);
-    
+  /*Allow the user to override the reported architecture.  */
+  if (object_arch)
+    {
+      ARM_CLEAR_FEATURE (flags, flags, arm_arch_any);
+      ARM_MERGE_FEATURE_SETS (flags, flags, *object_arch);
+    }
+
   tmp = flags;
   arch = 0;
   for (p = cpu_arch_ver; p->val; p++)
@@ -20019,65 +20532,54 @@ aeabi_set_public_attributes (void)
          for (i = 0; p[i]; i++)
            p[i] = TOUPPER (p[i]);
        }
-      elf32_arm_add_eabi_attr_string (stdoutput, 5, p);
+      bfd_elf_add_proc_attr_string (stdoutput, 5, p);
     }
   /* Tag_CPU_arch.  */
-  elf32_arm_add_eabi_attr_int (stdoutput, 6, arch);
+  bfd_elf_add_proc_attr_int (stdoutput, 6, arch);
   /* Tag_CPU_arch_profile.  */
   if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7a))
-    elf32_arm_add_eabi_attr_int (stdoutput, 7, 'A');
+    bfd_elf_add_proc_attr_int (stdoutput, 7, 'A');
   else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7r))
-    elf32_arm_add_eabi_attr_int (stdoutput, 7, 'R');
+    bfd_elf_add_proc_attr_int (stdoutput, 7, 'R');
   else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7m))
-    elf32_arm_add_eabi_attr_int (stdoutput, 7, 'M');
+    bfd_elf_add_proc_attr_int (stdoutput, 7, 'M');
   /* Tag_ARM_ISA_use.  */
   if (ARM_CPU_HAS_FEATURE (arm_arch_used, arm_arch_full))
-    elf32_arm_add_eabi_attr_int (stdoutput, 8, 1);
+    bfd_elf_add_proc_attr_int (stdoutput, 8, 1);
   /* Tag_THUMB_ISA_use.  */
   if (ARM_CPU_HAS_FEATURE (thumb_arch_used, arm_arch_full))
-    elf32_arm_add_eabi_attr_int (stdoutput, 9,
+    bfd_elf_add_proc_attr_int (stdoutput, 9,
        ARM_CPU_HAS_FEATURE (thumb_arch_used, arm_arch_t2) ? 2 : 1);
   /* Tag_VFP_arch.  */
   if (ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_vfp_ext_v3)
       || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_vfp_ext_v3))
-    elf32_arm_add_eabi_attr_int (stdoutput, 10, 3);
+    bfd_elf_add_proc_attr_int (stdoutput, 10, 3);
   else if (ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_vfp_ext_v2)
            || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_vfp_ext_v2))
-    elf32_arm_add_eabi_attr_int (stdoutput, 10, 2);
+    bfd_elf_add_proc_attr_int (stdoutput, 10, 2);
   else if (ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_vfp_ext_v1)
            || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_vfp_ext_v1)
            || ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_vfp_ext_v1xd)
            || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_vfp_ext_v1xd))
-    elf32_arm_add_eabi_attr_int (stdoutput, 10, 1);
+    bfd_elf_add_proc_attr_int (stdoutput, 10, 1);
   /* Tag_WMMX_arch.  */
   if (ARM_CPU_HAS_FEATURE (thumb_arch_used, arm_cext_iwmmxt)
       || ARM_CPU_HAS_FEATURE (arm_arch_used, arm_cext_iwmmxt))
-    elf32_arm_add_eabi_attr_int (stdoutput, 11, 1);
+    bfd_elf_add_proc_attr_int (stdoutput, 11, 1);
   /* Tag_NEON_arch.  */
   if (ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_neon_ext_v1)
       || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_neon_ext_v1))
-    elf32_arm_add_eabi_attr_int (stdoutput, 12, 1);
+    bfd_elf_add_proc_attr_int (stdoutput, 12, 1);
 }
 
-/* Add the .ARM.attributes section.  */
+/* Add the default contents for the .ARM.attributes section.  */
 void
 arm_md_end (void)
 {
-  segT s;
-  char *p;
-  addressT addr;
-  offsetT size;
-  
   if (EF_ARM_EABI_VERSION (meabi_flags) < EF_ARM_EABI_VER4)
     return;
 
   aeabi_set_public_attributes ();
-  size = elf32_arm_eabi_attr_size (stdoutput);
-  s = subseg_new (".ARM.attributes", 0);
-  bfd_set_section_flags (stdoutput, s, SEC_READONLY | SEC_DATA);
-  addr = frag_now_fix ();
-  p = frag_more (size);
-  elf32_arm_set_eabi_attr_contents (stdoutput, (bfd_byte *)p, size);
 }
 #endif /* OBJ_ELF */
 
@@ -20157,6 +20659,37 @@ s_arm_arch (int ignored ATTRIBUTE_UNUSED)
 }
 
 
+/* Parse a .object_arch directive.  */
+
+static void
+s_arm_object_arch (int ignored ATTRIBUTE_UNUSED)
+{
+  const struct arm_arch_option_table *opt;
+  char saved_char;
+  char *name;
+
+  name = input_line_pointer;
+  while (*input_line_pointer && !ISSPACE(*input_line_pointer))
+    input_line_pointer++;
+  saved_char = *input_line_pointer;
+  *input_line_pointer = 0;
+
+  /* Skip the first "all" entry.  */
+  for (opt = arm_archs + 1; opt->name != NULL; opt++)
+    if (streq (opt->name, name))
+      {
+       object_arch = &opt->value;
+       *input_line_pointer = saved_char;
+       demand_empty_rest_of_line ();
+       return;
+      }
+
+  as_bad (_("unknown architecture `%s'\n"), name);
+  *input_line_pointer = saved_char;
+  ignore_rest_of_line ();
+}
+
+
 /* Parse a .fpu directive.  */
 
 static void
@@ -20187,3 +20720,9 @@ s_arm_fpu (int ignored ATTRIBUTE_UNUSED)
   ignore_rest_of_line ();
 }
 
+/* Copy symbol information.  */
+void
+arm_copy_symbol_attributes (symbolS *dest, symbolS *src)
+{
+  ARM_GET_FLAG (dest) = ARM_GET_FLAG (src);
+}
This page took 0.062999 seconds and 4 git commands to generate.