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 }