[AArch64][SVE 08/32] Generalise aarch64_double_precision_fmovable
authorRichard Sandiford <richard.sandiford@arm.com>
Wed, 21 Sep 2016 15:48:59 +0000 (16:48 +0100)
committerRichard Sandiford <richard.sandiford@arm.com>
Wed, 21 Sep 2016 15:48:59 +0000 (16:48 +0100)
SVE has single-bit floating-point constants that don't really
have any relation to the AArch64 8-bit floating-point encoding.
(E.g. one of the constants selects between 0 and 1.)  The easiest
way of representing them in the aarch64_opnd_info seemed to be
to use the IEEE float representation directly, rather than invent
some new scheme.

This patch paves the way for that by making the code that converts IEEE
doubles to IEEE floats accept any value in the range of an IEEE float,
not just zero and 8-bit floats.  It leaves the range checking to the
caller (which already handles it).

gas/
* config/tc-aarch64.c (aarch64_double_precision_fmovable): Rename
to...
(can_convert_double_to_float): ...this.  Accept any double-precision
value that converts to single precision without loss of precision.
(parse_aarch64_imm_float): Update accordingly.

gas/ChangeLog
gas/config/tc-aarch64.c

index 8b79b2ff5e58d16cec645edded7ee4a6c5061dab..6b279823503e560b8ea1992babebe6adb257841d 100644 (file)
@@ -1,3 +1,11 @@
+2016-09-21  Richard Sandiford  <richard.sandiford@arm.com>
+
+       * config/tc-aarch64.c (aarch64_double_precision_fmovable): Rename
+       to...
+       (can_convert_double_to_float): ...this.  Accept any double-precision
+       value that converts to single precision without loss of precision.
+       (parse_aarch64_imm_float): Update accordingly.
+
 2016-09-21  Richard Sandiford  <richard.sandiford@arm.com>
 
        * config/tc-aarch64.c (parse_immediate_expression): Add a
index eec08c7dd3087e67effa54ecd489d09c52ce1617..40f6253e3e699ffd6842206cd60b0c256e1a1822 100644 (file)
@@ -2093,56 +2093,52 @@ aarch64_imm_float_p (uint32_t imm)
     && ((imm & 0x7e000000) == pattern);        /* bits 25 - 29 == ~ bit 30.  */
 }
 
-/* Like aarch64_imm_float_p but for a double-precision floating-point value.
-
-   Return TRUE if the value encoded in IMM can be expressed in the AArch64
-   8-bit signed floating-point format with 3-bit exponent and normalized 4
-   bits of precision (i.e. can be used in an FMOV instruction); return the
-   equivalent single-precision encoding in *FPWORD.
-
-   Otherwise return FALSE.  */
+/* Return TRUE if the IEEE double value encoded in IMM can be expressed
+   as an IEEE float without any loss of precision.  Store the value in
+   *FPWORD if so.  */
 
 static bfd_boolean
-aarch64_double_precision_fmovable (uint64_t imm, uint32_t *fpword)
+can_convert_double_to_float (uint64_t imm, uint32_t *fpword)
 {
   /* If a double-precision floating-point value has the following bit
-     pattern, it can be expressed in the AArch64 8-bit floating-point
-     format:
+     pattern, it can be expressed in a float:
 
-     6 66655555555 554444444...21111111111
-     3 21098765432 109876543...098765432109876543210
-     n Eeeeeeeeexx xxxx00000...000000000000000000000
+     6 66655555555 5544 44444444 33333333 33222222 22221111 111111
+     3 21098765432 1098 76543210 98765432 10987654 32109876 54321098 76543210
+     n E~~~eeeeeee ssss ssssssss ssssssss SSS00000 00000000 00000000 00000000
 
-     where n, e and each x are either 0 or 1 independently, with
-     E == ~ e.  */
+       ----------------------------->     nEeeeeee esssssss ssssssss sssssSSS
+        if Eeee_eeee != 1111_1111
+
+     where n, e, s and S are either 0 or 1 independently and where ~ is the
+     inverse of E.  */
 
   uint32_t pattern;
   uint32_t high32 = imm >> 32;
+  uint32_t low32 = imm;
 
-  /* Lower 32 bits need to be 0s.  */
-  if ((imm & 0xffffffff) != 0)
+  /* Lower 29 bits need to be 0s.  */
+  if ((imm & 0x1fffffff) != 0)
     return FALSE;
 
   /* Prepare the pattern for 'Eeeeeeeee'.  */
   if (((high32 >> 30) & 0x1) == 0)
-    pattern = 0x3fc00000;
+    pattern = 0x38000000;
   else
     pattern = 0x40000000;
 
-  if ((high32 & 0xffff) == 0                   /* bits 32 - 47 are 0.  */
-      && (high32 & 0x7fc00000) == pattern)     /* bits 54 - 61 == ~ bit 62.  */
-    {
-      /* Convert to the single-precision encoding.
-         i.e. convert
-          n Eeeeeeeeexx xxxx00000...000000000000000000000
-        to
-          n Eeeeeexx xxxx0000000000000000000.  */
-      *fpword = ((high32 & 0xfe000000)                 /* nEeeeee.  */
-                | (((high32 >> 16) & 0x3f) << 19));    /* xxxxxx.  */
-      return TRUE;
-    }
-  else
+  /* Check E~~~.  */
+  if ((high32 & 0x78000000) != pattern)
     return FALSE;
+
+  /* Check Eeee_eeee != 1111_1111.  */
+  if ((high32 & 0x7ff00000) == 0x47f00000)
+    return FALSE;
+
+  *fpword = ((high32 & 0xc0000000)             /* 1 n bit and 1 E bit.  */
+            | ((high32 << 3) & 0x3ffffff8)     /* 7 e and 20 s bits.  */
+            | (low32 >> 29));                  /* 3 S bits.  */
+  return TRUE;
 }
 
 /* Parse a floating-point immediate.  Return TRUE on success and return the
@@ -2181,7 +2177,7 @@ parse_aarch64_imm_float (char **ccp, int *immed, bfd_boolean dp_p,
 
       if (dp_p)
        {
-         if (! aarch64_double_precision_fmovable (val, &fpword))
+         if (!can_convert_double_to_float (val, &fpword))
            goto invalid_fp;
        }
       else if ((uint64_t) val > 0xffffffff)