github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/compile/internal/gc/float_test.go (about) 1 // Copyright 2016 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package gc 6 7 import ( 8 "math" 9 "os" 10 "runtime" 11 "testing" 12 ) 13 14 // For GO386=387, make sure fucomi* opcodes are not used 15 // for comparison operations. 16 // Note that this test will fail only on a Pentium MMX 17 // processor (with GOARCH=386 GO386=387), as it just runs 18 // some code and looks for an unimplemented instruction fault. 19 20 //go:noinline 21 func compare1(a, b float64) bool { 22 return a < b 23 } 24 25 //go:noinline 26 func compare2(a, b float32) bool { 27 return a < b 28 } 29 30 func TestFloatCompare(t *testing.T) { 31 if !compare1(3, 5) { 32 t.Errorf("compare1 returned false") 33 } 34 if !compare2(3, 5) { 35 t.Errorf("compare2 returned false") 36 } 37 } 38 39 func TestFloatCompareFolded(t *testing.T) { 40 // float64 comparisons 41 d1, d3, d5, d9 := float64(1), float64(3), float64(5), float64(9) 42 if d3 == d5 { 43 t.Errorf("d3 == d5 returned true") 44 } 45 if d3 != d3 { 46 t.Errorf("d3 != d3 returned true") 47 } 48 if d3 > d5 { 49 t.Errorf("d3 > d5 returned true") 50 } 51 if d3 >= d9 { 52 t.Errorf("d3 >= d9 returned true") 53 } 54 if d5 < d1 { 55 t.Errorf("d5 < d1 returned true") 56 } 57 if d9 <= d1 { 58 t.Errorf("d9 <= d1 returned true") 59 } 60 if math.NaN() == math.NaN() { 61 t.Errorf("math.NaN() == math.NaN() returned true") 62 } 63 if math.NaN() >= math.NaN() { 64 t.Errorf("math.NaN() >= math.NaN() returned true") 65 } 66 if math.NaN() <= math.NaN() { 67 t.Errorf("math.NaN() <= math.NaN() returned true") 68 } 69 if math.Copysign(math.NaN(), -1) < math.NaN() { 70 t.Errorf("math.Copysign(math.NaN(), -1) < math.NaN() returned true") 71 } 72 if math.Inf(1) != math.Inf(1) { 73 t.Errorf("math.Inf(1) != math.Inf(1) returned true") 74 } 75 if math.Inf(-1) != math.Inf(-1) { 76 t.Errorf("math.Inf(-1) != math.Inf(-1) returned true") 77 } 78 if math.Copysign(0, -1) != 0 { 79 t.Errorf("math.Copysign(0, -1) != 0 returned true") 80 } 81 if math.Copysign(0, -1) < 0 { 82 t.Errorf("math.Copysign(0, -1) < 0 returned true") 83 } 84 if 0 > math.Copysign(0, -1) { 85 t.Errorf("0 > math.Copysign(0, -1) returned true") 86 } 87 88 // float32 comparisons 89 s1, s3, s5, s9 := float32(1), float32(3), float32(5), float32(9) 90 if s3 == s5 { 91 t.Errorf("s3 == s5 returned true") 92 } 93 if s3 != s3 { 94 t.Errorf("s3 != s3 returned true") 95 } 96 if s3 > s5 { 97 t.Errorf("s3 > s5 returned true") 98 } 99 if s3 >= s9 { 100 t.Errorf("s3 >= s9 returned true") 101 } 102 if s5 < s1 { 103 t.Errorf("s5 < s1 returned true") 104 } 105 if s9 <= s1 { 106 t.Errorf("s9 <= s1 returned true") 107 } 108 sPosNaN, sNegNaN := float32(math.NaN()), float32(math.Copysign(math.NaN(), -1)) 109 if sPosNaN == sPosNaN { 110 t.Errorf("sPosNaN == sPosNaN returned true") 111 } 112 if sPosNaN >= sPosNaN { 113 t.Errorf("sPosNaN >= sPosNaN returned true") 114 } 115 if sPosNaN <= sPosNaN { 116 t.Errorf("sPosNaN <= sPosNaN returned true") 117 } 118 if sNegNaN < sPosNaN { 119 t.Errorf("sNegNaN < sPosNaN returned true") 120 } 121 sPosInf, sNegInf := float32(math.Inf(1)), float32(math.Inf(-1)) 122 if sPosInf != sPosInf { 123 t.Errorf("sPosInf != sPosInf returned true") 124 } 125 if sNegInf != sNegInf { 126 t.Errorf("sNegInf != sNegInf returned true") 127 } 128 sNegZero := float32(math.Copysign(0, -1)) 129 if sNegZero != 0 { 130 t.Errorf("sNegZero != 0 returned true") 131 } 132 if sNegZero < 0 { 133 t.Errorf("sNegZero < 0 returned true") 134 } 135 if 0 > sNegZero { 136 t.Errorf("0 > sNegZero returned true") 137 } 138 } 139 140 // For GO386=387, make sure fucomi* opcodes are not used 141 // for float->int conversions. 142 143 //go:noinline 144 func cvt1(a float64) uint64 { 145 return uint64(a) 146 } 147 148 //go:noinline 149 func cvt2(a float64) uint32 { 150 return uint32(a) 151 } 152 153 //go:noinline 154 func cvt3(a float32) uint64 { 155 return uint64(a) 156 } 157 158 //go:noinline 159 func cvt4(a float32) uint32 { 160 return uint32(a) 161 } 162 163 //go:noinline 164 func cvt5(a float64) int64 { 165 return int64(a) 166 } 167 168 //go:noinline 169 func cvt6(a float64) int32 { 170 return int32(a) 171 } 172 173 //go:noinline 174 func cvt7(a float32) int64 { 175 return int64(a) 176 } 177 178 //go:noinline 179 func cvt8(a float32) int32 { 180 return int32(a) 181 } 182 183 // make sure to cover int, uint cases (issue #16738) 184 //go:noinline 185 func cvt9(a float64) int { 186 return int(a) 187 } 188 189 //go:noinline 190 func cvt10(a float64) uint { 191 return uint(a) 192 } 193 194 //go:noinline 195 func cvt11(a float32) int { 196 return int(a) 197 } 198 199 //go:noinline 200 func cvt12(a float32) uint { 201 return uint(a) 202 } 203 204 //go:noinline 205 func f2i64p(v float64) *int64 { 206 return ip64(int64(v / 0.1)) 207 } 208 209 //go:noinline 210 func ip64(v int64) *int64 { 211 return &v 212 } 213 214 func TestFloatConvert(t *testing.T) { 215 if got := cvt1(3.5); got != 3 { 216 t.Errorf("cvt1 got %d, wanted 3", got) 217 } 218 if got := cvt2(3.5); got != 3 { 219 t.Errorf("cvt2 got %d, wanted 3", got) 220 } 221 if got := cvt3(3.5); got != 3 { 222 t.Errorf("cvt3 got %d, wanted 3", got) 223 } 224 if got := cvt4(3.5); got != 3 { 225 t.Errorf("cvt4 got %d, wanted 3", got) 226 } 227 if got := cvt5(3.5); got != 3 { 228 t.Errorf("cvt5 got %d, wanted 3", got) 229 } 230 if got := cvt6(3.5); got != 3 { 231 t.Errorf("cvt6 got %d, wanted 3", got) 232 } 233 if got := cvt7(3.5); got != 3 { 234 t.Errorf("cvt7 got %d, wanted 3", got) 235 } 236 if got := cvt8(3.5); got != 3 { 237 t.Errorf("cvt8 got %d, wanted 3", got) 238 } 239 if got := cvt9(3.5); got != 3 { 240 t.Errorf("cvt9 got %d, wanted 3", got) 241 } 242 if got := cvt10(3.5); got != 3 { 243 t.Errorf("cvt10 got %d, wanted 3", got) 244 } 245 if got := cvt11(3.5); got != 3 { 246 t.Errorf("cvt11 got %d, wanted 3", got) 247 } 248 if got := cvt12(3.5); got != 3 { 249 t.Errorf("cvt12 got %d, wanted 3", got) 250 } 251 if got := *f2i64p(10); got != 100 { 252 t.Errorf("f2i64p got %d, wanted 100", got) 253 } 254 } 255 256 func TestFloatConvertFolded(t *testing.T) { 257 // Assign constants to variables so that they are (hopefully) constant folded 258 // by the SSA backend rather than the frontend. 259 u64, u32, u16, u8 := uint64(1<<63), uint32(1<<31), uint16(1<<15), uint8(1<<7) 260 i64, i32, i16, i8 := int64(-1<<63), int32(-1<<31), int16(-1<<15), int8(-1<<7) 261 du64, du32, du16, du8 := float64(1<<63), float64(1<<31), float64(1<<15), float64(1<<7) 262 di64, di32, di16, di8 := float64(-1<<63), float64(-1<<31), float64(-1<<15), float64(-1<<7) 263 su64, su32, su16, su8 := float32(1<<63), float32(1<<31), float32(1<<15), float32(1<<7) 264 si64, si32, si16, si8 := float32(-1<<63), float32(-1<<31), float32(-1<<15), float32(-1<<7) 265 266 // integer to float 267 if float64(u64) != du64 { 268 t.Errorf("float64(u64) != du64") 269 } 270 if float64(u32) != du32 { 271 t.Errorf("float64(u32) != du32") 272 } 273 if float64(u16) != du16 { 274 t.Errorf("float64(u16) != du16") 275 } 276 if float64(u8) != du8 { 277 t.Errorf("float64(u8) != du8") 278 } 279 if float64(i64) != di64 { 280 t.Errorf("float64(i64) != di64") 281 } 282 if float64(i32) != di32 { 283 t.Errorf("float64(i32) != di32") 284 } 285 if float64(i16) != di16 { 286 t.Errorf("float64(i16) != di16") 287 } 288 if float64(i8) != di8 { 289 t.Errorf("float64(i8) != di8") 290 } 291 if float32(u64) != su64 { 292 t.Errorf("float32(u64) != su64") 293 } 294 if float32(u32) != su32 { 295 t.Errorf("float32(u32) != su32") 296 } 297 if float32(u16) != su16 { 298 t.Errorf("float32(u16) != su16") 299 } 300 if float32(u8) != su8 { 301 t.Errorf("float32(u8) != su8") 302 } 303 if float32(i64) != si64 { 304 t.Errorf("float32(i64) != si64") 305 } 306 if float32(i32) != si32 { 307 t.Errorf("float32(i32) != si32") 308 } 309 if float32(i16) != si16 { 310 t.Errorf("float32(i16) != si16") 311 } 312 if float32(i8) != si8 { 313 t.Errorf("float32(i8) != si8") 314 } 315 316 // float to integer 317 if uint64(du64) != u64 { 318 t.Errorf("uint64(du64) != u64") 319 } 320 if uint32(du32) != u32 { 321 t.Errorf("uint32(du32) != u32") 322 } 323 if uint16(du16) != u16 { 324 t.Errorf("uint16(du16) != u16") 325 } 326 if uint8(du8) != u8 { 327 t.Errorf("uint8(du8) != u8") 328 } 329 if int64(di64) != i64 { 330 t.Errorf("int64(di64) != i64") 331 } 332 if int32(di32) != i32 { 333 t.Errorf("int32(di32) != i32") 334 } 335 if int16(di16) != i16 { 336 t.Errorf("int16(di16) != i16") 337 } 338 if int8(di8) != i8 { 339 t.Errorf("int8(di8) != i8") 340 } 341 if uint64(su64) != u64 { 342 t.Errorf("uint64(su64) != u64") 343 } 344 if uint32(su32) != u32 { 345 t.Errorf("uint32(su32) != u32") 346 } 347 if uint16(su16) != u16 { 348 t.Errorf("uint16(su16) != u16") 349 } 350 if uint8(su8) != u8 { 351 t.Errorf("uint8(su8) != u8") 352 } 353 if int64(si64) != i64 { 354 t.Errorf("int64(si64) != i64") 355 } 356 if int32(si32) != i32 { 357 t.Errorf("int32(si32) != i32") 358 } 359 if int16(si16) != i16 { 360 t.Errorf("int16(si16) != i16") 361 } 362 if int8(si8) != i8 { 363 t.Errorf("int8(si8) != i8") 364 } 365 } 366 367 func TestFloat32StoreToLoadConstantFold(t *testing.T) { 368 // Test that math.Float32{,from}bits constant fold correctly. 369 // In particular we need to be careful that signaling NaN (sNaN) values 370 // are not converted to quiet NaN (qNaN) values during compilation. 371 // See issue #27193 for more information. 372 373 // TODO: this method for detecting 387 won't work if the compiler has been 374 // built using GOARCH=386 GO386=387 and either the target is a different 375 // architecture or the GO386=387 environment variable is not set when the 376 // test is run. 377 if runtime.GOARCH == "386" && os.Getenv("GO386") == "387" { 378 t.Skip("signaling NaNs are not propagated on 387 (issue #27516)") 379 } 380 381 // signaling NaNs 382 { 383 const nan = uint32(0x7f800001) // sNaN 384 if x := math.Float32bits(math.Float32frombits(nan)); x != nan { 385 t.Errorf("got %#x, want %#x", x, nan) 386 } 387 } 388 { 389 const nan = uint32(0x7fbfffff) // sNaN 390 if x := math.Float32bits(math.Float32frombits(nan)); x != nan { 391 t.Errorf("got %#x, want %#x", x, nan) 392 } 393 } 394 { 395 const nan = uint32(0xff800001) // sNaN 396 if x := math.Float32bits(math.Float32frombits(nan)); x != nan { 397 t.Errorf("got %#x, want %#x", x, nan) 398 } 399 } 400 { 401 const nan = uint32(0xffbfffff) // sNaN 402 if x := math.Float32bits(math.Float32frombits(nan)); x != nan { 403 t.Errorf("got %#x, want %#x", x, nan) 404 } 405 } 406 407 // quiet NaNs 408 { 409 const nan = uint32(0x7fc00000) // qNaN 410 if x := math.Float32bits(math.Float32frombits(nan)); x != nan { 411 t.Errorf("got %#x, want %#x", x, nan) 412 } 413 } 414 { 415 const nan = uint32(0x7fffffff) // qNaN 416 if x := math.Float32bits(math.Float32frombits(nan)); x != nan { 417 t.Errorf("got %#x, want %#x", x, nan) 418 } 419 } 420 { 421 const nan = uint32(0x8fc00000) // qNaN 422 if x := math.Float32bits(math.Float32frombits(nan)); x != nan { 423 t.Errorf("got %#x, want %#x", x, nan) 424 } 425 } 426 { 427 const nan = uint32(0x8fffffff) // qNaN 428 if x := math.Float32bits(math.Float32frombits(nan)); x != nan { 429 t.Errorf("got %#x, want %#x", x, nan) 430 } 431 } 432 433 // infinities 434 { 435 const inf = uint32(0x7f800000) // +∞ 436 if x := math.Float32bits(math.Float32frombits(inf)); x != inf { 437 t.Errorf("got %#x, want %#x", x, inf) 438 } 439 } 440 { 441 const negInf = uint32(0xff800000) // -∞ 442 if x := math.Float32bits(math.Float32frombits(negInf)); x != negInf { 443 t.Errorf("got %#x, want %#x", x, negInf) 444 } 445 } 446 447 // numbers 448 { 449 const zero = uint32(0) // +0.0 450 if x := math.Float32bits(math.Float32frombits(zero)); x != zero { 451 t.Errorf("got %#x, want %#x", x, zero) 452 } 453 } 454 { 455 const negZero = uint32(1 << 31) // -0.0 456 if x := math.Float32bits(math.Float32frombits(negZero)); x != negZero { 457 t.Errorf("got %#x, want %#x", x, negZero) 458 } 459 } 460 { 461 const one = uint32(0x3f800000) // 1.0 462 if x := math.Float32bits(math.Float32frombits(one)); x != one { 463 t.Errorf("got %#x, want %#x", x, one) 464 } 465 } 466 { 467 const negOne = uint32(0xbf800000) // -1.0 468 if x := math.Float32bits(math.Float32frombits(negOne)); x != negOne { 469 t.Errorf("got %#x, want %#x", x, negOne) 470 } 471 } 472 { 473 const frac = uint32(0x3fc00000) // +1.5 474 if x := math.Float32bits(math.Float32frombits(frac)); x != frac { 475 t.Errorf("got %#x, want %#x", x, frac) 476 } 477 } 478 { 479 const negFrac = uint32(0xbfc00000) // -1.5 480 if x := math.Float32bits(math.Float32frombits(negFrac)); x != negFrac { 481 t.Errorf("got %#x, want %#x", x, negFrac) 482 } 483 } 484 } 485 486 var sinkFloat float64 487 488 func BenchmarkMul2(b *testing.B) { 489 for i := 0; i < b.N; i++ { 490 var m float64 = 1 491 for j := 0; j < 500; j++ { 492 m *= 2 493 } 494 sinkFloat = m 495 } 496 } 497 func BenchmarkMulNeg2(b *testing.B) { 498 for i := 0; i < b.N; i++ { 499 var m float64 = 1 500 for j := 0; j < 500; j++ { 501 m *= -2 502 } 503 sinkFloat = m 504 } 505 }