Blob Blame History Raw
*** ../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)
  	      {