Add to the AArch64 GAS the missing support for hexadecimal-format
authorYufeng Zhang <yufeng.zhang@arm.com>
Tue, 5 Mar 2013 16:31:44 +0000 (16:31 +0000)
committerYufeng Zhang <yufeng.zhang@arm.com>
Tue, 5 Mar 2013 16:31:44 +0000 (16:31 +0000)
floating-point literal in the FMOV instruction.

gas/

* config/tc-aarch64.c (aarch64_imm_float_p): Rename 'e' to 'pattern';
add comment.
(aarch64_double_precision_fmovable): New function.
(parse_aarch64_imm_float): Add parameter 'dp_p'; call the new
function; handle hexadecimal representation of IEEE754 encoding.
(parse_operands): Update the call to parse_aarch64_imm_float.

gas/testsuite/

* gas/aarch64/diagnostic.s: Add test.
* gas/aarch64/diagnostic.l: Update.
* gas/aarch64/illegal.s: Add test.
* gas/aarch64/illegal.l: Update.
* gas/aarch64/fpmov.s: New file.
* gas/aarch64/fpmov.d: New file.

gas/ChangeLog
gas/config/tc-aarch64.c
gas/testsuite/ChangeLog
gas/testsuite/gas/aarch64/diagnostic.l
gas/testsuite/gas/aarch64/diagnostic.s
gas/testsuite/gas/aarch64/fpmov.d [new file with mode: 0644]
gas/testsuite/gas/aarch64/fpmov.s [new file with mode: 0644]
gas/testsuite/gas/aarch64/illegal.l
gas/testsuite/gas/aarch64/illegal.s

index a547f13..31cb2af 100644 (file)
@@ -1,3 +1,12 @@
+2013-03-05  Yufeng Zhang  <yufeng.zhang@arm.com>
+
+       * config/tc-aarch64.c (aarch64_imm_float_p): Rename 'e' to 'pattern';
+       add comment.
+       (aarch64_double_precision_fmovable): New function.
+       (parse_aarch64_imm_float): Add parameter 'dp_p'; call the new
+       function; handle hexadecimal representation of IEEE754 encoding.
+       (parse_operands): Update the call to parse_aarch64_imm_float.
+
 2013-02-28  H.J. Lu  <hongjiu.lu@intel.com>
 
        * config/tc-i386.c (_i386_insn): Replace have_hle with hle_prefix.
index c10c723..6cd7e9d 100644 (file)
@@ -1989,49 +1989,140 @@ encode_imm_float_bits (uint32_t imm)
     | ((imm >> (31 - 7)) & 0x80);      /* b[31]    -> b[7]   */
 }
 
-/* Return TRUE if IMM is a valid floating-point immediate; return FALSE
-   otherwise.  */
+/* Return TRUE if the single-precision floating-point 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; in other words, the
+   floating-point value must be expressable as
+     (+/-) n / 16 * power (2, r)
+   where n and r are integers such that 16 <= n <=31 and -3 <= r <= 4.  */
+
 static bfd_boolean
 aarch64_imm_float_p (uint32_t imm)
 {
-  /* 3 32222222 2221111111111
+  /* If a single-precision floating-point value has the following bit
+     pattern, it can be expressed in the AArch64 8-bit floating-point
+     format:
+
+     3 32222222 2221111111111
      1 09876543 21098765432109876543210
-     n Eeeeeexx xxxx0000000000000000000  */
-  uint32_t e;
+     n Eeeeeexx xxxx0000000000000000000
+
+     where n, e and each x are either 0 or 1 independently, with
+     E == ~ e.  */
 
-  e = (imm >> 30) & 0x1;
-  if (e == 0)
-    e = 0x3e000000;
+  uint32_t pattern;
+
+  /* Prepare the pattern for 'Eeeeee'.  */
+  if (((imm >> 30) & 0x1) == 0)
+    pattern = 0x3e000000;
   else
-    e = 0x40000000;
-  return (imm & 0x7ffff) == 0  /* lower 19 bits are 0 */
-    && ((imm & 0x7e000000) == e);      /* bits 25-29 = ~ bit 30 */
+    pattern = 0x40000000;
+
+  return (imm & 0x7ffff) == 0          /* lower 19 bits are 0.  */
+    && ((imm & 0x7e000000) == pattern);        /* bits 25 - 29 == ~ bit 30.  */
 }
 
-/* Note: this accepts the floating-point 0 constant.  */
+/* 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.  */
+
 static bfd_boolean
