github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/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 // TestAssembly checks to make sure the assembly generated for 22 // functions contains certain expected instructions. 23 func TestAssembly(t *testing.T) { 24 testenv.MustHaveGoBuild(t) 25 if runtime.GOOS == "windows" { 26 // TODO: remove if we can get "go tool compile -S" to work on windows. 27 t.Skipf("skipping test: recursive windows compile not working") 28 } 29 dir, err := ioutil.TempDir("", "TestAssembly") 30 if err != nil { 31 t.Fatalf("could not create directory: %v", err) 32 } 33 defer os.RemoveAll(dir) 34 35 nameRegexp := regexp.MustCompile("func \\w+") 36 t.Run("platform", func(t *testing.T) { 37 for _, ats := range allAsmTests { 38 ats := ats 39 t.Run(ats.os+"/"+ats.arch, func(tt *testing.T) { 40 tt.Parallel() 41 42 asm := ats.compileToAsm(tt, dir) 43 44 for _, at := range ats.tests { 45 funcName := nameRegexp.FindString(at.function)[len("func "):] 46 fa := funcAsm(tt, asm, funcName) 47 if fa != "" { 48 at.verifyAsm(tt, fa) 49 } 50 } 51 }) 52 } 53 }) 54 } 55 56 var nextTextRegexp = regexp.MustCompile(`\n\S`) 57 58 // funcAsm returns the assembly listing for the given function name. 59 func funcAsm(t *testing.T, asm string, funcName string) string { 60 if i := strings.Index(asm, fmt.Sprintf("TEXT\t\"\".%s(SB)", funcName)); i >= 0 { 61 asm = asm[i:] 62 } else { 63 t.Errorf("could not find assembly for function %v", funcName) 64 return "" 65 } 66 67 // Find the next line that doesn't begin with whitespace. 68 loc := nextTextRegexp.FindStringIndex(asm) 69 if loc != nil { 70 asm = asm[:loc[0]] 71 } 72 73 return asm 74 } 75 76 type asmTest struct { 77 // function to compile, must be named fX, 78 // where X is this test's index in asmTests.tests. 79 function string 80 // regexps that must match the generated assembly 81 regexps []string 82 } 83 84 func (at asmTest) verifyAsm(t *testing.T, fa string) { 85 for _, r := range at.regexps { 86 if b, err := regexp.MatchString(r, fa); !b || err != nil { 87 t.Errorf("expected:%s\ngo:%s\nasm:%s\n", r, at.function, fa) 88 } 89 } 90 } 91 92 type asmTests struct { 93 arch string 94 os string 95 imports []string 96 tests []*asmTest 97 } 98 99 func (ats *asmTests) generateCode() []byte { 100 var buf bytes.Buffer 101 fmt.Fprintln(&buf, "package main") 102 for _, s := range ats.imports { 103 fmt.Fprintf(&buf, "import %q\n", s) 104 } 105 106 for _, t := range ats.tests { 107 fmt.Fprintln(&buf, t.function) 108 } 109 110 return buf.Bytes() 111 } 112 113 // compile compiles the package pkg for architecture arch and 114 // returns the generated assembly. dir is a scratch directory. 115 func (ats *asmTests) compileToAsm(t *testing.T, dir string) string { 116 // create test directory 117 testDir := filepath.Join(dir, fmt.Sprintf("%s_%s", ats.arch, ats.os)) 118 err := os.Mkdir(testDir, 0700) 119 if err != nil { 120 t.Fatalf("could not create directory: %v", err) 121 } 122 123 // Create source. 124 src := filepath.Join(testDir, "test.go") 125 err = ioutil.WriteFile(src, ats.generateCode(), 0600) 126 if err != nil { 127 t.Fatalf("error writing code: %v", err) 128 } 129 130 // First, install any dependencies we need. This builds the required export data 131 // for any packages that are imported. 132 for _, i := range ats.imports { 133 out := filepath.Join(testDir, i+".a") 134 135 if s := ats.runGo(t, "build", "-o", out, "-gcflags=-dolinkobj=false", i); s != "" { 136 t.Fatalf("Stdout = %s\nWant empty", s) 137 } 138 } 139 140 // Now, compile the individual file for which we want to see the generated assembly. 141 asm := ats.runGo(t, "tool", "compile", "-I", testDir, "-S", "-o", filepath.Join(testDir, "out.o"), src) 142 return asm 143 } 144 145 // runGo runs go command with the given args and returns stdout string. 146 // go is run with GOARCH and GOOS set as ats.arch and ats.os respectively 147 func (ats *asmTests) runGo(t *testing.T, args ...string) string { 148 var stdout, stderr bytes.Buffer 149 cmd := exec.Command(testenv.GoToolPath(t), args...) 150 cmd.Env = append(os.Environ(), "GOARCH="+ats.arch, "GOOS="+ats.os) 151 cmd.Stdout = &stdout 152 cmd.Stderr = &stderr 153 154 if err := cmd.Run(); err != nil { 155 t.Fatalf("error running cmd: %v\nstdout:\n%sstderr:\n%s\n", err, stdout.String(), stderr.String()) 156 } 157 158 if s := stderr.String(); s != "" { 159 t.Fatalf("Stderr = %s\nWant empty", s) 160 } 161 162 return stdout.String() 163 } 164 165 var allAsmTests = []*asmTests{ 166 { 167 arch: "amd64", 168 os: "linux", 169 imports: []string{"encoding/binary", "math/bits", "unsafe"}, 170 tests: linuxAMD64Tests, 171 }, 172 { 173 arch: "386", 174 os: "linux", 175 imports: []string{"encoding/binary"}, 176 tests: linux386Tests, 177 }, 178 { 179 arch: "s390x", 180 os: "linux", 181 imports: []string{"encoding/binary", "math/bits"}, 182 tests: linuxS390XTests, 183 }, 184 { 185 arch: "arm", 186 os: "linux", 187 imports: []string{"math/bits"}, 188 tests: linuxARMTests, 189 }, 190 { 191 arch: "arm64", 192 os: "linux", 193 imports: []string{"math/bits"}, 194 tests: linuxARM64Tests, 195 }, 196 { 197 arch: "mips", 198 os: "linux", 199 imports: []string{"math/bits"}, 200 tests: linuxMIPSTests, 201 }, 202 { 203 arch: "ppc64le", 204 os: "linux", 205 tests: linuxPPC64LETests, 206 }, 207 } 208 209 var linuxAMD64Tests = []*asmTest{ 210 { 211 ` 212 func f0(x int) int { 213 return x * 64 214 } 215 `, 216 []string{"\tSHLQ\t\\$6,"}, 217 }, 218 { 219 ` 220 func f1(x int) int { 221 return x * 96 222 } 223 `, 224 []string{"\tSHLQ\t\\$5,", "\tLEAQ\t\\(.*\\)\\(.*\\*2\\),"}, 225 }, 226 // Load-combining tests. 227 { 228 ` 229 func f2(b []byte) uint64 { 230 return binary.LittleEndian.Uint64(b) 231 } 232 `, 233 []string{"\tMOVQ\t\\(.*\\),"}, 234 }, 235 { 236 ` 237 func f3(b []byte, i int) uint64 { 238 return binary.LittleEndian.Uint64(b[i:]) 239 } 240 `, 241 []string{"\tMOVQ\t\\(.*\\)\\(.*\\*1\\),"}, 242 }, 243 { 244 ` 245 func f4(b []byte) uint32 { 246 return binary.LittleEndian.Uint32(b) 247 } 248 `, 249 []string{"\tMOVL\t\\(.*\\),"}, 250 }, 251 { 252 ` 253 func f5(b []byte, i int) uint32 { 254 return binary.LittleEndian.Uint32(b[i:]) 255 } 256 `, 257 []string{"\tMOVL\t\\(.*\\)\\(.*\\*1\\),"}, 258 }, 259 { 260 ` 261 func f6(b []byte) uint64 { 262 return binary.BigEndian.Uint64(b) 263 } 264 `, 265 []string{"\tBSWAPQ\t"}, 266 }, 267 { 268 ` 269 func f7(b []byte, i int) uint64 { 270 return binary.BigEndian.Uint64(b[i:]) 271 } 272 `, 273 []string{"\tBSWAPQ\t"}, 274 }, 275 { 276 ` 277 func f8(b []byte, v uint64) { 278 binary.BigEndian.PutUint64(b, v) 279 } 280 `, 281 []string{"\tBSWAPQ\t"}, 282 }, 283 { 284 ` 285 func f9(b []byte, i int, v uint64) { 286 binary.BigEndian.PutUint64(b[i:], v) 287 } 288 `, 289 []string{"\tBSWAPQ\t"}, 290 }, 291 { 292 ` 293 func f10(b []byte) uint32 { 294 return binary.BigEndian.Uint32(b) 295 } 296 `, 297 []string{"\tBSWAPL\t"}, 298 }, 299 { 300 ` 301 func f11(b []byte, i int) uint32 { 302 return binary.BigEndian.Uint32(b[i:]) 303 } 304 `, 305 []string{"\tBSWAPL\t"}, 306 }, 307 { 308 ` 309 func f12(b []byte, v uint32) { 310 binary.BigEndian.PutUint32(b, v) 311 } 312 `, 313 []string{"\tBSWAPL\t"}, 314 }, 315 { 316 ` 317 func f13(b []byte, i int, v uint32) { 318 binary.BigEndian.PutUint32(b[i:], v) 319 } 320 `, 321 []string{"\tBSWAPL\t"}, 322 }, 323 { 324 ` 325 func f14(b []byte) uint16 { 326 return binary.BigEndian.Uint16(b) 327 } 328 `, 329 []string{"\tROLW\t\\$8,"}, 330 }, 331 { 332 ` 333 func f15(b []byte, i int) uint16 { 334 return binary.BigEndian.Uint16(b[i:]) 335 } 336 `, 337 []string{"\tROLW\t\\$8,"}, 338 }, 339 { 340 ` 341 func f16(b []byte, v uint16) { 342 binary.BigEndian.PutUint16(b, v) 343 } 344 `, 345 []string{"\tROLW\t\\$8,"}, 346 }, 347 { 348 ` 349 func f17(b []byte, i int, v uint16) { 350 binary.BigEndian.PutUint16(b[i:], v) 351 } 352 `, 353 []string{"\tROLW\t\\$8,"}, 354 }, 355 // Structure zeroing. See issue #18370. 356 { 357 ` 358 type T1 struct { 359 a, b, c int 360 } 361 func f18(t *T1) { 362 *t = T1{} 363 } 364 `, 365 []string{"\tMOVQ\t\\$0, \\(.*\\)", "\tMOVQ\t\\$0, 8\\(.*\\)", "\tMOVQ\t\\$0, 16\\(.*\\)"}, 366 }, 367 // SSA-able composite literal initialization. Issue 18872. 368 { 369 ` 370 type T18872 struct { 371 a, b, c, d int 372 } 373 374 func f18872(p *T18872) { 375 *p = T18872{1, 2, 3, 4} 376 } 377 `, 378 []string{"\tMOVQ\t[$]1", "\tMOVQ\t[$]2", "\tMOVQ\t[$]3", "\tMOVQ\t[$]4"}, 379 }, 380 // Also test struct containing pointers (this was special because of write barriers). 381 { 382 ` 383 type T2 struct { 384 a, b, c *int 385 } 386 func f19(t *T2) { 387 *t = T2{} 388 } 389 `, 390 []string{"\tMOVQ\t\\$0, \\(.*\\)", "\tMOVQ\t\\$0, 8\\(.*\\)", "\tMOVQ\t\\$0, 16\\(.*\\)", "\tCALL\truntime\\.writebarrierptr\\(SB\\)"}, 391 }, 392 // Rotate tests 393 { 394 ` 395 func f20(x uint64) uint64 { 396 return x<<7 | x>>57 397 } 398 `, 399 []string{"\tROLQ\t[$]7,"}, 400 }, 401 { 402 ` 403 func f21(x uint64) uint64 { 404 return x<<7 + x>>57 405 } 406 `, 407 []string{"\tROLQ\t[$]7,"}, 408 }, 409 { 410 ` 411 func f22(x uint64) uint64 { 412 return x<<7 ^ x>>57 413 } 414 `, 415 []string{"\tROLQ\t[$]7,"}, 416 }, 417 { 418 ` 419 func f23(x uint32) uint32 { 420 return x<<7 + x>>25 421 } 422 `, 423 []string{"\tROLL\t[$]7,"}, 424 }, 425 { 426 ` 427 func f24(x uint32) uint32 { 428 return x<<7 | x>>25 429 } 430 `, 431 []string{"\tROLL\t[$]7,"}, 432 }, 433 { 434 ` 435 func f25(x uint32) uint32 { 436 return x<<7 ^ x>>25 437 } 438 `, 439 []string{"\tROLL\t[$]7,"}, 440 }, 441 { 442 ` 443 func f26(x uint16) uint16 { 444 return x<<7 + x>>9 445 } 446 `, 447 []string{"\tROLW\t[$]7,"}, 448 }, 449 { 450 ` 451 func f27(x uint16) uint16 { 452 return x<<7 | x>>9 453 } 454 `, 455 []string{"\tROLW\t[$]7,"}, 456 }, 457 { 458 ` 459 func f28(x uint16) uint16 { 460 return x<<7 ^ x>>9 461 } 462 `, 463 []string{"\tROLW\t[$]7,"}, 464 }, 465 { 466 ` 467 func f29(x uint8) uint8 { 468 return x<<7 + x>>1 469 } 470 `, 471 []string{"\tROLB\t[$]7,"}, 472 }, 473 { 474 ` 475 func f30(x uint8) uint8 { 476 return x<<7 | x>>1 477 } 478 `, 479 []string{"\tROLB\t[$]7,"}, 480 }, 481 { 482 ` 483 func f31(x uint8) uint8 { 484 return x<<7 ^ x>>1 485 } 486 `, 487 []string{"\tROLB\t[$]7,"}, 488 }, 489 // Rotate after inlining (see issue 18254). 490 { 491 ` 492 func f32(x uint32) uint32 { 493 return g(x, 7) 494 } 495 func g(x uint32, k uint) uint32 { 496 return x<<k | x>>(32-k) 497 } 498 `, 499 []string{"\tROLL\t[$]7,"}, 500 }, 501 { 502 ` 503 func f33(m map[int]int) int { 504 return m[5] 505 } 506 `, 507 []string{"\tMOVQ\t[$]5,"}, 508 }, 509 // Direct use of constants in fast map access calls. Issue 19015. 510 { 511 ` 512 func f34(m map[int]int) bool { 513 _, ok := m[5] 514 return ok 515 } 516 `, 517 []string{"\tMOVQ\t[$]5,"}, 518 }, 519 { 520 ` 521 func f35(m map[string]int) int { 522 return m["abc"] 523 } 524 `, 525 []string{"\"abc\""}, 526 }, 527 { 528 ` 529 func f36(m map[string]int) bool { 530 _, ok := m["abc"] 531 return ok 532 } 533 `, 534 []string{"\"abc\""}, 535 }, 536 // Bit test ops on amd64, issue 18943. 537 { 538 ` 539 func f37(a, b uint64) int { 540 if a&(1<<(b&63)) != 0 { 541 return 1 542 } 543 return -1 544 } 545 `, 546 []string{"\tBTQ\t"}, 547 }, 548 { 549 ` 550 func f38(a, b uint64) bool { 551 return a&(1<<(b&63)) != 0 552 } 553 `, 554 []string{"\tBTQ\t"}, 555 }, 556 { 557 ` 558 func f39(a uint64) int { 559 if a&(1<<60) != 0 { 560 return 1 561 } 562 return -1 563 } 564 `, 565 []string{"\tBTQ\t\\$60"}, 566 }, 567 { 568 ` 569 func f40(a uint64) bool { 570 return a&(1<<60) != 0 571 } 572 `, 573 []string{"\tBTQ\t\\$60"}, 574 }, 575 // Intrinsic tests for math/bits 576 { 577 ` 578 func f41(a uint64) int { 579 return bits.TrailingZeros64(a) 580 } 581 `, 582 []string{"\tBSFQ\t", "\tMOVL\t\\$64,", "\tCMOVQEQ\t"}, 583 }, 584 { 585 ` 586 func f42(a uint32) int { 587 return bits.TrailingZeros32(a) 588 } 589 `, 590 []string{"\tBSFQ\t", "\tORQ\t[^$]", "\tMOVQ\t\\$4294967296,"}, 591 }, 592 { 593 ` 594 func f43(a uint16) int { 595 return bits.TrailingZeros16(a) 596 } 597 `, 598 []string{"\tBSFQ\t", "\tORQ\t\\$65536,"}, 599 }, 600 { 601 ` 602 func f44(a uint8) int { 603 return bits.TrailingZeros8(a) 604 } 605 `, 606 []string{"\tBSFQ\t", "\tORQ\t\\$256,"}, 607 }, 608 { 609 ` 610 func f45(a uint64) uint64 { 611 return bits.ReverseBytes64(a) 612 } 613 `, 614 []string{"\tBSWAPQ\t"}, 615 }, 616 { 617 ` 618 func f46(a uint32) uint32 { 619 return bits.ReverseBytes32(a) 620 } 621 `, 622 []string{"\tBSWAPL\t"}, 623 }, 624 { 625 ` 626 func f47(a uint16) uint16 { 627 return bits.ReverseBytes16(a) 628 } 629 `, 630 []string{"\tROLW\t\\$8,"}, 631 }, 632 { 633 ` 634 func f48(a uint64) int { 635 return bits.Len64(a) 636 } 637 `, 638 []string{"\tBSRQ\t"}, 639 }, 640 { 641 ` 642 func f49(a uint32) int { 643 return bits.Len32(a) 644 } 645 `, 646 []string{"\tBSRQ\t"}, 647 }, 648 { 649 ` 650 func f50(a uint16) int { 651 return bits.Len16(a) 652 } 653 `, 654 []string{"\tBSRQ\t"}, 655 }, 656 /* see ssa.go 657 { 658 ` 659 func f51(a uint8) int { 660 return bits.Len8(a) 661 } 662 `, 663 []string{"\tBSRQ\t"}, 664 }, 665 */ 666 { 667 ` 668 func f52(a uint) int { 669 return bits.Len(a) 670 } 671 `, 672 []string{"\tBSRQ\t"}, 673 }, 674 { 675 ` 676 func f53(a uint64) int { 677 return bits.LeadingZeros64(a) 678 } 679 `, 680 []string{"\tBSRQ\t"}, 681 }, 682 { 683 ` 684 func f54(a uint32) int { 685 return bits.LeadingZeros32(a) 686 } 687 `, 688 []string{"\tBSRQ\t"}, 689 }, 690 { 691 ` 692 func f55(a uint16) int { 693 return bits.LeadingZeros16(a) 694 } 695 `, 696 []string{"\tBSRQ\t"}, 697 }, 698 /* see ssa.go 699 { 700 ` 701 func f56(a uint8) int { 702 return bits.LeadingZeros8(a) 703 } 704 `, 705 []string{"\tBSRQ\t"}, 706 }, 707 */ 708 { 709 ` 710 func f57(a uint) int { 711 return bits.LeadingZeros(a) 712 } 713 `, 714 []string{"\tBSRQ\t"}, 715 }, 716 { 717 ` 718 func pop1(x uint64) int { 719 return bits.OnesCount64(x) 720 }`, 721 []string{"\tPOPCNTQ\t", "support_popcnt"}, 722 }, 723 { 724 ` 725 func pop2(x uint32) int { 726 return bits.OnesCount32(x) 727 }`, 728 []string{"\tPOPCNTL\t", "support_popcnt"}, 729 }, 730 { 731 ` 732 func pop3(x uint16) int { 733 return bits.OnesCount16(x) 734 }`, 735 []string{"\tPOPCNTL\t", "support_popcnt"}, 736 }, 737 { 738 ` 739 func pop4(x uint) int { 740 return bits.OnesCount(x) 741 }`, 742 []string{"\tPOPCNTQ\t", "support_popcnt"}, 743 }, 744 // see issue 19595. 745 // We want to merge load+op in f58, but not in f59. 746 { 747 ` 748 func f58(p, q *int) { 749 x := *p 750 *q += x 751 }`, 752 []string{"\tADDQ\t\\("}, 753 }, 754 { 755 ` 756 func f59(p, q *int) { 757 x := *p 758 for i := 0; i < 10; i++ { 759 *q += x 760 } 761 }`, 762 []string{"\tADDQ\t[A-Z]"}, 763 }, 764 // Floating-point strength reduction 765 { 766 ` 767 func f60(f float64) float64 { 768 return f * 2.0 769 }`, 770 []string{"\tADDSD\t"}, 771 }, 772 { 773 ` 774 func f62(f float64) float64 { 775 return f / 16.0 776 }`, 777 []string{"\tMULSD\t"}, 778 }, 779 { 780 ` 781 func f63(f float64) float64 { 782 return f / 0.125 783 }`, 784 []string{"\tMULSD\t"}, 785 }, 786 { 787 ` 788 func f64(f float64) float64 { 789 return f / 0.5 790 }`, 791 []string{"\tADDSD\t"}, 792 }, 793 // Check that compare to constant string uses 2/4/8 byte compares 794 { 795 ` 796 func f65(a string) bool { 797 return a == "xx" 798 }`, 799 []string{"\tCMPW\t[A-Z]"}, 800 }, 801 { 802 ` 803 func f66(a string) bool { 804 return a == "xxxx" 805 }`, 806 []string{"\tCMPL\t[A-Z]"}, 807 }, 808 { 809 ` 810 func f67(a string) bool { 811 return a == "xxxxxxxx" 812 }`, 813 []string{"\tCMPQ\t[A-Z]"}, 814 }, 815 // Non-constant rotate 816 { 817 `func rot64l(x uint64, y int) uint64 { 818 z := uint(y & 63) 819 return x << z | x >> (64-z) 820 }`, 821 []string{"\tROLQ\t"}, 822 }, 823 { 824 `func rot64r(x uint64, y int) uint64 { 825 z := uint(y & 63) 826 return x >> z | x << (64-z) 827 }`, 828 []string{"\tRORQ\t"}, 829 }, 830 { 831 `func rot32l(x uint32, y int) uint32 { 832 z := uint(y & 31) 833 return x << z | x >> (32-z) 834 }`, 835 []string{"\tROLL\t"}, 836 }, 837 { 838 `func rot32r(x uint32, y int) uint32 { 839 z := uint(y & 31) 840 return x >> z | x << (32-z) 841 }`, 842 []string{"\tRORL\t"}, 843 }, 844 { 845 `func rot16l(x uint16, y int) uint16 { 846 z := uint(y & 15) 847 return x << z | x >> (16-z) 848 }`, 849 []string{"\tROLW\t"}, 850 }, 851 { 852 `func rot16r(x uint16, y int) uint16 { 853 z := uint(y & 15) 854 return x >> z | x << (16-z) 855 }`, 856 []string{"\tRORW\t"}, 857 }, 858 { 859 `func rot8l(x uint8, y int) uint8 { 860 z := uint(y & 7) 861 return x << z | x >> (8-z) 862 }`, 863 []string{"\tROLB\t"}, 864 }, 865 { 866 `func rot8r(x uint8, y int) uint8 { 867 z := uint(y & 7) 868 return x >> z | x << (8-z) 869 }`, 870 []string{"\tRORB\t"}, 871 }, 872 // Check that array compare uses 2/4/8 byte compares 873 { 874 ` 875 func f68(a,b [2]byte) bool { 876 return a == b 877 }`, 878 []string{"\tCMPW\t[A-Z]"}, 879 }, 880 { 881 ` 882 func f69(a,b [3]uint16) bool { 883 return a == b 884 }`, 885 []string{"\tCMPL\t[A-Z]"}, 886 }, 887 { 888 ` 889 func f70(a,b [15]byte) bool { 890 return a == b 891 }`, 892 []string{"\tCMPQ\t[A-Z]"}, 893 }, 894 { 895 ` 896 func f71(a,b unsafe.Pointer) bool { // This was a TODO in mapaccess1_faststr 897 return *((*[4]byte)(a)) != *((*[4]byte)(b)) 898 }`, 899 []string{"\tCMPL\t[A-Z]"}, 900 }, 901 { 902 // make sure assembly output has matching offset and base register. 903 ` 904 func f72(a, b int) int { 905 var x [16]byte // use some frame 906 _ = x 907 return b 908 } 909 `, 910 []string{"b\\+40\\(SP\\)"}, 911 }, 912 } 913 914 var linux386Tests = []*asmTest{ 915 { 916 ` 917 func f0(b []byte) uint32 { 918 return binary.LittleEndian.Uint32(b) 919 } 920 `, 921 []string{"\tMOVL\t\\(.*\\),"}, 922 }, 923 { 924 ` 925 func f1(b []byte, i int) uint32 { 926 return binary.LittleEndian.Uint32(b[i:]) 927 } 928 `, 929 []string{"\tMOVL\t\\(.*\\)\\(.*\\*1\\),"}, 930 }, 931 } 932 933 var linuxS390XTests = []*asmTest{ 934 { 935 ` 936 func f0(b []byte) uint32 { 937 return binary.LittleEndian.Uint32(b) 938 } 939 `, 940 []string{"\tMOVWBR\t\\(.*\\),"}, 941 }, 942 { 943 ` 944 func f1(b []byte, i int) uint32 { 945 return binary.LittleEndian.Uint32(b[i:]) 946 } 947 `, 948 []string{"\tMOVWBR\t\\(.*\\)\\(.*\\*1\\),"}, 949 }, 950 { 951 ` 952 func f2(b []byte) uint64 { 953 return binary.LittleEndian.Uint64(b) 954 } 955 `, 956 []string{"\tMOVDBR\t\\(.*\\),"}, 957 }, 958 { 959 ` 960 func f3(b []byte, i int) uint64 { 961 return binary.LittleEndian.Uint64(b[i:]) 962 } 963 `, 964 []string{"\tMOVDBR\t\\(.*\\)\\(.*\\*1\\),"}, 965 }, 966 { 967 ` 968 func f4(b []byte) uint32 { 969 return binary.BigEndian.Uint32(b) 970 } 971 `, 972 []string{"\tMOVWZ\t\\(.*\\),"}, 973 }, 974 { 975 ` 976 func f5(b []byte, i int) uint32 { 977 return binary.BigEndian.Uint32(b[i:]) 978 } 979 `, 980 []string{"\tMOVWZ\t\\(.*\\)\\(.*\\*1\\),"}, 981 }, 982 { 983 ` 984 func f6(b []byte) uint64 { 985 return binary.BigEndian.Uint64(b) 986 } 987 `, 988 []string{"\tMOVD\t\\(.*\\),"}, 989 }, 990 { 991 ` 992 func f7(b []byte, i int) uint64 { 993 return binary.BigEndian.Uint64(b[i:]) 994 } 995 `, 996 []string{"\tMOVD\t\\(.*\\)\\(.*\\*1\\),"}, 997 }, 998 { 999 ` 1000 func f8(x uint64) uint64 { 1001 return x<<7 + x>>57 1002 } 1003 `, 1004 []string{"\tRLLG\t[$]7,"}, 1005 }, 1006 { 1007 ` 1008 func f9(x uint64) uint64 { 1009 return x<<7 | x>>57 1010 } 1011 `, 1012 []string{"\tRLLG\t[$]7,"}, 1013 }, 1014 { 1015 ` 1016 func f10(x uint64) uint64 { 1017 return x<<7 ^ x>>57 1018 } 1019 `, 1020 []string{"\tRLLG\t[$]7,"}, 1021 }, 1022 { 1023 ` 1024 func f11(x uint32) uint32 { 1025 return x<<7 + x>>25 1026 } 1027 `, 1028 []string{"\tRLL\t[$]7,"}, 1029 }, 1030 { 1031 ` 1032 func f12(x uint32) uint32 { 1033 return x<<7 | x>>25 1034 } 1035 `, 1036 []string{"\tRLL\t[$]7,"}, 1037 }, 1038 { 1039 ` 1040 func f13(x uint32) uint32 { 1041 return x<<7 ^ x>>25 1042 } 1043 `, 1044 []string{"\tRLL\t[$]7,"}, 1045 }, 1046 // Fused multiply-add/sub instructions. 1047 { 1048 ` 1049 func f14(x, y, z float64) float64 { 1050 return x * y + z 1051 } 1052 `, 1053 []string{"\tFMADD\t"}, 1054 }, 1055 { 1056 ` 1057 func f15(x, y, z float64) float64 { 1058 return x * y - z 1059 } 1060 `, 1061 []string{"\tFMSUB\t"}, 1062 }, 1063 { 1064 ` 1065 func f16(x, y, z float32) float32 { 1066 return x * y + z 1067 } 1068 `, 1069 []string{"\tFMADDS\t"}, 1070 }, 1071 { 1072 ` 1073 func f17(x, y, z float32) float32 { 1074 return x * y - z 1075 } 1076 `, 1077 []string{"\tFMSUBS\t"}, 1078 }, 1079 // Intrinsic tests for math/bits 1080 { 1081 ` 1082 func f18(a uint64) int { 1083 return bits.TrailingZeros64(a) 1084 } 1085 `, 1086 []string{"\tFLOGR\t"}, 1087 }, 1088 { 1089 ` 1090 func f19(a uint32) int { 1091 return bits.TrailingZeros32(a) 1092 } 1093 `, 1094 []string{"\tFLOGR\t", "\tMOVWZ\t"}, 1095 }, 1096 { 1097 ` 1098 func f20(a uint16) int { 1099 return bits.TrailingZeros16(a) 1100 } 1101 `, 1102 []string{"\tFLOGR\t", "\tOR\t\\$65536,"}, 1103 }, 1104 { 1105 ` 1106 func f21(a uint8) int { 1107 return bits.TrailingZeros8(a) 1108 } 1109 `, 1110 []string{"\tFLOGR\t", "\tOR\t\\$256,"}, 1111 }, 1112 // Intrinsic tests for math/bits 1113 { 1114 ` 1115 func f22(a uint64) uint64 { 1116 return bits.ReverseBytes64(a) 1117 } 1118 `, 1119 []string{"\tMOVDBR\t"}, 1120 }, 1121 { 1122 ` 1123 func f23(a uint32) uint32 { 1124 return bits.ReverseBytes32(a) 1125 } 1126 `, 1127 []string{"\tMOVWBR\t"}, 1128 }, 1129 { 1130 ` 1131 func f24(a uint64) int { 1132 return bits.Len64(a) 1133 } 1134 `, 1135 []string{"\tFLOGR\t"}, 1136 }, 1137 { 1138 ` 1139 func f25(a uint32) int { 1140 return bits.Len32(a) 1141 } 1142 `, 1143 []string{"\tFLOGR\t"}, 1144 }, 1145 { 1146 ` 1147 func f26(a uint16) int { 1148 return bits.Len16(a) 1149 } 1150 `, 1151 []string{"\tFLOGR\t"}, 1152 }, 1153 { 1154 ` 1155 func f27(a uint8) int { 1156 return bits.Len8(a) 1157 } 1158 `, 1159 []string{"\tFLOGR\t"}, 1160 }, 1161 { 1162 ` 1163 func f28(a uint) int { 1164 return bits.Len(a) 1165 } 1166 `, 1167 []string{"\tFLOGR\t"}, 1168 }, 1169 { 1170 ` 1171 func f29(a uint64) int { 1172 return bits.LeadingZeros64(a) 1173 } 1174 `, 1175 []string{"\tFLOGR\t"}, 1176 }, 1177 { 1178 ` 1179 func f30(a uint32) int { 1180 return bits.LeadingZeros32(a) 1181 } 1182 `, 1183 []string{"\tFLOGR\t"}, 1184 }, 1185 { 1186 ` 1187 func f31(a uint16) int { 1188 return bits.LeadingZeros16(a) 1189 } 1190 `, 1191 []string{"\tFLOGR\t"}, 1192 }, 1193 { 1194 ` 1195 func f32(a uint8) int { 1196 return bits.LeadingZeros8(a) 1197 } 1198 `, 1199 []string{"\tFLOGR\t"}, 1200 }, 1201 { 1202 ` 1203 func f33(a uint) int { 1204 return bits.LeadingZeros(a) 1205 } 1206 `, 1207 []string{"\tFLOGR\t"}, 1208 }, 1209 } 1210 1211 var linuxARMTests = []*asmTest{ 1212 { 1213 ` 1214 func f0(x uint32) uint32 { 1215 return x<<7 + x>>25 1216 } 1217 `, 1218 []string{"\tMOVW\tR[0-9]+@>25,"}, 1219 }, 1220 { 1221 ` 1222 func f1(x uint32) uint32 { 1223 return x<<7 | x>>25 1224 } 1225 `, 1226 []string{"\tMOVW\tR[0-9]+@>25,"}, 1227 }, 1228 { 1229 ` 1230 func f2(x uint32) uint32 { 1231 return x<<7 ^ x>>25 1232 } 1233 `, 1234 []string{"\tMOVW\tR[0-9]+@>25,"}, 1235 }, 1236 { 1237 ` 1238 func f3(a uint64) int { 1239 return bits.Len64(a) 1240 } 1241 `, 1242 []string{"\tCLZ\t"}, 1243 }, 1244 { 1245 ` 1246 func f4(a uint32) int { 1247 return bits.Len32(a) 1248 } 1249 `, 1250 []string{"\tCLZ\t"}, 1251 }, 1252 { 1253 ` 1254 func f5(a uint16) int { 1255 return bits.Len16(a) 1256 } 1257 `, 1258 []string{"\tCLZ\t"}, 1259 }, 1260 { 1261 ` 1262 func f6(a uint8) int { 1263 return bits.Len8(a) 1264 } 1265 `, 1266 []string{"\tCLZ\t"}, 1267 }, 1268 { 1269 ` 1270 func f7(a uint) int { 1271 return bits.Len(a) 1272 } 1273 `, 1274 []string{"\tCLZ\t"}, 1275 }, 1276 { 1277 ` 1278 func f8(a uint64) int { 1279 return bits.LeadingZeros64(a) 1280 } 1281 `, 1282 []string{"\tCLZ\t"}, 1283 }, 1284 { 1285 ` 1286 func f9(a uint32) int { 1287 return bits.LeadingZeros32(a) 1288 } 1289 `, 1290 []string{"\tCLZ\t"}, 1291 }, 1292 { 1293 ` 1294 func f10(a uint16) int { 1295 return bits.LeadingZeros16(a) 1296 } 1297 `, 1298 []string{"\tCLZ\t"}, 1299 }, 1300 { 1301 ` 1302 func f11(a uint8) int { 1303 return bits.LeadingZeros8(a) 1304 } 1305 `, 1306 []string{"\tCLZ\t"}, 1307 }, 1308 { 1309 ` 1310 func f12(a uint) int { 1311 return bits.LeadingZeros(a) 1312 } 1313 `, 1314 []string{"\tCLZ\t"}, 1315 }, 1316 { 1317 // make sure assembly output has matching offset and base register. 1318 ` 1319 func f13(a, b int) int { 1320 var x [16]byte // use some frame 1321 _ = x 1322 return b 1323 } 1324 `, 1325 []string{"b\\+4\\(FP\\)"}, 1326 }, 1327 } 1328 1329 var linuxARM64Tests = []*asmTest{ 1330 { 1331 ` 1332 func f0(x uint64) uint64 { 1333 return x<<7 + x>>57 1334 } 1335 `, 1336 []string{"\tROR\t[$]57,"}, 1337 }, 1338 { 1339 ` 1340 func f1(x uint64) uint64 { 1341 return x<<7 | x>>57 1342 } 1343 `, 1344 []string{"\tROR\t[$]57,"}, 1345 }, 1346 { 1347 ` 1348 func f2(x uint64) uint64 { 1349 return x<<7 ^ x>>57 1350 } 1351 `, 1352 []string{"\tROR\t[$]57,"}, 1353 }, 1354 { 1355 ` 1356 func f3(x uint32) uint32 { 1357 return x<<7 + x>>25 1358 } 1359 `, 1360 []string{"\tRORW\t[$]25,"}, 1361 }, 1362 { 1363 ` 1364 func f4(x uint32) uint32 { 1365 return x<<7 | x>>25 1366 } 1367 `, 1368 []string{"\tRORW\t[$]25,"}, 1369 }, 1370 { 1371 ` 1372 func f5(x uint32) uint32 { 1373 return x<<7 ^ x>>25 1374 } 1375 `, 1376 []string{"\tRORW\t[$]25,"}, 1377 }, 1378 { 1379 ` 1380 func f22(a uint64) uint64 { 1381 return bits.ReverseBytes64(a) 1382 } 1383 `, 1384 []string{"\tREV\t"}, 1385 }, 1386 { 1387 ` 1388 func f23(a uint32) uint32 { 1389 return bits.ReverseBytes32(a) 1390 } 1391 `, 1392 []string{"\tREVW\t"}, 1393 }, 1394 { 1395 ` 1396 func f24(a uint64) int { 1397 return bits.Len64(a) 1398 } 1399 `, 1400 []string{"\tCLZ\t"}, 1401 }, 1402 { 1403 ` 1404 func f25(a uint32) int { 1405 return bits.Len32(a) 1406 } 1407 `, 1408 []string{"\tCLZ\t"}, 1409 }, 1410 { 1411 ` 1412 func f26(a uint16) int { 1413 return bits.Len16(a) 1414 } 1415 `, 1416 []string{"\tCLZ\t"}, 1417 }, 1418 { 1419 ` 1420 func f27(a uint8) int { 1421 return bits.Len8(a) 1422 } 1423 `, 1424 []string{"\tCLZ\t"}, 1425 }, 1426 { 1427 ` 1428 func f28(a uint) int { 1429 return bits.Len(a) 1430 } 1431 `, 1432 []string{"\tCLZ\t"}, 1433 }, 1434 { 1435 ` 1436 func f29(a uint64) int { 1437 return bits.LeadingZeros64(a) 1438 } 1439 `, 1440 []string{"\tCLZ\t"}, 1441 }, 1442 { 1443 ` 1444 func f30(a uint32) int { 1445 return bits.LeadingZeros32(a) 1446 } 1447 `, 1448 []string{"\tCLZ\t"}, 1449 }, 1450 { 1451 ` 1452 func f31(a uint16) int { 1453 return bits.LeadingZeros16(a) 1454 } 1455 `, 1456 []string{"\tCLZ\t"}, 1457 }, 1458 { 1459 ` 1460 func f32(a uint8) int { 1461 return bits.LeadingZeros8(a) 1462 } 1463 `, 1464 []string{"\tCLZ\t"}, 1465 }, 1466 { 1467 ` 1468 func f33(a uint) int { 1469 return bits.LeadingZeros(a) 1470 } 1471 `, 1472 []string{"\tCLZ\t"}, 1473 }, 1474 { 1475 ` 1476 func f34(a uint64) uint64 { 1477 return a & ((1<<63)-1) 1478 } 1479 `, 1480 []string{"\tAND\t"}, 1481 }, 1482 { 1483 ` 1484 func f35(a uint64) uint64 { 1485 return a & (1<<63) 1486 } 1487 `, 1488 []string{"\tAND\t"}, 1489 }, 1490 { 1491 // make sure offsets are folded into load and store. 1492 ` 1493 func f36(_, a [20]byte) (b [20]byte) { 1494 b = a 1495 return 1496 } 1497 `, 1498 []string{"\tMOVD\t\"\"\\.a\\+[0-9]+\\(FP\\), R[0-9]+", "\tMOVD\tR[0-9]+, \"\"\\.b\\+[0-9]+\\(FP\\)"}, 1499 }, 1500 } 1501 1502 var linuxMIPSTests = []*asmTest{ 1503 { 1504 ` 1505 func f0(a uint64) int { 1506 return bits.Len64(a) 1507 } 1508 `, 1509 []string{"\tCLZ\t"}, 1510 }, 1511 { 1512 ` 1513 func f1(a uint32) int { 1514 return bits.Len32(a) 1515 } 1516 `, 1517 []string{"\tCLZ\t"}, 1518 }, 1519 { 1520 ` 1521 func f2(a uint16) int { 1522 return bits.Len16(a) 1523 } 1524 `, 1525 []string{"\tCLZ\t"}, 1526 }, 1527 { 1528 ` 1529 func f3(a uint8) int { 1530 return bits.Len8(a) 1531 } 1532 `, 1533 []string{"\tCLZ\t"}, 1534 }, 1535 { 1536 ` 1537 func f4(a uint) int { 1538 return bits.Len(a) 1539 } 1540 `, 1541 []string{"\tCLZ\t"}, 1542 }, 1543 { 1544 ` 1545 func f5(a uint64) int { 1546 return bits.LeadingZeros64(a) 1547 } 1548 `, 1549 []string{"\tCLZ\t"}, 1550 }, 1551 { 1552 ` 1553 func f6(a uint32) int { 1554 return bits.LeadingZeros32(a) 1555 } 1556 `, 1557 []string{"\tCLZ\t"}, 1558 }, 1559 { 1560 ` 1561 func f7(a uint16) int { 1562 return bits.LeadingZeros16(a) 1563 } 1564 `, 1565 []string{"\tCLZ\t"}, 1566 }, 1567 { 1568 ` 1569 func f8(a uint8) int { 1570 return bits.LeadingZeros8(a) 1571 } 1572 `, 1573 []string{"\tCLZ\t"}, 1574 }, 1575 { 1576 ` 1577 func f9(a uint) int { 1578 return bits.LeadingZeros(a) 1579 } 1580 `, 1581 []string{"\tCLZ\t"}, 1582 }, 1583 } 1584 1585 var linuxPPC64LETests = []*asmTest{ 1586 // Fused multiply-add/sub instructions. 1587 { 1588 ` 1589 func f0(x, y, z float64) float64 { 1590 return x * y + z 1591 } 1592 `, 1593 []string{"\tFMADD\t"}, 1594 }, 1595 { 1596 ` 1597 func f1(x, y, z float64) float64 { 1598 return x * y - z 1599 } 1600 `, 1601 []string{"\tFMSUB\t"}, 1602 }, 1603 { 1604 ` 1605 func f2(x, y, z float32) float32 { 1606 return x * y + z 1607 } 1608 `, 1609 []string{"\tFMADDS\t"}, 1610 }, 1611 { 1612 ` 1613 func f3(x, y, z float32) float32 { 1614 return x * y - z 1615 } 1616 `, 1617 []string{"\tFMSUBS\t"}, 1618 }, 1619 { 1620 ` 1621 func f4(x uint32) uint32 { 1622 return x<<7 | x>>25 1623 } 1624 `, 1625 []string{"\tROTLW\t"}, 1626 }, 1627 { 1628 ` 1629 func f5(x uint32) uint32 { 1630 return x<<7 + x>>25 1631 } 1632 `, 1633 []string{"\tROTLW\t"}, 1634 }, 1635 { 1636 ` 1637 func f6(x uint32) uint32 { 1638 return x<<7 ^ x>>25 1639 } 1640 `, 1641 []string{"\tROTLW\t"}, 1642 }, 1643 { 1644 ` 1645 func f7(x uint64) uint64 { 1646 return x<<7 | x>>57 1647 } 1648 `, 1649 []string{"\tROTL\t"}, 1650 }, 1651 { 1652 ` 1653 func f8(x uint64) uint64 { 1654 return x<<7 + x>>57 1655 } 1656 `, 1657 []string{"\tROTL\t"}, 1658 }, 1659 { 1660 ` 1661 func f9(x uint64) uint64 { 1662 return x<<7 ^ x>>57 1663 } 1664 `, 1665 []string{"\tROTL\t"}, 1666 }, 1667 } 1668 1669 // TestLineNumber checks to make sure the generated assembly has line numbers 1670 // see issue #16214 1671 func TestLineNumber(t *testing.T) { 1672 testenv.MustHaveGoBuild(t) 1673 dir, err := ioutil.TempDir("", "TestLineNumber") 1674 if err != nil { 1675 t.Fatalf("could not create directory: %v", err) 1676 } 1677 defer os.RemoveAll(dir) 1678 1679 src := filepath.Join(dir, "x.go") 1680 err = ioutil.WriteFile(src, []byte(issue16214src), 0644) 1681 if err != nil { 1682 t.Fatalf("could not write file: %v", err) 1683 } 1684 1685 cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-S", "-o", filepath.Join(dir, "out.o"), src) 1686 out, err := cmd.CombinedOutput() 1687 if err != nil { 1688 t.Fatalf("fail to run go tool compile: %v", err) 1689 } 1690 1691 if strings.Contains(string(out), "unknown line number") { 1692 t.Errorf("line number missing in assembly:\n%s", out) 1693 } 1694 } 1695 1696 var issue16214src = ` 1697 package main 1698 1699 func Mod32(x uint32) uint32 { 1700 return x % 3 // frontend rewrites it as HMUL with 2863311531, the LITERAL node has unknown Pos 1701 } 1702 `