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