github.com/mangodowner/go-gm@v0.0.0-20180818020936-8baa2bd4408c/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 func f73(a,b [3]int16) bool { 915 return a == b 916 }`, 917 []string{"\tCMPL\t[A-Z]"}, 918 }, 919 { 920 ` 921 func f74(a,b [12]int8) bool { 922 return a == b 923 }`, 924 []string{"\tCMPQ\t[A-Z]", "\tCMPL\t[A-Z]"}, 925 }, 926 } 927 928 var linux386Tests = []*asmTest{ 929 { 930 ` 931 func f0(b []byte) uint32 { 932 return binary.LittleEndian.Uint32(b) 933 } 934 `, 935 []string{"\tMOVL\t\\(.*\\),"}, 936 }, 937 { 938 ` 939 func f1(b []byte, i int) uint32 { 940 return binary.LittleEndian.Uint32(b[i:]) 941 } 942 `, 943 []string{"\tMOVL\t\\(.*\\)\\(.*\\*1\\),"}, 944 }, 945 } 946 947 var linuxS390XTests = []*asmTest{ 948 { 949 ` 950 func f0(b []byte) uint32 { 951 return binary.LittleEndian.Uint32(b) 952 } 953 `, 954 []string{"\tMOVWBR\t\\(.*\\),"}, 955 }, 956 { 957 ` 958 func f1(b []byte, i int) uint32 { 959 return binary.LittleEndian.Uint32(b[i:]) 960 } 961 `, 962 []string{"\tMOVWBR\t\\(.*\\)\\(.*\\*1\\),"}, 963 }, 964 { 965 ` 966 func f2(b []byte) uint64 { 967 return binary.LittleEndian.Uint64(b) 968 } 969 `, 970 []string{"\tMOVDBR\t\\(.*\\),"}, 971 }, 972 { 973 ` 974 func f3(b []byte, i int) uint64 { 975 return binary.LittleEndian.Uint64(b[i:]) 976 } 977 `, 978 []string{"\tMOVDBR\t\\(.*\\)\\(.*\\*1\\),"}, 979 }, 980 { 981 ` 982 func f4(b []byte) uint32 { 983 return binary.BigEndian.Uint32(b) 984 } 985 `, 986 []string{"\tMOVWZ\t\\(.*\\),"}, 987 }, 988 { 989 ` 990 func f5(b []byte, i int) uint32 { 991 return binary.BigEndian.Uint32(b[i:]) 992 } 993 `, 994 []string{"\tMOVWZ\t\\(.*\\)\\(.*\\*1\\),"}, 995 }, 996 { 997 ` 998 func f6(b []byte) uint64 { 999 return binary.BigEndian.Uint64(b) 1000 } 1001 `, 1002 []string{"\tMOVD\t\\(.*\\),"}, 1003 }, 1004 { 1005 ` 1006 func f7(b []byte, i int) uint64 { 1007 return binary.BigEndian.Uint64(b[i:]) 1008 } 1009 `, 1010 []string{"\tMOVD\t\\(.*\\)\\(.*\\*1\\),"}, 1011 }, 1012 { 1013 ` 1014 func f8(x uint64) uint64 { 1015 return x<<7 + x>>57 1016 } 1017 `, 1018 []string{"\tRLLG\t[$]7,"}, 1019 }, 1020 { 1021 ` 1022 func f9(x uint64) uint64 { 1023 return x<<7 | x>>57 1024 } 1025 `, 1026 []string{"\tRLLG\t[$]7,"}, 1027 }, 1028 { 1029 ` 1030 func f10(x uint64) uint64 { 1031 return x<<7 ^ x>>57 1032 } 1033 `, 1034 []string{"\tRLLG\t[$]7,"}, 1035 }, 1036 { 1037 ` 1038 func f11(x uint32) uint32 { 1039 return x<<7 + x>>25 1040 } 1041 `, 1042 []string{"\tRLL\t[$]7,"}, 1043 }, 1044 { 1045 ` 1046 func f12(x uint32) uint32 { 1047 return x<<7 | x>>25 1048 } 1049 `, 1050 []string{"\tRLL\t[$]7,"}, 1051 }, 1052 { 1053 ` 1054 func f13(x uint32) uint32 { 1055 return x<<7 ^ x>>25 1056 } 1057 `, 1058 []string{"\tRLL\t[$]7,"}, 1059 }, 1060 // Fused multiply-add/sub instructions. 1061 { 1062 ` 1063 func f14(x, y, z float64) float64 { 1064 return x * y + z 1065 } 1066 `, 1067 []string{"\tFMADD\t"}, 1068 }, 1069 { 1070 ` 1071 func f15(x, y, z float64) float64 { 1072 return x * y - z 1073 } 1074 `, 1075 []string{"\tFMSUB\t"}, 1076 }, 1077 { 1078 ` 1079 func f16(x, y, z float32) float32 { 1080 return x * y + z 1081 } 1082 `, 1083 []string{"\tFMADDS\t"}, 1084 }, 1085 { 1086 ` 1087 func f17(x, y, z float32) float32 { 1088 return x * y - z 1089 } 1090 `, 1091 []string{"\tFMSUBS\t"}, 1092 }, 1093 // Intrinsic tests for math/bits 1094 { 1095 ` 1096 func f18(a uint64) int { 1097 return bits.TrailingZeros64(a) 1098 } 1099 `, 1100 []string{"\tFLOGR\t"}, 1101 }, 1102 { 1103 ` 1104 func f19(a uint32) int { 1105 return bits.TrailingZeros32(a) 1106 } 1107 `, 1108 []string{"\tFLOGR\t", "\tMOVWZ\t"}, 1109 }, 1110 { 1111 ` 1112 func f20(a uint16) int { 1113 return bits.TrailingZeros16(a) 1114 } 1115 `, 1116 []string{"\tFLOGR\t", "\tOR\t\\$65536,"}, 1117 }, 1118 { 1119 ` 1120 func f21(a uint8) int { 1121 return bits.TrailingZeros8(a) 1122 } 1123 `, 1124 []string{"\tFLOGR\t", "\tOR\t\\$256,"}, 1125 }, 1126 // Intrinsic tests for math/bits 1127 { 1128 ` 1129 func f22(a uint64) uint64 { 1130 return bits.ReverseBytes64(a) 1131 } 1132 `, 1133 []string{"\tMOVDBR\t"}, 1134 }, 1135 { 1136 ` 1137 func f23(a uint32) uint32 { 1138 return bits.ReverseBytes32(a) 1139 } 1140 `, 1141 []string{"\tMOVWBR\t"}, 1142 }, 1143 { 1144 ` 1145 func f24(a uint64) int { 1146 return bits.Len64(a) 1147 } 1148 `, 1149 []string{"\tFLOGR\t"}, 1150 }, 1151 { 1152 ` 1153 func f25(a uint32) int { 1154 return bits.Len32(a) 1155 } 1156 `, 1157 []string{"\tFLOGR\t"}, 1158 }, 1159 { 1160 ` 1161 func f26(a uint16) int { 1162 return bits.Len16(a) 1163 } 1164 `, 1165 []string{"\tFLOGR\t"}, 1166 }, 1167 { 1168 ` 1169 func f27(a uint8) int { 1170 return bits.Len8(a) 1171 } 1172 `, 1173 []string{"\tFLOGR\t"}, 1174 }, 1175 { 1176 ` 1177 func f28(a uint) int { 1178 return bits.Len(a) 1179 } 1180 `, 1181 []string{"\tFLOGR\t"}, 1182 }, 1183 { 1184 ` 1185 func f29(a uint64) int { 1186 return bits.LeadingZeros64(a) 1187 } 1188 `, 1189 []string{"\tFLOGR\t"}, 1190 }, 1191 { 1192 ` 1193 func f30(a uint32) int { 1194 return bits.LeadingZeros32(a) 1195 } 1196 `, 1197 []string{"\tFLOGR\t"}, 1198 }, 1199 { 1200 ` 1201 func f31(a uint16) int { 1202 return bits.LeadingZeros16(a) 1203 } 1204 `, 1205 []string{"\tFLOGR\t"}, 1206 }, 1207 { 1208 ` 1209 func f32(a uint8) int { 1210 return bits.LeadingZeros8(a) 1211 } 1212 `, 1213 []string{"\tFLOGR\t"}, 1214 }, 1215 { 1216 ` 1217 func f33(a uint) int { 1218 return bits.LeadingZeros(a) 1219 } 1220 `, 1221 []string{"\tFLOGR\t"}, 1222 }, 1223 } 1224 1225 var linuxARMTests = []*asmTest{ 1226 { 1227 ` 1228 func f0(x uint32) uint32 { 1229 return x<<7 + x>>25 1230 } 1231 `, 1232 []string{"\tMOVW\tR[0-9]+@>25,"}, 1233 }, 1234 { 1235 ` 1236 func f1(x uint32) uint32 { 1237 return x<<7 | x>>25 1238 } 1239 `, 1240 []string{"\tMOVW\tR[0-9]+@>25,"}, 1241 }, 1242 { 1243 ` 1244 func f2(x uint32) uint32 { 1245 return x<<7 ^ x>>25 1246 } 1247 `, 1248 []string{"\tMOVW\tR[0-9]+@>25,"}, 1249 }, 1250 { 1251 ` 1252 func f3(a uint64) int { 1253 return bits.Len64(a) 1254 } 1255 `, 1256 []string{"\tCLZ\t"}, 1257 }, 1258 { 1259 ` 1260 func f4(a uint32) int { 1261 return bits.Len32(a) 1262 } 1263 `, 1264 []string{"\tCLZ\t"}, 1265 }, 1266 { 1267 ` 1268 func f5(a uint16) int { 1269 return bits.Len16(a) 1270 } 1271 `, 1272 []string{"\tCLZ\t"}, 1273 }, 1274 { 1275 ` 1276 func f6(a uint8) int { 1277 return bits.Len8(a) 1278 } 1279 `, 1280 []string{"\tCLZ\t"}, 1281 }, 1282 { 1283 ` 1284 func f7(a uint) int { 1285 return bits.Len(a) 1286 } 1287 `, 1288 []string{"\tCLZ\t"}, 1289 }, 1290 { 1291 ` 1292 func f8(a uint64) int { 1293 return bits.LeadingZeros64(a) 1294 } 1295 `, 1296 []string{"\tCLZ\t"}, 1297 }, 1298 { 1299 ` 1300 func f9(a uint32) int { 1301 return bits.LeadingZeros32(a) 1302 } 1303 `, 1304 []string{"\tCLZ\t"}, 1305 }, 1306 { 1307 ` 1308 func f10(a uint16) int { 1309 return bits.LeadingZeros16(a) 1310 } 1311 `, 1312 []string{"\tCLZ\t"}, 1313 }, 1314 { 1315 ` 1316 func f11(a uint8) int { 1317 return bits.LeadingZeros8(a) 1318 } 1319 `, 1320 []string{"\tCLZ\t"}, 1321 }, 1322 { 1323 ` 1324 func f12(a uint) int { 1325 return bits.LeadingZeros(a) 1326 } 1327 `, 1328 []string{"\tCLZ\t"}, 1329 }, 1330 { 1331 // make sure assembly output has matching offset and base register. 1332 ` 1333 func f13(a, b int) int { 1334 var x [16]byte // use some frame 1335 _ = x 1336 return b 1337 } 1338 `, 1339 []string{"b\\+4\\(FP\\)"}, 1340 }, 1341 } 1342 1343 var linuxARM64Tests = []*asmTest{ 1344 { 1345 ` 1346 func f0(x uint64) uint64 { 1347 return x<<7 + x>>57 1348 } 1349 `, 1350 []string{"\tROR\t[$]57,"}, 1351 }, 1352 { 1353 ` 1354 func f1(x uint64) uint64 { 1355 return x<<7 | x>>57 1356 } 1357 `, 1358 []string{"\tROR\t[$]57,"}, 1359 }, 1360 { 1361 ` 1362 func f2(x uint64) uint64 { 1363 return x<<7 ^ x>>57 1364 } 1365 `, 1366 []string{"\tROR\t[$]57,"}, 1367 }, 1368 { 1369 ` 1370 func f3(x uint32) uint32 { 1371 return x<<7 + x>>25 1372 } 1373 `, 1374 []string{"\tRORW\t[$]25,"}, 1375 }, 1376 { 1377 ` 1378 func f4(x uint32) uint32 { 1379 return x<<7 | x>>25 1380 } 1381 `, 1382 []string{"\tRORW\t[$]25,"}, 1383 }, 1384 { 1385 ` 1386 func f5(x uint32) uint32 { 1387 return x<<7 ^ x>>25 1388 } 1389 `, 1390 []string{"\tRORW\t[$]25,"}, 1391 }, 1392 { 1393 ` 1394 func f22(a uint64) uint64 { 1395 return bits.ReverseBytes64(a) 1396 } 1397 `, 1398 []string{"\tREV\t"}, 1399 }, 1400 { 1401 ` 1402 func f23(a uint32) uint32 { 1403 return bits.ReverseBytes32(a) 1404 } 1405 `, 1406 []string{"\tREVW\t"}, 1407 }, 1408 { 1409 ` 1410 func f24(a uint64) int { 1411 return bits.Len64(a) 1412 } 1413 `, 1414 []string{"\tCLZ\t"}, 1415 }, 1416 { 1417 ` 1418 func f25(a uint32) int { 1419 return bits.Len32(a) 1420 } 1421 `, 1422 []string{"\tCLZ\t"}, 1423 }, 1424 { 1425 ` 1426 func f26(a uint16) int { 1427 return bits.Len16(a) 1428 } 1429 `, 1430 []string{"\tCLZ\t"}, 1431 }, 1432 { 1433 ` 1434 func f27(a uint8) int { 1435 return bits.Len8(a) 1436 } 1437 `, 1438 []string{"\tCLZ\t"}, 1439 }, 1440 { 1441 ` 1442 func f28(a uint) int { 1443 return bits.Len(a) 1444 } 1445 `, 1446 []string{"\tCLZ\t"}, 1447 }, 1448 { 1449 ` 1450 func f29(a uint64) int { 1451 return bits.LeadingZeros64(a) 1452 } 1453 `, 1454 []string{"\tCLZ\t"}, 1455 }, 1456 { 1457 ` 1458 func f30(a uint32) int { 1459 return bits.LeadingZeros32(a) 1460 } 1461 `, 1462 []string{"\tCLZ\t"}, 1463 }, 1464 { 1465 ` 1466 func f31(a uint16) int { 1467 return bits.LeadingZeros16(a) 1468 } 1469 `, 1470 []string{"\tCLZ\t"}, 1471 }, 1472 { 1473 ` 1474 func f32(a uint8) int { 1475 return bits.LeadingZeros8(a) 1476 } 1477 `, 1478 []string{"\tCLZ\t"}, 1479 }, 1480 { 1481 ` 1482 func f33(a uint) int { 1483 return bits.LeadingZeros(a) 1484 } 1485 `, 1486 []string{"\tCLZ\t"}, 1487 }, 1488 { 1489 ` 1490 func f34(a uint64) uint64 { 1491 return a & ((1<<63)-1) 1492 } 1493 `, 1494 []string{"\tAND\t"}, 1495 }, 1496 { 1497 ` 1498 func f35(a uint64) uint64 { 1499 return a & (1<<63) 1500 } 1501 `, 1502 []string{"\tAND\t"}, 1503 }, 1504 { 1505 // make sure offsets are folded into load and store. 1506 ` 1507 func f36(_, a [20]byte) (b [20]byte) { 1508 b = a 1509 return 1510 } 1511 `, 1512 []string{"\tMOVD\t\"\"\\.a\\+[0-9]+\\(FP\\), R[0-9]+", "\tMOVD\tR[0-9]+, \"\"\\.b\\+[0-9]+\\(FP\\)"}, 1513 }, 1514 } 1515 1516 var linuxMIPSTests = []*asmTest{ 1517 { 1518 ` 1519 func f0(a uint64) int { 1520 return bits.Len64(a) 1521 } 1522 `, 1523 []string{"\tCLZ\t"}, 1524 }, 1525 { 1526 ` 1527 func f1(a uint32) int { 1528 return bits.Len32(a) 1529 } 1530 `, 1531 []string{"\tCLZ\t"}, 1532 }, 1533 { 1534 ` 1535 func f2(a uint16) int { 1536 return bits.Len16(a) 1537 } 1538 `, 1539 []string{"\tCLZ\t"}, 1540 }, 1541 { 1542 ` 1543 func f3(a uint8) int { 1544 return bits.Len8(a) 1545 } 1546 `, 1547 []string{"\tCLZ\t"}, 1548 }, 1549 { 1550 ` 1551 func f4(a uint) int { 1552 return bits.Len(a) 1553 } 1554 `, 1555 []string{"\tCLZ\t"}, 1556 }, 1557 { 1558 ` 1559 func f5(a uint64) int { 1560 return bits.LeadingZeros64(a) 1561 } 1562 `, 1563 []string{"\tCLZ\t"}, 1564 }, 1565 { 1566 ` 1567 func f6(a uint32) int { 1568 return bits.LeadingZeros32(a) 1569 } 1570 `, 1571 []string{"\tCLZ\t"}, 1572 }, 1573 { 1574 ` 1575 func f7(a uint16) int { 1576 return bits.LeadingZeros16(a) 1577 } 1578 `, 1579 []string{"\tCLZ\t"}, 1580 }, 1581 { 1582 ` 1583 func f8(a uint8) int { 1584 return bits.LeadingZeros8(a) 1585 } 1586 `, 1587 []string{"\tCLZ\t"}, 1588 }, 1589 { 1590 ` 1591 func f9(a uint) int { 1592 return bits.LeadingZeros(a) 1593 } 1594 `, 1595 []string{"\tCLZ\t"}, 1596 }, 1597 } 1598 1599 var linuxPPC64LETests = []*asmTest{ 1600 // Fused multiply-add/sub instructions. 1601 { 1602 ` 1603 func f0(x, y, z float64) float64 { 1604 return x * y + z 1605 } 1606 `, 1607 []string{"\tFMADD\t"}, 1608 }, 1609 { 1610 ` 1611 func f1(x, y, z float64) float64 { 1612 return x * y - z 1613 } 1614 `, 1615 []string{"\tFMSUB\t"}, 1616 }, 1617 { 1618 ` 1619 func f2(x, y, z float32) float32 { 1620 return x * y + z 1621 } 1622 `, 1623 []string{"\tFMADDS\t"}, 1624 }, 1625 { 1626 ` 1627 func f3(x, y, z float32) float32 { 1628 return x * y - z 1629 } 1630 `, 1631 []string{"\tFMSUBS\t"}, 1632 }, 1633 { 1634 ` 1635 func f4(x uint32) uint32 { 1636 return x<<7 | x>>25 1637 } 1638 `, 1639 []string{"\tROTLW\t"}, 1640 }, 1641 { 1642 ` 1643 func f5(x uint32) uint32 { 1644 return x<<7 + x>>25 1645 } 1646 `, 1647 []string{"\tROTLW\t"}, 1648 }, 1649 { 1650 ` 1651 func f6(x uint32) uint32 { 1652 return x<<7 ^ x>>25 1653 } 1654 `, 1655 []string{"\tROTLW\t"}, 1656 }, 1657 { 1658 ` 1659 func f7(x uint64) uint64 { 1660 return x<<7 | x>>57 1661 } 1662 `, 1663 []string{"\tROTL\t"}, 1664 }, 1665 { 1666 ` 1667 func f8(x uint64) uint64 { 1668 return x<<7 + x>>57 1669 } 1670 `, 1671 []string{"\tROTL\t"}, 1672 }, 1673 { 1674 ` 1675 func f9(x uint64) uint64 { 1676 return x<<7 ^ x>>57 1677 } 1678 `, 1679 []string{"\tROTL\t"}, 1680 }, 1681 } 1682 1683 // TestLineNumber checks to make sure the generated assembly has line numbers 1684 // see issue #16214 1685 func TestLineNumber(t *testing.T) { 1686 testenv.MustHaveGoBuild(t) 1687 dir, err := ioutil.TempDir("", "TestLineNumber") 1688 if err != nil { 1689 t.Fatalf("could not create directory: %v", err) 1690 } 1691 defer os.RemoveAll(dir) 1692 1693 src := filepath.Join(dir, "x.go") 1694 err = ioutil.WriteFile(src, []byte(issue16214src), 0644) 1695 if err != nil { 1696 t.Fatalf("could not write file: %v", err) 1697 } 1698 1699 cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-S", "-o", filepath.Join(dir, "out.o"), src) 1700 out, err := cmd.CombinedOutput() 1701 if err != nil { 1702 t.Fatalf("fail to run go tool compile: %v", err) 1703 } 1704 1705 if strings.Contains(string(out), "unknown line number") { 1706 t.Errorf("line number missing in assembly:\n%s", out) 1707 } 1708 } 1709 1710 var issue16214src = ` 1711 package main 1712 1713 func Mod32(x uint32) uint32 { 1714 return x % 3 // frontend rewrites it as HMUL with 2863311531, the LITERAL node has unknown Pos 1715 } 1716 `