-parse_aarch64_imm_float (char **ccp, int *immed)
+aarch64_double_precision_fmovable (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:
+
+     6 66655555555 554444444...21111111111
+     3 21098765432 109876543...098765432109876543210
+     n Eeeeeeeeexx xxxx00000...000000000000000000000
+
+     where n, e and each x are either 0 or 1 independently, with
+     E == ~ e.  */
+
+  uint32_t pattern;
+  uint32_t high32 = imm >> 32;
+
+  /* Lower 32 bits need to be 0s.  */
+  if ((imm & 0xffffffff) != 0)
+    return FALSE;
+
+  /* Prepare the pattern for 'Eeeeeeeee'.  */
+  if (((high32 >> 30) & 0x1) == 0)
+    pattern = 0x3fc00000;
+  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
+    return FALSE;
+}
+
+/* Parse a floating-point immediate.  Return TRUE on success and return the
+   value in *IMMED in the format of IEEE754 single-precision encoding.
+   *CCP points to the start of the string; DP_P is TRUE when the immediate
+   is expected to be in double-precision (N.B. this only matters when
+   hexadecimal representation is involved).
+
+   N.B. 0.0 is accepted by this function.  */
+
+static bfd_boolean
+parse_aarch64_imm_float (char **ccp, int *immed, bfd_boolean dp_p)
 {
   char *str = *ccp;
   char *fpnum;
   LITTLENUM_TYPE words[MAX_LITTLENUMS];
   int found_fpchar = 0;
+  int64_t val = 0;
+  unsigned fpword = 0;
+  bfd_boolean hex_p = FALSE;
 
   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 hack that is not very efficient, 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 FALSE;
+    {
+      /* Support the hexadecimal representation of the IEEE754 encoding.
+        Double-precision is expected when DP_P is TRUE, otherwise the
+        representation should be in single-precision.  */
+      if (! parse_constant_immediate (&str, &val))
+       goto invalid_fp;
+
+      if (dp_p)
+       {
+         if (! aarch64_double_precision_fmovable (val, &fpword))
+           goto invalid_fp;
+       }
+      else if ((uint64_t) val > 0xffffffff)
+       goto invalid_fp;
+      else
+       fpword = val;
+
+      hex_p = TRUE;
+    }
   else
     {
+      /* 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'.  */
       for (; *fpnum != '\0' && *fpnum != ' ' && *fpnum != '\n'; fpnum++)
        if (*fpnum == '.' || *fpnum == 'e' || *fpnum == 'E')
          {
@@ -2043,25 +2134,25 @@ parse_aarch64_imm_float (char **ccp, int *immed)
        return FALSE;
     }
 
-  if ((str = atof_ieee (str, 's', words)) != NULL)
+  if (! hex_p)
     {
-      unsigned fpword = 0;
       int i;
 
+      if ((str = atof_ieee (str, 's', words)) == NULL)
+       goto invalid_fp;
+
       /* Our FP word must be 32 bits (single-precision FP).  */
       for (i = 0; i < 32 / LITTLENUM_NUMBER_OF_BITS; i++)
        {
          fpword <<= LITTLENUM_NUMBER_OF_BITS;
          fpword |= words[i];
        }
+    }
 
-      if (aarch64_imm_float_p (fpword) || (fpword & 0x7fffffff) == 0)
-       *immed = fpword;
-      else
-       goto invalid_fp;
-
+  if (aarch64_imm_float_p (fpword) || (fpword & 0x7fffffff) == 0)
+    {
+      *immed = fpword;
       *ccp = str;
-
       return TRUE;
     }
 
@@ -4691,7 +4782,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
            bfd_boolean res1 = FALSE, res2 = FALSE;
            /* N.B. -0.0 will be rejected; although -0.0 shouldn't be rejected,
               it is probably not worth the effort to support it.  */
-           if (!(res1 = parse_aarch64_imm_float (&str, &qfloat))
+           if (!(res1 = parse_aarch64_imm_float (&str, &qfloat, FALSE))
                && !(res2 = parse_constant_immediate (&str, &val)))
              goto failure;
            if ((res1 && qfloat == 0) || (res2 && val == 0))
@@ -4752,7 +4843,10 @@ parse_operands (char *str, const aarch64_opcode *opcode)
        case AARCH64_OPND_SIMD_FPIMM:
          {
            int qfloat;
-           if (! parse_aarch64_imm_float (&str, &qfloat))
+           bfd_boolean dp_p
+             = (aarch64_get_qualifier_esize (inst.base.operands[0].qualifier)
+                == 8);
+           if (! parse_aarch64_imm_float (&str, &qfloat, dp_p))
              goto failure;
            if (qfloat == 0)
              {
index dd23d56..d89f44f 100644 (file)
@@ -1,3 +1,12 @@
+2013-03-05  Yufeng Zhang  <yufeng.zhang@arm.com>
+
+       * gas/aarch64/diagnostic.s: Add test.
+       * gas/aarch64/diagnostic.l: Update.
+       * gas/aarch64/illegal.s: Add test.
+       * gas/aarch64/illegal.l: Update.
+       * gas/aarch64/fpmov.s: New file.
+       * gas/aarch64/fpmov.d: New file.
+
 2013-03-01  H.J. Lu  <hongjiu.lu@intel.com>
 
        * gas/i386/inval.s: Add tests for invalid addresses and eiz.
index 5745012..0a08011 100644 (file)
@@ -86,3 +86,4 @@
 [^:]*:88: Error: shift is not permitted at operand 2 -- `movi v1.2d,4294967295,lsl#0'
 [^:]*:89: Error: shift amount expected to be 0 at operand 2 -- `movi v1.8b,97,lsl#8'
 [^:]*:90: Error: unknown or missing system register name at operand 1 -- `msr dummy,x1'
+[^:]*:91: Error: invalid floating-point constant at operand 2 -- `fmov s0,0x42000000'
index 1fa1b74..99ebf8f 100644 (file)
@@ -88,3 +88,4 @@
        movi    v1.2d, 4294967295, lsl #0
        movi    v1.8b, 97, lsl #8
        msr     dummy, x1
+       fmov    s0, 0x42000000
diff --git a/gas/testsuite/gas/aarch64/fpmov.d b/gas/testsuite/gas/aarch64/fpmov.d
new file mode 100644 (file)
index 0000000..6afb3c5
--- /dev/null
@@ -0,0 +1,19 @@
+#objdump: -dr
+
+.*:     file format .*
+
+Disassembly of section .*:
+
+0000000000000000 <.*>:
+   0:  1e251000        fmov    s0, #1\.200000000000000000e\+01
+   4:  1e251000        fmov    s0, #1\.200000000000000000e\+01
+   8:  1e251000        fmov    s0, #1\.200000000000000000e\+01
+   c:  1e351000        fmov    s0, #-1\.200000000000000000e\+01
+  10:  1e351000        fmov    s0, #-1\.200000000000000000e\+01
+  14:  1e351000        fmov    s0, #-1\.200000000000000000e\+01
+  18:  1e751000        fmov    d0, #-1\.200000000000000000e\+01
+  1c:  1e751000        fmov    d0, #-1\.200000000000000000e\+01
+  20:  1e751000        fmov    d0, #-1\.200000000000000000e\+01
+  24:  1e69f000        fmov    d0, #2\.421875000000000000e-01
+  28:  1e69f000        fmov    d0, #2\.421875000000000000e-01
+  2c:  1e29f000        fmov    s0, #2\.421875000000000000e-01
diff --git a/gas/testsuite/gas/aarch64/fpmov.s b/gas/testsuite/gas/aarch64/fpmov.s
new file mode 100644 (file)
index 0000000..ffc9881
--- /dev/null
@@ -0,0 +1,17 @@
+// fpmov.s Test file for AArch64 floating-point move instructions.
+
+       .text
+
+       // fp mov immediate
+       fmov    s0, 12.0
+       fmov    s0, 1.2e1
+       fmov    s0, 0x41400000
+       fmov    s0, -12.0
+       fmov    s0, -1.2e1
+       fmov    s0, 0xc1400000
+       fmov    d0, -12.0
+       fmov    d0, -1.2e1
+       fmov    d0, 0xC028000000000000
+       fmov    d0, 0.2421875
+       fmov    d0, 0x3fcf000000000000
+       fmov    s0, 0x3e780000
index 5bc9c3c..d7740b9 100644 (file)
 [^:]*:538: Error: .*`mov x0,##5'
 [^:]*:540: Error: .*`msr daifset,x0'
 [^:]*:541: Error: .*`msr daifclr,x0'
-[^:]*:546: Error: .*
+[^:]*:543: Error: .*`fmov s0,#0x11'
+[^:]*:544: Error: .*`fmov s0,#0xC0280000C1400000'
+[^:]*:545: Error: .*`fmov d0,#0xC02f800000000000'
+[^:]*:550: Error: .*
index c13dec4..d2bc08a 100644 (file)
        msr     daifset, x0
        msr     daifclr, x0
 
+       fmov    s0, #0x11
+       fmov    s0, #0xC0280000C1400000
+       fmov    d0, #0xC02f800000000000
+
        // No 16-byte relocation
        ldr     q0, =one_label