github.com/kdevb0x/go@v0.0.0-20180115030120-39687051e9e7/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 f70(a,b [15]byte) bool { 1008 return a == b 1009 }`, 1010 pos: []string{"\tCMPQ\t[A-Z]"}, 1011 }, 1012 { 1013 fn: ` 1014 func f71(a,b unsafe.Pointer) bool { // This was a TODO in mapaccess1_faststr 1015 return *((*[4]byte)(a)) != *((*[4]byte)(b)) 1016 }`, 1017 pos: []string{"\tCMPL\t[A-Z]"}, 1018 }, 1019 { 1020 // make sure assembly output has matching offset and base register. 1021 fn: ` 1022 func f72(a, b int) int { 1023 runtime.GC() // use some frame 1024 return b 1025 } 1026 `, 1027 pos: []string{"b\\+24\\(SP\\)"}, 1028 }, 1029 { 1030 // check load combining 1031 fn: ` 1032 func f73(a, b byte) (byte,byte) { 1033 return f73(f73(a,b)) 1034 } 1035 `, 1036 pos: []string{"\tMOVW\t"}, 1037 }, 1038 { 1039 fn: ` 1040 func f74(a, b uint16) (uint16,uint16) { 1041 return f74(f74(a,b)) 1042 } 1043 `, 1044 pos: []string{"\tMOVL\t"}, 1045 }, 1046 { 1047 fn: ` 1048 func f75(a, b uint32) (uint32,uint32) { 1049 return f75(f75(a,b)) 1050 } 1051 `, 1052 pos: []string{"\tMOVQ\t"}, 1053 }, 1054 { 1055 fn: ` 1056 func f76(a, b uint64) (uint64,uint64) { 1057 return f76(f76(a,b)) 1058 } 1059 `, 1060 pos: []string{"\tMOVUPS\t"}, 1061 }, 1062 // Make sure we don't put pointers in SSE registers across safe points. 1063 { 1064 fn: ` 1065 func $(p, q *[2]*int) { 1066 a, b := p[0], p[1] 1067 runtime.GC() 1068 q[0], q[1] = a, b 1069 } 1070 `, 1071 neg: []string{"MOVUPS"}, 1072 }, 1073 { 1074 // check that stack store is optimized away 1075 fn: ` 1076 func $() int { 1077 var x int 1078 return *(&x) 1079 } 1080 `, 1081 pos: []string{"TEXT\t.*, [$]0-8"}, 1082 }, 1083 // math.Abs using integer registers 1084 { 1085 fn: ` 1086 func $(x float64) float64 { 1087 return math.Abs(x) 1088 } 1089 `, 1090 pos: []string{"\tSHLQ\t[$]1,", "\tSHRQ\t[$]1,"}, 1091 }, 1092 // math.Copysign using integer registers 1093 { 1094 fn: ` 1095 func $(x, y float64) float64 { 1096 return math.Copysign(x, y) 1097 } 1098 `, 1099 pos: []string{"\tSHLQ\t[$]1,", "\tSHRQ\t[$]1,", "\tSHRQ\t[$]63,", "\tSHLQ\t[$]63,", "\tORQ\t"}, 1100 }, 1101 // int <-> fp moves 1102 { 1103 fn: ` 1104 func $(x float64) uint64 { 1105 return math.Float64bits(x+1) + 1 1106 } 1107 `, 1108 pos: []string{"\tMOVQ\tX.*, [^X].*"}, 1109 }, 1110 { 1111 fn: ` 1112 func $(x float32) uint32 { 1113 return math.Float32bits(x+1) + 1 1114 } 1115 `, 1116 pos: []string{"\tMOVL\tX.*, [^X].*"}, 1117 }, 1118 { 1119 fn: ` 1120 func $(x uint64) float64 { 1121 return math.Float64frombits(x+1) + 1 1122 } 1123 `, 1124 pos: []string{"\tMOVQ\t[^X].*, X.*"}, 1125 }, 1126 { 1127 fn: ` 1128 func $(x uint32) float32 { 1129 return math.Float32frombits(x+1) + 1 1130 } 1131 `, 1132 pos: []string{"\tMOVL\t[^X].*, X.*"}, 1133 }, 1134 { 1135 fn: ` 1136 func $(x uint32) bool { 1137 return x > 4 1138 } 1139 `, 1140 pos: []string{"\tSETHI\t\\("}, 1141 }, 1142 // Check that len() and cap() div by a constant power of two 1143 // are compiled into SHRQ. 1144 { 1145 fn: ` 1146 func $(a []int) int { 1147 return len(a) / 1024 1148 } 1149 `, 1150 pos: []string{"\tSHRQ\t\\$10,"}, 1151 }, 1152 { 1153 fn: ` 1154 func $(s string) int { 1155 return len(s) / (4097 >> 1) 1156 } 1157 `, 1158 pos: []string{"\tSHRQ\t\\$11,"}, 1159 }, 1160 { 1161 fn: ` 1162 func $(a []int) int { 1163 return cap(a) / ((1 << 11) + 2048) 1164 } 1165 `, 1166 pos: []string{"\tSHRQ\t\\$12,"}, 1167 }, 1168 // Check that len() and cap() mod by a constant power of two 1169 // are compiled into ANDQ. 1170 { 1171 fn: ` 1172 func $(a []int) int { 1173 return len(a) % 1024 1174 } 1175 `, 1176 pos: []string{"\tANDQ\t\\$1023,"}, 1177 }, 1178 { 1179 fn: ` 1180 func $(s string) int { 1181 return len(s) % (4097 >> 1) 1182 } 1183 `, 1184 pos: []string{"\tANDQ\t\\$2047,"}, 1185 }, 1186 { 1187 fn: ` 1188 func $(a []int) int { 1189 return cap(a) % ((1 << 11) + 2048) 1190 } 1191 `, 1192 pos: []string{"\tANDQ\t\\$4095,"}, 1193 }, 1194 { 1195 // Test that small memmove was replaced with direct movs 1196 fn: ` 1197 func $() { 1198 x := [...]byte{1, 2, 3, 4, 5, 6, 7} 1199 copy(x[1:], x[:]) 1200 } 1201 `, 1202 neg: []string{"memmove"}, 1203 }, 1204 { 1205 // Same as above but with different size 1206 fn: ` 1207 func $() { 1208 x := [...]byte{1, 2, 3, 4} 1209 copy(x[1:], x[:]) 1210 } 1211 `, 1212 neg: []string{"memmove"}, 1213 }, 1214 { 1215 // Same as above but with different size 1216 fn: ` 1217 func $() { 1218 x := [...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} 1219 copy(x[1:], x[:]) 1220 } 1221 `, 1222 neg: []string{"memmove"}, 1223 }, 1224 // Nil checks before calling interface methods 1225 { 1226 fn: ` 1227 type I interface { 1228 foo000() 1229 foo001() 1230 foo002() 1231 foo003() 1232 foo004() 1233 foo005() 1234 foo006() 1235 foo007() 1236 foo008() 1237 foo009() 1238 foo010() 1239 foo011() 1240 foo012() 1241 foo013() 1242 foo014() 1243 foo015() 1244 foo016() 1245 foo017() 1246 foo018() 1247 foo019() 1248 foo020() 1249 foo021() 1250 foo022() 1251 foo023() 1252 foo024() 1253 foo025() 1254 foo026() 1255 foo027() 1256 foo028() 1257 foo029() 1258 foo030() 1259 foo031() 1260 foo032() 1261 foo033() 1262 foo034() 1263 foo035() 1264 foo036() 1265 foo037() 1266 foo038() 1267 foo039() 1268 foo040() 1269 foo041() 1270 foo042() 1271 foo043() 1272 foo044() 1273 foo045() 1274 foo046() 1275 foo047() 1276 foo048() 1277 foo049() 1278 foo050() 1279 foo051() 1280 foo052() 1281 foo053() 1282 foo054() 1283 foo055() 1284 foo056() 1285 foo057() 1286 foo058() 1287 foo059() 1288 foo060() 1289 foo061() 1290 foo062() 1291 foo063() 1292 foo064() 1293 foo065() 1294 foo066() 1295 foo067() 1296 foo068() 1297 foo069() 1298 foo070() 1299 foo071() 1300 foo072() 1301 foo073() 1302 foo074() 1303 foo075() 1304 foo076() 1305 foo077() 1306 foo078() 1307 foo079() 1308 foo080() 1309 foo081() 1310 foo082() 1311 foo083() 1312 foo084() 1313 foo085() 1314 foo086() 1315 foo087() 1316 foo088() 1317 foo089() 1318 foo090() 1319 foo091() 1320 foo092() 1321 foo093() 1322 foo094() 1323 foo095() 1324 foo096() 1325 foo097() 1326 foo098() 1327 foo099() 1328 foo100() 1329 foo101() 1330 foo102() 1331 foo103() 1332 foo104() 1333 foo105() 1334 foo106() 1335 foo107() 1336 foo108() 1337 foo109() 1338 foo110() 1339 foo111() 1340 foo112() 1341 foo113() 1342 foo114() 1343 foo115() 1344 foo116() 1345 foo117() 1346 foo118() 1347 foo119() 1348 foo120() 1349 foo121() 1350 foo122() 1351 foo123() 1352 foo124() 1353 foo125() 1354 foo126() 1355 foo127() 1356 foo128() 1357 foo129() 1358 foo130() 1359 foo131() 1360 foo132() 1361 foo133() 1362 foo134() 1363 foo135() 1364 foo136() 1365 foo137() 1366 foo138() 1367 foo139() 1368 foo140() 1369 foo141() 1370 foo142() 1371 foo143() 1372 foo144() 1373 foo145() 1374 foo146() 1375 foo147() 1376 foo148() 1377 foo149() 1378 foo150() 1379 foo151() 1380 foo152() 1381 foo153() 1382 foo154() 1383 foo155() 1384 foo156() 1385 foo157() 1386 foo158() 1387 foo159() 1388 foo160() 1389 foo161() 1390 foo162() 1391 foo163() 1392 foo164() 1393 foo165() 1394 foo166() 1395 foo167() 1396 foo168() 1397 foo169() 1398 foo170() 1399 foo171() 1400 foo172() 1401 foo173() 1402 foo174() 1403 foo175() 1404 foo176() 1405 foo177() 1406 foo178() 1407 foo179() 1408 foo180() 1409 foo181() 1410 foo182() 1411 foo183() 1412 foo184() 1413 foo185() 1414 foo186() 1415 foo187() 1416 foo188() 1417 foo189() 1418 foo190() 1419 foo191() 1420 foo192() 1421 foo193() 1422 foo194() 1423 foo195() 1424 foo196() 1425 foo197() 1426 foo198() 1427 foo199() 1428 foo200() 1429 foo201() 1430 foo202() 1431 foo203() 1432 foo204() 1433 foo205() 1434 foo206() 1435 foo207() 1436 foo208() 1437 foo209() 1438 foo210() 1439 foo211() 1440 foo212() 1441 foo213() 1442 foo214() 1443 foo215() 1444 foo216() 1445 foo217() 1446 foo218() 1447 foo219() 1448 foo220() 1449 foo221() 1450 foo222() 1451 foo223() 1452 foo224() 1453 foo225() 1454 foo226() 1455 foo227() 1456 foo228() 1457 foo229() 1458 foo230() 1459 foo231() 1460 foo232() 1461 foo233() 1462 foo234() 1463 foo235() 1464 foo236() 1465 foo237() 1466 foo238() 1467 foo239() 1468 foo240() 1469 foo241() 1470 foo242() 1471 foo243() 1472 foo244() 1473 foo245() 1474 foo246() 1475 foo247() 1476 foo248() 1477 foo249() 1478 foo250() 1479 foo251() 1480 foo252() 1481 foo253() 1482 foo254() 1483 foo255() 1484 foo256() 1485 foo257() 1486 foo258() 1487 foo259() 1488 foo260() 1489 foo261() 1490 foo262() 1491 foo263() 1492 foo264() 1493 foo265() 1494 foo266() 1495 foo267() 1496 foo268() 1497 foo269() 1498 foo270() 1499 foo271() 1500 foo272() 1501 foo273() 1502 foo274() 1503 foo275() 1504 foo276() 1505 foo277() 1506 foo278() 1507 foo279() 1508 foo280() 1509 foo281() 1510 foo282() 1511 foo283() 1512 foo284() 1513 foo285() 1514 foo286() 1515 foo287() 1516 foo288() 1517 foo289() 1518 foo290() 1519 foo291() 1520 foo292() 1521 foo293() 1522 foo294() 1523 foo295() 1524 foo296() 1525 foo297() 1526 foo298() 1527 foo299() 1528 foo300() 1529 foo301() 1530 foo302() 1531 foo303() 1532 foo304() 1533 foo305() 1534 foo306() 1535 foo307() 1536 foo308() 1537 foo309() 1538 foo310() 1539 foo311() 1540 foo312() 1541 foo313() 1542 foo314() 1543 foo315() 1544 foo316() 1545 foo317() 1546 foo318() 1547 foo319() 1548 foo320() 1549 foo321() 1550 foo322() 1551 foo323() 1552 foo324() 1553 foo325() 1554 foo326() 1555 foo327() 1556 foo328() 1557 foo329() 1558 foo330() 1559 foo331() 1560 foo332() 1561 foo333() 1562 foo334() 1563 foo335() 1564 foo336() 1565 foo337() 1566 foo338() 1567 foo339() 1568 foo340() 1569 foo341() 1570 foo342() 1571 foo343() 1572 foo344() 1573 foo345() 1574 foo346() 1575 foo347() 1576 foo348() 1577 foo349() 1578 foo350() 1579 foo351() 1580 foo352() 1581 foo353() 1582 foo354() 1583 foo355() 1584 foo356() 1585 foo357() 1586 foo358() 1587 foo359() 1588 foo360() 1589 foo361() 1590 foo362() 1591 foo363() 1592 foo364() 1593 foo365() 1594 foo366() 1595 foo367() 1596 foo368() 1597 foo369() 1598 foo370() 1599 foo371() 1600 foo372() 1601 foo373() 1602 foo374() 1603 foo375() 1604 foo376() 1605 foo377() 1606 foo378() 1607 foo379() 1608 foo380() 1609 foo381() 1610 foo382() 1611 foo383() 1612 foo384() 1613 foo385() 1614 foo386() 1615 foo387() 1616 foo388() 1617 foo389() 1618 foo390() 1619 foo391() 1620 foo392() 1621 foo393() 1622 foo394() 1623 foo395() 1624 foo396() 1625 foo397() 1626 foo398() 1627 foo399() 1628 foo400() 1629 foo401() 1630 foo402() 1631 foo403() 1632 foo404() 1633 foo405() 1634 foo406() 1635 foo407() 1636 foo408() 1637 foo409() 1638 foo410() 1639 foo411() 1640 foo412() 1641 foo413() 1642 foo414() 1643 foo415() 1644 foo416() 1645 foo417() 1646 foo418() 1647 foo419() 1648 foo420() 1649 foo421() 1650 foo422() 1651 foo423() 1652 foo424() 1653 foo425() 1654 foo426() 1655 foo427() 1656 foo428() 1657 foo429() 1658 foo430() 1659 foo431() 1660 foo432() 1661 foo433() 1662 foo434() 1663 foo435() 1664 foo436() 1665 foo437() 1666 foo438() 1667 foo439() 1668 foo440() 1669 foo441() 1670 foo442() 1671 foo443() 1672 foo444() 1673 foo445() 1674 foo446() 1675 foo447() 1676 foo448() 1677 foo449() 1678 foo450() 1679 foo451() 1680 foo452() 1681 foo453() 1682 foo454() 1683 foo455() 1684 foo456() 1685 foo457() 1686 foo458() 1687 foo459() 1688 foo460() 1689 foo461() 1690 foo462() 1691 foo463() 1692 foo464() 1693 foo465() 1694 foo466() 1695 foo467() 1696 foo468() 1697 foo469() 1698 foo470() 1699 foo471() 1700 foo472() 1701 foo473() 1702 foo474() 1703 foo475() 1704 foo476() 1705 foo477() 1706 foo478() 1707 foo479() 1708 foo480() 1709 foo481() 1710 foo482() 1711 foo483() 1712 foo484() 1713 foo485() 1714 foo486() 1715 foo487() 1716 foo488() 1717 foo489() 1718 foo490() 1719 foo491() 1720 foo492() 1721 foo493() 1722 foo494() 1723 foo495() 1724 foo496() 1725 foo497() 1726 foo498() 1727 foo499() 1728 foo500() 1729 foo501() 1730 foo502() 1731 foo503() 1732 foo504() 1733 foo505() 1734 foo506() 1735 foo507() 1736 foo508() 1737 foo509() 1738 foo510() 1739 foo511() 1740 } 1741 func $(i I) { 1742 i.foo511() 1743 } 1744 `, 1745 pos: []string{"TESTB"}, 1746 }, 1747 { 1748 fn: ` 1749 func $(i I) { 1750 i.foo001() 1751 } 1752 `, 1753 neg: []string{"TESTB"}, 1754 }, 1755 } 1756 1757 var linux386Tests = []*asmTest{ 1758 { 1759 fn: ` 1760 func f0(b []byte) uint32 { 1761 return binary.LittleEndian.Uint32(b) 1762 } 1763 `, 1764 pos: []string{"\tMOVL\t\\(.*\\),"}, 1765 }, 1766 { 1767 fn: ` 1768 func f1(b []byte, i int) uint32 { 1769 return binary.LittleEndian.Uint32(b[i:]) 1770 } 1771 `, 1772 pos: []string{"\tMOVL\t\\(.*\\)\\(.*\\*1\\),"}, 1773 }, 1774 1775 // multiplication by powers of two 1776 { 1777 fn: ` 1778 func $(n int) int { 1779 return 32*n 1780 } 1781 `, 1782 pos: []string{"SHLL"}, 1783 neg: []string{"IMULL"}, 1784 }, 1785 { 1786 fn: ` 1787 func $(n int) int { 1788 return -64*n 1789 } 1790 `, 1791 pos: []string{"SHLL"}, 1792 neg: []string{"IMULL"}, 1793 }, 1794 1795 // multiplication merging tests 1796 { 1797 fn: ` 1798 func $(n int) int { 1799 return 9*n + 14*n 1800 }`, 1801 pos: []string{"\tIMULL\t[$]23"}, // 23*n 1802 }, 1803 { 1804 fn: ` 1805 func $(a, n int) int { 1806 return 19*a + a*n 1807 }`, 1808 pos: []string{"\tADDL\t[$]19", "\tIMULL"}, // (n+19)*a 1809 }, 1810 { 1811 // check that stack store is optimized away 1812 fn: ` 1813 func $() int { 1814 var x int 1815 return *(&x) 1816 } 1817 `, 1818 pos: []string{"TEXT\t.*, [$]0-4"}, 1819 }, 1820 { 1821 fn: ` 1822 func mul3(n int) int { 1823 return 23*n - 9*n 1824 }`, 1825 pos: []string{"\tIMULL\t[$]14"}, // 14*n 1826 }, 1827 { 1828 fn: ` 1829 func mul4(a, n int) int { 1830 return n*a - a*19 1831 }`, 1832 pos: []string{"\tADDL\t[$]-19", "\tIMULL"}, // (n-19)*a 1833 }, 1834 // Check that len() and cap() div by a constant power of two 1835 // are compiled into SHRL. 1836 { 1837 fn: ` 1838 func $(a []int) int { 1839 return len(a) / 1024 1840 } 1841 `, 1842 pos: []string{"\tSHRL\t\\$10,"}, 1843 }, 1844 { 1845 fn: ` 1846 func $(s string) int { 1847 return len(s) / (4097 >> 1) 1848 } 1849 `, 1850 pos: []string{"\tSHRL\t\\$11,"}, 1851 }, 1852 { 1853 fn: ` 1854 func $(a []int) int { 1855 return cap(a) / ((1 << 11) + 2048) 1856 } 1857 `, 1858 pos: []string{"\tSHRL\t\\$12,"}, 1859 }, 1860 // Check that len() and cap() mod by a constant power of two 1861 // are compiled into ANDL. 1862 { 1863 fn: ` 1864 func $(a []int) int { 1865 return len(a) % 1024 1866 } 1867 `, 1868 pos: []string{"\tANDL\t\\$1023,"}, 1869 }, 1870 { 1871 fn: ` 1872 func $(s string) int { 1873 return len(s) % (4097 >> 1) 1874 } 1875 `, 1876 pos: []string{"\tANDL\t\\$2047,"}, 1877 }, 1878 { 1879 fn: ` 1880 func $(a []int) int { 1881 return cap(a) % ((1 << 11) + 2048) 1882 } 1883 `, 1884 pos: []string{"\tANDL\t\\$4095,"}, 1885 }, 1886 { 1887 // Test that small memmove was replaced with direct movs 1888 fn: ` 1889 func $() { 1890 x := [...]byte{1, 2, 3, 4, 5, 6, 7} 1891 copy(x[1:], x[:]) 1892 } 1893 `, 1894 neg: []string{"memmove"}, 1895 }, 1896 { 1897 // Same as above but with different size 1898 fn: ` 1899 func $() { 1900 x := [...]byte{1, 2, 3, 4} 1901 copy(x[1:], x[:]) 1902 } 1903 `, 1904 neg: []string{"memmove"}, 1905 }, 1906 } 1907 1908 var linuxS390XTests = []*asmTest{ 1909 { 1910 fn: ` 1911 func f0(b []byte) uint32 { 1912 return binary.LittleEndian.Uint32(b) 1913 } 1914 `, 1915 pos: []string{"\tMOVWBR\t\\(.*\\),"}, 1916 }, 1917 { 1918 fn: ` 1919 func f1(b []byte, i int) uint32 { 1920 return binary.LittleEndian.Uint32(b[i:]) 1921 } 1922 `, 1923 pos: []string{"\tMOVWBR\t\\(.*\\)\\(.*\\*1\\),"}, 1924 }, 1925 { 1926 fn: ` 1927 func f2(b []byte) uint64 { 1928 return binary.LittleEndian.Uint64(b) 1929 } 1930 `, 1931 pos: []string{"\tMOVDBR\t\\(.*\\),"}, 1932 }, 1933 { 1934 fn: ` 1935 func f3(b []byte, i int) uint64 { 1936 return binary.LittleEndian.Uint64(b[i:]) 1937 } 1938 `, 1939 pos: []string{"\tMOVDBR\t\\(.*\\)\\(.*\\*1\\),"}, 1940 }, 1941 { 1942 fn: ` 1943 func f4(b []byte) uint32 { 1944 return binary.BigEndian.Uint32(b) 1945 } 1946 `, 1947 pos: []string{"\tMOVWZ\t\\(.*\\),"}, 1948 }, 1949 { 1950 fn: ` 1951 func f5(b []byte, i int) uint32 { 1952 return binary.BigEndian.Uint32(b[i:]) 1953 } 1954 `, 1955 pos: []string{"\tMOVWZ\t\\(.*\\)\\(.*\\*1\\),"}, 1956 }, 1957 { 1958 fn: ` 1959 func f6(b []byte) uint64 { 1960 return binary.BigEndian.Uint64(b) 1961 } 1962 `, 1963 pos: []string{"\tMOVD\t\\(.*\\),"}, 1964 }, 1965 { 1966 fn: ` 1967 func f7(b []byte, i int) uint64 { 1968 return binary.BigEndian.Uint64(b[i:]) 1969 } 1970 `, 1971 pos: []string{"\tMOVD\t\\(.*\\)\\(.*\\*1\\),"}, 1972 }, 1973 { 1974 fn: ` 1975 func f8(x uint64) uint64 { 1976 return x<<7 + x>>57 1977 } 1978 `, 1979 pos: []string{"\tRLLG\t[$]7,"}, 1980 }, 1981 { 1982 fn: ` 1983 func f9(x uint64) uint64 { 1984 return x<<7 | x>>57 1985 } 1986 `, 1987 pos: []string{"\tRLLG\t[$]7,"}, 1988 }, 1989 { 1990 fn: ` 1991 func f10(x uint64) uint64 { 1992 return x<<7 ^ x>>57 1993 } 1994 `, 1995 pos: []string{"\tRLLG\t[$]7,"}, 1996 }, 1997 { 1998 fn: ` 1999 func f11(x uint32) uint32 { 2000 return x<<7 + x>>25 2001 } 2002 `, 2003 pos: []string{"\tRLL\t[$]7,"}, 2004 }, 2005 { 2006 fn: ` 2007 func f12(x uint32) uint32 { 2008 return x<<7 | x>>25 2009 } 2010 `, 2011 pos: []string{"\tRLL\t[$]7,"}, 2012 }, 2013 { 2014 fn: ` 2015 func f13(x uint32) uint32 { 2016 return x<<7 ^ x>>25 2017 } 2018 `, 2019 pos: []string{"\tRLL\t[$]7,"}, 2020 }, 2021 // Fused multiply-add/sub instructions. 2022 { 2023 fn: ` 2024 func f14(x, y, z float64) float64 { 2025 return x * y + z 2026 } 2027 `, 2028 pos: []string{"\tFMADD\t"}, 2029 }, 2030 { 2031 fn: ` 2032 func f15(x, y, z float64) float64 { 2033 return x * y - z 2034 } 2035 `, 2036 pos: []string{"\tFMSUB\t"}, 2037 }, 2038 { 2039 fn: ` 2040 func f16(x, y, z float32) float32 { 2041 return x * y + z 2042 } 2043 `, 2044 pos: []string{"\tFMADDS\t"}, 2045 }, 2046 { 2047 fn: ` 2048 func f17(x, y, z float32) float32 { 2049 return x * y - z 2050 } 2051 `, 2052 pos: []string{"\tFMSUBS\t"}, 2053 }, 2054 // Intrinsic tests for math/bits 2055 { 2056 fn: ` 2057 func f18(a uint64) int { 2058 return bits.TrailingZeros64(a) 2059 } 2060 `, 2061 pos: []string{"\tFLOGR\t"}, 2062 }, 2063 { 2064 fn: ` 2065 func f19(a uint32) int { 2066 return bits.TrailingZeros32(a) 2067 } 2068 `, 2069 pos: []string{"\tFLOGR\t", "\tMOVWZ\t"}, 2070 }, 2071 { 2072 fn: ` 2073 func f20(a uint16) int { 2074 return bits.TrailingZeros16(a) 2075 } 2076 `, 2077 pos: []string{"\tFLOGR\t", "\tOR\t\\$65536,"}, 2078 }, 2079 { 2080 fn: ` 2081 func f21(a uint8) int { 2082 return bits.TrailingZeros8(a) 2083 } 2084 `, 2085 pos: []string{"\tFLOGR\t", "\tOR\t\\$256,"}, 2086 }, 2087 // Intrinsic tests for math/bits 2088 { 2089 fn: ` 2090 func f22(a uint64) uint64 { 2091 return bits.ReverseBytes64(a) 2092 } 2093 `, 2094 pos: []string{"\tMOVDBR\t"}, 2095 }, 2096 { 2097 fn: ` 2098 func f23(a uint32) uint32 { 2099 return bits.ReverseBytes32(a) 2100 } 2101 `, 2102 pos: []string{"\tMOVWBR\t"}, 2103 }, 2104 { 2105 fn: ` 2106 func f24(a uint64) int { 2107 return bits.Len64(a) 2108 } 2109 `, 2110 pos: []string{"\tFLOGR\t"}, 2111 }, 2112 { 2113 fn: ` 2114 func f25(a uint32) int { 2115 return bits.Len32(a) 2116 } 2117 `, 2118 pos: []string{"\tFLOGR\t"}, 2119 }, 2120 { 2121 fn: ` 2122 func f26(a uint16) int { 2123 return bits.Len16(a) 2124 } 2125 `, 2126 pos: []string{"\tFLOGR\t"}, 2127 }, 2128 { 2129 fn: ` 2130 func f27(a uint8) int { 2131 return bits.Len8(a) 2132 } 2133 `, 2134 pos: []string{"\tFLOGR\t"}, 2135 }, 2136 { 2137 fn: ` 2138 func f28(a uint) int { 2139 return bits.Len(a) 2140 } 2141 `, 2142 pos: []string{"\tFLOGR\t"}, 2143 }, 2144 { 2145 fn: ` 2146 func f29(a uint64) int { 2147 return bits.LeadingZeros64(a) 2148 } 2149 `, 2150 pos: []string{"\tFLOGR\t"}, 2151 }, 2152 { 2153 fn: ` 2154 func f30(a uint32) int { 2155 return bits.LeadingZeros32(a) 2156 } 2157 `, 2158 pos: []string{"\tFLOGR\t"}, 2159 }, 2160 { 2161 fn: ` 2162 func f31(a uint16) int { 2163 return bits.LeadingZeros16(a) 2164 } 2165 `, 2166 pos: []string{"\tFLOGR\t"}, 2167 }, 2168 { 2169 fn: ` 2170 func f32(a uint8) int { 2171 return bits.LeadingZeros8(a) 2172 } 2173 `, 2174 pos: []string{"\tFLOGR\t"}, 2175 }, 2176 { 2177 fn: ` 2178 func f33(a uint) int { 2179 return bits.LeadingZeros(a) 2180 } 2181 `, 2182 pos: []string{"\tFLOGR\t"}, 2183 }, 2184 // Intrinsic tests for math. 2185 { 2186 fn: ` 2187 func ceil(x float64) float64 { 2188 return math.Ceil(x) 2189 } 2190 `, 2191 pos: []string{"\tFIDBR\t[$]6"}, 2192 }, 2193 { 2194 fn: ` 2195 func floor(x float64) float64 { 2196 return math.Floor(x) 2197 } 2198 `, 2199 pos: []string{"\tFIDBR\t[$]7"}, 2200 }, 2201 { 2202 fn: ` 2203 func round(x float64) float64 { 2204 return math.Round(x) 2205 } 2206 `, 2207 pos: []string{"\tFIDBR\t[$]1"}, 2208 }, 2209 { 2210 fn: ` 2211 func trunc(x float64) float64 { 2212 return math.Trunc(x) 2213 } 2214 `, 2215 pos: []string{"\tFIDBR\t[$]5"}, 2216 }, 2217 { 2218 fn: ` 2219 func roundToEven(x float64) float64 { 2220 return math.RoundToEven(x) 2221 } 2222 `, 2223 pos: []string{"\tFIDBR\t[$]4"}, 2224 }, 2225 { 2226 // check that stack store is optimized away 2227 fn: ` 2228 func $() int { 2229 var x int 2230 return *(&x) 2231 } 2232 `, 2233 pos: []string{"TEXT\t.*, [$]0-8"}, 2234 }, 2235 // Constant propagation through raw bits conversions. 2236 { 2237 // uint32 constant converted to float32 constant 2238 fn: ` 2239 func $(x float32) float32 { 2240 if x > math.Float32frombits(0x3f800000) { 2241 return -x 2242 } 2243 return x 2244 } 2245 `, 2246 pos: []string{"\tFMOVS\t[$]f32.3f800000\\(SB\\)"}, 2247 }, 2248 { 2249 // float32 constant converted to uint32 constant 2250 fn: ` 2251 func $(x uint32) uint32 { 2252 if x > math.Float32bits(1) { 2253 return -x 2254 } 2255 return x 2256 } 2257 `, 2258 neg: []string{"\tFMOVS\t"}, 2259 }, 2260 // Constant propagation through float comparisons. 2261 { 2262 fn: ` 2263 func $() bool { 2264 return 0.5 == float64(uint32(1)) || 2265 1.5 > float64(uint64(1<<63)) || 2266 math.NaN() == math.NaN() 2267 } 2268 `, 2269 pos: []string{"\tMOV(B|BZ|D)\t[$]0,"}, 2270 neg: []string{"\tFCMPU\t", "\tMOV(B|BZ|D)\t[$]1,"}, 2271 }, 2272 { 2273 fn: ` 2274 func $() bool { 2275 return float32(0.5) <= float32(int64(1)) && 2276 float32(1.5) >= float32(int32(-1<<31)) && 2277 float32(math.NaN()) != float32(math.NaN()) 2278 } 2279 `, 2280 pos: []string{"\tMOV(B|BZ|D)\t[$]1,"}, 2281 neg: []string{"\tCEBR\t", "\tMOV(B|BZ|D)\t[$]0,"}, 2282 }, 2283 // math tests 2284 { 2285 fn: ` 2286 func $(x float64) float64 { 2287 return math.Abs(x) 2288 } 2289 `, 2290 pos: []string{"\tLPDFR\t"}, 2291 neg: []string{"\tMOVD\t"}, // no integer loads/stores 2292 }, 2293 { 2294 fn: ` 2295 func $(x float32) float32 { 2296 return float32(math.Abs(float64(x))) 2297 } 2298 `, 2299 pos: []string{"\tLPDFR\t"}, 2300 neg: []string{"\tLDEBR\t", "\tLEDBR\t"}, // no float64 conversion 2301 }, 2302 { 2303 fn: ` 2304 func $(x float64) float64 { 2305 return math.Float64frombits(math.Float64bits(x)|1<<63) 2306 } 2307 `, 2308 pos: []string{"\tLNDFR\t"}, 2309 neg: []string{"\tMOVD\t"}, // no integer loads/stores 2310 }, 2311 { 2312 fn: ` 2313 func $(x float64) float64 { 2314 return -math.Abs(x) 2315 } 2316 `, 2317 pos: []string{"\tLNDFR\t"}, 2318 neg: []string{"\tMOVD\t"}, // no integer loads/stores 2319 }, 2320 { 2321 fn: ` 2322 func $(x, y float64) float64 { 2323 return math.Copysign(x, y) 2324 } 2325 `, 2326 pos: []string{"\tCPSDR\t"}, 2327 neg: []string{"\tMOVD\t"}, // no integer loads/stores 2328 }, 2329 { 2330 fn: ` 2331 func $(x float64) float64 { 2332 return math.Copysign(x, -1) 2333 } 2334 `, 2335 pos: []string{"\tLNDFR\t"}, 2336 neg: []string{"\tMOVD\t"}, // no integer loads/stores 2337 }, 2338 { 2339 fn: ` 2340 func $(x float64) float64 { 2341 return math.Copysign(-1, x) 2342 } 2343 `, 2344 pos: []string{"\tCPSDR\t"}, 2345 neg: []string{"\tMOVD\t"}, // no integer loads/stores 2346 }, 2347 } 2348 2349 var linuxARMTests = []*asmTest{ 2350 // multiplication by powers of two 2351 { 2352 fn: ` 2353 func $(n int) int { 2354 return 16*n 2355 } 2356 `, 2357 pos: []string{"\tSLL\t[$]4"}, 2358 neg: []string{"\tMUL\t"}, 2359 }, 2360 { 2361 fn: ` 2362 func $(n int) int { 2363 return -32*n 2364 } 2365 `, 2366 pos: []string{"\tSLL\t[$]5"}, 2367 neg: []string{"\tMUL\t"}, 2368 }, 2369 2370 { 2371 fn: ` 2372 func f0(x uint32) uint32 { 2373 return x<<7 + x>>25 2374 } 2375 `, 2376 pos: []string{"\tMOVW\tR[0-9]+@>25,"}, 2377 }, 2378 { 2379 fn: ` 2380 func f1(x uint32) uint32 { 2381 return x<<7 | x>>25 2382 } 2383 `, 2384 pos: []string{"\tMOVW\tR[0-9]+@>25,"}, 2385 }, 2386 { 2387 fn: ` 2388 func f2(x uint32) uint32 { 2389 return x<<7 ^ x>>25 2390 } 2391 `, 2392 pos: []string{"\tMOVW\tR[0-9]+@>25,"}, 2393 }, 2394 { 2395 fn: ` 2396 func f3(a uint64) int { 2397 return bits.Len64(a) 2398 } 2399 `, 2400 pos: []string{"\tCLZ\t"}, 2401 }, 2402 { 2403 fn: ` 2404 func f4(a uint32) int { 2405 return bits.Len32(a) 2406 } 2407 `, 2408 pos: []string{"\tCLZ\t"}, 2409 }, 2410 { 2411 fn: ` 2412 func f5(a uint16) int { 2413 return bits.Len16(a) 2414 } 2415 `, 2416 pos: []string{"\tCLZ\t"}, 2417 }, 2418 { 2419 fn: ` 2420 func f6(a uint8) int { 2421 return bits.Len8(a) 2422 } 2423 `, 2424 pos: []string{"\tCLZ\t"}, 2425 }, 2426 { 2427 fn: ` 2428 func f7(a uint) int { 2429 return bits.Len(a) 2430 } 2431 `, 2432 pos: []string{"\tCLZ\t"}, 2433 }, 2434 { 2435 fn: ` 2436 func f8(a uint64) int { 2437 return bits.LeadingZeros64(a) 2438 } 2439 `, 2440 pos: []string{"\tCLZ\t"}, 2441 }, 2442 { 2443 fn: ` 2444 func f9(a uint32) int { 2445 return bits.LeadingZeros32(a) 2446 } 2447 `, 2448 pos: []string{"\tCLZ\t"}, 2449 }, 2450 { 2451 fn: ` 2452 func f10(a uint16) int { 2453 return bits.LeadingZeros16(a) 2454 } 2455 `, 2456 pos: []string{"\tCLZ\t"}, 2457 }, 2458 { 2459 fn: ` 2460 func f11(a uint8) int { 2461 return bits.LeadingZeros8(a) 2462 } 2463 `, 2464 pos: []string{"\tCLZ\t"}, 2465 }, 2466 { 2467 fn: ` 2468 func f12(a uint) int { 2469 return bits.LeadingZeros(a) 2470 } 2471 `, 2472 pos: []string{"\tCLZ\t"}, 2473 }, 2474 { 2475 // make sure assembly output has matching offset and base register. 2476 fn: ` 2477 func f13(a, b int) int { 2478 runtime.GC() // use some frame 2479 return b 2480 } 2481 `, 2482 pos: []string{"b\\+4\\(FP\\)"}, 2483 }, 2484 { 2485 // check that stack store is optimized away 2486 fn: ` 2487 func $() int { 2488 var x int 2489 return *(&x) 2490 } 2491 `, 2492 pos: []string{"TEXT\t.*, [$]-4-4"}, 2493 }, 2494 } 2495 2496 var linuxARM64Tests = []*asmTest{ 2497 // multiplication by powers of two 2498 { 2499 fn: ` 2500 func $(n int) int { 2501 return 64*n 2502 } 2503 `, 2504 pos: []string{"\tLSL\t[$]6"}, 2505 neg: []string{"\tMUL\t"}, 2506 }, 2507 { 2508 fn: ` 2509 func $(n int) int { 2510 return -128*n 2511 } 2512 `, 2513 pos: []string{"\tLSL\t[$]7"}, 2514 neg: []string{"\tMUL\t"}, 2515 }, 2516 2517 { 2518 fn: ` 2519 func f0(x uint64) uint64 { 2520 return x<<7 + x>>57 2521 } 2522 `, 2523 pos: []string{"\tROR\t[$]57,"}, 2524 }, 2525 { 2526 fn: ` 2527 func f1(x uint64) uint64 { 2528 return x<<7 | x>>57 2529 } 2530 `, 2531 pos: []string{"\tROR\t[$]57,"}, 2532 }, 2533 { 2534 fn: ` 2535 func f2(x uint64) uint64 { 2536 return x<<7 ^ x>>57 2537 } 2538 `, 2539 pos: []string{"\tROR\t[$]57,"}, 2540 }, 2541 { 2542 fn: ` 2543 func f3(x uint32) uint32 { 2544 return x<<7 + x>>25 2545 } 2546 `, 2547 pos: []string{"\tRORW\t[$]25,"}, 2548 }, 2549 { 2550 fn: ` 2551 func f4(x uint32) uint32 { 2552 return x<<7 | x>>25 2553 } 2554 `, 2555 pos: []string{"\tRORW\t[$]25,"}, 2556 }, 2557 { 2558 fn: ` 2559 func f5(x uint32) uint32 { 2560 return x<<7 ^ x>>25 2561 } 2562 `, 2563 pos: []string{"\tRORW\t[$]25,"}, 2564 }, 2565 { 2566 fn: ` 2567 func f22(a uint64) uint64 { 2568 return bits.ReverseBytes64(a) 2569 } 2570 `, 2571 pos: []string{"\tREV\t"}, 2572 }, 2573 { 2574 fn: ` 2575 func f23(a uint32) uint32 { 2576 return bits.ReverseBytes32(a) 2577 } 2578 `, 2579 pos: []string{"\tREVW\t"}, 2580 }, 2581 { 2582 fn: ` 2583 func f24(a uint64) int { 2584 return bits.Len64(a) 2585 } 2586 `, 2587 pos: []string{"\tCLZ\t"}, 2588 }, 2589 { 2590 fn: ` 2591 func f25(a uint32) int { 2592 return bits.Len32(a) 2593 } 2594 `, 2595 pos: []string{"\tCLZ\t"}, 2596 }, 2597 { 2598 fn: ` 2599 func f26(a uint16) int { 2600 return bits.Len16(a) 2601 } 2602 `, 2603 pos: []string{"\tCLZ\t"}, 2604 }, 2605 { 2606 fn: ` 2607 func f27(a uint8) int { 2608 return bits.Len8(a) 2609 } 2610 `, 2611 pos: []string{"\tCLZ\t"}, 2612 }, 2613 { 2614 fn: ` 2615 func f28(a uint) int { 2616 return bits.Len(a) 2617 } 2618 `, 2619 pos: []string{"\tCLZ\t"}, 2620 }, 2621 { 2622 fn: ` 2623 func f29(a uint64) int { 2624 return bits.LeadingZeros64(a) 2625 } 2626 `, 2627 pos: []string{"\tCLZ\t"}, 2628 }, 2629 { 2630 fn: ` 2631 func f30(a uint32) int { 2632 return bits.LeadingZeros32(a) 2633 } 2634 `, 2635 pos: []string{"\tCLZ\t"}, 2636 }, 2637 { 2638 fn: ` 2639 func f31(a uint16) int { 2640 return bits.LeadingZeros16(a) 2641 } 2642 `, 2643 pos: []string{"\tCLZ\t"}, 2644 }, 2645 { 2646 fn: ` 2647 func f32(a uint8) int { 2648 return bits.LeadingZeros8(a) 2649 } 2650 `, 2651 pos: []string{"\tCLZ\t"}, 2652 }, 2653 { 2654 fn: ` 2655 func f33(a uint) int { 2656 return bits.LeadingZeros(a) 2657 } 2658 `, 2659 pos: []string{"\tCLZ\t"}, 2660 }, 2661 { 2662 fn: ` 2663 func f34(a uint64) uint64 { 2664 return a & ((1<<63)-1) 2665 } 2666 `, 2667 pos: []string{"\tAND\t"}, 2668 }, 2669 { 2670 fn: ` 2671 func f35(a uint64) uint64 { 2672 return a & (1<<63) 2673 } 2674 `, 2675 pos: []string{"\tAND\t"}, 2676 }, 2677 { 2678 // make sure offsets are folded into load and store. 2679 fn: ` 2680 func f36(_, a [20]byte) (b [20]byte) { 2681 b = a 2682 return 2683 } 2684 `, 2685 pos: []string{"\tMOVD\t\"\"\\.a\\+[0-9]+\\(FP\\), R[0-9]+", "\tMOVD\tR[0-9]+, \"\"\\.b\\+[0-9]+\\(FP\\)"}, 2686 }, 2687 { 2688 // check that stack store is optimized away 2689 fn: ` 2690 func $() int { 2691 var x int 2692 return *(&x) 2693 } 2694 `, 2695 pos: []string{"TEXT\t.*, [$]-8-8"}, 2696 }, 2697 { 2698 // check that we don't emit comparisons for constant shift 2699 fn: ` 2700 //go:nosplit 2701 func $(x int) int { 2702 return x << 17 2703 } 2704 `, 2705 pos: []string{"LSL\t\\$17"}, 2706 neg: []string{"CMP"}, 2707 }, 2708 } 2709 2710 var linuxMIPSTests = []*asmTest{ 2711 { 2712 fn: ` 2713 func f0(a uint64) int { 2714 return bits.Len64(a) 2715 } 2716 `, 2717 pos: []string{"\tCLZ\t"}, 2718 }, 2719 { 2720 fn: ` 2721 func f1(a uint32) int { 2722 return bits.Len32(a) 2723 } 2724 `, 2725 pos: []string{"\tCLZ\t"}, 2726 }, 2727 { 2728 fn: ` 2729 func f2(a uint16) int { 2730 return bits.Len16(a) 2731 } 2732 `, 2733 pos: []string{"\tCLZ\t"}, 2734 }, 2735 { 2736 fn: ` 2737 func f3(a uint8) int { 2738 return bits.Len8(a) 2739 } 2740 `, 2741 pos: []string{"\tCLZ\t"}, 2742 }, 2743 { 2744 fn: ` 2745 func f4(a uint) int { 2746 return bits.Len(a) 2747 } 2748 `, 2749 pos: []string{"\tCLZ\t"}, 2750 }, 2751 { 2752 fn: ` 2753 func f5(a uint64) int { 2754 return bits.LeadingZeros64(a) 2755 } 2756 `, 2757 pos: []string{"\tCLZ\t"}, 2758 }, 2759 { 2760 fn: ` 2761 func f6(a uint32) int { 2762 return bits.LeadingZeros32(a) 2763 } 2764 `, 2765 pos: []string{"\tCLZ\t"}, 2766 }, 2767 { 2768 fn: ` 2769 func f7(a uint16) int { 2770 return bits.LeadingZeros16(a) 2771 } 2772 `, 2773 pos: []string{"\tCLZ\t"}, 2774 }, 2775 { 2776 fn: ` 2777 func f8(a uint8) int { 2778 return bits.LeadingZeros8(a) 2779 } 2780 `, 2781 pos: []string{"\tCLZ\t"}, 2782 }, 2783 { 2784 fn: ` 2785 func f9(a uint) int { 2786 return bits.LeadingZeros(a) 2787 } 2788 `, 2789 pos: []string{"\tCLZ\t"}, 2790 }, 2791 { 2792 // check that stack store is optimized away 2793 fn: ` 2794 func $() int { 2795 var x int 2796 return *(&x) 2797 } 2798 `, 2799 pos: []string{"TEXT\t.*, [$]-4-4"}, 2800 }, 2801 } 2802 2803 var linuxMIPS64Tests = []*asmTest{ 2804 { 2805 // check that we don't emit comparisons for constant shift 2806 fn: ` 2807 func $(x int) int { 2808 return x << 17 2809 } 2810 `, 2811 pos: []string{"SLLV\t\\$17"}, 2812 neg: []string{"SGT"}, 2813 }, 2814 } 2815 2816 var linuxPPC64LETests = []*asmTest{ 2817 // Fused multiply-add/sub instructions. 2818 { 2819 fn: ` 2820 func f0(x, y, z float64) float64 { 2821 return x * y + z 2822 } 2823 `, 2824 pos: []string{"\tFMADD\t"}, 2825 }, 2826 { 2827 fn: ` 2828 func f1(x, y, z float64) float64 { 2829 return x * y - z 2830 } 2831 `, 2832 pos: []string{"\tFMSUB\t"}, 2833 }, 2834 { 2835 fn: ` 2836 func f2(x, y, z float32) float32 { 2837 return x * y + z 2838 } 2839 `, 2840 pos: []string{"\tFMADDS\t"}, 2841 }, 2842 { 2843 fn: ` 2844 func f3(x, y, z float32) float32 { 2845 return x * y - z 2846 } 2847 `, 2848 pos: []string{"\tFMSUBS\t"}, 2849 }, 2850 { 2851 fn: ` 2852 func f4(x uint32) uint32 { 2853 return x<<7 | x>>25 2854 } 2855 `, 2856 pos: []string{"\tROTLW\t"}, 2857 }, 2858 { 2859 fn: ` 2860 func f5(x uint32) uint32 { 2861 return x<<7 + x>>25 2862 } 2863 `, 2864 pos: []string{"\tROTLW\t"}, 2865 }, 2866 { 2867 fn: ` 2868 func f6(x uint32) uint32 { 2869 return x<<7 ^ x>>25 2870 } 2871 `, 2872 pos: []string{"\tROTLW\t"}, 2873 }, 2874 { 2875 fn: ` 2876 func f7(x uint64) uint64 { 2877 return x<<7 | x>>57 2878 } 2879 `, 2880 pos: []string{"\tROTL\t"}, 2881 }, 2882 { 2883 fn: ` 2884 func f8(x uint64) uint64 { 2885 return x<<7 + x>>57 2886 } 2887 `, 2888 pos: []string{"\tROTL\t"}, 2889 }, 2890 { 2891 fn: ` 2892 func f9(x uint64) uint64 { 2893 return x<<7 ^ x>>57 2894 } 2895 `, 2896 pos: []string{"\tROTL\t"}, 2897 }, 2898 { 2899 fn: ` 2900 func f10(a uint32) uint32 { 2901 return bits.RotateLeft32(a, 9) 2902 } 2903 `, 2904 pos: []string{"\tROTLW\t"}, 2905 }, 2906 { 2907 fn: ` 2908 func f11(a uint64) uint64 { 2909 return bits.RotateLeft64(a, 37) 2910 } 2911 `, 2912 pos: []string{"\tROTL\t"}, 2913 }, 2914 2915 { 2916 fn: ` 2917 func f12(a, b float64) float64 { 2918 return math.Copysign(a, b) 2919 } 2920 `, 2921 pos: []string{"\tFCPSGN\t"}, 2922 }, 2923 2924 { 2925 fn: ` 2926 func f13(a float64) float64 { 2927 return math.Abs(a) 2928 } 2929 `, 2930 pos: []string{"\tFABS\t"}, 2931 }, 2932 2933 { 2934 fn: ` 2935 func f14(b []byte) uint16 { 2936 return binary.LittleEndian.Uint16(b) 2937 } 2938 `, 2939 pos: []string{"\tMOVHZ\t"}, 2940 }, 2941 { 2942 fn: ` 2943 func f15(b []byte) uint32 { 2944 return binary.LittleEndian.Uint32(b) 2945 } 2946 `, 2947 pos: []string{"\tMOVWZ\t"}, 2948 }, 2949 2950 { 2951 fn: ` 2952 func f16(b []byte) uint64 { 2953 return binary.LittleEndian.Uint64(b) 2954 } 2955 `, 2956 pos: []string{"\tMOVD\t"}, 2957 neg: []string{"MOVBZ", "MOVHZ", "MOVWZ"}, 2958 }, 2959 2960 { 2961 fn: ` 2962 func f17(b []byte, v uint16) { 2963 binary.LittleEndian.PutUint16(b, v) 2964 } 2965 `, 2966 pos: []string{"\tMOVH\t"}, 2967 }, 2968 2969 { 2970 fn: ` 2971 func f18(b []byte, v uint32) { 2972 binary.LittleEndian.PutUint32(b, v) 2973 } 2974 `, 2975 pos: []string{"\tMOVW\t"}, 2976 }, 2977 2978 { 2979 fn: ` 2980 func f19(b []byte, v uint64) { 2981 binary.LittleEndian.PutUint64(b, v) 2982 } 2983 `, 2984 pos: []string{"\tMOVD\t"}, 2985 neg: []string{"MOVB", "MOVH", "MOVW"}, 2986 }, 2987 2988 { 2989 // check that stack store is optimized away 2990 fn: ` 2991 func $() int { 2992 var x int 2993 return *(&x) 2994 } 2995 `, 2996 pos: []string{"TEXT\t.*, [$]0-8"}, 2997 }, 2998 // Constant propagation through raw bits conversions. 2999 { 3000 // uint32 constant converted to float32 constant 3001 fn: ` 3002 func $(x float32) float32 { 3003 if x > math.Float32frombits(0x3f800000) { 3004 return -x 3005 } 3006 return x 3007 } 3008 `, 3009 pos: []string{"\tFMOVS\t[$]f32.3f800000\\(SB\\)"}, 3010 }, 3011 { 3012 // float32 constant converted to uint32 constant 3013 fn: ` 3014 func $(x uint32) uint32 { 3015 if x > math.Float32bits(1) { 3016 return -x 3017 } 3018 return x 3019 } 3020 `, 3021 neg: []string{"\tFMOVS\t"}, 3022 }, 3023 } 3024 3025 var plan9AMD64Tests = []*asmTest{ 3026 // We should make sure that the compiler doesn't generate floating point 3027 // instructions for non-float operations on Plan 9, because floating point 3028 // operations are not allowed in the note handler. 3029 // Array zeroing. 3030 { 3031 fn: ` 3032 func $() [16]byte { 3033 var a [16]byte 3034 return a 3035 } 3036 `, 3037 pos: []string{"\tMOVQ\t\\$0, \"\""}, 3038 }, 3039 // Array copy. 3040 { 3041 fn: ` 3042 func $(a [16]byte) (b [16]byte) { 3043 b = a 3044 return 3045 } 3046 `, 3047 pos: []string{"\tMOVQ\t\"\"\\.a\\+[0-9]+\\(SP\\), (AX|CX)", "\tMOVQ\t(AX|CX), \"\"\\.b\\+[0-9]+\\(SP\\)"}, 3048 }, 3049 } 3050 3051 // TestLineNumber checks to make sure the generated assembly has line numbers 3052 // see issue #16214 3053 func TestLineNumber(t *testing.T) { 3054 testenv.MustHaveGoBuild(t) 3055 dir, err := ioutil.TempDir("", "TestLineNumber") 3056 if err != nil { 3057 t.Fatalf("could not create directory: %v", err) 3058 } 3059 defer os.RemoveAll(dir) 3060 3061 src := filepath.Join(dir, "x.go") 3062 err = ioutil.WriteFile(src, []byte(issue16214src), 0644) 3063 if err != nil { 3064 t.Fatalf("could not write file: %v", err) 3065 } 3066 3067 cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-S", "-o", filepath.Join(dir, "out.o"), src) 3068 out, err := cmd.CombinedOutput() 3069 if err != nil { 3070 t.Fatalf("fail to run go tool compile: %v", err) 3071 } 3072 3073 if strings.Contains(string(out), "unknown line number") { 3074 t.Errorf("line number missing in assembly:\n%s", out) 3075 } 3076 } 3077 3078 var issue16214src = ` 3079 package main 3080 3081 func Mod32(x uint32) uint32 { 3082 return x % 3 // frontend rewrites it as HMUL with 2863311531, the LITERAL node has unknown Pos 3083 } 3084 `