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