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