github.com/hlts2/go@v0.0.0-20170904000733-812b34efaed8/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/bits"}, 240 tests: linuxS390XTests, 241 }, 242 { 243 arch: "arm", 244 os: "linux", 245 imports: []string{"math/bits"}, 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 tests: linuxPPC64LETests, 269 }, 270 { 271 arch: "amd64", 272 os: "plan9", 273 tests: plan9AMD64Tests, 274 }, 275 } 276 277 var linuxAMD64Tests = []*asmTest{ 278 { 279 fn: ` 280 func f0(x int) int { 281 return x * 64 282 } 283 `, 284 pos: []string{"\tSHLQ\t\\$6,"}, 285 }, 286 { 287 fn: ` 288 func f1(x int) int { 289 return x * 96 290 } 291 `, 292 pos: []string{"\tSHLQ\t\\$5,", "\tLEAQ\t\\(.*\\)\\(.*\\*2\\),"}, 293 }, 294 // Load-combining tests. 295 { 296 fn: ` 297 func f2(b []byte) uint64 { 298 return binary.LittleEndian.Uint64(b) 299 } 300 `, 301 pos: []string{"\tMOVQ\t\\(.*\\),"}, 302 }, 303 { 304 fn: ` 305 func f3(b []byte, i int) uint64 { 306 return binary.LittleEndian.Uint64(b[i:]) 307 } 308 `, 309 pos: []string{"\tMOVQ\t\\(.*\\)\\(.*\\*1\\),"}, 310 }, 311 { 312 fn: ` 313 func f4(b []byte) uint32 { 314 return binary.LittleEndian.Uint32(b) 315 } 316 `, 317 pos: []string{"\tMOVL\t\\(.*\\),"}, 318 }, 319 { 320 fn: ` 321 func f5(b []byte, i int) uint32 { 322 return binary.LittleEndian.Uint32(b[i:]) 323 } 324 `, 325 pos: []string{"\tMOVL\t\\(.*\\)\\(.*\\*1\\),"}, 326 }, 327 { 328 fn: ` 329 func f6(b []byte) uint64 { 330 return binary.BigEndian.Uint64(b) 331 } 332 `, 333 pos: []string{"\tBSWAPQ\t"}, 334 }, 335 { 336 fn: ` 337 func f7(b []byte, i int) uint64 { 338 return binary.BigEndian.Uint64(b[i:]) 339 } 340 `, 341 pos: []string{"\tBSWAPQ\t"}, 342 }, 343 { 344 fn: ` 345 func f8(b []byte, v uint64) { 346 binary.BigEndian.PutUint64(b, v) 347 } 348 `, 349 pos: []string{"\tBSWAPQ\t"}, 350 }, 351 { 352 fn: ` 353 func f9(b []byte, i int, v uint64) { 354 binary.BigEndian.PutUint64(b[i:], v) 355 } 356 `, 357 pos: []string{"\tBSWAPQ\t"}, 358 }, 359 { 360 fn: ` 361 func f10(b []byte) uint32 { 362 return binary.BigEndian.Uint32(b) 363 } 364 `, 365 pos: []string{"\tBSWAPL\t"}, 366 }, 367 { 368 fn: ` 369 func f11(b []byte, i int) uint32 { 370 return binary.BigEndian.Uint32(b[i:]) 371 } 372 `, 373 pos: []string{"\tBSWAPL\t"}, 374 }, 375 { 376 fn: ` 377 func f12(b []byte, v uint32) { 378 binary.BigEndian.PutUint32(b, v) 379 } 380 `, 381 pos: []string{"\tBSWAPL\t"}, 382 }, 383 { 384 fn: ` 385 func f13(b []byte, i int, v uint32) { 386 binary.BigEndian.PutUint32(b[i:], v) 387 } 388 `, 389 pos: []string{"\tBSWAPL\t"}, 390 }, 391 { 392 fn: ` 393 func f14(b []byte) uint16 { 394 return binary.BigEndian.Uint16(b) 395 } 396 `, 397 pos: []string{"\tROLW\t\\$8,"}, 398 }, 399 { 400 fn: ` 401 func f15(b []byte, i int) uint16 { 402 return binary.BigEndian.Uint16(b[i:]) 403 } 404 `, 405 pos: []string{"\tROLW\t\\$8,"}, 406 }, 407 { 408 fn: ` 409 func f16(b []byte, v uint16) { 410 binary.BigEndian.PutUint16(b, v) 411 } 412 `, 413 pos: []string{"\tROLW\t\\$8,"}, 414 }, 415 { 416 fn: ` 417 func f17(b []byte, i int, v uint16) { 418 binary.BigEndian.PutUint16(b[i:], v) 419 } 420 `, 421 pos: []string{"\tROLW\t\\$8,"}, 422 }, 423 // Structure zeroing. See issue #18370. 424 { 425 fn: ` 426 type T1 struct { 427 a, b, c int 428 } 429 func $(t *T1) { 430 *t = T1{} 431 } 432 `, 433 pos: []string{"\tXORPS\tX., X", "\tMOVUPS\tX., \\(.*\\)", "\tMOVQ\t\\$0, 16\\(.*\\)"}, 434 }, 435 // SSA-able composite literal initialization. Issue 18872. 436 { 437 fn: ` 438 type T18872 struct { 439 a, b, c, d int 440 } 441 442 func f18872(p *T18872) { 443 *p = T18872{1, 2, 3, 4} 444 } 445 `, 446 pos: []string{"\tMOVQ\t[$]1", "\tMOVQ\t[$]2", "\tMOVQ\t[$]3", "\tMOVQ\t[$]4"}, 447 }, 448 // Also test struct containing pointers (this was special because of write barriers). 449 { 450 fn: ` 451 type T2 struct { 452 a, b, c *int 453 } 454 func f19(t *T2) { 455 *t = T2{} 456 } 457 `, 458 pos: []string{"\tXORPS\tX., X", "\tMOVUPS\tX., \\(.*\\)", "\tMOVQ\t\\$0, 16\\(.*\\)", "\tCALL\truntime\\.writebarrierptr\\(SB\\)"}, 459 }, 460 // Rotate tests 461 { 462 fn: ` 463 func f20(x uint64) uint64 { 464 return x<<7 | x>>57 465 } 466 `, 467 pos: []string{"\tROLQ\t[$]7,"}, 468 }, 469 { 470 fn: ` 471 func f21(x uint64) uint64 { 472 return x<<7 + x>>57 473 } 474 `, 475 pos: []string{"\tROLQ\t[$]7,"}, 476 }, 477 { 478 fn: ` 479 func f22(x uint64) uint64 { 480 return x<<7 ^ x>>57 481 } 482 `, 483 pos: []string{"\tROLQ\t[$]7,"}, 484 }, 485 { 486 fn: ` 487 func f23(x uint32) uint32 { 488 return x<<7 + x>>25 489 } 490 `, 491 pos: []string{"\tROLL\t[$]7,"}, 492 }, 493 { 494 fn: ` 495 func f24(x uint32) uint32 { 496 return x<<7 | x>>25 497 } 498 `, 499 pos: []string{"\tROLL\t[$]7,"}, 500 }, 501 { 502 fn: ` 503 func f25(x uint32) uint32 { 504 return x<<7 ^ x>>25 505 } 506 `, 507 pos: []string{"\tROLL\t[$]7,"}, 508 }, 509 { 510 fn: ` 511 func f26(x uint16) uint16 { 512 return x<<7 + x>>9 513 } 514 `, 515 pos: []string{"\tROLW\t[$]7,"}, 516 }, 517 { 518 fn: ` 519 func f27(x uint16) uint16 { 520 return x<<7 | x>>9 521 } 522 `, 523 pos: []string{"\tROLW\t[$]7,"}, 524 }, 525 { 526 fn: ` 527 func f28(x uint16) uint16 { 528 return x<<7 ^ x>>9 529 } 530 `, 531 pos: []string{"\tROLW\t[$]7,"}, 532 }, 533 { 534 fn: ` 535 func f29(x uint8) uint8 { 536 return x<<7 + x>>1 537 } 538 `, 539 pos: []string{"\tROLB\t[$]7,"}, 540 }, 541 { 542 fn: ` 543 func f30(x uint8) uint8 { 544 return x<<7 | x>>1 545 } 546 `, 547 pos: []string{"\tROLB\t[$]7,"}, 548 }, 549 { 550 fn: ` 551 func f31(x uint8) uint8 { 552 return x<<7 ^ x>>1 553 } 554 `, 555 pos: []string{"\tROLB\t[$]7,"}, 556 }, 557 // Rotate after inlining (see issue 18254). 558 { 559 fn: ` 560 func f32(x uint32) uint32 { 561 return g(x, 7) 562 } 563 func g(x uint32, k uint) uint32 { 564 return x<<k | x>>(32-k) 565 } 566 `, 567 pos: []string{"\tROLL\t[$]7,"}, 568 }, 569 { 570 fn: ` 571 func f33(m map[int]int) int { 572 return m[5] 573 } 574 `, 575 pos: []string{"\tMOVQ\t[$]5,"}, 576 }, 577 // Direct use of constants in fast map access calls. Issue 19015. 578 { 579 fn: ` 580 func f34(m map[int]int) bool { 581 _, ok := m[5] 582 return ok 583 } 584 `, 585 pos: []string{"\tMOVQ\t[$]5,"}, 586 }, 587 { 588 fn: ` 589 func f35(m map[string]int) int { 590 return m["abc"] 591 } 592 `, 593 pos: []string{"\"abc\""}, 594 }, 595 { 596 fn: ` 597 func f36(m map[string]int) bool { 598 _, ok := m["abc"] 599 return ok 600 } 601 `, 602 pos: []string{"\"abc\""}, 603 }, 604 // Bit test ops on amd64, issue 18943. 605 { 606 fn: ` 607 func f37(a, b uint64) int { 608 if a&(1<<(b&63)) != 0 { 609 return 1 610 } 611 return -1 612 } 613 `, 614 pos: []string{"\tBTQ\t"}, 615 }, 616 { 617 fn: ` 618 func f38(a, b uint64) bool { 619 return a&(1<<(b&63)) != 0 620 } 621 `, 622 pos: []string{"\tBTQ\t"}, 623 }, 624 { 625 fn: ` 626 func f39(a uint64) int { 627 if a&(1<<60) != 0 { 628 return 1 629 } 630 return -1 631 } 632 `, 633 pos: []string{"\tBTQ\t\\$60"}, 634 }, 635 { 636 fn: ` 637 func f40(a uint64) bool { 638 return a&(1<<60) != 0 639 } 640 `, 641 pos: []string{"\tBTQ\t\\$60"}, 642 }, 643 // Intrinsic tests for math/bits 644 { 645 fn: ` 646 func f41(a uint64) int { 647 return bits.TrailingZeros64(a) 648 } 649 `, 650 pos: []string{"\tBSFQ\t", "\tMOVL\t\\$64,", "\tCMOVQEQ\t"}, 651 }, 652 { 653 fn: ` 654 func f42(a uint32) int { 655 return bits.TrailingZeros32(a) 656 } 657 `, 658 pos: []string{"\tBSFQ\t", "\tORQ\t[^$]", "\tMOVQ\t\\$4294967296,"}, 659 }, 660 { 661 fn: ` 662 func f43(a uint16) int { 663 return bits.TrailingZeros16(a) 664 } 665 `, 666 pos: []string{"\tBSFQ\t", "\tORQ\t\\$65536,"}, 667 }, 668 { 669 fn: ` 670 func f44(a uint8) int { 671 return bits.TrailingZeros8(a) 672 } 673 `, 674 pos: []string{"\tBSFQ\t", "\tORQ\t\\$256,"}, 675 }, 676 { 677 fn: ` 678 func f45(a uint64) uint64 { 679 return bits.ReverseBytes64(a) 680 } 681 `, 682 pos: []string{"\tBSWAPQ\t"}, 683 }, 684 { 685 fn: ` 686 func f46(a uint32) uint32 { 687 return bits.ReverseBytes32(a) 688 } 689 `, 690 pos: []string{"\tBSWAPL\t"}, 691 }, 692 { 693 fn: ` 694 func f47(a uint16) uint16 { 695 return bits.ReverseBytes16(a) 696 } 697 `, 698 pos: []string{"\tROLW\t\\$8,"}, 699 }, 700 { 701 fn: ` 702 func f48(a uint64) int { 703 return bits.Len64(a) 704 } 705 `, 706 pos: []string{"\tBSRQ\t"}, 707 }, 708 { 709 fn: ` 710 func f49(a uint32) int { 711 return bits.Len32(a) 712 } 713 `, 714 pos: []string{"\tBSRQ\t"}, 715 }, 716 { 717 fn: ` 718 func f50(a uint16) int { 719 return bits.Len16(a) 720 } 721 `, 722 pos: []string{"\tBSRQ\t"}, 723 }, 724 /* see ssa.go 725 { 726 fn:` 727 func f51(a uint8) int { 728 return bits.Len8(a) 729 } 730 `, 731 pos:[]string{"\tBSRQ\t"}, 732 }, 733 */ 734 { 735 fn: ` 736 func f52(a uint) int { 737 return bits.Len(a) 738 } 739 `, 740 pos: []string{"\tBSRQ\t"}, 741 }, 742 { 743 fn: ` 744 func f53(a uint64) int { 745 return bits.LeadingZeros64(a) 746 } 747 `, 748 pos: []string{"\tBSRQ\t"}, 749 }, 750 { 751 fn: ` 752 func f54(a uint32) int { 753 return bits.LeadingZeros32(a) 754 } 755 `, 756 pos: []string{"\tBSRQ\t"}, 757 }, 758 { 759 fn: ` 760 func f55(a uint16) int { 761 return bits.LeadingZeros16(a) 762 } 763 `, 764 pos: []string{"\tBSRQ\t"}, 765 }, 766 /* see ssa.go 767 { 768 fn:` 769 func f56(a uint8) int { 770 return bits.LeadingZeros8(a) 771 } 772 `, 773 pos:[]string{"\tBSRQ\t"}, 774 }, 775 */ 776 { 777 fn: ` 778 func f57(a uint) int { 779 return bits.LeadingZeros(a) 780 } 781 `, 782 pos: []string{"\tBSRQ\t"}, 783 }, 784 { 785 fn: ` 786 func pop1(x uint64) int { 787 return bits.OnesCount64(x) 788 }`, 789 pos: []string{"\tPOPCNTQ\t", "support_popcnt"}, 790 }, 791 { 792 fn: ` 793 func pop2(x uint32) int { 794 return bits.OnesCount32(x) 795 }`, 796 pos: []string{"\tPOPCNTL\t", "support_popcnt"}, 797 }, 798 { 799 fn: ` 800 func pop3(x uint16) int { 801 return bits.OnesCount16(x) 802 }`, 803 pos: []string{"\tPOPCNTL\t", "support_popcnt"}, 804 }, 805 { 806 fn: ` 807 func pop4(x uint) int { 808 return bits.OnesCount(x) 809 }`, 810 pos: []string{"\tPOPCNTQ\t", "support_popcnt"}, 811 }, 812 // multiplication merging tests 813 { 814 fn: ` 815 func mul1(n int) int { 816 return 15*n + 31*n 817 }`, 818 pos: []string{"\tIMULQ\t[$]46"}, // 46*n 819 }, 820 { 821 fn: ` 822 func mul2(n int) int { 823 return 5*n + 7*(n+1) + 11*(n+2) 824 }`, 825 pos: []string{"\tIMULQ\t[$]23", "\tADDQ\t[$]29"}, // 23*n + 29 826 }, 827 { 828 fn: ` 829 func mul3(a, n int) int { 830 return a*n + 19*n 831 }`, 832 pos: []string{"\tADDQ\t[$]19", "\tIMULQ"}, // (a+19)*n 833 }, 834 { 835 fn: ` 836 func mul4(n int) int { 837 return 23*n - 9*n 838 }`, 839 pos: []string{"\tIMULQ\t[$]14"}, // 14*n 840 }, 841 { 842 fn: ` 843 func mul5(a, n int) int { 844 return a*n - 19*n 845 }`, 846 pos: []string{"\tADDQ\t[$]-19", "\tIMULQ"}, // (a-19)*n 847 }, 848 849 // see issue 19595. 850 // We want to merge load+op in f58, but not in f59. 851 { 852 fn: ` 853 func f58(p, q *int) { 854 x := *p 855 *q += x 856 }`, 857 pos: []string{"\tADDQ\t\\("}, 858 }, 859 { 860 fn: ` 861 func f59(p, q *int) { 862 x := *p 863 for i := 0; i < 10; i++ { 864 *q += x 865 } 866 }`, 867 pos: []string{"\tADDQ\t[A-Z]"}, 868 }, 869 // Floating-point strength reduction 870 { 871 fn: ` 872 func f60(f float64) float64 { 873 return f * 2.0 874 }`, 875 pos: []string{"\tADDSD\t"}, 876 }, 877 { 878 fn: ` 879 func f62(f float64) float64 { 880 return f / 16.0 881 }`, 882 pos: []string{"\tMULSD\t"}, 883 }, 884 { 885 fn: ` 886 func f63(f float64) float64 { 887 return f / 0.125 888 }`, 889 pos: []string{"\tMULSD\t"}, 890 }, 891 { 892 fn: ` 893 func f64(f float64) float64 { 894 return f / 0.5 895 }`, 896 pos: []string{"\tADDSD\t"}, 897 }, 898 // Check that compare to constant string uses 2/4/8 byte compares 899 { 900 fn: ` 901 func f65(a string) bool { 902 return a == "xx" 903 }`, 904 pos: []string{"\tCMPW\t[A-Z]"}, 905 }, 906 { 907 fn: ` 908 func f66(a string) bool { 909 return a == "xxxx" 910 }`, 911 pos: []string{"\tCMPL\t[A-Z]"}, 912 }, 913 { 914 fn: ` 915 func f67(a string) bool { 916 return a == "xxxxxxxx" 917 }`, 918 pos: []string{"\tCMPQ\t[A-Z]"}, 919 }, 920 // Non-constant rotate 921 { 922 fn: `func rot64l(x uint64, y int) uint64 { 923 z := uint(y & 63) 924 return x << z | x >> (64-z) 925 }`, 926 pos: []string{"\tROLQ\t"}, 927 }, 928 { 929 fn: `func rot64r(x uint64, y int) uint64 { 930 z := uint(y & 63) 931 return x >> z | x << (64-z) 932 }`, 933 pos: []string{"\tRORQ\t"}, 934 }, 935 { 936 fn: `func rot32l(x uint32, y int) uint32 { 937 z := uint(y & 31) 938 return x << z | x >> (32-z) 939 }`, 940 pos: []string{"\tROLL\t"}, 941 }, 942 { 943 fn: `func rot32r(x uint32, y int) uint32 { 944 z := uint(y & 31) 945 return x >> z | x << (32-z) 946 }`, 947 pos: []string{"\tRORL\t"}, 948 }, 949 { 950 fn: `func rot16l(x uint16, y int) uint16 { 951 z := uint(y & 15) 952 return x << z | x >> (16-z) 953 }`, 954 pos: []string{"\tROLW\t"}, 955 }, 956 { 957 fn: `func rot16r(x uint16, y int) uint16 { 958 z := uint(y & 15) 959 return x >> z | x << (16-z) 960 }`, 961 pos: []string{"\tRORW\t"}, 962 }, 963 { 964 fn: `func rot8l(x uint8, y int) uint8 { 965 z := uint(y & 7) 966 return x << z | x >> (8-z) 967 }`, 968 pos: []string{"\tROLB\t"}, 969 }, 970 { 971 fn: `func rot8r(x uint8, y int) uint8 { 972 z := uint(y & 7) 973 return x >> z | x << (8-z) 974 }`, 975 pos: []string{"\tRORB\t"}, 976 }, 977 // Check that array compare uses 2/4/8 byte compares 978 { 979 fn: ` 980 func f68(a,b [2]byte) bool { 981 return a == b 982 }`, 983 pos: []string{"\tCMPW\t[A-Z]"}, 984 }, 985 { 986 fn: ` 987 func f69(a,b [3]uint16) bool { 988 return a == b 989 }`, 990 pos: []string{"\tCMPL\t[A-Z]"}, 991 }, 992 { 993 fn: ` 994 func f70(a,b [15]byte) bool { 995 return a == b 996 }`, 997 pos: []string{"\tCMPQ\t[A-Z]"}, 998 }, 999 { 1000 fn: ` 1001 func f71(a,b unsafe.Pointer) bool { // This was a TODO in mapaccess1_faststr 1002 return *((*[4]byte)(a)) != *((*[4]byte)(b)) 1003 }`, 1004 pos: []string{"\tCMPL\t[A-Z]"}, 1005 }, 1006 { 1007 // make sure assembly output has matching offset and base register. 1008 fn: ` 1009 func f72(a, b int) int { 1010 //go:noinline 1011 func() {_, _ = a, b} () // use some frame 1012 return b 1013 } 1014 `, 1015 pos: []string{"b\\+40\\(SP\\)"}, 1016 }, 1017 { 1018 // check load combining 1019 fn: ` 1020 func f73(a, b byte) (byte,byte) { 1021 return f73(f73(a,b)) 1022 } 1023 `, 1024 pos: []string{"\tMOVW\t"}, 1025 }, 1026 { 1027 fn: ` 1028 func f74(a, b uint16) (uint16,uint16) { 1029 return f74(f74(a,b)) 1030 } 1031 `, 1032 pos: []string{"\tMOVL\t"}, 1033 }, 1034 { 1035 fn: ` 1036 func f75(a, b uint32) (uint32,uint32) { 1037 return f75(f75(a,b)) 1038 } 1039 `, 1040 pos: []string{"\tMOVQ\t"}, 1041 }, 1042 { 1043 fn: ` 1044 func f76(a, b uint64) (uint64,uint64) { 1045 return f76(f76(a,b)) 1046 } 1047 `, 1048 pos: []string{"\tMOVUPS\t"}, 1049 }, 1050 // Make sure we don't put pointers in SSE registers across safe points. 1051 { 1052 fn: ` 1053 func $(p, q *[2]*int) { 1054 a, b := p[0], p[1] 1055 runtime.GC() 1056 q[0], q[1] = a, b 1057 } 1058 `, 1059 neg: []string{"MOVUPS"}, 1060 }, 1061 { 1062 // check that stack store is optimized away 1063 fn: ` 1064 func $() int { 1065 var x int 1066 return *(&x) 1067 } 1068 `, 1069 pos: []string{"TEXT\t.*, [$]0-8"}, 1070 }, 1071 // math.Abs using integer registers 1072 { 1073 fn: ` 1074 func $(x float64) float64 { 1075 return math.Abs(x) 1076 } 1077 `, 1078 pos: []string{"\tSHLQ\t[$]1,", "\tSHRQ\t[$]1,"}, 1079 }, 1080 // math.Copysign using integer registers 1081 { 1082 fn: ` 1083 func $(x, y float64) float64 { 1084 return math.Copysign(x, y) 1085 } 1086 `, 1087 pos: []string{"\tSHLQ\t[$]1,", "\tSHRQ\t[$]1,", "\tSHRQ\t[$]63,", "\tSHLQ\t[$]63,", "\tORQ\t"}, 1088 }, 1089 // int <-> fp moves 1090 { 1091 fn: ` 1092 func $(x float64) uint64 { 1093 return math.Float64bits(x+1) + 1 1094 } 1095 `, 1096 pos: []string{"\tMOVQ\tX.*, [^X].*"}, 1097 }, 1098 { 1099 fn: ` 1100 func $(x float32) uint32 { 1101 return math.Float32bits(x+1) + 1 1102 } 1103 `, 1104 pos: []string{"\tMOVL\tX.*, [^X].*"}, 1105 }, 1106 { 1107 fn: ` 1108 func $(x uint64) float64 { 1109 return math.Float64frombits(x+1) + 1 1110 } 1111 `, 1112 pos: []string{"\tMOVQ\t[^X].*, X.*"}, 1113 }, 1114 { 1115 fn: ` 1116 func $(x uint32) float32 { 1117 return math.Float32frombits(x+1) + 1 1118 } 1119 `, 1120 pos: []string{"\tMOVL\t[^X].*, X.*"}, 1121 }, 1122 } 1123 1124 var linux386Tests = []*asmTest{ 1125 { 1126 fn: ` 1127 func f0(b []byte) uint32 { 1128 return binary.LittleEndian.Uint32(b) 1129 } 1130 `, 1131 pos: []string{"\tMOVL\t\\(.*\\),"}, 1132 }, 1133 { 1134 fn: ` 1135 func f1(b []byte, i int) uint32 { 1136 return binary.LittleEndian.Uint32(b[i:]) 1137 } 1138 `, 1139 pos: []string{"\tMOVL\t\\(.*\\)\\(.*\\*1\\),"}, 1140 }, 1141 1142 // multiplication merging tests 1143 { 1144 fn: ` 1145 func $(n int) int { 1146 return 9*n + 14*n 1147 }`, 1148 pos: []string{"\tIMULL\t[$]23"}, // 23*n 1149 }, 1150 { 1151 fn: ` 1152 func $(a, n int) int { 1153 return 19*a + a*n 1154 }`, 1155 pos: []string{"\tADDL\t[$]19", "\tIMULL"}, // (n+19)*a 1156 }, 1157 { 1158 // check that stack store is optimized away 1159 fn: ` 1160 func $() int { 1161 var x int 1162 return *(&x) 1163 } 1164 `, 1165 pos: []string{"TEXT\t.*, [$]0-4"}, 1166 }, 1167 { 1168 fn: ` 1169 func mul3(n int) int { 1170 return 23*n - 9*n 1171 }`, 1172 pos: []string{"\tIMULL\t[$]14"}, // 14*n 1173 }, 1174 { 1175 fn: ` 1176 func mul4(a, n int) int { 1177 return n*a - a*19 1178 }`, 1179 pos: []string{"\tADDL\t[$]-19", "\tIMULL"}, // (n-19)*a 1180 }, 1181 } 1182 1183 var linuxS390XTests = []*asmTest{ 1184 { 1185 fn: ` 1186 func f0(b []byte) uint32 { 1187 return binary.LittleEndian.Uint32(b) 1188 } 1189 `, 1190 pos: []string{"\tMOVWBR\t\\(.*\\),"}, 1191 }, 1192 { 1193 fn: ` 1194 func f1(b []byte, i int) uint32 { 1195 return binary.LittleEndian.Uint32(b[i:]) 1196 } 1197 `, 1198 pos: []string{"\tMOVWBR\t\\(.*\\)\\(.*\\*1\\),"}, 1199 }, 1200 { 1201 fn: ` 1202 func f2(b []byte) uint64 { 1203 return binary.LittleEndian.Uint64(b) 1204 } 1205 `, 1206 pos: []string{"\tMOVDBR\t\\(.*\\),"}, 1207 }, 1208 { 1209 fn: ` 1210 func f3(b []byte, i int) uint64 { 1211 return binary.LittleEndian.Uint64(b[i:]) 1212 } 1213 `, 1214 pos: []string{"\tMOVDBR\t\\(.*\\)\\(.*\\*1\\),"}, 1215 }, 1216 { 1217 fn: ` 1218 func f4(b []byte) uint32 { 1219 return binary.BigEndian.Uint32(b) 1220 } 1221 `, 1222 pos: []string{"\tMOVWZ\t\\(.*\\),"}, 1223 }, 1224 { 1225 fn: ` 1226 func f5(b []byte, i int) uint32 { 1227 return binary.BigEndian.Uint32(b[i:]) 1228 } 1229 `, 1230 pos: []string{"\tMOVWZ\t\\(.*\\)\\(.*\\*1\\),"}, 1231 }, 1232 { 1233 fn: ` 1234 func f6(b []byte) uint64 { 1235 return binary.BigEndian.Uint64(b) 1236 } 1237 `, 1238 pos: []string{"\tMOVD\t\\(.*\\),"}, 1239 }, 1240 { 1241 fn: ` 1242 func f7(b []byte, i int) uint64 { 1243 return binary.BigEndian.Uint64(b[i:]) 1244 } 1245 `, 1246 pos: []string{"\tMOVD\t\\(.*\\)\\(.*\\*1\\),"}, 1247 }, 1248 { 1249 fn: ` 1250 func f8(x uint64) uint64 { 1251 return x<<7 + x>>57 1252 } 1253 `, 1254 pos: []string{"\tRLLG\t[$]7,"}, 1255 }, 1256 { 1257 fn: ` 1258 func f9(x uint64) uint64 { 1259 return x<<7 | x>>57 1260 } 1261 `, 1262 pos: []string{"\tRLLG\t[$]7,"}, 1263 }, 1264 { 1265 fn: ` 1266 func f10(x uint64) uint64 { 1267 return x<<7 ^ x>>57 1268 } 1269 `, 1270 pos: []string{"\tRLLG\t[$]7,"}, 1271 }, 1272 { 1273 fn: ` 1274 func f11(x uint32) uint32 { 1275 return x<<7 + x>>25 1276 } 1277 `, 1278 pos: []string{"\tRLL\t[$]7,"}, 1279 }, 1280 { 1281 fn: ` 1282 func f12(x uint32) uint32 { 1283 return x<<7 | x>>25 1284 } 1285 `, 1286 pos: []string{"\tRLL\t[$]7,"}, 1287 }, 1288 { 1289 fn: ` 1290 func f13(x uint32) uint32 { 1291 return x<<7 ^ x>>25 1292 } 1293 `, 1294 pos: []string{"\tRLL\t[$]7,"}, 1295 }, 1296 // Fused multiply-add/sub instructions. 1297 { 1298 fn: ` 1299 func f14(x, y, z float64) float64 { 1300 return x * y + z 1301 } 1302 `, 1303 pos: []string{"\tFMADD\t"}, 1304 }, 1305 { 1306 fn: ` 1307 func f15(x, y, z float64) float64 { 1308 return x * y - z 1309 } 1310 `, 1311 pos: []string{"\tFMSUB\t"}, 1312 }, 1313 { 1314 fn: ` 1315 func f16(x, y, z float32) float32 { 1316 return x * y + z 1317 } 1318 `, 1319 pos: []string{"\tFMADDS\t"}, 1320 }, 1321 { 1322 fn: ` 1323 func f17(x, y, z float32) float32 { 1324 return x * y - z 1325 } 1326 `, 1327 pos: []string{"\tFMSUBS\t"}, 1328 }, 1329 // Intrinsic tests for math/bits 1330 { 1331 fn: ` 1332 func f18(a uint64) int { 1333 return bits.TrailingZeros64(a) 1334 } 1335 `, 1336 pos: []string{"\tFLOGR\t"}, 1337 }, 1338 { 1339 fn: ` 1340 func f19(a uint32) int { 1341 return bits.TrailingZeros32(a) 1342 } 1343 `, 1344 pos: []string{"\tFLOGR\t", "\tMOVWZ\t"}, 1345 }, 1346 { 1347 fn: ` 1348 func f20(a uint16) int { 1349 return bits.TrailingZeros16(a) 1350 } 1351 `, 1352 pos: []string{"\tFLOGR\t", "\tOR\t\\$65536,"}, 1353 }, 1354 { 1355 fn: ` 1356 func f21(a uint8) int { 1357 return bits.TrailingZeros8(a) 1358 } 1359 `, 1360 pos: []string{"\tFLOGR\t", "\tOR\t\\$256,"}, 1361 }, 1362 // Intrinsic tests for math/bits 1363 { 1364 fn: ` 1365 func f22(a uint64) uint64 { 1366 return bits.ReverseBytes64(a) 1367 } 1368 `, 1369 pos: []string{"\tMOVDBR\t"}, 1370 }, 1371 { 1372 fn: ` 1373 func f23(a uint32) uint32 { 1374 return bits.ReverseBytes32(a) 1375 } 1376 `, 1377 pos: []string{"\tMOVWBR\t"}, 1378 }, 1379 { 1380 fn: ` 1381 func f24(a uint64) int { 1382 return bits.Len64(a) 1383 } 1384 `, 1385 pos: []string{"\tFLOGR\t"}, 1386 }, 1387 { 1388 fn: ` 1389 func f25(a uint32) int { 1390 return bits.Len32(a) 1391 } 1392 `, 1393 pos: []string{"\tFLOGR\t"}, 1394 }, 1395 { 1396 fn: ` 1397 func f26(a uint16) int { 1398 return bits.Len16(a) 1399 } 1400 `, 1401 pos: []string{"\tFLOGR\t"}, 1402 }, 1403 { 1404 fn: ` 1405 func f27(a uint8) int { 1406 return bits.Len8(a) 1407 } 1408 `, 1409 pos: []string{"\tFLOGR\t"}, 1410 }, 1411 { 1412 fn: ` 1413 func f28(a uint) int { 1414 return bits.Len(a) 1415 } 1416 `, 1417 pos: []string{"\tFLOGR\t"}, 1418 }, 1419 { 1420 fn: ` 1421 func f29(a uint64) int { 1422 return bits.LeadingZeros64(a) 1423 } 1424 `, 1425 pos: []string{"\tFLOGR\t"}, 1426 }, 1427 { 1428 fn: ` 1429 func f30(a uint32) int { 1430 return bits.LeadingZeros32(a) 1431 } 1432 `, 1433 pos: []string{"\tFLOGR\t"}, 1434 }, 1435 { 1436 fn: ` 1437 func f31(a uint16) int { 1438 return bits.LeadingZeros16(a) 1439 } 1440 `, 1441 pos: []string{"\tFLOGR\t"}, 1442 }, 1443 { 1444 fn: ` 1445 func f32(a uint8) int { 1446 return bits.LeadingZeros8(a) 1447 } 1448 `, 1449 pos: []string{"\tFLOGR\t"}, 1450 }, 1451 { 1452 fn: ` 1453 func f33(a uint) int { 1454 return bits.LeadingZeros(a) 1455 } 1456 `, 1457 pos: []string{"\tFLOGR\t"}, 1458 }, 1459 { 1460 // check that stack store is optimized away 1461 fn: ` 1462 func $() int { 1463 var x int 1464 return *(&x) 1465 } 1466 `, 1467 pos: []string{"TEXT\t.*, [$]0-8"}, 1468 }, 1469 } 1470 1471 var linuxARMTests = []*asmTest{ 1472 { 1473 fn: ` 1474 func f0(x uint32) uint32 { 1475 return x<<7 + x>>25 1476 } 1477 `, 1478 pos: []string{"\tMOVW\tR[0-9]+@>25,"}, 1479 }, 1480 { 1481 fn: ` 1482 func f1(x uint32) uint32 { 1483 return x<<7 | x>>25 1484 } 1485 `, 1486 pos: []string{"\tMOVW\tR[0-9]+@>25,"}, 1487 }, 1488 { 1489 fn: ` 1490 func f2(x uint32) uint32 { 1491 return x<<7 ^ x>>25 1492 } 1493 `, 1494 pos: []string{"\tMOVW\tR[0-9]+@>25,"}, 1495 }, 1496 { 1497 fn: ` 1498 func f3(a uint64) int { 1499 return bits.Len64(a) 1500 } 1501 `, 1502 pos: []string{"\tCLZ\t"}, 1503 }, 1504 { 1505 fn: ` 1506 func f4(a uint32) int { 1507 return bits.Len32(a) 1508 } 1509 `, 1510 pos: []string{"\tCLZ\t"}, 1511 }, 1512 { 1513 fn: ` 1514 func f5(a uint16) int { 1515 return bits.Len16(a) 1516 } 1517 `, 1518 pos: []string{"\tCLZ\t"}, 1519 }, 1520 { 1521 fn: ` 1522 func f6(a uint8) int { 1523 return bits.Len8(a) 1524 } 1525 `, 1526 pos: []string{"\tCLZ\t"}, 1527 }, 1528 { 1529 fn: ` 1530 func f7(a uint) int { 1531 return bits.Len(a) 1532 } 1533 `, 1534 pos: []string{"\tCLZ\t"}, 1535 }, 1536 { 1537 fn: ` 1538 func f8(a uint64) int { 1539 return bits.LeadingZeros64(a) 1540 } 1541 `, 1542 pos: []string{"\tCLZ\t"}, 1543 }, 1544 { 1545 fn: ` 1546 func f9(a uint32) int { 1547 return bits.LeadingZeros32(a) 1548 } 1549 `, 1550 pos: []string{"\tCLZ\t"}, 1551 }, 1552 { 1553 fn: ` 1554 func f10(a uint16) int { 1555 return bits.LeadingZeros16(a) 1556 } 1557 `, 1558 pos: []string{"\tCLZ\t"}, 1559 }, 1560 { 1561 fn: ` 1562 func f11(a uint8) int { 1563 return bits.LeadingZeros8(a) 1564 } 1565 `, 1566 pos: []string{"\tCLZ\t"}, 1567 }, 1568 { 1569 fn: ` 1570 func f12(a uint) int { 1571 return bits.LeadingZeros(a) 1572 } 1573 `, 1574 pos: []string{"\tCLZ\t"}, 1575 }, 1576 { 1577 // make sure assembly output has matching offset and base register. 1578 fn: ` 1579 func f13(a, b int) int { 1580 //go:noinline 1581 func() {_, _ = a, b} () // use some frame 1582 return b 1583 } 1584 `, 1585 pos: []string{"b\\+4\\(FP\\)"}, 1586 }, 1587 { 1588 // check that stack store is optimized away 1589 fn: ` 1590 func $() int { 1591 var x int 1592 return *(&x) 1593 } 1594 `, 1595 pos: []string{"TEXT\t.*, [$]-4-4"}, 1596 }, 1597 } 1598 1599 var linuxARM64Tests = []*asmTest{ 1600 { 1601 fn: ` 1602 func f0(x uint64) uint64 { 1603 return x<<7 + x>>57 1604 } 1605 `, 1606 pos: []string{"\tROR\t[$]57,"}, 1607 }, 1608 { 1609 fn: ` 1610 func f1(x uint64) uint64 { 1611 return x<<7 | x>>57 1612 } 1613 `, 1614 pos: []string{"\tROR\t[$]57,"}, 1615 }, 1616 { 1617 fn: ` 1618 func f2(x uint64) uint64 { 1619 return x<<7 ^ x>>57 1620 } 1621 `, 1622 pos: []string{"\tROR\t[$]57,"}, 1623 }, 1624 { 1625 fn: ` 1626 func f3(x uint32) uint32 { 1627 return x<<7 + x>>25 1628 } 1629 `, 1630 pos: []string{"\tRORW\t[$]25,"}, 1631 }, 1632 { 1633 fn: ` 1634 func f4(x uint32) uint32 { 1635 return x<<7 | x>>25 1636 } 1637 `, 1638 pos: []string{"\tRORW\t[$]25,"}, 1639 }, 1640 { 1641 fn: ` 1642 func f5(x uint32) uint32 { 1643 return x<<7 ^ x>>25 1644 } 1645 `, 1646 pos: []string{"\tRORW\t[$]25,"}, 1647 }, 1648 { 1649 fn: ` 1650 func f22(a uint64) uint64 { 1651 return bits.ReverseBytes64(a) 1652 } 1653 `, 1654 pos: []string{"\tREV\t"}, 1655 }, 1656 { 1657 fn: ` 1658 func f23(a uint32) uint32 { 1659 return bits.ReverseBytes32(a) 1660 } 1661 `, 1662 pos: []string{"\tREVW\t"}, 1663 }, 1664 { 1665 fn: ` 1666 func f24(a uint64) int { 1667 return bits.Len64(a) 1668 } 1669 `, 1670 pos: []string{"\tCLZ\t"}, 1671 }, 1672 { 1673 fn: ` 1674 func f25(a uint32) int { 1675 return bits.Len32(a) 1676 } 1677 `, 1678 pos: []string{"\tCLZ\t"}, 1679 }, 1680 { 1681 fn: ` 1682 func f26(a uint16) int { 1683 return bits.Len16(a) 1684 } 1685 `, 1686 pos: []string{"\tCLZ\t"}, 1687 }, 1688 { 1689 fn: ` 1690 func f27(a uint8) int { 1691 return bits.Len8(a) 1692 } 1693 `, 1694 pos: []string{"\tCLZ\t"}, 1695 }, 1696 { 1697 fn: ` 1698 func f28(a uint) int { 1699 return bits.Len(a) 1700 } 1701 `, 1702 pos: []string{"\tCLZ\t"}, 1703 }, 1704 { 1705 fn: ` 1706 func f29(a uint64) int { 1707 return bits.LeadingZeros64(a) 1708 } 1709 `, 1710 pos: []string{"\tCLZ\t"}, 1711 }, 1712 { 1713 fn: ` 1714 func f30(a uint32) int { 1715 return bits.LeadingZeros32(a) 1716 } 1717 `, 1718 pos: []string{"\tCLZ\t"}, 1719 }, 1720 { 1721 fn: ` 1722 func f31(a uint16) int { 1723 return bits.LeadingZeros16(a) 1724 } 1725 `, 1726 pos: []string{"\tCLZ\t"}, 1727 }, 1728 { 1729 fn: ` 1730 func f32(a uint8) int { 1731 return bits.LeadingZeros8(a) 1732 } 1733 `, 1734 pos: []string{"\tCLZ\t"}, 1735 }, 1736 { 1737 fn: ` 1738 func f33(a uint) int { 1739 return bits.LeadingZeros(a) 1740 } 1741 `, 1742 pos: []string{"\tCLZ\t"}, 1743 }, 1744 { 1745 fn: ` 1746 func f34(a uint64) uint64 { 1747 return a & ((1<<63)-1) 1748 } 1749 `, 1750 pos: []string{"\tAND\t"}, 1751 }, 1752 { 1753 fn: ` 1754 func f35(a uint64) uint64 { 1755 return a & (1<<63) 1756 } 1757 `, 1758 pos: []string{"\tAND\t"}, 1759 }, 1760 { 1761 // make sure offsets are folded into load and store. 1762 fn: ` 1763 func f36(_, a [20]byte) (b [20]byte) { 1764 b = a 1765 return 1766 } 1767 `, 1768 pos: []string{"\tMOVD\t\"\"\\.a\\+[0-9]+\\(FP\\), R[0-9]+", "\tMOVD\tR[0-9]+, \"\"\\.b\\+[0-9]+\\(FP\\)"}, 1769 }, 1770 { 1771 // check that stack store is optimized away 1772 fn: ` 1773 func $() int { 1774 var x int 1775 return *(&x) 1776 } 1777 `, 1778 pos: []string{"TEXT\t.*, [$]-8-8"}, 1779 }, 1780 { 1781 // check that we don't emit comparisons for constant shift 1782 fn: ` 1783 //go:nosplit 1784 func $(x int) int { 1785 return x << 17 1786 } 1787 `, 1788 pos: []string{"LSL\t\\$17"}, 1789 neg: []string{"CMP"}, 1790 }, 1791 } 1792 1793 var linuxMIPSTests = []*asmTest{ 1794 { 1795 fn: ` 1796 func f0(a uint64) int { 1797 return bits.Len64(a) 1798 } 1799 `, 1800 pos: []string{"\tCLZ\t"}, 1801 }, 1802 { 1803 fn: ` 1804 func f1(a uint32) int { 1805 return bits.Len32(a) 1806 } 1807 `, 1808 pos: []string{"\tCLZ\t"}, 1809 }, 1810 { 1811 fn: ` 1812 func f2(a uint16) int { 1813 return bits.Len16(a) 1814 } 1815 `, 1816 pos: []string{"\tCLZ\t"}, 1817 }, 1818 { 1819 fn: ` 1820 func f3(a uint8) int { 1821 return bits.Len8(a) 1822 } 1823 `, 1824 pos: []string{"\tCLZ\t"}, 1825 }, 1826 { 1827 fn: ` 1828 func f4(a uint) int { 1829 return bits.Len(a) 1830 } 1831 `, 1832 pos: []string{"\tCLZ\t"}, 1833 }, 1834 { 1835 fn: ` 1836 func f5(a uint64) int { 1837 return bits.LeadingZeros64(a) 1838 } 1839 `, 1840 pos: []string{"\tCLZ\t"}, 1841 }, 1842 { 1843 fn: ` 1844 func f6(a uint32) int { 1845 return bits.LeadingZeros32(a) 1846 } 1847 `, 1848 pos: []string{"\tCLZ\t"}, 1849 }, 1850 { 1851 fn: ` 1852 func f7(a uint16) int { 1853 return bits.LeadingZeros16(a) 1854 } 1855 `, 1856 pos: []string{"\tCLZ\t"}, 1857 }, 1858 { 1859 fn: ` 1860 func f8(a uint8) int { 1861 return bits.LeadingZeros8(a) 1862 } 1863 `, 1864 pos: []string{"\tCLZ\t"}, 1865 }, 1866 { 1867 fn: ` 1868 func f9(a uint) int { 1869 return bits.LeadingZeros(a) 1870 } 1871 `, 1872 pos: []string{"\tCLZ\t"}, 1873 }, 1874 { 1875 // check that stack store is optimized away 1876 fn: ` 1877 func $() int { 1878 var x int 1879 return *(&x) 1880 } 1881 `, 1882 pos: []string{"TEXT\t.*, [$]-4-4"}, 1883 }, 1884 } 1885 1886 var linuxMIPS64Tests = []*asmTest{ 1887 { 1888 // check that we don't emit comparisons for constant shift 1889 fn: ` 1890 func $(x int) int { 1891 return x << 17 1892 } 1893 `, 1894 pos: []string{"SLLV\t\\$17"}, 1895 neg: []string{"SGT"}, 1896 }, 1897 } 1898 1899 var linuxPPC64LETests = []*asmTest{ 1900 // Fused multiply-add/sub instructions. 1901 { 1902 fn: ` 1903 func f0(x, y, z float64) float64 { 1904 return x * y + z 1905 } 1906 `, 1907 pos: []string{"\tFMADD\t"}, 1908 }, 1909 { 1910 fn: ` 1911 func f1(x, y, z float64) float64 { 1912 return x * y - z 1913 } 1914 `, 1915 pos: []string{"\tFMSUB\t"}, 1916 }, 1917 { 1918 fn: ` 1919 func f2(x, y, z float32) float32 { 1920 return x * y + z 1921 } 1922 `, 1923 pos: []string{"\tFMADDS\t"}, 1924 }, 1925 { 1926 fn: ` 1927 func f3(x, y, z float32) float32 { 1928 return x * y - z 1929 } 1930 `, 1931 pos: []string{"\tFMSUBS\t"}, 1932 }, 1933 { 1934 fn: ` 1935 func f4(x uint32) uint32 { 1936 return x<<7 | x>>25 1937 } 1938 `, 1939 pos: []string{"\tROTLW\t"}, 1940 }, 1941 { 1942 fn: ` 1943 func f5(x uint32) uint32 { 1944 return x<<7 + x>>25 1945 } 1946 `, 1947 pos: []string{"\tROTLW\t"}, 1948 }, 1949 { 1950 fn: ` 1951 func f6(x uint32) uint32 { 1952 return x<<7 ^ x>>25 1953 } 1954 `, 1955 pos: []string{"\tROTLW\t"}, 1956 }, 1957 { 1958 fn: ` 1959 func f7(x uint64) uint64 { 1960 return x<<7 | x>>57 1961 } 1962 `, 1963 pos: []string{"\tROTL\t"}, 1964 }, 1965 { 1966 fn: ` 1967 func f8(x uint64) uint64 { 1968 return x<<7 + x>>57 1969 } 1970 `, 1971 pos: []string{"\tROTL\t"}, 1972 }, 1973 { 1974 fn: ` 1975 func f9(x uint64) uint64 { 1976 return x<<7 ^ x>>57 1977 } 1978 `, 1979 pos: []string{"\tROTL\t"}, 1980 }, 1981 { 1982 // check that stack store is optimized away 1983 fn: ` 1984 func $() int { 1985 var x int 1986 return *(&x) 1987 } 1988 `, 1989 pos: []string{"TEXT\t.*, [$]0-8"}, 1990 }, 1991 } 1992 1993 var plan9AMD64Tests = []*asmTest{ 1994 // We should make sure that the compiler doesn't generate floating point 1995 // instructions for non-float operations on Plan 9, because floating point 1996 // operations are not allowed in the note handler. 1997 // Array zeroing. 1998 { 1999 fn: ` 2000 func $() [16]byte { 2001 var a [16]byte 2002 return a 2003 } 2004 `, 2005 pos: []string{"\tMOVQ\t\\$0, \"\""}, 2006 }, 2007 // Array copy. 2008 { 2009 fn: ` 2010 func $(a [16]byte) (b [16]byte) { 2011 b = a 2012 return 2013 } 2014 `, 2015 pos: []string{"\tMOVQ\t\"\"\\.a\\+[0-9]+\\(SP\\), (AX|CX)", "\tMOVQ\t(AX|CX), \"\"\\.b\\+[0-9]+\\(SP\\)"}, 2016 }, 2017 } 2018 2019 // TestLineNumber checks to make sure the generated assembly has line numbers 2020 // see issue #16214 2021 func TestLineNumber(t *testing.T) { 2022 testenv.MustHaveGoBuild(t) 2023 dir, err := ioutil.TempDir("", "TestLineNumber") 2024 if err != nil { 2025 t.Fatalf("could not create directory: %v", err) 2026 } 2027 defer os.RemoveAll(dir) 2028 2029 src := filepath.Join(dir, "x.go") 2030 err = ioutil.WriteFile(src, []byte(issue16214src), 0644) 2031 if err != nil { 2032 t.Fatalf("could not write file: %v", err) 2033 } 2034 2035 cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-S", "-o", filepath.Join(dir, "out.o"), src) 2036 out, err := cmd.CombinedOutput() 2037 if err != nil { 2038 t.Fatalf("fail to run go tool compile: %v", err) 2039 } 2040 2041 if strings.Contains(string(out), "unknown line number") { 2042 t.Errorf("line number missing in assembly:\n%s", out) 2043 } 2044 } 2045 2046 var issue16214src = ` 2047 package main 2048 2049 func Mod32(x uint32) uint32 { 2050 return x % 3 // frontend rewrites it as HMUL with 2863311531, the LITERAL node has unknown Pos 2051 } 2052 `