github.com/slayercat/go@v0.0.0-20170428012452-c51559813f61/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"}, 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 // TODO: add a test for *t = T{3,4,5} when we fix that. 368 // Also test struct containing pointers (this was special because of write barriers). 369 { 370 ` 371 type T2 struct { 372 a, b, c *int 373 } 374 func f19(t *T2) { 375 *t = T2{} 376 } 377 `, 378 []string{"\tMOVQ\t\\$0, \\(.*\\)", "\tMOVQ\t\\$0, 8\\(.*\\)", "\tMOVQ\t\\$0, 16\\(.*\\)", "\tCALL\truntime\\.writebarrierptr\\(SB\\)"}, 379 }, 380 // Rotate tests 381 { 382 ` 383 func f20(x uint64) uint64 { 384 return x<<7 | x>>57 385 } 386 `, 387 []string{"\tROLQ\t[$]7,"}, 388 }, 389 { 390 ` 391 func f21(x uint64) uint64 { 392 return x<<7 + x>>57 393 } 394 `, 395 []string{"\tROLQ\t[$]7,"}, 396 }, 397 { 398 ` 399 func f22(x uint64) uint64 { 400 return x<<7 ^ x>>57 401 } 402 `, 403 []string{"\tROLQ\t[$]7,"}, 404 }, 405 { 406 ` 407 func f23(x uint32) uint32 { 408 return x<<7 + x>>25 409 } 410 `, 411 []string{"\tROLL\t[$]7,"}, 412 }, 413 { 414 ` 415 func f24(x uint32) uint32 { 416 return x<<7 | x>>25 417 } 418 `, 419 []string{"\tROLL\t[$]7,"}, 420 }, 421 { 422 ` 423 func f25(x uint32) uint32 { 424 return x<<7 ^ x>>25 425 } 426 `, 427 []string{"\tROLL\t[$]7,"}, 428 }, 429 { 430 ` 431 func f26(x uint16) uint16 { 432 return x<<7 + x>>9 433 } 434 `, 435 []string{"\tROLW\t[$]7,"}, 436 }, 437 { 438 ` 439 func f27(x uint16) uint16 { 440 return x<<7 | x>>9 441 } 442 `, 443 []string{"\tROLW\t[$]7,"}, 444 }, 445 { 446 ` 447 func f28(x uint16) uint16 { 448 return x<<7 ^ x>>9 449 } 450 `, 451 []string{"\tROLW\t[$]7,"}, 452 }, 453 { 454 ` 455 func f29(x uint8) uint8 { 456 return x<<7 + x>>1 457 } 458 `, 459 []string{"\tROLB\t[$]7,"}, 460 }, 461 { 462 ` 463 func f30(x uint8) uint8 { 464 return x<<7 | x>>1 465 } 466 `, 467 []string{"\tROLB\t[$]7,"}, 468 }, 469 { 470 ` 471 func f31(x uint8) uint8 { 472 return x<<7 ^ x>>1 473 } 474 `, 475 []string{"\tROLB\t[$]7,"}, 476 }, 477 // Rotate after inlining (see issue 18254). 478 { 479 ` 480 func f32(x uint32) uint32 { 481 return g(x, 7) 482 } 483 func g(x uint32, k uint) uint32 { 484 return x<<k | x>>(32-k) 485 } 486 `, 487 []string{"\tROLL\t[$]7,"}, 488 }, 489 { 490 ` 491 func f33(m map[int]int) int { 492 return m[5] 493 } 494 `, 495 []string{"\tMOVQ\t[$]5,"}, 496 }, 497 // Direct use of constants in fast map access calls. Issue 19015. 498 { 499 ` 500 func f34(m map[int]int) bool { 501 _, ok := m[5] 502 return ok 503 } 504 `, 505 []string{"\tMOVQ\t[$]5,"}, 506 }, 507 { 508 ` 509 func f35(m map[string]int) int { 510 return m["abc"] 511 } 512 `, 513 []string{"\"abc\""}, 514 }, 515 { 516 ` 517 func f36(m map[string]int) bool { 518 _, ok := m["abc"] 519 return ok 520 } 521 `, 522 []string{"\"abc\""}, 523 }, 524 // Bit test ops on amd64, issue 18943. 525 { 526 ` 527 func f37(a, b uint64) int { 528 if a&(1<<(b&63)) != 0 { 529 return 1 530 } 531 return -1 532 } 533 `, 534 []string{"\tBTQ\t"}, 535 }, 536 { 537 ` 538 func f38(a, b uint64) bool { 539 return a&(1<<(b&63)) != 0 540 } 541 `, 542 []string{"\tBTQ\t"}, 543 }, 544 { 545 ` 546 func f39(a uint64) int { 547 if a&(1<<60) != 0 { 548 return 1 549 } 550 return -1 551 } 552 `, 553 []string{"\tBTQ\t\\$60"}, 554 }, 555 { 556 ` 557 func f40(a uint64) bool { 558 return a&(1<<60) != 0 559 } 560 `, 561 []string{"\tBTQ\t\\$60"}, 562 }, 563 // Intrinsic tests for math/bits 564 { 565 ` 566 func f41(a uint64) int { 567 return bits.TrailingZeros64(a) 568 } 569 `, 570 []string{"\tBSFQ\t", "\tMOVQ\t\\$64,", "\tCMOVQEQ\t"}, 571 }, 572 { 573 ` 574 func f42(a uint32) int { 575 return bits.TrailingZeros32(a) 576 } 577 `, 578 []string{"\tBSFQ\t", "\tORQ\t[^$]", "\tMOVQ\t\\$4294967296,"}, 579 }, 580 { 581 ` 582 func f43(a uint16) int { 583 return bits.TrailingZeros16(a) 584 } 585 `, 586 []string{"\tBSFQ\t", "\tORQ\t\\$65536,"}, 587 }, 588 { 589 ` 590 func f44(a uint8) int { 591 return bits.TrailingZeros8(a) 592 } 593 `, 594 []string{"\tBSFQ\t", "\tORQ\t\\$256,"}, 595 }, 596 { 597 ` 598 func f45(a uint64) uint64 { 599 return bits.ReverseBytes64(a) 600 } 601 `, 602 []string{"\tBSWAPQ\t"}, 603 }, 604 { 605 ` 606 func f46(a uint32) uint32 { 607 return bits.ReverseBytes32(a) 608 } 609 `, 610 []string{"\tBSWAPL\t"}, 611 }, 612 { 613 ` 614 func f47(a uint16) uint16 { 615 return bits.ReverseBytes16(a) 616 } 617 `, 618 []string{"\tROLW\t\\$8,"}, 619 }, 620 { 621 ` 622 func f48(a uint64) int { 623 return bits.Len64(a) 624 } 625 `, 626 []string{"\tBSRQ\t"}, 627 }, 628 { 629 ` 630 func f49(a uint32) int { 631 return bits.Len32(a) 632 } 633 `, 634 []string{"\tBSRQ\t"}, 635 }, 636 { 637 ` 638 func f50(a uint16) int { 639 return bits.Len16(a) 640 } 641 `, 642 []string{"\tBSRQ\t"}, 643 }, 644 /* see ssa.go 645 { 646 ` 647 func f51(a uint8) int { 648 return bits.Len8(a) 649 } 650 `, 651 []string{"\tBSRQ\t"}, 652 }, 653 */ 654 { 655 ` 656 func f52(a uint) int { 657 return bits.Len(a) 658 } 659 `, 660 []string{"\tBSRQ\t"}, 661 }, 662 { 663 ` 664 func f53(a uint64) int { 665 return bits.LeadingZeros64(a) 666 } 667 `, 668 []string{"\tBSRQ\t"}, 669 }, 670 { 671 ` 672 func f54(a uint32) int { 673 return bits.LeadingZeros32(a) 674 } 675 `, 676 []string{"\tBSRQ\t"}, 677 }, 678 { 679 ` 680 func f55(a uint16) int { 681 return bits.LeadingZeros16(a) 682 } 683 `, 684 []string{"\tBSRQ\t"}, 685 }, 686 /* see ssa.go 687 { 688 ` 689 func f56(a uint8) int { 690 return bits.LeadingZeros8(a) 691 } 692 `, 693 []string{"\tBSRQ\t"}, 694 }, 695 */ 696 { 697 ` 698 func f57(a uint) int { 699 return bits.LeadingZeros(a) 700 } 701 `, 702 []string{"\tBSRQ\t"}, 703 }, 704 { 705 ` 706 func pop1(x uint64) int { 707 return bits.OnesCount64(x) 708 }`, 709 []string{"\tPOPCNTQ\t", "support_popcnt"}, 710 }, 711 { 712 ` 713 func pop2(x uint32) int { 714 return bits.OnesCount32(x) 715 }`, 716 []string{"\tPOPCNTL\t", "support_popcnt"}, 717 }, 718 { 719 ` 720 func pop3(x uint16) int { 721 return bits.OnesCount16(x) 722 }`, 723 []string{"\tPOPCNTL\t", "support_popcnt"}, 724 }, 725 { 726 ` 727 func pop4(x uint) int { 728 return bits.OnesCount(x) 729 }`, 730 []string{"\tPOPCNTQ\t", "support_popcnt"}, 731 }, 732 // see issue 19595. 733 // We want to merge load+op in f58, but not in f59. 734 { 735 ` 736 func f58(p, q *int) { 737 x := *p 738 *q += x 739 }`, 740 []string{"\tADDQ\t\\("}, 741 }, 742 { 743 ` 744 func f59(p, q *int) { 745 x := *p 746 for i := 0; i < 10; i++ { 747 *q += x 748 } 749 }`, 750 []string{"\tADDQ\t[A-Z]"}, 751 }, 752 // Floating-point strength reduction 753 { 754 ` 755 func f60(f float64) float64 { 756 return f * 2.0 757 }`, 758 []string{"\tADDSD\t"}, 759 }, 760 { 761 ` 762 func f62(f float64) float64 { 763 return f / 16.0 764 }`, 765 []string{"\tMULSD\t"}, 766 }, 767 { 768 ` 769 func f63(f float64) float64 { 770 return f / 0.125 771 }`, 772 []string{"\tMULSD\t"}, 773 }, 774 { 775 ` 776 func f64(f float64) float64 { 777 return f / 0.5 778 }`, 779 []string{"\tADDSD\t"}, 780 }, 781 // Check that compare to constant string uses 2/4/8 byte compares 782 { 783 ` 784 func f65(a string) bool { 785 return a == "xx" 786 }`, 787 []string{"\tCMPW\t[A-Z]"}, 788 }, 789 { 790 ` 791 func f66(a string) bool { 792 return a == "xxxx" 793 }`, 794 []string{"\tCMPL\t[A-Z]"}, 795 }, 796 { 797 ` 798 func f67(a string) bool { 799 return a == "xxxxxxxx" 800 }`, 801 []string{"\tCMPQ\t[A-Z]"}, 802 }, 803 // Non-constant rotate 804 { 805 `func rot64l(x uint64, y int) uint64 { 806 z := uint(y & 63) 807 return x << z | x >> (64-z) 808 }`, 809 []string{"\tROLQ\t"}, 810 }, 811 { 812 `func rot64r(x uint64, y int) uint64 { 813 z := uint(y & 63) 814 return x >> z | x << (64-z) 815 }`, 816 []string{"\tRORQ\t"}, 817 }, 818 { 819 `func rot32l(x uint32, y int) uint32 { 820 z := uint(y & 31) 821 return x << z | x >> (32-z) 822 }`, 823 []string{"\tROLL\t"}, 824 }, 825 { 826 `func rot32r(x uint32, y int) uint32 { 827 z := uint(y & 31) 828 return x >> z | x << (32-z) 829 }`, 830 []string{"\tRORL\t"}, 831 }, 832 { 833 `func rot16l(x uint16, y int) uint16 { 834 z := uint(y & 15) 835 return x << z | x >> (16-z) 836 }`, 837 []string{"\tROLW\t"}, 838 }, 839 { 840 `func rot16r(x uint16, y int) uint16 { 841 z := uint(y & 15) 842 return x >> z | x << (16-z) 843 }`, 844 []string{"\tRORW\t"}, 845 }, 846 { 847 `func rot8l(x uint8, y int) uint8 { 848 z := uint(y & 7) 849 return x << z | x >> (8-z) 850 }`, 851 []string{"\tROLB\t"}, 852 }, 853 { 854 `func rot8r(x uint8, y int) uint8 { 855 z := uint(y & 7) 856 return x >> z | x << (8-z) 857 }`, 858 []string{"\tRORB\t"}, 859 }, 860 } 861 862 var linux386Tests = []*asmTest{ 863 { 864 ` 865 func f0(b []byte) uint32 { 866 return binary.LittleEndian.Uint32(b) 867 } 868 `, 869 []string{"\tMOVL\t\\(.*\\),"}, 870 }, 871 { 872 ` 873 func f1(b []byte, i int) uint32 { 874 return binary.LittleEndian.Uint32(b[i:]) 875 } 876 `, 877 []string{"\tMOVL\t\\(.*\\)\\(.*\\*1\\),"}, 878 }, 879 } 880 881 var linuxS390XTests = []*asmTest{ 882 { 883 ` 884 func f0(b []byte) uint32 { 885 return binary.LittleEndian.Uint32(b) 886 } 887 `, 888 []string{"\tMOVWBR\t\\(.*\\),"}, 889 }, 890 { 891 ` 892 func f1(b []byte, i int) uint32 { 893 return binary.LittleEndian.Uint32(b[i:]) 894 } 895 `, 896 []string{"\tMOVWBR\t\\(.*\\)\\(.*\\*1\\),"}, 897 }, 898 { 899 ` 900 func f2(b []byte) uint64 { 901 return binary.LittleEndian.Uint64(b) 902 } 903 `, 904 []string{"\tMOVDBR\t\\(.*\\),"}, 905 }, 906 { 907 ` 908 func f3(b []byte, i int) uint64 { 909 return binary.LittleEndian.Uint64(b[i:]) 910 } 911 `, 912 []string{"\tMOVDBR\t\\(.*\\)\\(.*\\*1\\),"}, 913 }, 914 { 915 ` 916 func f4(b []byte) uint32 { 917 return binary.BigEndian.Uint32(b) 918 } 919 `, 920 []string{"\tMOVWZ\t\\(.*\\),"}, 921 }, 922 { 923 ` 924 func f5(b []byte, i int) uint32 { 925 return binary.BigEndian.Uint32(b[i:]) 926 } 927 `, 928 []string{"\tMOVWZ\t\\(.*\\)\\(.*\\*1\\),"}, 929 }, 930 { 931 ` 932 func f6(b []byte) uint64 { 933 return binary.BigEndian.Uint64(b) 934 } 935 `, 936 []string{"\tMOVD\t\\(.*\\),"}, 937 }, 938 { 939 ` 940 func f7(b []byte, i int) uint64 { 941 return binary.BigEndian.Uint64(b[i:]) 942 } 943 `, 944 []string{"\tMOVD\t\\(.*\\)\\(.*\\*1\\),"}, 945 }, 946 { 947 ` 948 func f8(x uint64) uint64 { 949 return x<<7 + x>>57 950 } 951 `, 952 []string{"\tRLLG\t[$]7,"}, 953 }, 954 { 955 ` 956 func f9(x uint64) uint64 { 957 return x<<7 | x>>57 958 } 959 `, 960 []string{"\tRLLG\t[$]7,"}, 961 }, 962 { 963 ` 964 func f10(x uint64) uint64 { 965 return x<<7 ^ x>>57 966 } 967 `, 968 []string{"\tRLLG\t[$]7,"}, 969 }, 970 { 971 ` 972 func f11(x uint32) uint32 { 973 return x<<7 + x>>25 974 } 975 `, 976 []string{"\tRLL\t[$]7,"}, 977 }, 978 { 979 ` 980 func f12(x uint32) uint32 { 981 return x<<7 | x>>25 982 } 983 `, 984 []string{"\tRLL\t[$]7,"}, 985 }, 986 { 987 ` 988 func f13(x uint32) uint32 { 989 return x<<7 ^ x>>25 990 } 991 `, 992 []string{"\tRLL\t[$]7,"}, 993 }, 994 // Fused multiply-add/sub instructions. 995 { 996 ` 997 func f14(x, y, z float64) float64 { 998 return x * y + z 999 } 1000 `, 1001 []string{"\tFMADD\t"}, 1002 }, 1003 { 1004 ` 1005 func f15(x, y, z float64) float64 { 1006 return x * y - z 1007 } 1008 `, 1009 []string{"\tFMSUB\t"}, 1010 }, 1011 { 1012 ` 1013 func f16(x, y, z float32) float32 { 1014 return x * y + z 1015 } 1016 `, 1017 []string{"\tFMADDS\t"}, 1018 }, 1019 { 1020 ` 1021 func f17(x, y, z float32) float32 { 1022 return x * y - z 1023 } 1024 `, 1025 []string{"\tFMSUBS\t"}, 1026 }, 1027 // Intrinsic tests for math/bits 1028 { 1029 ` 1030 func f18(a uint64) int { 1031 return bits.TrailingZeros64(a) 1032 } 1033 `, 1034 []string{"\tFLOGR\t"}, 1035 }, 1036 { 1037 ` 1038 func f19(a uint32) int { 1039 return bits.TrailingZeros32(a) 1040 } 1041 `, 1042 []string{"\tFLOGR\t", "\tMOVWZ\t"}, 1043 }, 1044 { 1045 ` 1046 func f20(a uint16) int { 1047 return bits.TrailingZeros16(a) 1048 } 1049 `, 1050 []string{"\tFLOGR\t", "\tOR\t\\$65536,"}, 1051 }, 1052 { 1053 ` 1054 func f21(a uint8) int { 1055 return bits.TrailingZeros8(a) 1056 } 1057 `, 1058 []string{"\tFLOGR\t", "\tOR\t\\$256,"}, 1059 }, 1060 // Intrinsic tests for math/bits 1061 { 1062 ` 1063 func f22(a uint64) uint64 { 1064 return bits.ReverseBytes64(a) 1065 } 1066 `, 1067 []string{"\tMOVDBR\t"}, 1068 }, 1069 { 1070 ` 1071 func f23(a uint32) uint32 { 1072 return bits.ReverseBytes32(a) 1073 } 1074 `, 1075 []string{"\tMOVWBR\t"}, 1076 }, 1077 { 1078 ` 1079 func f24(a uint64) int { 1080 return bits.Len64(a) 1081 } 1082 `, 1083 []string{"\tFLOGR\t"}, 1084 }, 1085 { 1086 ` 1087 func f25(a uint32) int { 1088 return bits.Len32(a) 1089 } 1090 `, 1091 []string{"\tFLOGR\t"}, 1092 }, 1093 { 1094 ` 1095 func f26(a uint16) int { 1096 return bits.Len16(a) 1097 } 1098 `, 1099 []string{"\tFLOGR\t"}, 1100 }, 1101 { 1102 ` 1103 func f27(a uint8) int { 1104 return bits.Len8(a) 1105 } 1106 `, 1107 []string{"\tFLOGR\t"}, 1108 }, 1109 { 1110 ` 1111 func f28(a uint) int { 1112 return bits.Len(a) 1113 } 1114 `, 1115 []string{"\tFLOGR\t"}, 1116 }, 1117 { 1118 ` 1119 func f29(a uint64) int { 1120 return bits.LeadingZeros64(a) 1121 } 1122 `, 1123 []string{"\tFLOGR\t"}, 1124 }, 1125 { 1126 ` 1127 func f30(a uint32) int { 1128 return bits.LeadingZeros32(a) 1129 } 1130 `, 1131 []string{"\tFLOGR\t"}, 1132 }, 1133 { 1134 ` 1135 func f31(a uint16) int { 1136 return bits.LeadingZeros16(a) 1137 } 1138 `, 1139 []string{"\tFLOGR\t"}, 1140 }, 1141 { 1142 ` 1143 func f32(a uint8) int { 1144 return bits.LeadingZeros8(a) 1145 } 1146 `, 1147 []string{"\tFLOGR\t"}, 1148 }, 1149 { 1150 ` 1151 func f33(a uint) int { 1152 return bits.LeadingZeros(a) 1153 } 1154 `, 1155 []string{"\tFLOGR\t"}, 1156 }, 1157 } 1158 1159 var linuxARMTests = []*asmTest{ 1160 { 1161 ` 1162 func f0(x uint32) uint32 { 1163 return x<<7 + x>>25 1164 } 1165 `, 1166 []string{"\tMOVW\tR[0-9]+@>25,"}, 1167 }, 1168 { 1169 ` 1170 func f1(x uint32) uint32 { 1171 return x<<7 | x>>25 1172 } 1173 `, 1174 []string{"\tMOVW\tR[0-9]+@>25,"}, 1175 }, 1176 { 1177 ` 1178 func f2(x uint32) uint32 { 1179 return x<<7 ^ x>>25 1180 } 1181 `, 1182 []string{"\tMOVW\tR[0-9]+@>25,"}, 1183 }, 1184 { 1185 ` 1186 func f3(a uint64) int { 1187 return bits.Len64(a) 1188 } 1189 `, 1190 []string{"\tCLZ\t"}, 1191 }, 1192 { 1193 ` 1194 func f4(a uint32) int { 1195 return bits.Len32(a) 1196 } 1197 `, 1198 []string{"\tCLZ\t"}, 1199 }, 1200 { 1201 ` 1202 func f5(a uint16) int { 1203 return bits.Len16(a) 1204 } 1205 `, 1206 []string{"\tCLZ\t"}, 1207 }, 1208 { 1209 ` 1210 func f6(a uint8) int { 1211 return bits.Len8(a) 1212 } 1213 `, 1214 []string{"\tCLZ\t"}, 1215 }, 1216 { 1217 ` 1218 func f7(a uint) int { 1219 return bits.Len(a) 1220 } 1221 `, 1222 []string{"\tCLZ\t"}, 1223 }, 1224 { 1225 ` 1226 func f8(a uint64) int { 1227 return bits.LeadingZeros64(a) 1228 } 1229 `, 1230 []string{"\tCLZ\t"}, 1231 }, 1232 { 1233 ` 1234 func f9(a uint32) int { 1235 return bits.LeadingZeros32(a) 1236 } 1237 `, 1238 []string{"\tCLZ\t"}, 1239 }, 1240 { 1241 ` 1242 func f10(a uint16) int { 1243 return bits.LeadingZeros16(a) 1244 } 1245 `, 1246 []string{"\tCLZ\t"}, 1247 }, 1248 { 1249 ` 1250 func f11(a uint8) int { 1251 return bits.LeadingZeros8(a) 1252 } 1253 `, 1254 []string{"\tCLZ\t"}, 1255 }, 1256 { 1257 ` 1258 func f12(a uint) int { 1259 return bits.LeadingZeros(a) 1260 } 1261 `, 1262 []string{"\tCLZ\t"}, 1263 }, 1264 } 1265 1266 var linuxARM64Tests = []*asmTest{ 1267 { 1268 ` 1269 func f0(x uint64) uint64 { 1270 return x<<7 + x>>57 1271 } 1272 `, 1273 []string{"\tROR\t[$]57,"}, 1274 }, 1275 { 1276 ` 1277 func f1(x uint64) uint64 { 1278 return x<<7 | x>>57 1279 } 1280 `, 1281 []string{"\tROR\t[$]57,"}, 1282 }, 1283 { 1284 ` 1285 func f2(x uint64) uint64 { 1286 return x<<7 ^ x>>57 1287 } 1288 `, 1289 []string{"\tROR\t[$]57,"}, 1290 }, 1291 { 1292 ` 1293 func f3(x uint32) uint32 { 1294 return x<<7 + x>>25 1295 } 1296 `, 1297 []string{"\tRORW\t[$]25,"}, 1298 }, 1299 { 1300 ` 1301 func f4(x uint32) uint32 { 1302 return x<<7 | x>>25 1303 } 1304 `, 1305 []string{"\tRORW\t[$]25,"}, 1306 }, 1307 { 1308 ` 1309 func f5(x uint32) uint32 { 1310 return x<<7 ^ x>>25 1311 } 1312 `, 1313 []string{"\tRORW\t[$]25,"}, 1314 }, 1315 { 1316 ` 1317 func f22(a uint64) uint64 { 1318 return bits.ReverseBytes64(a) 1319 } 1320 `, 1321 []string{"\tREV\t"}, 1322 }, 1323 { 1324 ` 1325 func f23(a uint32) uint32 { 1326 return bits.ReverseBytes32(a) 1327 } 1328 `, 1329 []string{"\tREVW\t"}, 1330 }, 1331 { 1332 ` 1333 func f24(a uint64) int { 1334 return bits.Len64(a) 1335 } 1336 `, 1337 []string{"\tCLZ\t"}, 1338 }, 1339 { 1340 ` 1341 func f25(a uint32) int { 1342 return bits.Len32(a) 1343 } 1344 `, 1345 []string{"\tCLZ\t"}, 1346 }, 1347 { 1348 ` 1349 func f26(a uint16) int { 1350 return bits.Len16(a) 1351 } 1352 `, 1353 []string{"\tCLZ\t"}, 1354 }, 1355 { 1356 ` 1357 func f27(a uint8) int { 1358 return bits.Len8(a) 1359 } 1360 `, 1361 []string{"\tCLZ\t"}, 1362 }, 1363 { 1364 ` 1365 func f28(a uint) int { 1366 return bits.Len(a) 1367 } 1368 `, 1369 []string{"\tCLZ\t"}, 1370 }, 1371 { 1372 ` 1373 func f29(a uint64) int { 1374 return bits.LeadingZeros64(a) 1375 } 1376 `, 1377 []string{"\tCLZ\t"}, 1378 }, 1379 { 1380 ` 1381 func f30(a uint32) int { 1382 return bits.LeadingZeros32(a) 1383 } 1384 `, 1385 []string{"\tCLZ\t"}, 1386 }, 1387 { 1388 ` 1389 func f31(a uint16) int { 1390 return bits.LeadingZeros16(a) 1391 } 1392 `, 1393 []string{"\tCLZ\t"}, 1394 }, 1395 { 1396 ` 1397 func f32(a uint8) int { 1398 return bits.LeadingZeros8(a) 1399 } 1400 `, 1401 []string{"\tCLZ\t"}, 1402 }, 1403 { 1404 ` 1405 func f33(a uint) int { 1406 return bits.LeadingZeros(a) 1407 } 1408 `, 1409 []string{"\tCLZ\t"}, 1410 }, 1411 { 1412 ` 1413 func f34(a uint64) uint64 { 1414 return a & ((1<<63)-1) 1415 } 1416 `, 1417 []string{"\tAND\t"}, 1418 }, 1419 { 1420 ` 1421 func f35(a uint64) uint64 { 1422 return a & (1<<63) 1423 } 1424 `, 1425 []string{"\tAND\t"}, 1426 }, 1427 } 1428 1429 var linuxMIPSTests = []*asmTest{ 1430 { 1431 ` 1432 func f0(a uint64) int { 1433 return bits.Len64(a) 1434 } 1435 `, 1436 []string{"\tCLZ\t"}, 1437 }, 1438 { 1439 ` 1440 func f1(a uint32) int { 1441 return bits.Len32(a) 1442 } 1443 `, 1444 []string{"\tCLZ\t"}, 1445 }, 1446 { 1447 ` 1448 func f2(a uint16) int { 1449 return bits.Len16(a) 1450 } 1451 `, 1452 []string{"\tCLZ\t"}, 1453 }, 1454 { 1455 ` 1456 func f3(a uint8) int { 1457 return bits.Len8(a) 1458 } 1459 `, 1460 []string{"\tCLZ\t"}, 1461 }, 1462 { 1463 ` 1464 func f4(a uint) int { 1465 return bits.Len(a) 1466 } 1467 `, 1468 []string{"\tCLZ\t"}, 1469 }, 1470 { 1471 ` 1472 func f5(a uint64) int { 1473 return bits.LeadingZeros64(a) 1474 } 1475 `, 1476 []string{"\tCLZ\t"}, 1477 }, 1478 { 1479 ` 1480 func f6(a uint32) int { 1481 return bits.LeadingZeros32(a) 1482 } 1483 `, 1484 []string{"\tCLZ\t"}, 1485 }, 1486 { 1487 ` 1488 func f7(a uint16) int { 1489 return bits.LeadingZeros16(a) 1490 } 1491 `, 1492 []string{"\tCLZ\t"}, 1493 }, 1494 { 1495 ` 1496 func f8(a uint8) int { 1497 return bits.LeadingZeros8(a) 1498 } 1499 `, 1500 []string{"\tCLZ\t"}, 1501 }, 1502 { 1503 ` 1504 func f9(a uint) int { 1505 return bits.LeadingZeros(a) 1506 } 1507 `, 1508 []string{"\tCLZ\t"}, 1509 }, 1510 } 1511 1512 var linuxPPC64LETests = []*asmTest{ 1513 // Fused multiply-add/sub instructions. 1514 { 1515 ` 1516 func f0(x, y, z float64) float64 { 1517 return x * y + z 1518 } 1519 `, 1520 []string{"\tFMADD\t"}, 1521 }, 1522 { 1523 ` 1524 func f1(x, y, z float64) float64 { 1525 return x * y - z 1526 } 1527 `, 1528 []string{"\tFMSUB\t"}, 1529 }, 1530 { 1531 ` 1532 func f2(x, y, z float32) float32 { 1533 return x * y + z 1534 } 1535 `, 1536 []string{"\tFMADDS\t"}, 1537 }, 1538 { 1539 ` 1540 func f3(x, y, z float32) float32 { 1541 return x * y - z 1542 } 1543 `, 1544 []string{"\tFMSUBS\t"}, 1545 }, 1546 { 1547 ` 1548 func f4(x uint32) uint32 { 1549 return x<<7 | x>>25 1550 } 1551 `, 1552 []string{"\tROTLW\t"}, 1553 }, 1554 { 1555 ` 1556 func f5(x uint32) uint32 { 1557 return x<<7 + x>>25 1558 } 1559 `, 1560 []string{"\tROTLW\t"}, 1561 }, 1562 { 1563 ` 1564 func f6(x uint32) uint32 { 1565 return x<<7 ^ x>>25 1566 } 1567 `, 1568 []string{"\tROTLW\t"}, 1569 }, 1570 { 1571 ` 1572 func f7(x uint64) uint64 { 1573 return x<<7 | x>>57 1574 } 1575 `, 1576 []string{"\tROTL\t"}, 1577 }, 1578 { 1579 ` 1580 func f8(x uint64) uint64 { 1581 return x<<7 + x>>57 1582 } 1583 `, 1584 []string{"\tROTL\t"}, 1585 }, 1586 { 1587 ` 1588 func f9(x uint64) uint64 { 1589 return x<<7 ^ x>>57 1590 } 1591 `, 1592 []string{"\tROTL\t"}, 1593 }, 1594 } 1595 1596 // TestLineNumber checks to make sure the generated assembly has line numbers 1597 // see issue #16214 1598 func TestLineNumber(t *testing.T) { 1599 testenv.MustHaveGoBuild(t) 1600 dir, err := ioutil.TempDir("", "TestLineNumber") 1601 if err != nil { 1602 t.Fatalf("could not create directory: %v", err) 1603 } 1604 defer os.RemoveAll(dir) 1605 1606 src := filepath.Join(dir, "x.go") 1607 err = ioutil.WriteFile(src, []byte(issue16214src), 0644) 1608 if err != nil { 1609 t.Fatalf("could not write file: %v", err) 1610 } 1611 1612 cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-S", "-o", filepath.Join(dir, "out.o"), src) 1613 out, err := cmd.CombinedOutput() 1614 if err != nil { 1615 t.Fatalf("fail to run go tool compile: %v", err) 1616 } 1617 1618 if strings.Contains(string(out), "unknown line number") { 1619 t.Errorf("line number missing in assembly:\n%s", out) 1620 } 1621 } 1622 1623 var issue16214src = ` 1624 package main 1625 1626 func Mod32(x uint32) uint32 { 1627 return x % 3 // frontend rewrites it as HMUL with 2863311531, the LITERAL node has unknown Pos 1628 } 1629 `