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