github.com/llir/llvm@v0.3.6/ir/constant/const_float.go (about)

     1  package constant
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"math"
     7  	"math/big"
     8  	"strconv"
     9  	"strings"
    10  
    11  	"github.com/llir/llvm/ir/types"
    12  	"github.com/mewmew/float"
    13  	"github.com/mewmew/float/bfloat"
    14  	"github.com/mewmew/float/binary128"
    15  	"github.com/mewmew/float/binary16"
    16  	"github.com/mewmew/float/float128ppc"
    17  	"github.com/mewmew/float/float80x86"
    18  	"github.com/pkg/errors"
    19  )
    20  
    21  // --- [ Floating-point constants ] --------------------------------------------
    22  
    23  // Float is an LLVM IR floating-point constant.
    24  type Float struct {
    25  	// Floating-point type.
    26  	Typ *types.FloatType
    27  	// Floating-point constant.
    28  	X *big.Float
    29  	// NaN specifies whether the floating-point constant is Not-a-Number.
    30  	NaN bool
    31  }
    32  
    33  // NewFloat returns a new floating-point constant based on the given
    34  // floating-point type and double precision floating-point value.
    35  func NewFloat(typ *types.FloatType, x float64) *Float {
    36  	if math.IsNaN(x) {
    37  		f := &Float{Typ: typ, X: &big.Float{}, NaN: true}
    38  		// Store sign of NaN.
    39  		if math.Signbit(x) {
    40  			f.X.SetFloat64(-1)
    41  		}
    42  		return f
    43  	}
    44  	return &Float{Typ: typ, X: big.NewFloat(x)}
    45  }
    46  
    47  // NewFloatFromString returns a new floating-point constant based on the given
    48  // floating-point type and floating-point string.
    49  //
    50  // The floating-point string may be expressed in one of the following forms.
    51  //
    52  //    * fraction floating-point literal
    53  //         [+-]? [0-9]+ [.] [0-9]*
    54  //    * scientific notation floating-point literal
    55  //         [+-]? [0-9]+ [.] [0-9]* [eE] [+-]? [0-9]+
    56  //    * hexadecimal floating-point literal
    57  //         0x[0-9A-Fa-f]{16}  // HexFP
    58  //         0xK[0-9A-Fa-f]{20} // HexFP80
    59  //         0xL[0-9A-Fa-f]{32} // HexFP128
    60  //         0xM[0-9A-Fa-f]{32} // HexPPC128
    61  //         0xH[0-9A-Fa-f]{4}  // HexHalf
    62  func NewFloatFromString(typ *types.FloatType, s string) (*Float, error) {
    63  	// Hexadecimal floating-point literal.
    64  	if strings.HasPrefix(s, "0x") {
    65  		switch {
    66  		// x86_fp80 (x86 extended precision)
    67  		case strings.HasPrefix(s, "0xK"):
    68  			// From https://llvm.org/docs/LangRef.html#simple-constants
    69  			//
    70  			// > The 80-bit format used by x86 is represented as 0xK followed by 20
    71  			// > hexadecimal digits.
    72  			hex := strings.TrimPrefix(s, "0xK")
    73  			const hexLen = 8
    74  			part1 := hex[:hexLen/2]
    75  			part2 := hex[hexLen/2:]
    76  			se, err := strconv.ParseUint(part1, 16, 16)
    77  			if err != nil {
    78  				return nil, errors.WithStack(err)
    79  			}
    80  			m, err := strconv.ParseUint(part2, 16, 64)
    81  			if err != nil {
    82  				return nil, errors.WithStack(err)
    83  			}
    84  			f := float80x86.NewFromBits(uint16(se), m)
    85  			x, nan := f.Big()
    86  			return &Float{Typ: typ, X: x, NaN: nan}, nil
    87  		// fp128 (IEEE 754 quadruple precision)
    88  		case strings.HasPrefix(s, "0xL"):
    89  			// From https://llvm.org/docs/LangRef.html#simple-constants
    90  			//
    91  			// > The IEEE 128-bit format is represented by 0xL followed by 32
    92  			// > hexadecimal digits.
    93  			hex := strings.TrimPrefix(s, "0xL")
    94  			const maxHexLen = 32
    95  			if len(hex) < maxHexLen {
    96  				// pad with leading zeroes (e.g. for case like `0xL01`)
    97  				hex = strings.Repeat("0", maxHexLen-len(hex)) + hex
    98  			}
    99  			part1 := hex[:maxHexLen/2]
   100  			part2 := hex[maxHexLen/2:]
   101  			a, err := strconv.ParseUint(part1, 16, 64)
   102  			if err != nil {
   103  				return nil, errors.WithStack(err)
   104  			}
   105  			b, err := strconv.ParseUint(part2, 16, 64)
   106  			if err != nil {
   107  				return nil, errors.WithStack(err)
   108  			}
   109  			f := binary128.NewFromBits(a, b)
   110  			x, nan := f.Big()
   111  			return &Float{Typ: typ, X: x, NaN: nan}, nil
   112  		// ppc_fp128 (PowerPC double-double arithmetic)
   113  		case strings.HasPrefix(s, "0xM"):
   114  			// From https://llvm.org/docs/LangRef.html#simple-constants
   115  			//
   116  			// > The 128-bit format used by PowerPC (two adjacent doubles) is
   117  			// > represented by 0xM followed by 32 hexadecimal digits.
   118  			hex := strings.TrimPrefix(s, "0xM")
   119  			const maxHexLen = 32
   120  			part1 := hex[:maxHexLen/2]
   121  			part2 := hex[maxHexLen/2:]
   122  			a, err := strconv.ParseUint(part1, 16, 64)
   123  			if err != nil {
   124  				return nil, errors.WithStack(err)
   125  			}
   126  			b, err := strconv.ParseUint(part2, 16, 64)
   127  			if err != nil {
   128  				return nil, errors.WithStack(err)
   129  			}
   130  			f := float128ppc.NewFromBits(a, b)
   131  			x, nan := f.Big()
   132  			return &Float{Typ: typ, X: x, NaN: nan}, nil
   133  		// half (IEEE 754 half precision)
   134  		case strings.HasPrefix(s, "0xH"):
   135  			// From https://llvm.org/docs/LangRef.html#simple-constants
   136  			//
   137  			// > The IEEE 16-bit format (half precision) is represented by 0xH
   138  			// > followed by 4 hexadecimal digits.
   139  			hex := strings.TrimPrefix(s, "0xH")
   140  			bits, err := strconv.ParseUint(hex, 16, 16)
   141  			if err != nil {
   142  				return nil, errors.WithStack(err)
   143  			}
   144  			f := binary16.NewFromBits(uint16(bits))
   145  			x, nan := f.Big()
   146  			return &Float{Typ: typ, X: x, NaN: nan}, nil
   147  		// Hexadecimal floating-point literal.
   148  		case strings.HasPrefix(s, "0xR"):
   149  			// From https://llvm.org/docs/LangRef.html#simple-constants
   150  			//
   151  			// > The bfloat 16-bit format is represented by 0xR followed by 4 hexadecimal digits.
   152  			hex := strings.TrimPrefix(s, "0xR")
   153  			bits, err := strconv.ParseUint(hex, 16, 16)
   154  			if err != nil {
   155  				return nil, errors.WithStack(err)
   156  			}
   157  			f := bfloat.NewFromBits(uint16(bits))
   158  			x, nan := f.Big()
   159  			return &Float{Typ: typ, X: x, NaN: nan}, nil
   160  			// HexBFloatConstant
   161  		default:
   162  			// From https://llvm.org/docs/LangRef.html#simple-constants
   163  			//
   164  			// > When using the hexadecimal form, constants of types half, float,
   165  			// > and double are represented using the 16-digit form shown above
   166  			// > (which matches the IEEE754 representation for double).
   167  			hex := strings.TrimPrefix(s, "0x")
   168  			bits, err := strconv.ParseUint(hex, 16, 64)
   169  			if err != nil {
   170  				return nil, errors.WithStack(err)
   171  			}
   172  			switch typ.Kind {
   173  			case types.FloatKindHalf:
   174  				// TODO: verify if this is a correct implementation. We should
   175  				// probably be using binary16.NewFromBits.
   176  				f16 := math.Float64frombits(bits)
   177  				if math.IsNaN(f16) {
   178  					f := &Float{Typ: typ, X: &big.Float{}, NaN: true}
   179  					// Store sign of NaN.
   180  					if math.Signbit(f16) {
   181  						f.X.SetFloat64(-1)
   182  					}
   183  					return f, nil
   184  				}
   185  				c := big.NewFloat(f16)
   186  				const precision = 11
   187  				c.SetPrec(precision)
   188  				return &Float{
   189  					Typ: typ,
   190  					X:   c,
   191  				}, nil
   192  			case types.FloatKindFloat:
   193  				// ref: https://groups.google.com/d/msg/llvm-dev/IlqV3TbSk6M/27dAggZOMb0J
   194  				//
   195  				// The exact bit representation of the float is laid out with the
   196  				// corresponding bitwise representation of a double: the sign bit is
   197  				// copied over, the exponent is encoded in the larger width, and the
   198  				// 23 bits of significand fills in the top 23 bits of significand in
   199  				// the double. A double has 52 bits of significand, so this means
   200  				// that the last 29 bits of significand will always be ignored. As
   201  				// an error-detection measure, the IR parser requires them to be
   202  				// zero.
   203  				f32 := math.Float64frombits(bits)
   204  				if math.IsNaN(f32) {
   205  					f := &Float{Typ: typ, X: &big.Float{}, NaN: true}
   206  					// Store sign of NaN.
   207  					if math.Signbit(f32) {
   208  						f.X.SetFloat64(-1)
   209  					}
   210  					return f, nil
   211  				}
   212  				x := big.NewFloat(f32)
   213  				const precision = 24
   214  				x.SetPrec(precision)
   215  				return &Float{Typ: typ, X: x}, nil
   216  			case types.FloatKindDouble:
   217  				f64 := math.Float64frombits(bits)
   218  				if math.IsNaN(f64) {
   219  					f := &Float{Typ: typ, X: &big.Float{}, NaN: true}
   220  					// Store sign of NaN.
   221  					if math.Signbit(f64) {
   222  						f.X.SetFloat64(-1)
   223  					}
   224  					return f, nil
   225  				}
   226  				x := big.NewFloat(f64)
   227  				const precision = 53
   228  				x.SetPrec(precision)
   229  				return &Float{Typ: typ, X: x}, nil
   230  			default:
   231  				panic(fmt.Errorf("support for hexadecimal floating-point literal %q of kind %v not yet implemented", s, typ.Kind))
   232  			}
   233  		}
   234  	}
   235  	const base = 10
   236  	switch typ.Kind {
   237  	case types.FloatKindHalf:
   238  		const precision = 11
   239  		x, _, err := big.ParseFloat(s, base, precision, big.ToNearestEven)
   240  		if err != nil {
   241  			return nil, errors.WithStack(err)
   242  		}
   243  		c := &Float{
   244  			Typ: typ,
   245  			X:   x,
   246  		}
   247  		return c, nil
   248  	case types.FloatKindFloat:
   249  		const precision = 24
   250  		x, _, err := big.ParseFloat(s, base, precision, big.ToNearestEven)
   251  		if err != nil {
   252  			return nil, errors.WithStack(err)
   253  		}
   254  		c := &Float{
   255  			Typ: typ,
   256  			X:   x,
   257  		}
   258  		return c, nil
   259  	case types.FloatKindDouble:
   260  		const precision = 53
   261  		x, _, err := big.ParseFloat(s, base, precision, big.ToNearestEven)
   262  		if err != nil {
   263  			return nil, errors.WithStack(err)
   264  		}
   265  		c := &Float{
   266  			Typ: typ,
   267  			X:   x,
   268  		}
   269  		return c, nil
   270  	default:
   271  		panic(fmt.Errorf("support for floating-point kind %v not yet implemented", typ.Kind))
   272  	}
   273  }
   274  
   275  // String returns the LLVM syntax representation of the constant as a type-value
   276  // pair.
   277  func (c *Float) String() string {
   278  	return fmt.Sprintf("%s %s", c.Type(), c.Ident())
   279  }
   280  
   281  // Type returns the type of the constant.
   282  func (c *Float) Type() types.Type {
   283  	return c.Typ
   284  }
   285  
   286  // Ident returns the identifier associated with the constant.
   287  func (c *Float) Ident() string {
   288  	// FloatLit
   289  	//
   290  	// Print hexadecimal representation of floating-point literal if NaN, Inf,
   291  	// inexact or extended precision (x86_fp80, fp128 or ppc_fp128).
   292  	switch c.Typ.Kind {
   293  	// half (IEEE 754 half precision)
   294  	case types.FloatKindHalf:
   295  		const hexPrefix = 'H'
   296  		if c.NaN {
   297  			bits := binary16.NaN.Bits()
   298  			if c.X != nil && c.X.Signbit() {
   299  				bits = binary16.NegNaN.Bits()
   300  			}
   301  			return fmt.Sprintf("0x%c%04X", hexPrefix, bits)
   302  		}
   303  		if c.X.IsInf() || !float.IsExact16(c.X) {
   304  			f, acc := binary16.NewFromBig(c.X)
   305  			if acc != big.Exact {
   306  				log.Printf("unable to represent floating-point constant %v of type %v exactly; please submit a bug report to llir/llvm with this error message", c.X, c.Typ)
   307  			}
   308  			bits := f.Bits()
   309  			return fmt.Sprintf("0x%c%04X", hexPrefix, bits)
   310  		}
   311  		// c is representable without loss as floating-point literal, this case is
   312  		// handled for half, float and double below the switch statement.
   313  	// float (IEEE 754 single precision)
   314  	case types.FloatKindFloat:
   315  		// ref: https://groups.google.com/d/msg/llvm-dev/IlqV3TbSk6M/27dAggZOMb0J
   316  		//
   317  		// The exact bit representation of the float is laid out with the
   318  		// corresponding bitwise representation of a double: the sign bit is
   319  		// copied over, the exponent is encoded in the larger width, and the 23
   320  		// bits of significand fills in the top 23 bits of significand in the
   321  		// double. A double has 52 bits of significand, so this means that the
   322  		// last 29 bits of significand will always be ignored. As an error
   323  		// detection measure, the IR parser requires them to be zero.
   324  		if c.NaN {
   325  			f := math.NaN()
   326  			if c.X != nil && c.X.Signbit() {
   327  				f = math.Copysign(f, -1)
   328  			}
   329  			bits := math.Float64bits(f)
   330  			// zero out last 29 bits.
   331  			bits &^= 0x1FFFFFFF
   332  			return fmt.Sprintf("0x%X", bits)
   333  		}
   334  		if c.X.IsInf() || !float.IsExact32(c.X) {
   335  			f, _ := c.X.Float64()
   336  			bits := math.Float64bits(f)
   337  			// Note, to match Clang output we do not zero-pad the hexadecimal
   338  			// output.
   339  			// zero out last 29 bits.
   340  			bits &^= 0x1FFFFFFF
   341  			return fmt.Sprintf("0x%X", bits)
   342  		}
   343  		// c is representable without loss as floating-point literal, this case is
   344  		// handled for half, float and double below the switch statement.
   345  	// double (IEEE 754 double precision)
   346  	case types.FloatKindDouble:
   347  		if c.NaN {
   348  			// To use the same cannonical representation as LLVM IR for NaN values, we
   349  			// explicitly a qNaN value (quiet NaN) with the leading bit in the mantissa
   350  			// set, rather than the trailing bit as used for the cannonical
   351  			// representation in Go (see math.NaN).
   352  			//
   353  			// For further background, see https://github.com/llir/llvm/issues/133
   354  			//
   355  			//      exponent    mantissa
   356  			//    s 11111111111 1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx = quiet     (qNaN)
   357  			//    s 11111111111 0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx = signaling (sNaN) **
   358  			//                  ^ quiet bit
   359  			//
   360  			// Where ** denote that at least one of the 'x' bits has to be set, since the
   361  			// mantissa must be non-zero to denote NaN.
   362  			//
   363  			// quiet NaN:
   364  			//    0x7FF8000000000000 = 0b0_11111111111_100000000000000000000000000000000000000000000000000
   365  			f := math.Float64frombits(0x7FF8000000000000) // quiet NaN
   366  			if c.X != nil && c.X.Signbit() {
   367  				f = math.Copysign(f, -1)
   368  			}
   369  			bits := math.Float64bits(f)
   370  			return fmt.Sprintf("0x%X", bits)
   371  		}
   372  		if c.X.IsInf() || !float.IsExact64(c.X) {
   373  			f, _ := c.X.Float64()
   374  			bits := math.Float64bits(f)
   375  			// Note, to match Clang output we do not zero-pad the hexadecimal
   376  			// output.
   377  			return fmt.Sprintf("0x%X", bits)
   378  		}
   379  		// c is representable without loss as floating-point literal, this case is
   380  		// handled for half, float and double below the switch statement.
   381  	// x86_fp80 (x86 extended precision)
   382  	case types.FloatKindX86_FP80:
   383  		// always represent x86_fp80 in hexadecimal floating-point notation.
   384  		const hexPrefix = 'K'
   385  		if c.NaN {
   386  			se, m := float80x86.NaN.Bits()
   387  			if c.X != nil && c.X.Signbit() {
   388  				se, m = float80x86.NegNaN.Bits()
   389  			}
   390  			return fmt.Sprintf("0x%c%04X%016X", hexPrefix, se, m)
   391  		}
   392  		f, acc := float80x86.NewFromBig(c.X)
   393  		if acc != big.Exact {
   394  			log.Printf("unable to represent floating-point constant %v of type %v exactly; please submit a bug report to llir/llvm with this error message", c.X, c.Typ)
   395  		}
   396  		se, m := f.Bits()
   397  		return fmt.Sprintf("0x%c%04X%016X", hexPrefix, se, m)
   398  	// fp128 (IEEE 754 quadruple precision)
   399  	case types.FloatKindFP128:
   400  		// always represent fp128 in hexadecimal floating-point notation.
   401  		const hexPrefix = 'L'
   402  		if c.NaN {
   403  			a, b := binary128.NaN.Bits()
   404  			if c.X != nil && c.X.Signbit() {
   405  				a, b = binary128.NegNaN.Bits()
   406  			}
   407  			return fmt.Sprintf("0x%c%016X%016X", hexPrefix, a, b)
   408  		}
   409  		f, acc := binary128.NewFromBig(c.X)
   410  		if acc != big.Exact {
   411  			log.Printf("unable to represent floating-point constant %v of type %v exactly; please submit a bug report to llir/llvm with this error message", c.X, c.Typ)
   412  		}
   413  		a, b := f.Bits()
   414  		return fmt.Sprintf("0x%c%016X%016X", hexPrefix, a, b)
   415  	// ppc_fp128 (PowerPC double-double arithmetic)
   416  	case types.FloatKindPPC_FP128:
   417  		// always represent ppc_fp128 in hexadecimal floating-point notation.
   418  		const hexPrefix = 'M'
   419  		if c.NaN {
   420  			a, b := float128ppc.NaN.Bits()
   421  			if c.X != nil && c.X.Signbit() {
   422  				a, b = float128ppc.NegNaN.Bits()
   423  			}
   424  			return fmt.Sprintf("0x%c%016X%016X", hexPrefix, a, b)
   425  		}
   426  		f, acc := float128ppc.NewFromBig(c.X)
   427  		if acc != big.Exact {
   428  			log.Printf("unable to represent floating-point constant %v of type %v exactly; please submit a bug report to llir/llvm with this error message", c.X, c.Typ)
   429  		}
   430  		a, b := f.Bits()
   431  		return fmt.Sprintf("0x%c%016X%016X", hexPrefix, a, b)
   432  	default:
   433  		panic(fmt.Errorf("support for floating-point kind %v not yet implemented", c.Typ.Kind))
   434  	}
   435  	// Insert decimal point if not present.
   436  	//    3e4 -> 3.0e4
   437  	//    42  -> 42.0
   438  	s := c.X.Text('g', -1)
   439  	if !strings.ContainsRune(s, '.') {
   440  		if pos := strings.IndexByte(s, 'e'); pos != -1 {
   441  			s = s[:pos] + ".0" + s[pos:]
   442  		} else {
   443  			s += ".0"
   444  		}
   445  	}
   446  	return s
   447  }