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]

Re: [Patch, AArch64] Add support for hexadecimal-form floating-point immediate


On 05/11/12 19:19, Yufeng Zhang wrote:
Hi,

This patch adds to the AArch64 GAS the support for the floating-point
immediate as a string beginning â0xâ followed by the hexadecimal
representation of its IEEE754 encoding.  This kind of fp immediate can
appear as the 2nd operand of any of the following instructions:


I'm not sure about this. The code is using native format floating-point values to handle target representation. That's potentially unsafe in a cross environment.


It would be better if this was re-coded to use the floatformat API.

R.

FMOV Sd, #fpimm
FMOV Dd, #fpimm
FMOV Vn.<T>, #fpimm

OK to commit?


Thanks, Yufeng



include/opcode/

2012-11-05 Yufeng Zhang <yufeng.zhang@arm.com>

	* aarch64.h (aarch64_get_sp_fp_enc): New function declaration.
	(aarch64_get_dp_fp_enc): Ditto.
	(aarch64_get_sp_fp_from_enc): Ditto.
	(aarch64_get_dp_fp_from_enc): Ditto.

opcodes/

2012-11-05 Yufeng Zhang <yufeng.zhang@arm.com>

	* aarch64-opc.c (aarch64_get_sp_fp_enc): New function.
	(aarch64_get_dp_fp_enc): Ditto.
	(aarch64_get_sp_fp_from_enc): Ditto.
	(aarch64_get_dp_fp_from_enc): Ditto.
	(aarch64_print_operand): Update.

gas/

2012-11-05 Yufeng Zhang <yufeng.zhang@arm.com>

	* config/tc-aarch64.c (parse_aarch64_imm_float): Add parameter 'dp_p';
	handle hexadecimal representation of IEEE754 encoding.
	(parse_operands): Update the call to parse_aarch64_imm_float.

gas/testsuite/

2012-11-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.


fmov-hexadecimal-imm.patch



diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c index e7a2fe0..824b3ec 100644 --- a/gas/config/tc-aarch64.c +++ b/gas/config/tc-aarch64.c @@ -2024,8 +2024,13 @@ 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)
  {
@@ -2043,30 +2048,65 @@ aarch64_imm_float_p (uint32_t imm)
      && ((imm & 0x7e000000) == e);	/* bits 25-29 = ~ bit 30 */
  }

-/* Note: this accepts the floating-point 0 constant.  */
+/* 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)
+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)
+	{
+	  double d = aarch64_get_dp_fp_from_enc (val);
+
+	  /* If the double-precision floating-point value cannot be expressed
+	     in single-precision, it will not be expressable in our 8-bit
+	     format.  */
+	  if ((double)(float) d != d)
+	    goto invalid_fp;
+
+	  fpword = aarch64_get_sp_fp_enc ((float) d);
+	}
+      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'.
+	 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.  */
        for (; *fpnum != '\0' && *fpnum != ' ' && *fpnum != '\n'; fpnum++)
  	if (*fpnum == '.' || *fpnum == 'e' || *fpnum == 'E')
  	  {
@@ -2078,25 +2118,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;
      }

@@ -4717,7 +4757,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))
@@ -4778,7 +4818,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 714a2f0..2553548 100644
--- a/gas/testsuite/gas/aarch64/diagnostic.l
+++ b/gas/testsuite/gas/aarch64/diagnostic.l
@@ -85,3 +85,4 @@
  [^:]*:87: Error: immediate offset out of range -256 to 252 at operand 3 -- `ldnp w7,w15,\[x3,#256\]'
  [^:]*:88: Error: shift is not permitted at operand 2 -- `movi v1.2d,4294967295,lsl#0'
  [^:]*:89: Error: shift amount non-zero at operand 2 -- `movi v1.8b,97,lsl#8'
+[^:]*:90: 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 2b1c01c..0b34662 100644
--- a/gas/testsuite/gas/aarch64/diagnostic.s
+++ b/gas/testsuite/gas/aarch64/diagnostic.s
@@ -87,3 +87,4 @@
  	ldnp	w7, w15, [x3, #256]
  	movi	v1.2d, 4294967295, lsl #0
  	movi	v1.8b, 97, lsl #8
+	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 6c741cf..e17a1de 100644
--- a/gas/testsuite/gas/aarch64/illegal.l
+++ b/gas/testsuite/gas/aarch64/illegal.l
@@ -549,3 +549,6 @@
  [^:]*:538: Error: .*`mov x0,##5'
  [^:]*:540: Error: .*`msr daifset,x0'
  [^:]*:541: Error: .*`msr daifclr,x0'
