github.com/corona10/go@v0.0.0-20180224231303-7a218942be57/src/cmd/compile/internal/gc/asm_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 "bytes" 9 "fmt" 10 "internal/testenv" 11 "io/ioutil" 12 "os" 13 "os/exec" 14 "path/filepath" 15 "regexp" 16 "runtime" 17 "strings" 18 "testing" 19 ) 20 21 // This file contains code generation tests. 22 // 23 // Each test is defined in a variable of type asmTest. Tests are 24 // architecture-specific, and they are grouped in arrays of tests, one 25 // for each architecture. 26 // 27 // Each asmTest consists of a function to compile, an array of 28 // positive regexps that must match the generated assembly and 29 // an array of negative regexps that must not match generated assembly. 30 // For example, the following amd64 test 31 // 32 // { 33 // fn: ` 34 // func f0(x int) int { 35 // return x * 64 36 // } 37 // `, 38 // pos: []string{"\tSHLQ\t[$]6,"}, 39 // neg: []string{"MULQ"} 40 // } 41 // 42 // verifies that the code the compiler generates for a multiplication 43 // by 64 contains a 'SHLQ' instruction and does not contain a MULQ. 44 // 45 // Since all the tests for a given architecture are dumped in the same 46 // file, the function names must be unique. As a workaround for this 47 // restriction, the test harness supports the use of a '$' placeholder 48 // for function names. The func f0 above can be also written as 49 // 50 // { 51 // fn: ` 52 // func $(x int) int { 53 // return x * 64 54 // } 55 // `, 56 // pos: []string{"\tSHLQ\t[$]6,"}, 57 // neg: []string{"MULQ"} 58 // } 59 // 60 // Each '$'-function will be given a unique name of form f<N>_<arch>, 61 // where <N> is the test index in the test array, and <arch> is the 62 // test's architecture. 63 // 64 // It is allowed to mix named and unnamed functions in the same test 65 // array; the named functions will retain their original names. 66 67 // TestAssembly checks to make sure the assembly generated for 68 // functions contains certain expected instructions. 69 func TestAssembly(t *testing.T) { 70 testenv.MustHaveGoBuild(t) 71 if runtime.GOOS == "windows" { 72 // TODO: remove if we can get "go tool compile -S" to work on windows. 73 t.Skipf("skipping test: recursive windows compile not working") 74 } 75 dir, err := ioutil.TempDir("", "TestAssembly") 76 if err != nil { 77 t.Fatalf("could not create directory: %v", err) 78 } 79 defer os.RemoveAll(dir) 80 81 nameRegexp := regexp.MustCompile("func \\w+") 82 t.Run("platform", func(t *testing.T) { 83 for _, ats := range allAsmTests { 84 ats := ats 85 t.Run(ats.os+"/"+ats.arch, func(tt *testing.T) { 86 tt.Parallel() 87 88 asm := ats.compileToAsm(tt, dir) 89 90 for i, at := range ats.tests { 91 var funcName string 92 if strings.Contains(at.fn, "func $") { 93 funcName = fmt.Sprintf("f%d_%s", i, ats.arch) 94 } else { 95 funcName = nameRegexp.FindString(at.fn)[len("func "):] 96 } 97 fa := funcAsm(tt, asm, funcName) 98 if fa != "" { 99 at.verifyAsm(tt, fa) 100 } 101 } 102 }) 103 } 104 }) 105 } 106 107 var nextTextRegexp = regexp.MustCompile(`\n\S`) 108 109 // funcAsm returns the assembly listing for the given function name. 110 func funcAsm(t *testing.T, asm string, funcName string) string { 111 if i := strings.Index(asm, fmt.Sprintf("TEXT\t\"\".%s(SB)", funcName)); i >= 0 { 112 asm = asm[i:] 113 } else { 114 t.Errorf("could not find assembly for function %v", funcName) 115 return "" 116 } 117 118 // Find the next line that doesn't begin with whitespace. 119 loc := nextTextRegexp.FindStringIndex(asm) 120 if loc != nil { 121 asm = asm[:loc[0]] 122 } 123 124 return asm 125 } 126 127 type asmTest struct { 128 // function to compile 129 fn string 130 // regular expressions that must match the generated assembly 131 pos []string 132 // regular expressions that must not match the generated assembly 133 neg []string 134 } 135 136 func (at asmTest) verifyAsm(t *testing.T, fa string) { 137 for _, r := range at.pos { 138 if b, err := regexp.MatchString(r, fa); !b || err != nil { 139 t.Errorf("expected:%s\ngo:%s\nasm:%s\n", r, at.fn, fa) 140 } 141 } 142 for _, r := range at.neg { 143 if b, err := regexp.MatchString(r, fa); b || err != nil { 144 t.Errorf("not expected:%s\ngo:%s\nasm:%s\n", r, at.fn, fa) 145 } 146 } 147 } 148 149 type asmTests struct { 150 arch string 151 os string 152 imports []string 153 tests []*asmTest 154 } 155 156 func (ats *asmTests) generateCode() []byte { 157 var buf bytes.Buffer 158 fmt.Fprintln(&buf, "package main") 159 for _, s := range ats.imports { 160 fmt.Fprintf(&buf, "import %q\n", s) 161 } 162 163 for i, t := range ats.tests { 164 function := strings.Replace(t.fn, "func $", fmt.Sprintf("func f%d_%s", i, ats.arch), 1) 165 fmt.Fprintln(&buf, function) 166 } 167 168 return buf.Bytes() 169 } 170 171 // compile compiles the package pkg for architecture arch and 172 // returns the generated assembly. dir is a scratch directory. 173 func (ats *asmTests) compileToAsm(t *testing.T, dir string) string { 174 // create test directory 175 testDir := filepath.Join(dir, fmt.Sprintf("%s_%s", ats.arch, ats.os)) 176 err := os.Mkdir(testDir, 0700) 177 if err != nil { 178 t.Fatalf("could not create directory: %v", err) 179 } 180 181 // Create source. 182 src := filepath.Join(testDir, "test.go") 183 err = ioutil.WriteFile(src, ats.generateCode(), 0600) 184 if err != nil { 185 t.Fatalf("error writing code: %v", err) 186 } 187 188 // First, install any dependencies we need. This builds the required export data 189 // for any packages that are imported. 190 for _, i := range ats.imports { 191 out := filepath.Join(testDir, i+".a") 192 193 if s := ats.runGo(t, "build", "-o", out, "-gcflags=-dolinkobj=false", i); s != "" { 194 t.Fatalf("Stdout = %s\nWant empty", s) 195 } 196 } 197 198 // Now, compile the individual file for which we want to see the generated assembly. 199 asm := ats.runGo(t, "tool", "compile", "-I", testDir, "-S", "-o", filepath.Join(testDir, "out.o"), src) 200 return asm 201 } 202 203 // runGo runs go command with the given args and returns stdout string. 204 // go is run with GOARCH and GOOS set as ats.arch and ats.os respectively 205 func (ats *asmTests) runGo(t *testing.T, args ...string) string { 206 var stdout, stderr bytes.Buffer 207 cmd := exec.Command(testenv.GoToolPath(t), args...) 208 cmd.Env = append(os.Environ(), "GOARCH="+ats.arch, "GOOS="+ats.os) 209 cmd.Stdout = &stdout 210 cmd.Stderr = &stderr 211 212 if err := cmd.Run(); err != nil { 213 t.Fatalf("error running cmd: %v\nstdout:\n%sstderr:\n%s\n", err, stdout.String(), stderr.String()) 214 } 215 216 if s := stderr.String(); s != "" { 217 t.Fatalf("Stderr = %s\nWant empty", s) 218 } 219 220 return stdout.String() 221 } 222 223 var allAsmTests = []*asmTests{ 224 { 225 arch: "amd64", 226 os: "linux", 227 imports: []string{"encoding/binary", "math", "math/bits", "unsafe", "runtime"}, 228 tests: linuxAMD64Tests, 229 }, 230 { 231 arch: "386", 232 os: "linux", 233 imports: []string{"encoding/binary", "math"}, 234 tests: linux386Tests, 235 }, 236 { 237 arch: "s390x", 238 os: "linux", 239 imports: []string{"encoding/binary", "math", "math/bits"}, 240 tests: linuxS390XTests, 241 }, 242 { 243 arch: "arm", 244 os: "linux", 245 imports: []string{"math/bits", "runtime"}, 246 tests: linuxARMTests, 247 }, 248 { 249 arch: "arm64", 250 os: "linux", 251 imports: []string{"encoding/binary", "math", "math/bits"}, 252 tests: linuxARM64Tests, 253 }, 254 { 255 arch: "mips", 256 os: "linux", 257 imports: []string{"math/bits", "math"}, 258 tests: linuxMIPSTests, 259 }, 260 { 261 arch: "mips64", 262 os: "linux", 263 imports: []string{"math"}, 264 tests: linuxMIPS64Tests, 265 }, 266 { 267 arch: "ppc64le", 268 os: "linux", 269 imports: []string{"encoding/binary", "math", "math/bits"}, 270 tests: linuxPPC64LETests, 271 }, 272 { 273 arch: "amd64", 274 os: "plan9", 275 tests: plan9AMD64Tests, 276 }, 277 } 278 279 var linuxAMD64Tests = []*asmTest{ 280 // multiplication by powers of two 281 { 282 fn: ` 283 func $(n int) int { 284 return n * 64 285 } 286 `, 287 pos: []string{"\tSHLQ\t\\$6,"}, 288 neg: []string{"IMULQ"}, 289 }, 290 { 291 fn: ` 292 func $(n int) int { 293 return -128*n 294 } 295 `, 296 pos: []string{"SHLQ"}, 297 neg: []string{"IMULQ"}, 298 }, 299 300 { 301 fn: ` 302 func $(x int) int { 303 return x * 96 304 } 305 `, 306 pos: []string{"\tSHLQ\t\\$5,", "\tLEAQ\t\\(.*\\)\\(.*\\*2\\),"}, 307 }, 308 // Load-combining tests. 309 { 310 fn: ` 311 func f2(b []byte) uint64 { 312 return binary.LittleEndian.Uint64(b) 313 } 314 `, 315 pos: []string{"\tMOVQ\t\\(.*\\),"}, 316 }, 317 { 318 fn: ` 319 func f3(b []byte, i int) uint64 { 320 return binary.LittleEndian.Uint64(b[i:]) 321 } 322 `, 323 pos: []string{"\tMOVQ\t\\(.*\\)\\(.*\\*1\\),"}, 324 }, 325 { 326 fn: ` 327 func f4(b []byte) uint32 { 328 return binary.LittleEndian.Uint32(b) 329 } 330 `, 331 pos: []string{"\tMOVL\t\\(.*\\),"}, 332 }, 333 { 334 fn: ` 335 func f5(b []byte, i int) uint32 { 336 return binary.LittleEndian.Uint32(b[i:]) 337 } 338 `, 339 pos: []string{"\tMOVL\t\\(.*\\)\\(.*\\*1\\),"}, 340 }, 341 { 342 fn: ` 343 func f6(b []byte) uint64 { 344 return binary.BigEndian.Uint64(b) 345 } 346 `, 347 pos: []string{"\tBSWAPQ\t"}, 348 }, 349 { 350 fn: ` 351 func f7(b []byte, i int) uint64 { 352 return binary.BigEndian.Uint64(b[i:]) 353 } 354 `, 355 pos: []string{"\tBSWAPQ\t"}, 356 }, 357 { 358 fn: ` 359 func f8(b []byte, v uint64) { 360 binary.BigEndian.PutUint64(b, v) 361 } 362 `, 363 pos: []string{"\tBSWAPQ\t"}, 364 }, 365 { 366 fn: ` 367 func f9(b []byte, i int, v uint64) { 368 binary.BigEndian.PutUint64(b[i:], v) 369 } 370 `, 371 pos: []string{"\tBSWAPQ\t"}, 372 }, 373 { 374 fn: ` 375 func f10(b []byte) uint32 { 376 return binary.BigEndian.Uint32(b) 377 } 378 `, 379 pos: []string{"\tBSWAPL\t"}, 380 }, 381 { 382 fn: ` 383 func f11(b []byte, i int) uint32 { 384 return binary.BigEndian.Uint32(b[i:]) 385 } 386 `, 387 pos: []string{"\tBSWAPL\t"}, 388 }, 389 { 390 fn: ` 391 func f12(b []byte, v uint32) { 392 binary.BigEndian.PutUint32(b, v) 393 } 394 `, 395 pos: []string{"\tBSWAPL\t"}, 396 }, 397 { 398 fn: ` 399 func f13(b []byte, i int, v uint32) { 400 binary.BigEndian.PutUint32(b[i:], v) 401 } 402 `, 403 pos: []string{"\tBSWAPL\t"}, 404 }, 405 { 406 fn: ` 407 func f14(b []byte) uint16 { 408 return binary.BigEndian.Uint16(b) 409 } 410 `, 411 pos: []string{"\tROLW\t\\$8,"}, 412 }, 413 { 414 fn: ` 415 func f15(b []byte, i int) uint16 { 416 return binary.BigEndian.Uint16(b[i:]) 417 } 418 `, 419 pos: []string{"\tROLW\t\\$8,"}, 420 }, 421 { 422 fn: ` 423 func f16(b []byte, v uint16) { 424 binary.BigEndian.PutUint16(b, v) 425 } 426 `, 427 pos: []string{"\tROLW\t\\$8,"}, 428 }, 429 { 430 fn: ` 431 func f17(b []byte, i int, v uint16) { 432 binary.BigEndian.PutUint16(b[i:], v) 433 } 434 `, 435 pos: []string{"\tROLW\t\\$8,"}, 436 }, 437 // Structure zeroing. See issue #18370. 438 { 439 fn: ` 440 type T1 struct { 441 a, b, c int 442 } 443 func $(t *T1) { 444 *t = T1{} 445 } 446 `, 447 pos: []string{"\tXORPS\tX., X", "\tMOVUPS\tX., \\(.*\\)", "\tMOVQ\t\\$0, 16\\(.*\\)"}, 448 }, 449 // SSA-able composite literal initialization. Issue 18872. 450 { 451 fn: ` 452 type T18872 struct { 453 a, b, c, d int 454 } 455 456 func f18872(p *T18872) { 457 *p = T18872{1, 2, 3, 4} 458 } 459 `, 460 pos: []string{"\tMOVQ\t[$]1", "\tMOVQ\t[$]2", "\tMOVQ\t[$]3", "\tMOVQ\t[$]4"}, 461 }, 462 // Also test struct containing pointers (this was special because of write barriers). 463 { 464 fn: ` 465 type T2 struct { 466 a, b, c *int 467 } 468 func f19(t *T2) { 469 *t = T2{} 470 } 471 `, 472 pos: []string{"\tXORPS\tX., X", "\tMOVUPS\tX., \\(.*\\)", "\tMOVQ\t\\$0, 16\\(.*\\)", "\tCALL\truntime\\.gcWriteBarrier\\(SB\\)"}, 473 }, 474 // Rotate tests 475 { 476 fn: ` 477 func f20(x uint64) uint64 { 478 return x<<7 | x>>57 479 } 480 `, 481 pos: []string{"\tROLQ\t[$]7,"}, 482 }, 483 { 484 fn: ` 485 func f21(x uint64) uint64 { 486 return x<<7 + x>>57 487 } 488 `, 489 pos: []string{"\tROLQ\t[$]7,"}, 490 }, 491 { 492 fn: ` 493 func f22(x uint64) uint64 { 494 return x<<7 ^ x>>57 495 } 496 `, 497 pos: []string{"\tROLQ\t[$]7,"}, 498 }, 499 { 500 fn: ` 501 func f23(x uint32) uint32 { 502 return x<<7 + x>>25 503 } 504 `, 505 pos: []string{"\tROLL\t[$]7,"}, 506 }, 507 { 508 fn: ` 509 func f24(x uint32) uint32 { 510 return x<<7 | x>>25 511 } 512 `, 513 pos: []string{"\tROLL\t[$]7,"}, 514 }, 515 { 516 fn: ` 517 func f25(x uint32) uint32 { 518 return x<<7 ^ x>>25 519 } 520 `, 521 pos: []string{"\tROLL\t[$]7,"}, 522 }, 523 { 524 fn: ` 525 func f26(x uint16) uint16 { 526 return x<<7 + x>>9 527 } 528 `, 529 pos: []string{"\tROLW\t[$]7,"}, 530 }, 531 { 532 fn: ` 533 func f27(x uint16) uint16 { 534 return x<<7 | x>>9 535 } 536 `, 537 pos: []string{"\tROLW\t[$]7,"}, 538 }, 539 { 540 fn: ` 541 func f28(x uint16) uint16 { 542 return x<<7 ^ x>>9 543 } 544 `, 545 pos: []string{"\tROLW\t[$]7,"}, 546 }, 547 { 548 fn: ` 549 func f29(x uint8) uint8 { 550 return x<<7 + x>>1 551 } 552 `, 553 pos: []string{"\tROLB\t[$]7,"}, 554 }, 555 { 556 fn: ` 557 func f30(x uint8) uint8 { 558 return x<<7 | x>>1 559 } 560 `, 561 pos: []string{"\tROLB\t[$]7,"}, 562 }, 563 { 564 fn: ` 565 func f31(x uint8) uint8 { 566 return x<<7 ^ x>>1 567 } 568 `, 569 pos: []string{"\tROLB\t[$]7,"}, 570 }, 571 // Rotate after inlining (see issue 18254). 572 { 573 fn: ` 574 func f32(x uint32) uint32 { 575 return g(x, 7) 576 } 577 func g(x uint32, k uint) uint32 { 578 return x<<k | x>>(32-k) 579 } 580 `, 581 pos: []string{"\tROLL\t[$]7,"}, 582 }, 583 { 584 fn: ` 585 func f33(m map[int]int) int { 586 return m[5] 587 } 588 `, 589 pos: []string{"\tMOVQ\t[$]5,"}, 590 }, 591 // Direct use of constants in fast map access calls. Issue 19015. 592 { 593 fn: ` 594 func f34(m map[int]int) bool { 595 _, ok := m[5] 596 return ok 597 } 598 `, 599 pos: []string{"\tMOVQ\t[$]5,"}, 600 }, 601 { 602 fn: ` 603 func f35(m map[string]int) int { 604 return m["abc"] 605 } 606 `, 607 pos: []string{"\"abc\""}, 608 }, 609 { 610 fn: ` 611 func f36(m map[string]int) bool { 612 _, ok := m["abc"] 613 return ok 614 } 615 `, 616 pos: []string{"\"abc\""}, 617 }, 618 // Bit test ops on amd64, issue 18943. 619 { 620 fn: ` 621 func f37(a, b uint64) int { 622 if a&(1<<(b&63)) != 0 { 623 return 1 624 } 625 return -1 626 } 627 `, 628 pos: []string{"\tBTQ\t"}, 629 }, 630 { 631 fn: ` 632 func f38(a, b uint64) bool { 633 return a&(1<<(b&63)) != 0 634 } 635 `, 636 pos: []string{"\tBTQ\t"}, 637 }, 638 { 639 fn: ` 640 func f39(a uint64) int { 641 if a&(1<<60) != 0 { 642 return 1 643 } 644 return -1 645 } 646 `, 647 pos: []string{"\tBTQ\t\\$60"}, 648 }, 649 { 650 fn: ` 651 func f40(a uint64) bool { 652 return a&(1<<60) != 0 653 } 654 `, 655 pos: []string{"\tBTQ\t\\$60"}, 656 }, 657 // Intrinsic tests for math/bits 658 { 659 fn: ` 660 func f41(a uint64) int { 661 return bits.TrailingZeros64(a) 662 } 663 `, 664 pos: []string{"\tBSFQ\t", "\tMOVL\t\\$64,", "\tCMOVQEQ\t"}, 665 }, 666 { 667 fn: ` 668 func f42(a uint32) int { 669 return bits.TrailingZeros32(a) 670 } 671 `, 672 pos: []string{"\tBSFQ\t", "\tORQ\t[^$]", "\tMOVQ\t\\$4294967296,"}, 673 }, 674 { 675 fn: ` 676 func f43(a uint16) int { 677 return bits.TrailingZeros16(a) 678 } 679 `, 680 pos: []string{"\tBSFQ\t", "\tORQ\t\\$65536,"}, 681 }, 682 { 683 fn: ` 684 func f44(a uint8) int { 685 return bits.TrailingZeros8(a) 686 } 687 `, 688 pos: []string{"\tBSFQ\t", "\tORQ\t\\$256,"}, 689 }, 690 { 691 fn: ` 692 func f45(a uint64) uint64 { 693 return bits.ReverseBytes64(a) 694 } 695 `, 696 pos: []string{"\tBSWAPQ\t"}, 697 }, 698 { 699 fn: ` 700 func f46(a uint32) uint32 { 701 return bits.ReverseBytes32(a) 702 } 703 `, 704 pos: []string{"\tBSWAPL\t"}, 705 }, 706 { 707 fn: ` 708 func f47(a uint16) uint16 { 709 return bits.ReverseBytes16(a) 710 } 711 `, 712 pos: []string{"\tROLW\t\\$8,"}, 713 }, 714 { 715 fn: ` 716 func f48(a uint64) int { 717 return bits.Len64(a) 718 } 719 `, 720 pos: []string{"\tBSRQ\t"}, 721 }, 722 { 723 fn: ` 724 func f49(a uint32) int { 725 return bits.Len32(a) 726 } 727 `, 728 pos: []string{"\tBSRQ\t"}, 729 }, 730 { 731 fn: ` 732 func f50(a uint16) int { 733 return bits.Len16(a) 734 } 735 `, 736 pos: []string{"\tBSRQ\t"}, 737 }, 738 /* see ssa.go 739 { 740 fn:` 741 func f51(a uint8) int { 742 return bits.Len8(a) 743 } 744 `, 745 pos:[]string{"\tBSRQ\t"}, 746 }, 747 */ 748 { 749 fn: ` 750 func f52(a uint) int { 751 return bits.Len(a) 752 } 753 `, 754 pos: []string{"\tBSRQ\t"}, 755 }, 756 { 757 fn: ` 758 func f53(a uint64) int { 759 return bits.LeadingZeros64(a) 760 } 761 `, 762 pos: []string{"\tBSRQ\t"}, 763 }, 764 { 765 fn: ` 766 func f54(a uint32) int { 767 return bits.LeadingZeros32(a) 768 } 769 `, 770 pos: []string{"\tBSRQ\t"}, 771 }, 772 { 773 fn: ` 774 func f55(a uint16) int { 775 return bits.LeadingZeros16(a) 776 } 777 `, 778 pos: []string{"\tBSRQ\t"}, 779 }, 780 /* see ssa.go 781 { 782 fn:` 783 func f56(a uint8) int { 784 return bits.LeadingZeros8(a) 785 } 786 `, 787 pos:[]string{"\tBSRQ\t"}, 788 }, 789 */ 790 { 791 fn: ` 792 func f57(a uint) int { 793 return bits.LeadingZeros(a) 794 } 795 `, 796 pos: []string{"\tBSRQ\t"}, 797 }, 798 { 799 fn: ` 800 func pop1(x uint64) int { 801 return bits.OnesCount64(x) 802 }`, 803 pos: []string{"\tPOPCNTQ\t", "support_popcnt"}, 804 }, 805 { 806 fn: ` 807 func pop2(x uint32) int { 808 return bits.OnesCount32(x) 809 }`, 810 pos: []string{"\tPOPCNTL\t", "support_popcnt"}, 811 }, 812 { 813 fn: ` 814 func pop3(x uint16) int { 815 return bits.OnesCount16(x) 816 }`, 817 pos: []string{"\tPOPCNTL\t", "support_popcnt"}, 818 }, 819 { 820 fn: ` 821 func pop4(x uint) int { 822 return bits.OnesCount(x) 823 }`, 824 pos: []string{"\tPOPCNTQ\t", "support_popcnt"}, 825 }, 826 { 827 fn: ` 828 func $(x float64) float64 { 829 return math.Sqrt(x) 830 } 831 `, 832 pos: []string{"SQRTSD"}, 833 }, 834 // multiplication merging tests 835 { 836 fn: ` 837 func mul1(n int) int { 838 return 15*n + 31*n 839 }`, 840 pos: []string{"\tIMULQ\t[$]46"}, // 46*n 841 }, 842 { 843 fn: ` 844 func mul2(n int) int { 845 return 5*n + 7*(n+1) + 11*(n+2) 846 }`, 847 pos: []string{"\tIMULQ\t[$]23", "\tADDQ\t[$]29"}, // 23*n + 29 848 }, 849 { 850 fn: ` 851 func mul3(a, n int) int { 852 return a*n + 19*n 853 }`, 854 pos: []string{"\tADDQ\t[$]19", "\tIMULQ"}, // (a+19)*n 855 }, 856 { 857 fn: ` 858 func mul4(n int) int { 859 return 23*n - 9*n 860 }`, 861 pos: []string{"\tIMULQ\t[$]14"}, // 14*n 862 }, 863 { 864 fn: ` 865 func mul5(a, n int) int { 866 return a*n - 19*n 867 }`, 868 pos: []string{"\tADDQ\t[$]-19", "\tIMULQ"}, // (a-19)*n 869 }, 870 871 // see issue 19595. 872 // We want to merge load+op in f58, but not in f59. 873 { 874 fn: ` 875 func f58(p, q *int) { 876 x := *p 877 *q += x 878 }`, 879 pos: []string{"\tADDQ\t\\("}, 880 }, 881 { 882 fn: ` 883 func f59(p, q *int) { 884 x := *p 885 for i := 0; i < 10; i++ { 886 *q += x 887 } 888 }`, 889 pos: []string{"\tADDQ\t[A-Z]"}, 890 }, 891 // Floating-point strength reduction 892 { 893 fn: ` 894 func f60(f float64) float64 { 895 return f * 2.0 896 }`, 897 pos: []string{"\tADDSD\t"}, 898 }, 899 { 900 fn: ` 901 func f62(f float64) float64 { 902 return f / 16.0 903 }`, 904 pos: []string{"\tMULSD\t"}, 905 }, 906 { 907 fn: ` 908 func f63(f float64) float64 { 909 return f / 0.125 910 }`, 911 pos: []string{"\tMULSD\t"}, 912 }, 913 { 914 fn: ` 915 func f64(f float64) float64 { 916 return f / 0.5 917 }`, 918 pos: []string{"\tADDSD\t"}, 919 }, 920 // Check that compare to constant string uses 2/4/8 byte compares 921 { 922 fn: ` 923 func f65(a string) bool { 924 return a == "xx" 925 }`, 926 pos: []string{"\tCMPW\t[A-Z]"}, 927 }, 928 { 929 fn: ` 930 func f66(a string) bool { 931 return a == "xxxx" 932 }`, 933 pos: []string{"\tCMPL\t[A-Z]"}, 934 }, 935 { 936 fn: ` 937 func f67(a string) bool { 938 return a == "xxxxxxxx" 939 }`, 940 pos: []string{"\tCMPQ\t[A-Z]"}, 941 }, 942 // Non-constant rotate 943 { 944 fn: `func rot64l(x uint64, y int) uint64 { 945 z := uint(y & 63) 946 return x << z | x >> (64-z) 947 }`, 948 pos: []string{"\tROLQ\t"}, 949 }, 950 { 951 fn: `func rot64r(x uint64, y int) uint64 { 952 z := uint(y & 63) 953 return x >> z | x << (64-z) 954 }`, 955 pos: []string{"\tRORQ\t"}, 956 }, 957 { 958 fn: `func rot32l(x uint32, y int) uint32 { 959 z := uint(y & 31) 960 return x << z | x >> (32-z) 961 }`, 962 pos: []string{"\tROLL\t"}, 963 }, 964 { 965 fn: `func rot32r(x uint32, y int) uint32 { 966 z := uint(y & 31) 967 return x >> z | x << (32-z) 968 }`, 969 pos: []string{"\tRORL\t"}, 970 }, 971 { 972 fn: `func rot16l(x uint16, y int) uint16 { 973 z := uint(y & 15) 974 return x << z | x >> (16-z) 975 }`, 976 pos: []string{"\tROLW\t"}, 977 }, 978 { 979 fn: `func rot16r(x uint16, y int) uint16 { 980 z := uint(y & 15) 981 return x >> z | x << (16-z) 982 }`, 983 pos: []string{"\tRORW\t"}, 984 }, 985 { 986 fn: `func rot8l(x uint8, y int) uint8 { 987 z := uint(y & 7) 988 return x << z | x >> (8-z) 989 }`, 990 pos: []string{"\tROLB\t"}, 991 }, 992 { 993 fn: `func rot8r(x uint8, y int) uint8 { 994 z := uint(y & 7) 995 return x >> z | x << (8-z) 996 }`, 997 pos: []string{"\tRORB\t"}, 998 }, 999 // Check that array compare uses 2/4/8 byte compares 1000 { 1001 fn: ` 1002 func f68(a,b [2]byte) bool { 1003 return a == b 1004 }`, 1005 pos: []string{"\tCMPW\t[A-Z]"}, 1006 }, 1007 { 1008 fn: ` 1009 func f69(a,b [3]uint16) bool { 1010 return a == b 1011 }`, 1012 pos: []string{"\tCMPL\t[A-Z]"}, 1013 }, 1014 { 1015 fn: ` 1016 func $(a,b [3]int16) bool { 1017 return a == b 1018 }`, 1019 pos: []string{"\tCMPL\t[A-Z]"}, 1020 }, 1021 { 1022 fn: ` 1023 func $(a,b [12]int8) bool { 1024 return a == b 1025 }`, 1026 pos: []string{"\tCMPQ\t[A-Z]", "\tCMPL\t[A-Z]"}, 1027 }, 1028 { 1029 fn: ` 1030 func f70(a,b [15]byte) bool { 1031 return a == b 1032 }`, 1033 pos: []string{"\tCMPQ\t[A-Z]"}, 1034 }, 1035 { 1036 fn: ` 1037 func f71(a,b unsafe.Pointer) bool { // This was a TODO in mapaccess1_faststr 1038 return *((*[4]byte)(a)) != *((*[4]byte)(b)) 1039 }`, 1040 pos: []string{"\tCMPL\t[A-Z]"}, 1041 }, 1042 { 1043 // make sure assembly output has matching offset and base register. 1044 fn: ` 1045 func f72(a, b int) int { 1046 runtime.GC() // use some frame 1047 return b 1048 } 1049 `, 1050 pos: []string{"b\\+24\\(SP\\)"}, 1051 }, 1052 { 1053 // check load combining 1054 fn: ` 1055 func f73(a, b byte) (byte,byte) { 1056 return f73(f73(a,b)) 1057 } 1058 `, 1059 pos: []string{"\tMOVW\t"}, 1060 }, 1061 { 1062 fn: ` 1063 func f74(a, b uint16) (uint16,uint16) { 1064 return f74(f74(a,b)) 1065 } 1066 `, 1067 pos: []string{"\tMOVL\t"}, 1068 }, 1069 { 1070 fn: ` 1071 func f75(a, b uint32) (uint32,uint32) { 1072 return f75(f75(a,b)) 1073 } 1074 `, 1075 pos: []string{"\tMOVQ\t"}, 1076 }, 1077 // Make sure we don't put pointers in SSE registers across safe points. 1078 { 1079 fn: ` 1080 func $(p, q *[2]*int) { 1081 a, b := p[0], p[1] 1082 runtime.GC() 1083 q[0], q[1] = a, b 1084 } 1085 `, 1086 neg: []string{"MOVUPS"}, 1087 }, 1088 { 1089 // check that stack store is optimized away 1090 fn: ` 1091 func $() int { 1092 var x int 1093 return *(&x) 1094 } 1095 `, 1096 pos: []string{"TEXT\t.*, [$]0-8"}, 1097 }, 1098 // math.Abs using integer registers 1099 { 1100 fn: ` 1101 func $(x float64) float64 { 1102 return math.Abs(x) 1103 } 1104 `, 1105 pos: []string{"\tSHLQ\t[$]1,", "\tSHRQ\t[$]1,"}, 1106 }, 1107 // math.Copysign using integer registers 1108 { 1109 fn: ` 1110 func $(x, y float64) float64 { 1111 return math.Copysign(x, y) 1112 } 1113 `, 1114 pos: []string{"\tSHLQ\t[$]1,", "\tSHRQ\t[$]1,", "\tSHRQ\t[$]63,", "\tSHLQ\t[$]63,", "\tORQ\t"}, 1115 }, 1116 // int <-> fp moves 1117 { 1118 fn: ` 1119 func $(x float64) uint64 { 1120 return math.Float64bits(x+1) + 1 1121 } 1122 `, 1123 pos: []string{"\tMOVQ\tX.*, [^X].*"}, 1124 }, 1125 { 1126 fn: ` 1127 func $(x float32) uint32 { 1128 return math.Float32bits(x+1) + 1 1129 } 1130 `, 1131 pos: []string{"\tMOVL\tX.*, [^X].*"}, 1132 }, 1133 { 1134 fn: ` 1135 func $(x uint64) float64 { 1136 return math.Float64frombits(x+1) + 1 1137 } 1138 `, 1139 pos: []string{"\tMOVQ\t[^X].*, X.*"}, 1140 }, 1141 { 1142 fn: ` 1143 func $(x uint32) float32 { 1144 return math.Float32frombits(x+1) + 1 1145 } 1146 `, 1147 pos: []string{"\tMOVL\t[^X].*, X.*"}, 1148 }, 1149 { 1150 fn: ` 1151 func $(x uint32) bool { 1152 return x > 4 1153 } 1154 `, 1155 pos: []string{"\tSETHI\t.*\\(SP\\)"}, 1156 }, 1157 // Check that len() and cap() div by a constant power of two 1158 // are compiled into SHRQ. 1159 { 1160 fn: ` 1161 func $(a []int) int { 1162 return len(a) / 1024 1163 } 1164 `, 1165 pos: []string{"\tSHRQ\t\\$10,"}, 1166 }, 1167 { 1168 fn: ` 1169 func $(s string) int { 1170 return len(s) / (4097 >> 1) 1171 } 1172 `, 1173 pos: []string{"\tSHRQ\t\\$11,"}, 1174 }, 1175 { 1176 fn: ` 1177 func $(a []int) int { 1178 return cap(a) / ((1 << 11) + 2048) 1179 } 1180 `, 1181 pos: []string{"\tSHRQ\t\\$12,"}, 1182 }, 1183 // Check that len() and cap() mod by a constant power of two 1184 // are compiled into ANDQ. 1185 { 1186 fn: ` 1187 func $(a []int) int { 1188 return len(a) % 1024 1189 } 1190 `, 1191 pos: []string{"\tANDQ\t\\$1023,"}, 1192 }, 1193 { 1194 fn: ` 1195 func $(s string) int { 1196 return len(s) % (4097 >> 1) 1197 } 1198 `, 1199 pos: []string{"\tANDQ\t\\$2047,"}, 1200 }, 1201 { 1202 fn: ` 1203 func $(a []int) int { 1204 return cap(a) % ((1 << 11) + 2048) 1205 } 1206 `, 1207 pos: []string{"\tANDQ\t\\$4095,"}, 1208 }, 1209 { 1210 // Test that small memmove was replaced with direct movs 1211 fn: ` 1212 func $() { 1213 x := [...]byte{1, 2, 3, 4, 5, 6, 7} 1214 copy(x[1:], x[:]) 1215 } 1216 `, 1217 neg: []string{"memmove"}, 1218 }, 1219 { 1220 // Same as above but with different size 1221 fn: ` 1222 func $() { 1223 x := [...]byte{1, 2, 3, 4} 1224 copy(x[1:], x[:]) 1225 } 1226 `, 1227 neg: []string{"memmove"}, 1228 }, 1229 { 1230 // Same as above but with different size 1231 fn: ` 1232 func $() { 1233 x := [...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} 1234 copy(x[1:], x[:]) 1235 } 1236 `, 1237 neg: []string{"memmove"}, 1238 }, 1239 // Nil checks before calling interface methods 1240 { 1241 fn: ` 1242 type I interface { 1243 foo000() 1244 foo001() 1245 foo002() 1246 foo003() 1247 foo004() 1248 foo005() 1249 foo006() 1250 foo007() 1251 foo008() 1252 foo009() 1253 foo010() 1254 foo011() 1255 foo012() 1256 foo013() 1257 foo014() 1258 foo015() 1259 foo016() 1260 foo017() 1261 foo018() 1262 foo019() 1263 foo020() 1264 foo021() 1265 foo022() 1266 foo023() 1267 foo024() 1268 foo025() 1269 foo026() 1270 foo027() 1271 foo028() 1272 foo029() 1273 foo030() 1274 foo031() 1275 foo032() 1276 foo033() 1277 foo034() 1278 foo035() 1279 foo036() 1280 foo037() 1281 foo038() 1282 foo039() 1283 foo040() 1284 foo041() 1285 foo042() 1286 foo043() 1287 foo044() 1288 foo045() 1289 foo046() 1290 foo047() 1291 foo048() 1292 foo049() 1293 foo050() 1294 foo051() 1295 foo052() 1296 foo053() 1297 foo054() 1298 foo055() 1299 foo056() 1300 foo057() 1301 foo058() 1302 foo059() 1303 foo060() 1304 foo061() 1305 foo062() 1306 foo063() 1307 foo064() 1308 foo065() 1309 foo066() 1310 foo067() 1311 foo068() 1312 foo069() 1313 foo070() 1314 foo071() 1315 foo072() 1316 foo073() 1317 foo074() 1318 foo075() 1319 foo076() 1320 foo077() 1321 foo078() 1322 foo079() 1323 foo080() 1324 foo081() 1325 foo082() 1326 foo083() 1327 foo084() 1328 foo085() 1329 foo086() 1330 foo087() 1331 foo088() 1332 foo089() 1333 foo090() 1334 foo091() 1335 foo092() 1336 foo093() 1337 foo094() 1338 foo095() 1339 foo096() 1340 foo097() 1341 foo098() 1342 foo099() 1343 foo100() 1344 foo101() 1345 foo102() 1346 foo103() 1347 foo104() 1348 foo105() 1349 foo106() 1350 foo107() 1351 foo108() 1352 foo109() 1353 foo110() 1354 foo111() 1355 foo112() 1356 foo113() 1357 foo114() 1358 foo115() 1359 foo116() 1360 foo117() 1361 foo118() 1362 foo119() 1363 foo120() 1364 foo121() 1365 foo122() 1366 foo123() 1367 foo124() 1368 foo125() 1369 foo126() 1370 foo127() 1371 foo128() 1372 foo129() 1373 foo130() 1374 foo131() 1375 foo132() 1376 foo133() 1377 foo134() 1378 foo135() 1379 foo136() 1380 foo137() 1381 foo138() 1382 foo139() 1383 foo140() 1384 foo141() 1385 foo142() 1386 foo143() 1387 foo144() 1388 foo145() 1389 foo146() 1390 foo147() 1391 foo148() 1392 foo149() 1393 foo150() 1394 foo151() 1395 foo152() 1396 foo153() 1397 foo154() 1398 foo155() 1399 foo156() 1400 foo157() 1401 foo158() 1402 foo159() 1403 foo160() 1404 foo161() 1405 foo162() 1406 foo163() 1407 foo164() 1408 foo165() 1409 foo166() 1410 foo167() 1411 foo168() 1412 foo169() 1413 foo170() 1414 foo171() 1415 foo172() 1416 foo173() 1417 foo174() 1418 foo175() 1419 foo176() 1420 foo177() 1421 foo178() 1422 foo179() 1423 foo180() 1424 foo181() 1425 foo182() 1426 foo183() 1427 foo184() 1428 foo185() 1429 foo186() 1430 foo187() 1431 foo188() 1432 foo189() 1433 foo190() 1434 foo191() 1435 foo192() 1436 foo193() 1437 foo194() 1438 foo195() 1439 foo196() 1440 foo197() 1441 foo198() 1442 foo199() 1443 foo200() 1444 foo201() 1445 foo202() 1446 foo203() 1447 foo204() 1448 foo205() 1449 foo206() 1450 foo207() 1451 foo208() 1452 foo209() 1453 foo210() 1454 foo211() 1455 foo212() 1456 foo213() 1457 foo214() 1458 foo215() 1459 foo216() 1460 foo217() 1461 foo218() 1462 foo219() 1463 foo220() 1464 foo221() 1465 foo222() 1466 foo223() 1467 foo224() 1468 foo225() 1469 foo226() 1470 foo227() 1471 foo228() 1472 foo229() 1473 foo230() 1474 foo231() 1475 foo232() 1476 foo233() 1477 foo234() 1478 foo235() 1479 foo236() 1480 foo237() 1481 foo238() 1482 foo239() 1483 foo240() 1484 foo241() 1485 foo242() 1486 foo243() 1487 foo244() 1488 foo245() 1489 foo246() 1490 foo247() 1491 foo248() 1492 foo249() 1493 foo250() 1494 foo251() 1495 foo252() 1496 foo253() 1497 foo254() 1498 foo255() 1499 foo256() 1500 foo257() 1501 foo258() 1502 foo259() 1503 foo260() 1504 foo261() 1505 foo262() 1506 foo263() 1507 foo264() 1508 foo265() 1509 foo266() 1510 foo267() 1511 foo268() 1512 foo269() 1513 foo270() 1514 foo271() 1515 foo272() 1516 foo273() 1517 foo274() 1518 foo275() 1519 foo276() 1520 foo277() 1521 foo278() 1522 foo279() 1523 foo280() 1524 foo281() 1525 foo282() 1526 foo283() 1527 foo284() 1528 foo285() 1529 foo286() 1530 foo287() 1531 foo288() 1532 foo289() 1533 foo290() 1534 foo291() 1535 foo292() 1536 foo293() 1537 foo294() 1538 foo295() 1539 foo296() 1540 foo297() 1541 foo298() 1542 foo299() 1543 foo300() 1544 foo301() 1545 foo302() 1546 foo303() 1547 foo304() 1548 foo305() 1549 foo306() 1550 foo307() 1551 foo308() 1552 foo309() 1553 foo310() 1554 foo311() 1555 foo312() 1556 foo313() 1557 foo314() 1558 foo315() 1559 foo316() 1560 foo317() 1561 foo318() 1562 foo319() 1563 foo320() 1564 foo321() 1565 foo322() 1566 foo323() 1567 foo324() 1568 foo325() 1569 foo326() 1570 foo327() 1571 foo328() 1572 foo329() 1573 foo330() 1574 foo331() 1575 foo332() 1576 foo333() 1577 foo334() 1578 foo335() 1579 foo336() 1580 foo337() 1581 foo338() 1582 foo339() 1583 foo340() 1584 foo341() 1585 foo342() 1586 foo343() 1587 foo344() 1588 foo345() 1589 foo346() 1590 foo347() 1591 foo348() 1592 foo349() 1593 foo350() 1594 foo351() 1595 foo352() 1596 foo353() 1597 foo354() 1598 foo355() 1599 foo356() 1600 foo357() 1601 foo358() 1602 foo359() 1603 foo360() 1604 foo361() 1605 foo362() 1606 foo363() 1607 foo364() 1608 foo365() 1609 foo366() 1610 foo367() 1611 foo368() 1612 foo369() 1613 foo370() 1614 foo371() 1615 foo372() 1616 foo373() 1617 foo374() 1618 foo375() 1619 foo376() 1620 foo377() 1621 foo378() 1622 foo379() 1623 foo380() 1624 foo381() 1625 foo382() 1626 foo383() 1627 foo384() 1628 foo385() 1629 foo386() 1630 foo387() 1631 foo388() 1632 foo389() 1633 foo390() 1634 foo391() 1635 foo392() 1636 foo393() 1637 foo394() 1638 foo395() 1639 foo396() 1640 foo397() 1641 foo398() 1642 foo399() 1643 foo400() 1644 foo401() 1645 foo402() 1646 foo403() 1647 foo404() 1648 foo405() 1649 foo406() 1650 foo407() 1651 foo408() 1652 foo409() 1653 foo410() 1654 foo411() 1655 foo412() 1656 foo413() 1657 foo414() 1658 foo415() 1659 foo416() 1660 foo417() 1661 foo418() 1662 foo419() 1663 foo420() 1664 foo421() 1665 foo422() 1666 foo423() 1667 foo424() 1668 foo425() 1669 foo426() 1670 foo427() 1671 foo428() 1672 foo429() 1673 foo430() 1674 foo431() 1675 foo432() 1676 foo433() 1677 foo434() 1678 foo435() 1679 foo436() 1680 foo437() 1681 foo438() 1682 foo439() 1683 foo440() 1684 foo441() 1685 foo442() 1686 foo443() 1687 foo444() 1688 foo445() 1689 foo446() 1690 foo447() 1691 foo448() 1692 foo449() 1693 foo450() 1694 foo451() 1695 foo452() 1696 foo453() 1697 foo454() 1698 foo455() 1699 foo456() 1700 foo457() 1701 foo458() 1702 foo459() 1703 foo460() 1704 foo461() 1705 foo462() 1706 foo463() 1707 foo464() 1708 foo465() 1709 foo466() 1710 foo467() 1711 foo468() 1712 foo469() 1713 foo470() 1714 foo471() 1715 foo472() 1716 foo473() 1717 foo474() 1718 foo475() 1719 foo476() 1720 foo477() 1721 foo478() 1722 foo479() 1723 foo480() 1724 foo481() 1725 foo482() 1726 foo483() 1727 foo484() 1728 foo485() 1729 foo486() 1730 foo487() 1731 foo488() 1732 foo489() 1733 foo490() 1734 foo491() 1735 foo492() 1736 foo493() 1737 foo494() 1738 foo495() 1739 foo496() 1740 foo497() 1741 foo498() 1742 foo499() 1743 foo500() 1744 foo501() 1745 foo502() 1746 foo503() 1747 foo504() 1748 foo505() 1749 foo506() 1750 foo507() 1751 foo508() 1752 foo509() 1753 foo510() 1754 foo511() 1755 } 1756 func $(i I) { 1757 i.foo511() 1758 } 1759 `, 1760 pos: []string{"TESTB"}, 1761 }, 1762 { 1763 fn: ` 1764 func $(i I) { 1765 i.foo001() 1766 } 1767 `, 1768 neg: []string{"TESTB"}, 1769 }, 1770 } 1771 1772 var linux386Tests = []*asmTest{ 1773 { 1774 fn: ` 1775 func f0(b []byte) uint32 { 1776 return binary.LittleEndian.Uint32(b) 1777 } 1778 `, 1779 pos: []string{"\tMOVL\t\\(.*\\),"}, 1780 }, 1781 { 1782 fn: ` 1783 func f1(b []byte, i int) uint32 { 1784 return binary.LittleEndian.Uint32(b[i:]) 1785 } 1786 `, 1787 pos: []string{"\tMOVL\t\\(.*\\)\\(.*\\*1\\),"}, 1788 }, 1789 1790 // multiplication by powers of two 1791 { 1792 fn: ` 1793 func $(n int) int { 1794 return 32*n 1795 } 1796 `, 1797 pos: []string{"SHLL"}, 1798 neg: []string{"IMULL"}, 1799 }, 1800 { 1801 fn: ` 1802 func $(n int) int { 1803 return -64*n 1804 } 1805 `, 1806 pos: []string{"SHLL"}, 1807 neg: []string{"IMULL"}, 1808 }, 1809 1810 // multiplication merging tests 1811 { 1812 fn: ` 1813 func $(n int) int { 1814 return 9*n + 14*n 1815 }`, 1816 pos: []string{"\tIMULL\t[$]23"}, // 23*n 1817 }, 1818 { 1819 fn: ` 1820 func $(a, n int) int { 1821 return 19*a + a*n 1822 }`, 1823 pos: []string{"\tADDL\t[$]19", "\tIMULL"}, // (n+19)*a 1824 }, 1825 { 1826 // check that stack store is optimized away 1827 fn: ` 1828 func $() int { 1829 var x int 1830 return *(&x) 1831 } 1832 `, 1833 pos: []string{"TEXT\t.*, [$]0-4"}, 1834 }, 1835 { 1836 fn: ` 1837 func mul3(n int) int { 1838 return 23*n - 9*n 1839 }`, 1840 pos: []string{"\tIMULL\t[$]14"}, // 14*n 1841 }, 1842 { 1843 fn: ` 1844 func mul4(a, n int) int { 1845 return n*a - a*19 1846 }`, 1847 pos: []string{"\tADDL\t[$]-19", "\tIMULL"}, // (n-19)*a 1848 }, 1849 // Check that len() and cap() div by a constant power of two 1850 // are compiled into SHRL. 1851 { 1852 fn: ` 1853 func $(a []int) int { 1854 return len(a) / 1024 1855 } 1856 `, 1857 pos: []string{"\tSHRL\t\\$10,"}, 1858 }, 1859 { 1860 fn: ` 1861 func $(s string) int { 1862 return len(s) / (4097 >> 1) 1863 } 1864 `, 1865 pos: []string{"\tSHRL\t\\$11,"}, 1866 }, 1867 { 1868 fn: ` 1869 func $(a []int) int { 1870 return cap(a) / ((1 << 11) + 2048) 1871 } 1872 `, 1873 pos: []string{"\tSHRL\t\\$12,"}, 1874 }, 1875 // Check that len() and cap() mod by a constant power of two 1876 // are compiled into ANDL. 1877 { 1878 fn: ` 1879 func $(a []int) int { 1880 return len(a) % 1024 1881 } 1882 `, 1883 pos: []string{"\tANDL\t\\$1023,"}, 1884 }, 1885 { 1886 fn: ` 1887 func $(s string) int { 1888 return len(s) % (4097 >> 1) 1889 } 1890 `, 1891 pos: []string{"\tANDL\t\\$2047,"}, 1892 }, 1893 { 1894 fn: ` 1895 func $(a []int) int { 1896 return cap(a) % ((1 << 11) + 2048) 1897 } 1898 `, 1899 pos: []string{"\tANDL\t\\$4095,"}, 1900 }, 1901 { 1902 // Test that small memmove was replaced with direct movs 1903 fn: ` 1904 func $() { 1905 x := [...]byte{1, 2, 3, 4, 5, 6, 7} 1906 copy(x[1:], x[:]) 1907 } 1908 `, 1909 neg: []string{"memmove"}, 1910 }, 1911 { 1912 // Same as above but with different size 1913 fn: ` 1914 func $() { 1915 x := [...]byte{1, 2, 3, 4} 1916 copy(x[1:], x[:]) 1917 } 1918 `, 1919 neg: []string{"memmove"}, 1920 }, 1921 1922 // Intrinsic tests for math 1923 { 1924 fn: ` 1925 func $(x float64) float64 { 1926 return math.Sqrt(x) 1927 } 1928 `, 1929 pos: []string{"FSQRT|SQRTSD"}, // 387|sse2 1930 }, 1931 } 1932 1933 var linuxS390XTests = []*asmTest{ 1934 { 1935 fn: ` 1936 func f0(b []byte) uint32 { 1937 return binary.LittleEndian.Uint32(b) 1938 } 1939 `, 1940 pos: []string{"\tMOVWBR\t\\(.*\\),"}, 1941 }, 1942 { 1943 fn: ` 1944 func f1(b []byte, i int) uint32 { 1945 return binary.LittleEndian.Uint32(b[i:]) 1946 } 1947 `, 1948 pos: []string{"\tMOVWBR\t\\(.*\\)\\(.*\\*1\\),"}, 1949 }, 1950 { 1951 fn: ` 1952 func f2(b []byte) uint64 { 1953 return binary.LittleEndian.Uint64(b) 1954 } 1955 `, 1956 pos: []string{"\tMOVDBR\t\\(.*\\),"}, 1957 }, 1958 { 1959 fn: ` 1960 func f3(b []byte, i int) uint64 { 1961 return binary.LittleEndian.Uint64(b[i:]) 1962 } 1963 `, 1964 pos: []string{"\tMOVDBR\t\\(.*\\)\\(.*\\*1\\),"}, 1965 }, 1966 { 1967 fn: ` 1968 func f4(b []byte) uint32 { 1969 return binary.BigEndian.Uint32(b) 1970 } 1971 `, 1972 pos: []string{"\tMOVWZ\t\\(.*\\),"}, 1973 }, 1974 { 1975 fn: ` 1976 func f5(b []byte, i int) uint32 { 1977 return binary.BigEndian.Uint32(b[i:]) 1978 } 1979 `, 1980 pos: []string{"\tMOVWZ\t\\(.*\\)\\(.*\\*1\\),"}, 1981 }, 1982 { 1983 fn: ` 1984 func f6(b []byte) uint64 { 1985 return binary.BigEndian.Uint64(b) 1986 } 1987 `, 1988 pos: []string{"\tMOVD\t\\(.*\\),"}, 1989 }, 1990 { 1991 fn: ` 1992 func f7(b []byte, i int) uint64 { 1993 return binary.BigEndian.Uint64(b[i:]) 1994 } 1995 `, 1996 pos: []string{"\tMOVD\t\\(.*\\)\\(.*\\*1\\),"}, 1997 }, 1998 { 1999 fn: ` 2000 func f8(x uint64) uint64 { 2001 return x<<7 + x>>57 2002 } 2003 `, 2004 pos: []string{"\tRLLG\t[$]7,"}, 2005 }, 2006 { 2007 fn: ` 2008 func f9(x uint64) uint64 { 2009 return x<<7 | x>>57 2010 } 2011 `, 2012 pos: []string{"\tRLLG\t[$]7,"}, 2013 }, 2014 { 2015 fn: ` 2016 func f10(x uint64) uint64 { 2017 return x<<7 ^ x>>57 2018 } 2019 `, 2020 pos: []string{"\tRLLG\t[$]7,"}, 2021 }, 2022 { 2023 fn: ` 2024 func f11(x uint32) uint32 { 2025 return x<<7 + x>>25 2026 } 2027 `, 2028 pos: []string{"\tRLL\t[$]7,"}, 2029 }, 2030 { 2031 fn: ` 2032 func f12(x uint32) uint32 { 2033 return x<<7 | x>>25 2034 } 2035 `, 2036 pos: []string{"\tRLL\t[$]7,"}, 2037 }, 2038 { 2039 fn: ` 2040 func f13(x uint32) uint32 { 2041 return x<<7 ^ x>>25 2042 } 2043 `, 2044 pos: []string{"\tRLL\t[$]7,"}, 2045 }, 2046 // Fused multiply-add/sub instructions. 2047 { 2048 fn: ` 2049 func f14(x, y, z float64) float64 { 2050 return x * y + z 2051 } 2052 `, 2053 pos: []string{"\tFMADD\t"}, 2054 }, 2055 { 2056 fn: ` 2057 func f15(x, y, z float64) float64 { 2058 return x * y - z 2059 } 2060 `, 2061 pos: []string{"\tFMSUB\t"}, 2062 }, 2063 { 2064 fn: ` 2065 func f16(x, y, z float32) float32 { 2066 return x * y + z 2067 } 2068 `, 2069 pos: []string{"\tFMADDS\t"}, 2070 }, 2071 { 2072 fn: ` 2073 func f17(x, y, z float32) float32 { 2074 return x * y - z 2075 } 2076 `, 2077 pos: []string{"\tFMSUBS\t"}, 2078 }, 2079 // Intrinsic tests for math/bits 2080 { 2081 fn: ` 2082 func f18(a uint64) int { 2083 return bits.TrailingZeros64(a) 2084 } 2085 `, 2086 pos: []string{"\tFLOGR\t"}, 2087 }, 2088 { 2089 fn: ` 2090 func f19(a uint32) int { 2091 return bits.TrailingZeros32(a) 2092 } 2093 `, 2094 pos: []string{"\tFLOGR\t", "\tMOVWZ\t"}, 2095 }, 2096 { 2097 fn: ` 2098 func f20(a uint16) int { 2099 return bits.TrailingZeros16(a) 2100 } 2101 `, 2102 pos: []string{"\tFLOGR\t", "\tOR\t\\$65536,"}, 2103 }, 2104 { 2105 fn: ` 2106 func f21(a uint8) int { 2107 return bits.TrailingZeros8(a) 2108 } 2109 `, 2110 pos: []string{"\tFLOGR\t", "\tOR\t\\$256,"}, 2111 }, 2112 // Intrinsic tests for math/bits 2113 { 2114 fn: ` 2115 func f22(a uint64) uint64 { 2116 return bits.ReverseBytes64(a) 2117 } 2118 `, 2119 pos: []string{"\tMOVDBR\t"}, 2120 }, 2121 { 2122 fn: ` 2123 func f23(a uint32) uint32 { 2124 return bits.ReverseBytes32(a) 2125 } 2126 `, 2127 pos: []string{"\tMOVWBR\t"}, 2128 }, 2129 { 2130 fn: ` 2131 func f24(a uint64) int { 2132 return bits.Len64(a) 2133 } 2134 `, 2135 pos: []string{"\tFLOGR\t"}, 2136 }, 2137 { 2138 fn: ` 2139 func f25(a uint32) int { 2140 return bits.Len32(a) 2141 } 2142 `, 2143 pos: []string{"\tFLOGR\t"}, 2144 }, 2145 { 2146 fn: ` 2147 func f26(a uint16) int { 2148 return bits.Len16(a) 2149 } 2150 `, 2151 pos: []string{"\tFLOGR\t"}, 2152 }, 2153 { 2154 fn: ` 2155 func f27(a uint8) int { 2156 return bits.Len8(a) 2157 } 2158 `, 2159 pos: []string{"\tFLOGR\t"}, 2160 }, 2161 { 2162 fn: ` 2163 func f28(a uint) int { 2164 return bits.Len(a) 2165 } 2166 `, 2167 pos: []string{"\tFLOGR\t"}, 2168 }, 2169 { 2170 fn: ` 2171 func f29(a uint64) int { 2172 return bits.LeadingZeros64(a) 2173 } 2174 `, 2175 pos: []string{"\tFLOGR\t"}, 2176 }, 2177 { 2178 fn: ` 2179 func f30(a uint32) int { 2180 return bits.LeadingZeros32(a) 2181 } 2182 `, 2183 pos: []string{"\tFLOGR\t"}, 2184 }, 2185 { 2186 fn: ` 2187 func f31(a uint16) int { 2188 return bits.LeadingZeros16(a) 2189 } 2190 `, 2191 pos: []string{"\tFLOGR\t"}, 2192 }, 2193 { 2194 fn: ` 2195 func f32(a uint8) int { 2196 return bits.LeadingZeros8(a) 2197 } 2198 `, 2199 pos: []string{"\tFLOGR\t"}, 2200 }, 2201 { 2202 fn: ` 2203 func f33(a uint) int { 2204 return bits.LeadingZeros(a) 2205 } 2206 `, 2207 pos: []string{"\tFLOGR\t"}, 2208 }, 2209 // Intrinsic tests for math. 2210 { 2211 fn: ` 2212 func ceil(x float64) float64 { 2213 return math.Ceil(x) 2214 } 2215 `, 2216 pos: []string{"\tFIDBR\t[$]6"}, 2217 }, 2218 { 2219 fn: ` 2220 func floor(x float64) float64 { 2221 return math.Floor(x) 2222 } 2223 `, 2224 pos: []string{"\tFIDBR\t[$]7"}, 2225 }, 2226 { 2227 fn: ` 2228 func round(x float64) float64 { 2229 return math.Round(x) 2230 } 2231 `, 2232 pos: []string{"\tFIDBR\t[$]1"}, 2233 }, 2234 { 2235 fn: ` 2236 func trunc(x float64) float64 { 2237 return math.Trunc(x) 2238 } 2239 `, 2240 pos: []string{"\tFIDBR\t[$]5"}, 2241 }, 2242 { 2243 fn: ` 2244 func roundToEven(x float64) float64 { 2245 return math.RoundToEven(x) 2246 } 2247 `, 2248 pos: []string{"\tFIDBR\t[$]4"}, 2249 }, 2250 { 2251 // check that stack store is optimized away 2252 fn: ` 2253 func $() int { 2254 var x int 2255 return *(&x) 2256 } 2257 `, 2258 pos: []string{"TEXT\t.*, [$]0-8"}, 2259 }, 2260 // Constant propagation through raw bits conversions. 2261 { 2262 // uint32 constant converted to float32 constant 2263 fn: ` 2264 func $(x float32) float32 { 2265 if x > math.Float32frombits(0x3f800000) { 2266 return -x 2267 } 2268 return x 2269 } 2270 `, 2271 pos: []string{"\tFMOVS\t[$]f32.3f800000\\(SB\\)"}, 2272 }, 2273 { 2274 // float32 constant converted to uint32 constant 2275 fn: ` 2276 func $(x uint32) uint32 { 2277 if x > math.Float32bits(1) { 2278 return -x 2279 } 2280 return x 2281 } 2282 `, 2283 neg: []string{"\tFMOVS\t"}, 2284 }, 2285 // Constant propagation through float comparisons. 2286 { 2287 fn: ` 2288 func $() bool { 2289 return 0.5 == float64(uint32(1)) || 2290 1.5 > float64(uint64(1<<63)) || 2291 math.NaN() == math.NaN() 2292 } 2293 `, 2294 pos: []string{"\tMOV(B|BZ|D)\t[$]0,"}, 2295 neg: []string{"\tFCMPU\t", "\tMOV(B|BZ|D)\t[$]1,"}, 2296 }, 2297 { 2298 fn: ` 2299 func $() bool { 2300 return float32(0.5) <= float32(int64(1)) && 2301 float32(1.5) >= float32(int32(-1<<31)) && 2302 float32(math.NaN()) != float32(math.NaN()) 2303 } 2304 `, 2305 pos: []string{"\tMOV(B|BZ|D)\t[$]1,"}, 2306 neg: []string{"\tCEBR\t", "\tMOV(B|BZ|D)\t[$]0,"}, 2307 }, 2308 // math tests 2309 { 2310 fn: ` 2311 func $(x float64) float64 { 2312 return math.Abs(x) 2313 } 2314 `, 2315 pos: []string{"\tLPDFR\t"}, 2316 neg: []string{"\tMOVD\t"}, // no integer loads/stores 2317 }, 2318 { 2319 fn: ` 2320 func $(x float32) float32 { 2321 return float32(math.Abs(float64(x))) 2322 } 2323 `, 2324 pos: []string{"\tLPDFR\t"}, 2325 neg: []string{"\tLDEBR\t", "\tLEDBR\t"}, // no float64 conversion 2326 }, 2327 { 2328 fn: ` 2329 func $(x float64) float64 { 2330 return math.Float64frombits(math.Float64bits(x)|1<<63) 2331 } 2332 `, 2333 pos: []string{"\tLNDFR\t"}, 2334 neg: []string{"\tMOVD\t"}, // no integer loads/stores 2335 }, 2336 { 2337 fn: ` 2338 func $(x float64) float64 { 2339 return -math.Abs(x) 2340 } 2341 `, 2342 pos: []string{"\tLNDFR\t"}, 2343 neg: []string{"\tMOVD\t"}, // no integer loads/stores 2344 }, 2345 { 2346 fn: ` 2347 func $(x, y float64) float64 { 2348 return math.Copysign(x, y) 2349 } 2350 `, 2351 pos: []string{"\tCPSDR\t"}, 2352 neg: []string{"\tMOVD\t"}, // no integer loads/stores 2353 }, 2354 { 2355 fn: ` 2356 func $(x float64) float64 { 2357 return math.Copysign(x, -1) 2358 } 2359 `, 2360 pos: []string{"\tLNDFR\t"}, 2361 neg: []string{"\tMOVD\t"}, // no integer loads/stores 2362 }, 2363 { 2364 fn: ` 2365 func $(x float64) float64 { 2366 return math.Copysign(-1, x) 2367 } 2368 `, 2369 pos: []string{"\tCPSDR\t"}, 2370 neg: []string{"\tMOVD\t"}, // no integer loads/stores 2371 }, 2372 } 2373 2374 var linuxARMTests = []*asmTest{ 2375 // multiplication by powers of two 2376 { 2377 fn: ` 2378 func $(n int) int { 2379 return 16*n 2380 } 2381 `, 2382 pos: []string{"\tSLL\t[$]4"}, 2383 neg: []string{"\tMUL\t"}, 2384 }, 2385 { 2386 fn: ` 2387 func $(n int) int { 2388 return -32*n 2389 } 2390 `, 2391 pos: []string{"\tSLL\t[$]5"}, 2392 neg: []string{"\tMUL\t"}, 2393 }, 2394 2395 { 2396 fn: ` 2397 func f0(x uint32) uint32 { 2398 return x<<7 + x>>25 2399 } 2400 `, 2401 pos: []string{"\tMOVW\tR[0-9]+@>25,"}, 2402 }, 2403 { 2404 fn: ` 2405 func f1(x uint32) uint32 { 2406 return x<<7 | x>>25 2407 } 2408 `, 2409 pos: []string{"\tMOVW\tR[0-9]+@>25,"}, 2410 }, 2411 { 2412 fn: ` 2413 func f2(x uint32) uint32 { 2414 return x<<7 ^ x>>25 2415 } 2416 `, 2417 pos: []string{"\tMOVW\tR[0-9]+@>25,"}, 2418 }, 2419 { 2420 fn: ` 2421 func f3(a uint64) int { 2422 return bits.Len64(a) 2423 } 2424 `, 2425 pos: []string{"\tCLZ\t"}, 2426 }, 2427 { 2428 fn: ` 2429 func f4(a uint32) int { 2430 return bits.Len32(a) 2431 } 2432 `, 2433 pos: []string{"\tCLZ\t"}, 2434 }, 2435 { 2436 fn: ` 2437 func f5(a uint16) int { 2438 return bits.Len16(a) 2439 } 2440 `, 2441 pos: []string{"\tCLZ\t"}, 2442 }, 2443 { 2444 fn: ` 2445 func f6(a uint8) int { 2446 return bits.Len8(a) 2447 } 2448 `, 2449 pos: []string{"\tCLZ\t"}, 2450 }, 2451 { 2452 fn: ` 2453 func f7(a uint) int { 2454 return bits.Len(a) 2455 } 2456 `, 2457 pos: []string{"\tCLZ\t"}, 2458 }, 2459 { 2460 fn: ` 2461 func f8(a uint64) int { 2462 return bits.LeadingZeros64(a) 2463 } 2464 `, 2465 pos: []string{"\tCLZ\t"}, 2466 }, 2467 { 2468 fn: ` 2469 func f9(a uint32) int { 2470 return bits.LeadingZeros32(a) 2471 } 2472 `, 2473 pos: []string{"\tCLZ\t"}, 2474 }, 2475 { 2476 fn: ` 2477 func f10(a uint16) int { 2478 return bits.LeadingZeros16(a) 2479 } 2480 `, 2481 pos: []string{"\tCLZ\t"}, 2482 }, 2483 { 2484 fn: ` 2485 func f11(a uint8) int { 2486 return bits.LeadingZeros8(a) 2487 } 2488 `, 2489 pos: []string{"\tCLZ\t"}, 2490 }, 2491 { 2492 fn: ` 2493 func f12(a uint) int { 2494 return bits.LeadingZeros(a) 2495 } 2496 `, 2497 pos: []string{"\tCLZ\t"}, 2498 }, 2499 { 2500 // make sure assembly output has matching offset and base register. 2501 fn: ` 2502 func f13(a, b int) int { 2503 runtime.GC() // use some frame 2504 return b 2505 } 2506 `, 2507 pos: []string{"b\\+4\\(FP\\)"}, 2508 }, 2509 { 2510 // check that stack store is optimized away 2511 fn: ` 2512 func $() int { 2513 var x int 2514 return *(&x) 2515 } 2516 `, 2517 pos: []string{"TEXT\t.*, [$]-4-4"}, 2518 }, 2519 } 2520 2521 var linuxARM64Tests = []*asmTest{ 2522 // multiplication by powers of two 2523 { 2524 fn: ` 2525 func $(n int) int { 2526 return 64*n 2527 } 2528 `, 2529 pos: []string{"\tLSL\t[$]6"}, 2530 neg: []string{"\tMUL\t"}, 2531 }, 2532 { 2533 fn: ` 2534 func $(n int) int { 2535 return -128*n 2536 } 2537 `, 2538 pos: []string{"\tLSL\t[$]7"}, 2539 neg: []string{"\tMUL\t"}, 2540 }, 2541 2542 { 2543 fn: ` 2544 func f0(x uint64) uint64 { 2545 return x<<7 + x>>57 2546 } 2547 `, 2548 pos: []string{"\tROR\t[$]57,"}, 2549 }, 2550 { 2551 fn: ` 2552 func f1(x uint64) uint64 { 2553 return x<<7 | x>>57 2554 } 2555 `, 2556 pos: []string{"\tROR\t[$]57,"}, 2557 }, 2558 { 2559 fn: ` 2560 func f2(x uint64) uint64 { 2561 return x<<7 ^ x>>57 2562 } 2563 `, 2564 pos: []string{"\tROR\t[$]57,"}, 2565 }, 2566 { 2567 fn: ` 2568 func f3(x uint32) uint32 { 2569 return x<<7 + x>>25 2570 } 2571 `, 2572 pos: []string{"\tRORW\t[$]25,"}, 2573 }, 2574 { 2575 fn: ` 2576 func f4(x uint32) uint32 { 2577 return x<<7 | x>>25 2578 } 2579 `, 2580 pos: []string{"\tRORW\t[$]25,"}, 2581 }, 2582 { 2583 fn: ` 2584 func f5(x uint32) uint32 { 2585 return x<<7 ^ x>>25 2586 } 2587 `, 2588 pos: []string{"\tRORW\t[$]25,"}, 2589 }, 2590 { 2591 fn: ` 2592 func f22(a uint64) uint64 { 2593 return bits.ReverseBytes64(a) 2594 } 2595 `, 2596 pos: []string{"\tREV\t"}, 2597 }, 2598 { 2599 fn: ` 2600 func f23(a uint32) uint32 { 2601 return bits.ReverseBytes32(a) 2602 } 2603 `, 2604 pos: []string{"\tREVW\t"}, 2605 }, 2606 { 2607 fn: ` 2608 func f24(a uint64) int { 2609 return bits.Len64(a) 2610 } 2611 `, 2612 pos: []string{"\tCLZ\t"}, 2613 }, 2614 { 2615 fn: ` 2616 func f25(a uint32) int { 2617 return bits.Len32(a) 2618 } 2619 `, 2620 pos: []string{"\tCLZ\t"}, 2621 }, 2622 { 2623 fn: ` 2624 func f26(a uint16) int { 2625 return bits.Len16(a) 2626 } 2627 `, 2628 pos: []string{"\tCLZ\t"}, 2629 }, 2630 { 2631 fn: ` 2632 func f27(a uint8) int { 2633 return bits.Len8(a) 2634 } 2635 `, 2636 pos: []string{"\tCLZ\t"}, 2637 }, 2638 { 2639 fn: ` 2640 func f28(a uint) int { 2641 return bits.Len(a) 2642 } 2643 `, 2644 pos: []string{"\tCLZ\t"}, 2645 }, 2646 { 2647 fn: ` 2648 func f29(a uint64) int { 2649 return bits.LeadingZeros64(a) 2650 } 2651 `, 2652 pos: []string{"\tCLZ\t"}, 2653 }, 2654 { 2655 fn: ` 2656 func f30(a uint32) int { 2657 return bits.LeadingZeros32(a) 2658 } 2659 `, 2660 pos: []string{"\tCLZ\t"}, 2661 }, 2662 { 2663 fn: ` 2664 func f31(a uint16) int { 2665 return bits.LeadingZeros16(a) 2666 } 2667 `, 2668 pos: []string{"\tCLZ\t"}, 2669 }, 2670 { 2671 fn: ` 2672 func f32(a uint8) int { 2673 return bits.LeadingZeros8(a) 2674 } 2675 `, 2676 pos: []string{"\tCLZ\t"}, 2677 }, 2678 { 2679 fn: ` 2680 func f33(a uint) int { 2681 return bits.LeadingZeros(a) 2682 } 2683 `, 2684 pos: []string{"\tCLZ\t"}, 2685 }, 2686 { 2687 fn: ` 2688 func f34(a uint64) uint64 { 2689 return a & ((1<<63)-1) 2690 } 2691 `, 2692 pos: []string{"\tAND\t"}, 2693 }, 2694 { 2695 fn: ` 2696 func f35(a uint64) uint64 { 2697 return a & (1<<63) 2698 } 2699 `, 2700 pos: []string{"\tAND\t"}, 2701 }, 2702 { 2703 // make sure offsets are folded into load and store. 2704 fn: ` 2705 func f36(_, a [20]byte) (b [20]byte) { 2706 b = a 2707 return 2708 } 2709 `, 2710 pos: []string{"\tMOVD\t\"\"\\.a\\+[0-9]+\\(FP\\), R[0-9]+", "\tMOVD\tR[0-9]+, \"\"\\.b\\+[0-9]+\\(FP\\)"}, 2711 }, 2712 { 2713 // check that stack store is optimized away 2714 fn: ` 2715 func $() int { 2716 var x int 2717 return *(&x) 2718 } 2719 `, 2720 pos: []string{"TEXT\t.*, [$]-8-8"}, 2721 }, 2722 { 2723 // check that we don't emit comparisons for constant shift 2724 fn: ` 2725 //go:nosplit 2726 func $(x int) int { 2727 return x << 17 2728 } 2729 `, 2730 pos: []string{"LSL\t\\$17"}, 2731 neg: []string{"CMP"}, 2732 }, 2733 { 2734 fn: ` 2735 func $(a int32, ptr *int) { 2736 if a >= 0 { 2737 *ptr = 0 2738 } 2739 } 2740 `, 2741 pos: []string{"TBNZ"}, 2742 }, 2743 { 2744 fn: ` 2745 func $(a int64, ptr *int) { 2746 if a >= 0 { 2747 *ptr = 0 2748 } 2749 } 2750 `, 2751 pos: []string{"TBNZ"}, 2752 }, 2753 { 2754 fn: ` 2755 func $(a int32, ptr *int) { 2756 if a < 0 { 2757 *ptr = 0 2758 } 2759 } 2760 `, 2761 pos: []string{"TBZ"}, 2762 }, 2763 { 2764 fn: ` 2765 func $(a int64, ptr *int) { 2766 if a < 0 { 2767 *ptr = 0 2768 } 2769 } 2770 `, 2771 pos: []string{"TBZ"}, 2772 }, 2773 { 2774 fn: ` 2775 func $(x uint64) int { 2776 return bits.OnesCount64(x) 2777 } 2778 `, 2779 pos: []string{"\tVCNT\t", "\tVUADDLV\t"}, 2780 }, 2781 { 2782 fn: ` 2783 func $(x uint32) int { 2784 return bits.OnesCount32(x) 2785 } 2786 `, 2787 pos: []string{"\tVCNT\t", "\tVUADDLV\t"}, 2788 }, 2789 { 2790 fn: ` 2791 func $(x uint16) int { 2792 return bits.OnesCount16(x) 2793 } 2794 `, 2795 pos: []string{"\tVCNT\t", "\tVUADDLV\t"}, 2796 }, 2797 // Load-combining tests. 2798 { 2799 fn: ` 2800 func $(b []byte) uint64 { 2801 return binary.LittleEndian.Uint64(b) 2802 } 2803 `, 2804 pos: []string{"\tMOVD\t\\(R[0-9]+\\)"}, 2805 }, 2806 { 2807 fn: ` 2808 func $(b []byte, i int) uint64 { 2809 return binary.LittleEndian.Uint64(b[i:]) 2810 } 2811 `, 2812 pos: []string{"\tMOVD\t\\(R[0-9]+\\)"}, 2813 }, 2814 { 2815 fn: ` 2816 func $(b []byte) uint32 { 2817 return binary.LittleEndian.Uint32(b) 2818 } 2819 `, 2820 pos: []string{"\tMOVWU\t\\(R[0-9]+\\)"}, 2821 }, 2822 { 2823 fn: ` 2824 func $(b []byte, i int) uint32 { 2825 return binary.LittleEndian.Uint32(b[i:]) 2826 } 2827 `, 2828 pos: []string{"\tMOVWU\t\\(R[0-9]+\\)"}, 2829 }, 2830 { 2831 fn: ` 2832 func $(b []byte) uint64 { 2833 return binary.BigEndian.Uint64(b) 2834 } 2835 `, 2836 pos: []string{"\tREV\t"}, 2837 }, 2838 { 2839 fn: ` 2840 func $(b []byte, i int) uint64 { 2841 return binary.BigEndian.Uint64(b[i:]) 2842 } 2843 `, 2844 pos: []string{"\tREV\t"}, 2845 }, 2846 { 2847 fn: ` 2848 func $(b []byte) uint32 { 2849 return binary.BigEndian.Uint32(b) 2850 } 2851 `, 2852 pos: []string{"\tREVW\t"}, 2853 }, 2854 { 2855 fn: ` 2856 func $(b []byte, i int) uint32 { 2857 return binary.BigEndian.Uint32(b[i:]) 2858 } 2859 `, 2860 pos: []string{"\tREVW\t"}, 2861 }, 2862 { 2863 fn: ` 2864 func $(s []byte) uint16 { 2865 return uint16(s[0]) | uint16(s[1]) << 8 2866 } 2867 `, 2868 pos: []string{"\tMOVHU\t\\(R[0-9]+\\)"}, 2869 neg: []string{"ORR\tR[0-9]+<<8\t"}, 2870 }, 2871 // Intrinsic tests for math. 2872 { 2873 fn: ` 2874 func sqrt(x float64) float64 { 2875 return math.Sqrt(x) 2876 } 2877 `, 2878 pos: []string{"FSQRTD"}, 2879 }, 2880 { 2881 fn: ` 2882 func ceil(x float64) float64 { 2883 return math.Ceil(x) 2884 } 2885 `, 2886 pos: []string{"FRINTPD"}, 2887 }, 2888 { 2889 fn: ` 2890 func floor(x float64) float64 { 2891 return math.Floor(x) 2892 } 2893 `, 2894 pos: []string{"FRINTMD"}, 2895 }, 2896 { 2897 fn: ` 2898 func round(x float64) float64 { 2899 return math.Round(x) 2900 } 2901 `, 2902 pos: []string{"FRINTAD"}, 2903 }, 2904 { 2905 fn: ` 2906 func trunc(x float64) float64 { 2907 return math.Trunc(x) 2908 } 2909 `, 2910 pos: []string{"FRINTZD"}, 2911 }, 2912 { 2913 // make sure that CSEL is emitted for conditional moves 2914 fn: ` 2915 func f37(c int) int { 2916 x := c + 4 2917 if c < 0 { 2918 x = 182 2919 } 2920 return x 2921 } 2922 `, 2923 pos: []string{"\tCSEL\t"}, 2924 }, 2925 } 2926 2927 var linuxMIPSTests = []*asmTest{ 2928 // Intrinsic tests for math/bits 2929 { 2930 fn: ` 2931 func f0(a uint64) int { 2932 return bits.Len64(a) 2933 } 2934 `, 2935 pos: []string{"\tCLZ\t"}, 2936 }, 2937 { 2938 fn: ` 2939 func f1(a uint32) int { 2940 return bits.Len32(a) 2941 } 2942 `, 2943 pos: []string{"\tCLZ\t"}, 2944 }, 2945 { 2946 fn: ` 2947 func f2(a uint16) int { 2948 return bits.Len16(a) 2949 } 2950 `, 2951 pos: []string{"\tCLZ\t"}, 2952 }, 2953 { 2954 fn: ` 2955 func f3(a uint8) int { 2956 return bits.Len8(a) 2957 } 2958 `, 2959 pos: []string{"\tCLZ\t"}, 2960 }, 2961 { 2962 fn: ` 2963 func f4(a uint) int { 2964 return bits.Len(a) 2965 } 2966 `, 2967 pos: []string{"\tCLZ\t"}, 2968 }, 2969 { 2970 fn: ` 2971 func f5(a uint64) int { 2972 return bits.LeadingZeros64(a) 2973 } 2974 `, 2975 pos: []string{"\tCLZ\t"}, 2976 }, 2977 { 2978 fn: ` 2979 func f6(a uint32) int { 2980 return bits.LeadingZeros32(a) 2981 } 2982 `, 2983 pos: []string{"\tCLZ\t"}, 2984 }, 2985 { 2986 fn: ` 2987 func f7(a uint16) int { 2988 return bits.LeadingZeros16(a) 2989 } 2990 `, 2991 pos: []string{"\tCLZ\t"}, 2992 }, 2993 { 2994 fn: ` 2995 func f8(a uint8) int { 2996 return bits.LeadingZeros8(a) 2997 } 2998 `, 2999 pos: []string{"\tCLZ\t"}, 3000 }, 3001 { 3002 fn: ` 3003 func f9(a uint) int { 3004 return bits.LeadingZeros(a) 3005 } 3006 `, 3007 pos: []string{"\tCLZ\t"}, 3008 }, 3009 // Intrinsic tests for math. 3010 { 3011 fn: ` 3012 func $(x float64) float64 { 3013 return math.Sqrt(x) 3014 } 3015 `, 3016 pos: []string{"SQRTD"}, 3017 }, 3018 { 3019 // check that stack store is optimized away 3020 fn: ` 3021 func $() int { 3022 var x int 3023 return *(&x) 3024 } 3025 `, 3026 pos: []string{"TEXT\t.*, [$]-4-4"}, 3027 }, 3028 } 3029 3030 var linuxMIPS64Tests = []*asmTest{ 3031 { 3032 // check that we don't emit comparisons for constant shift 3033 fn: ` 3034 func $(x int) int { 3035 return x << 17 3036 } 3037 `, 3038 pos: []string{"SLLV\t\\$17"}, 3039 neg: []string{"SGT"}, 3040 }, 3041 // Intrinsic tests for math. 3042 { 3043 fn: ` 3044 func $(x float64) float64 { 3045 return math.Sqrt(x) 3046 } 3047 `, 3048 pos: []string{"SQRTD"}, 3049 }, 3050 } 3051 3052 var linuxPPC64LETests = []*asmTest{ 3053 // Fused multiply-add/sub instructions. 3054 { 3055 fn: ` 3056 func f0(x, y, z float64) float64 { 3057 return x * y + z 3058 } 3059 `, 3060 pos: []string{"\tFMADD\t"}, 3061 }, 3062 { 3063 fn: ` 3064 func f1(x, y, z float64) float64 { 3065 return x * y - z 3066 } 3067 `, 3068 pos: []string{"\tFMSUB\t"}, 3069 }, 3070 { 3071 fn: ` 3072 func f2(x, y, z float32) float32 { 3073 return x * y + z 3074 } 3075 `, 3076 pos: []string{"\tFMADDS\t"}, 3077 }, 3078 { 3079 fn: ` 3080 func f3(x, y, z float32) float32 { 3081 return x * y - z 3082 } 3083 `, 3084 pos: []string{"\tFMSUBS\t"}, 3085 }, 3086 { 3087 fn: ` 3088 func f4(x uint32) uint32 { 3089 return x<<7 | x>>25 3090 } 3091 `, 3092 pos: []string{"\tROTLW\t"}, 3093 }, 3094 { 3095 fn: ` 3096 func f5(x uint32) uint32 { 3097 return x<<7 + x>>25 3098 } 3099 `, 3100 pos: []string{"\tROTLW\t"}, 3101 }, 3102 { 3103 fn: ` 3104 func f6(x uint32) uint32 { 3105 return x<<7 ^ x>>25 3106 } 3107 `, 3108 pos: []string{"\tROTLW\t"}, 3109 }, 3110 { 3111 fn: ` 3112 func f7(x uint64) uint64 { 3113 return x<<7 | x>>57 3114 } 3115 `, 3116 pos: []string{"\tROTL\t"}, 3117 }, 3118 { 3119 fn: ` 3120 func f8(x uint64) uint64 { 3121 return x<<7 + x>>57 3122 } 3123 `, 3124 pos: []string{"\tROTL\t"}, 3125 }, 3126 { 3127 fn: ` 3128 func f9(x uint64) uint64 { 3129 return x<<7 ^ x>>57 3130 } 3131 `, 3132 pos: []string{"\tROTL\t"}, 3133 }, 3134 { 3135 fn: ` 3136 func f10(a uint32) uint32 { 3137 return bits.RotateLeft32(a, 9) 3138 } 3139 `, 3140 pos: []string{"\tROTLW\t"}, 3141 }, 3142 { 3143 fn: ` 3144 func f11(a uint64) uint64 { 3145 return bits.RotateLeft64(a, 37) 3146 } 3147 `, 3148 pos: []string{"\tROTL\t"}, 3149 }, 3150 3151 { 3152 fn: ` 3153 func f12(a, b float64) float64 { 3154 return math.Copysign(a, b) 3155 } 3156 `, 3157 pos: []string{"\tFCPSGN\t"}, 3158 }, 3159 3160 { 3161 fn: ` 3162 func f13(a float64) float64 { 3163 return math.Abs(a) 3164 } 3165 `, 3166 pos: []string{"\tFABS\t"}, 3167 }, 3168 3169 { 3170 fn: ` 3171 func f14(b []byte) uint16 { 3172 return binary.LittleEndian.Uint16(b) 3173 } 3174 `, 3175 pos: []string{"\tMOVHZ\t"}, 3176 }, 3177 { 3178 fn: ` 3179 func f15(b []byte) uint32 { 3180 return binary.LittleEndian.Uint32(b) 3181 } 3182 `, 3183 pos: []string{"\tMOVWZ\t"}, 3184 }, 3185 3186 { 3187 fn: ` 3188 func f16(b []byte) uint64 { 3189 return binary.LittleEndian.Uint64(b) 3190 } 3191 `, 3192 pos: []string{"\tMOVD\t"}, 3193 neg: []string{"MOVBZ", "MOVHZ", "MOVWZ"}, 3194 }, 3195 3196 { 3197 fn: ` 3198 func f17(b []byte, v uint16) { 3199 binary.LittleEndian.PutUint16(b, v) 3200 } 3201 `, 3202 pos: []string{"\tMOVH\t"}, 3203 }, 3204 3205 { 3206 fn: ` 3207 func f18(b []byte, v uint32) { 3208 binary.LittleEndian.PutUint32(b, v) 3209 } 3210 `, 3211 pos: []string{"\tMOVW\t"}, 3212 }, 3213 3214 { 3215 fn: ` 3216 func f19(b []byte, v uint64) { 3217 binary.LittleEndian.PutUint64(b, v) 3218 } 3219 `, 3220 pos: []string{"\tMOVD\t"}, 3221 neg: []string{"MOVB", "MOVH", "MOVW"}, 3222 }, 3223 3224 { 3225 // check that stack store is optimized away 3226 fn: ` 3227 func $() int { 3228 var x int 3229 return *(&x) 3230 } 3231 `, 3232 pos: []string{"TEXT\t.*, [$]0-8"}, 3233 }, 3234 // Constant propagation through raw bits conversions. 3235 { 3236 // uint32 constant converted to float32 constant 3237 fn: ` 3238 func $(x float32) float32 { 3239 if x > math.Float32frombits(0x3f800000) { 3240 return -x 3241 } 3242 return x 3243 } 3244 `, 3245 pos: []string{"\tFMOVS\t[$]f32.3f800000\\(SB\\)"}, 3246 }, 3247 { 3248 // float32 constant converted to uint32 constant 3249 fn: ` 3250 func $(x uint32) uint32 { 3251 if x > math.Float32bits(1) { 3252 return -x 3253 } 3254 return x 3255 } 3256 `, 3257 neg: []string{"\tFMOVS\t"}, 3258 }, 3259 } 3260 3261 var plan9AMD64Tests = []*asmTest{ 3262 // We should make sure that the compiler doesn't generate floating point 3263 // instructions for non-float operations on Plan 9, because floating point 3264 // operations are not allowed in the note handler. 3265 // Array zeroing. 3266 { 3267 fn: ` 3268 func $() [16]byte { 3269 var a [16]byte 3270 return a 3271 } 3272 `, 3273 pos: []string{"\tMOVQ\t\\$0, \"\""}, 3274 }, 3275 // Array copy. 3276 { 3277 fn: ` 3278 func $(a [16]byte) (b [16]byte) { 3279 b = a 3280 return 3281 } 3282 `, 3283 pos: []string{"\tMOVQ\t\"\"\\.a\\+[0-9]+\\(SP\\), (AX|CX)", "\tMOVQ\t(AX|CX), \"\"\\.b\\+[0-9]+\\(SP\\)"}, 3284 }, 3285 } 3286 3287 // TestLineNumber checks to make sure the generated assembly has line numbers 3288 // see issue #16214 3289 func TestLineNumber(t *testing.T) { 3290 testenv.MustHaveGoBuild(t) 3291 dir, err := ioutil.TempDir("", "TestLineNumber") 3292 if err != nil { 3293 t.Fatalf("could not create directory: %v", err) 3294 } 3295 defer os.RemoveAll(dir) 3296 3297 src := filepath.Join(dir, "x.go") 3298 err = ioutil.WriteFile(src, []byte(issue16214src), 0644) 3299 if err != nil { 3300 t.Fatalf("could not write file: %v", err) 3301 } 3302 3303 cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-S", "-o", filepath.Join(dir, "out.o"), src) 3304 out, err := cmd.CombinedOutput() 3305 if err != nil { 3306 t.Fatalf("fail to run go tool compile: %v", err) 3307 } 3308 3309 if strings.Contains(string(out), "unknown line number") { 3310 t.Errorf("line number missing in assembly:\n%s", out) 3311 } 3312 } 3313 3314 var issue16214src = ` 3315 package main 3316 3317 func Mod32(x uint32) uint32 { 3318 return x % 3 // frontend rewrites it as HMUL with 2863311531, the LITERAL node has unknown Pos 3319 } 3320 `