*** ../binutils-2.23.52.0.1.orig/gas/config/tc-aarch64.c 2013-12-16 17:13:40.458862152 +0000 --- gas/config/tc-aarch64.c 2014-02-19 16:24:27.743707831 +0000 *************** encode_imm_float_bits (uint32_t imm) *** 1989,2037 **** | ((imm >> (31 - 7)) & 0x80); /* b[31] -> b[7] */ } ! /* Return TRUE if IMM is a valid floating-point immediate; return FALSE ! otherwise. */ static bfd_boolean aarch64_imm_float_p (uint32_t imm) { ! /* 3 32222222 2221111111111 1 09876543 21098765432109876543210 ! n Eeeeeexx xxxx0000000000000000000 */ ! uint32_t e; ! e = (imm >> 30) & 0x1; ! if (e == 0) ! e = 0x3e000000; else ! e = 0x40000000; ! return (imm & 0x7ffff) == 0 /* lower 19 bits are 0 */ ! && ((imm & 0x7e000000) == e); /* bits 25-29 = ~ bit 30 */ } ! /* Note: this accepts the floating-point 0 constant. */ static bfd_boolean ! parse_aarch64_imm_float (char **ccp, int *immed) { char *str = *ccp; char *fpnum; LITTLENUM_TYPE words[MAX_LITTLENUMS]; int found_fpchar = 0; 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; else { for (; *fpnum != '\0' && *fpnum != ' ' && *fpnum != '\n'; fpnum++) if (*fpnum == '.' || *fpnum == 'e' || *fpnum == 'E') { --- 1989,2128 ---- | ((imm >> (31 - 7)) & 0x80); /* b[31] -> b[7] */ } ! /* 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) { ! /* 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 ! ! where n, e and each x are either 0 or 1 independently, with ! E == ~ e. */ ! uint32_t pattern; ! ! /* Prepare the pattern for 'Eeeeee'. */ ! if (((imm >> 30) & 0x1) == 0) ! pattern = 0x3e000000; else ! pattern = 0x40000000; ! ! return (imm & 0x7ffff) == 0 /* lower 19 bits are 0. */ ! && ((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. */ ! static bfd_boolean ! 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, '#'); fpnum = str; skip_whitespace (fpnum); if (strncmp (fpnum, "0x", 2) == 0) ! { ! /* 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') { *************** parse_aarch64_imm_float (char **ccp, int *** 2043,2067 **** return FALSE; } ! if ((str = atof_ieee (str, 's', words)) != NULL) { - unsigned fpword = 0; int i; /* 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; ! *ccp = str; - return TRUE; } --- 2134,2158 ---- return FALSE; } ! if (! hex_p) { 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; *ccp = str; return TRUE; } *************** parse_operands (char *str, const aarch64 *** 4687,4693 **** 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)) && !(res2 = parse_constant_immediate (&str, &val))) goto failure; if ((res1 && qfloat == 0) || (res2 && val == 0)) --- 4778,4784 ---- 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, FALSE)) && !(res2 = parse_constant_immediate (&str, &val))) goto failure; if ((res1 && qfloat == 0) || (res2 && val == 0)) *************** parse_operands (char *str, const aarch64 *** 4748,4754 **** case AARCH64_OPND_SIMD_FPIMM: { int qfloat; ! if (! parse_aarch64_imm_float (&str, &qfloat)) goto failure; if (qfloat == 0) { --- 4839,4848 ---- case AARCH64_OPND_SIMD_FPIMM: { int 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) {