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