[ARM] Add crypto-neon-fp-armv8.1 as an fpu option
[external/binutils.git] / gas / config / tc-arm.c
index 84e95d4..a76b4ca 100644 (file)
@@ -7752,14 +7752,15 @@ neon_cmode_for_move_imm (unsigned immlo, unsigned immhi, int float_p,
   return FAIL;
 }
 
+#if defined BFD_HOST_64_BIT
 /* Returns TRUE if double precision value V may be cast
    to single precision without loss of accuracy.  */
 
 static bfd_boolean
-is_double_a_single (long int v)
+is_double_a_single (bfd_int64_t v)
 {
-  int exp = (int) (v >> 52) & 0x7FF;
-  long int mantissa = (v & 0xFFFFFFFFFFFFFl);
+  int exp = (int)((v >> 52) & 0x7FF);
+  bfd_int64_t mantissa = (v & (bfd_int64_t)0xFFFFFFFFFFFFF);
 
   return (exp == 0 || exp == 0x7FF
          || (exp >= 1023 - 126 && exp <= 1023 + 127))
@@ -7770,11 +7771,11 @@ is_double_a_single (long int v)
    (ignoring the least significant bits in exponent and mantissa).  */
 
 static int
-double_to_single (long int v)
+double_to_single (bfd_int64_t v)
 {
   int sign = (int) ((v >> 63) & 1l);
-  int exp = (int) (v >> 52) & 0x7FF;
-  long int mantissa = (v & 0xFFFFFFFFFFFFFl);
+  int exp = (int) ((v >> 52) & 0x7FF);
+  bfd_int64_t mantissa = (v & (bfd_int64_t)0xFFFFFFFFFFFFF);
 
   if (exp == 0x7FF)
     exp = 0xFF;
@@ -7797,6 +7798,7 @@ double_to_single (long int v)
   mantissa >>= 29;
   return (sign << 31) | (exp << 23) | mantissa;
 }
+#endif /* BFD_HOST_64_BIT */
 
 enum lit_type
 {
@@ -7845,8 +7847,11 @@ move_or_literal_pool (int i, enum lit_type t, bfd_boolean mode_3)
   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
       if (inst.reloc.exp.X_op == O_big)
        {
          LITTLENUM_TYPE w[X_PRECISION];
@@ -7861,27 +7866,90 @@ move_or_literal_pool (int i, enum lit_type t, bfd_boolean mode_3)
          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
        v = inst.reloc.exp.X_add_number;
 
       if (!inst.operands[i].issingle)
        {
-         if (thumb_p && inst.reloc.exp.X_op == O_constant)
+         if (thumb_p)
            {
-             if (!unified_syntax && (v & ~0xFF) == 0)
+             if ((v & ~0xFF) == 0)
                {
                  /* 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_arch_t2)
+                 && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6t2))
+               {
+                 /* Check if on thumb2 it can be done with a mov.w or mvn.w 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;
+                   }
+
+                 if (newimm != (unsigned int) FAIL)
+                   {
+                     inst.instruction = 0xf04f0000 | (inst.operands[i].reg << 8);
+                     inst.instruction |= (isNegated?0x200000:0);
+                     inst.instruction |= (newimm & 0x800) << 15;
+                     inst.instruction |= (newimm & 0x700) << 4;
+                     inst.instruction |= (newimm & 0x0ff);
+                     return TRUE;
+                   }
+                 else if ((v & ~0xFFFF) == 0 || (v & ~0xFFFF0000) == 0)
+                   { 
+                     /* The number may be loaded with a movw/movt instruction.  */
+                     int imm;
+
+                     if ((inst.reloc.exp.X_add_number & ~0xFFFF) == 0)
+                       {
+                         inst.instruction= 0xf2400000;
+                         imm = v;
+                       }
+                     else
+                       {
+                         inst.instruction = 0xf2c00000;
+                         imm = v >> 16;
+                       }
+
+                     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 && inst.reloc.exp.X_op == O_constant)
+         else if (arm_p)
            {
              int value = encode_arm_immediate (v);
+
              if (value != FAIL)
                {
                  /* This can be done with a mov instruction.  */
@@ -7953,6 +8021,13 @@ move_or_literal_pool (int i, enum lit_type t, bfd_boolean mode_3)
              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))
            {
@@ -7965,6 +8040,7 @@ move_or_literal_pool (int i, enum lit_type t, bfd_boolean mode_3)
                  return TRUE;
                }
            }
+#endif
        }
     }
 
@@ -17797,7 +17873,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
@@ -17822,7 +17898,7 @@ md_assemble (char *str)
                inst.size_req = 2;
              else if (inst.size_req == 4)
                {
-                 as_bad (_("selected processor does not support Thumb-2 mode `%s'"), str);
+                 as_bad (_("selected processor does not support `%s' in Thumb-2 mode"), str);
                  return;
                }
            }
@@ -17888,7 +17964,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)
@@ -23074,7 +23150,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;
@@ -23082,10 +23158,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;
@@ -23488,7 +23603,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:
@@ -23526,6 +23640,7 @@ tc_gen_reloc (asection *section, fixS *fixp)
 
     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.
@@ -24874,6 +24989,8 @@ static const struct arm_option_fpu_value_table arm_fpus[] =
   {"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}
 };