+[^:]*:543: Error: .*`fmov s0,#0x11'
+[^:]*:544: Error: .*`fmov s0,#0xC0280000C1400000'
+[^:]*:545: Error: .*`fmov d0,#0xC02f800000000000'
diff --git a/gas/testsuite/gas/aarch64/illegal.s b/gas/testsuite/gas/aarch64/illegal.s
index 9a12463..8b78181 100644
--- a/gas/testsuite/gas/aarch64/illegal.s
+++ b/gas/testsuite/gas/aarch64/illegal.s
@@ -539,3 +539,7 @@

  	msr	daifset, x0
  	msr	daifclr, x0
+
+	fmov	s0, #0x11
+	fmov	s0, #0xC0280000C1400000
+	fmov	d0, #0xC02f800000000000
diff --git a/include/opcode/aarch64.h b/include/opcode/aarch64.h
index 3a26199..01fb71b 100644
--- a/include/opcode/aarch64.h
+++ b/include/opcode/aarch64.h
@@ -886,8 +886,20 @@ aarch64_num_of_operands (const aarch64_opcode *);
  extern int
  aarch64_stack_pointer_p (const aarch64_opnd_info *);

-extern
-int aarch64_zero_register_p (const aarch64_opnd_info *);
+extern int
+aarch64_zero_register_p (const aarch64_opnd_info *);
+
+extern uint32_t
+aarch64_get_sp_fp_enc (float);
+
+extern uint64_t
+aarch64_get_dp_fp_enc (double);
+
+extern float
+aarch64_get_sp_fp_from_enc (uint32_t);
+
+extern double
+aarch64_get_dp_fp_from_enc (uint64_t);

  /* Given an operand qualifier, return the expected data element size
     of a qualified operand.  */
diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c
index b5e0984..468fb9c 100644
--- a/opcodes/aarch64-opc.c
+++ b/opcodes/aarch64-opc.c
@@ -2111,7 +2111,7 @@ get_64bit_int_reg_name (int regno, int sp_reg_p)
    return int_reg[has_zr][1][regno];
  }

-/* Types for expanding an encoded 8-bit value to a floating-point value.  */
+/* Types for conversion between floating-point value and its encoding.  */

  typedef union
  {
@@ -2125,6 +2125,44 @@ typedef union
    float    f;
  } single_conv_t;

+/* Utility functions for the conversion.  */
+
+uint64_t
+aarch64_get_dp_fp_enc (double val)
+{
+  double_conv_t dc;
+
+  dc.d = val;
+  return dc.i;
+}
+
+double
+aarch64_get_dp_fp_from_enc (uint64_t val)
+{
+  double_conv_t dc;
+
+  dc.i = val;
+  return dc.d;
+}
+
+uint32_t
+aarch64_get_sp_fp_enc (float val)
+{
+  single_conv_t sc;
+
+  sc.f = val;
+  return sc.i;
+}
+
+float
+aarch64_get_sp_fp_from_enc (uint32_t val)
+{
+  single_conv_t sc;
+
+  sc.i = val;
+  return sc.f;
+}
+
  /* IMM8 is an 8-bit floating-point constant with sign, 3-bit exponent and
     normalized 4 bits of precision, encoded in "a:b:c:d:e:f:g:h" or FLD_imm8
     (depending on the type of the instruction).  IMM8 will be expanded to a
@@ -2468,16 +2506,14 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc,
  	{
  	case 4:	/* e.g. FMOV <Vd>.4S, #<imm>.  */
  	    {
-	      single_conv_t c;
-	      c.i = expand_fp_imm (0, opnd->imm.value);
-	      snprintf (buf, size,  "#%.18e", c.f);
+	      uint32_t val = expand_fp_imm (0, opnd->imm.value);
+	      snprintf (buf, size,  "#%.18e", aarch64_get_sp_fp_from_enc (val));
  	    }
  	  break;
-	case 8:	/* e.g. FMOV <Sd>, #<imm>.  */
+	case 8:	/* e.g. FMOV <Dd>, #<imm>.  */
  	    {
-	      double_conv_t c;
-	      c.i = expand_fp_imm (1, opnd->imm.value);
-	      snprintf (buf, size,  "#%.18e", c.d);
+	      uint64_t val = expand_fp_imm (1, opnd->imm.value);
+	      snprintf (buf, size,  "#%.18e", aarch64_get_dp_fp_from_enc (val));
  	    }
  	  break;
  	default: assert (0);




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