[Patch, AArch64] Add support for hexadecimal-form floating-point immediate
Richard Earnshaw
rearnsha@arm.com
Tue Dec 4 12:13:00 GMT 2012
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);
>
More information about the Binutils
mailing list