This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Patch, AArch64] Add missing support for hexadecimal-format floating-point literal in the FMOV instruction


Hi,

The AArch64 floating-point move (immediate) instruction FMOV can have the floating point constant specified either in decimal notation or as a string beginning "0x" followed by the hexadecimal representation of its IEEE754 encoding.

This patch adds the missing support for the latter notation.

OK for the trunk and 2.23 release branch?

Thanks,
Yufeng


gas/


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.

gas/testsuite/

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.
diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index c10c723..6cd7e9d 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -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)
 	      {
diff --git a/gas/testsuite/gas/aarch64/diagnostic.l b/gas/testsuite/gas/aarch64/diagnostic.l
index 5745012..0a08011 100644
--- a/gas/testsuite/gas/aarch64/diagnostic.l
+++ b/gas/testsuite/gas/aarch64/diagnostic.l
@@ -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'
diff --git a/gas/testsuite/gas/aarch64/diagnostic.s b/gas/testsuite/gas/aarch64/diagnostic.s
index 1fa1b74..99ebf8f 100644
--- a/gas/testsuite/gas/aarch64/diagnostic.s
+++ b/gas/testsuite/gas/aarch64/diagnostic.s
@@ -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
index 0000000..6afb3c5
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/fpmov.d
@@ -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
index 0000000..ffc9881
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/fpmov.s
@@ -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
diff --git a/gas/testsuite/gas/aarch64/illegal.l b/gas/testsuite/gas/aarch64/illegal.l
index 5bc9c3c..d7740b9 100644
--- a/gas/testsuite/gas/aarch64/illegal.l
+++ b/gas/testsuite/gas/aarch64/illegal.l
@@ -548,4 +548,7 @@
 [^:]*: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: .*
diff --git a/gas/testsuite/gas/aarch64/illegal.s b/gas/testsuite/gas/aarch64/illegal.s
index c13dec4..d2bc08a 100644
--- a/gas/testsuite/gas/aarch64/illegal.s
+++ b/gas/testsuite/gas/aarch64/illegal.s
@@ -540,6 +540,10 @@
 	msr	daifset, x0
 	msr	daifclr, x0
 
+	fmov	s0, #0x11
+	fmov	s0, #0xC0280000C1400000
+	fmov	d0, #0xC02f800000000000
+
 	// No 16-byte relocation
 	ldr	q0, =one_label
 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]