github.com/hlts2/go@v0.0.0-20170904000733-812b34efaed8/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  		fn: `
   836  		func mul4(n int) int {
   837  			return 23*n - 9*n
   838  		}`,
   839  		pos: []string{"\tIMULQ\t[$]14"}, // 14*n
   840  	},
   841  	{
   842  		fn: `
   843  		func mul5(a, n int) int {
   844  			return a*n - 19*n
   845  		}`,
   846  		pos: []string{"\tADDQ\t[$]-19", "\tIMULQ"}, // (a-19)*n
   847  	},
   848  
   849  	// see issue 19595.
   850  	// We want to merge load+op in f58, but not in f59.
   851  	{
   852  		fn: `
   853  		func f58(p, q *int) {
   854  			x := *p
   855  			*q += x
   856  		}`,
   857  		pos: []string{"\tADDQ\t\\("},
   858  	},
   859  	{
   860  		fn: `
   861  		func f59(p, q *int) {
   862  			x := *p
   863  			for i := 0; i < 10; i++ {
   864  				*q += x
   865  			}
   866  		}`,
   867  		pos: []string{"\tADDQ\t[A-Z]"},
   868  	},
   869  	// Floating-point strength reduction
   870  	{
   871  		fn: `
   872  		func f60(f float64) float64 {
   873  			return f * 2.0
   874  		}`,
   875  		pos: []string{"\tADDSD\t"},
   876  	},
   877  	{
   878  		fn: `
   879  		func f62(f float64) float64 {
   880  			return f / 16.0
   881  		}`,
   882  		pos: []string{"\tMULSD\t"},
   883  	},
   884  	{
   885  		fn: `
   886  		func f63(f float64) float64 {
   887  			return f / 0.125
   888  		}`,
   889  		pos: []string{"\tMULSD\t"},
   890  	},
   891  	{
   892  		fn: `
   893  		func f64(f float64) float64 {
   894  			return f / 0.5
   895  		}`,
   896  		pos: []string{"\tADDSD\t"},
   897  	},
   898  	// Check that compare to constant string uses 2/4/8 byte compares
   899  	{
   900  		fn: `
   901  		func f65(a string) bool {
   902  		    return a == "xx"
   903  		}`,
   904  		pos: []string{"\tCMPW\t[A-Z]"},
   905  	},
   906  	{
   907  		fn: `
   908  		func f66(a string) bool {
   909  		    return a == "xxxx"
   910  		}`,
   911  		pos: []string{"\tCMPL\t[A-Z]"},
   912  	},
   913  	{
   914  		fn: `
   915  		func f67(a string) bool {
   916  		    return a == "xxxxxxxx"
   917  		}`,
   918  		pos: []string{"\tCMPQ\t[A-Z]"},
   919  	},
   920  	// Non-constant rotate
   921  	{
   922  		fn: `func rot64l(x uint64, y int) uint64 {
   923  			z := uint(y & 63)
   924  			return x << z | x >> (64-z)
   925  		}`,
   926  		pos: []string{"\tROLQ\t"},
   927  	},
   928  	{
   929  		fn: `func rot64r(x uint64, y int) uint64 {
   930  			z := uint(y & 63)
   931  			return x >> z | x << (64-z)
   932  		}`,
   933  		pos: []string{"\tRORQ\t"},
   934  	},
   935  	{
   936  		fn: `func rot32l(x uint32, y int) uint32 {
   937  			z := uint(y & 31)
   938  			return x << z | x >> (32-z)
   939  		}`,
   940  		pos: []string{"\tROLL\t"},
   941  	},
   942  	{
   943  		fn: `func rot32r(x uint32, y int) uint32 {
   944  			z := uint(y & 31)
   945  			return x >> z | x << (32-z)
   946  		}`,
   947  		pos: []string{"\tRORL\t"},
   948  	},
   949  	{
   950  		fn: `func rot16l(x uint16, y int) uint16 {
   951  			z := uint(y & 15)
   952  			return x << z | x >> (16-z)
   953  		}`,
   954  		pos: []string{"\tROLW\t"},
   955  	},
   956  	{
   957  		fn: `func rot16r(x uint16, y int) uint16 {
   958  			z := uint(y & 15)
   959  			return x >> z | x << (16-z)
   960  		}`,
   961  		pos: []string{"\tRORW\t"},
   962  	},
   963  	{
   964  		fn: `func rot8l(x uint8, y int) uint8 {
   965  			z := uint(y & 7)
   966  			return x << z | x >> (8-z)
   967  		}`,
   968  		pos: []string{"\tROLB\t"},
   969  	},
   970  	{
   971  		fn: `func rot8r(x uint8, y int) uint8 {
   972  			z := uint(y & 7)
   973  			return x >> z | x << (8-z)
   974  		}`,
   975  		pos: []string{"\tRORB\t"},
   976  	},
   977  	// Check that array compare uses 2/4/8 byte compares
   978  	{
   979  		fn: `
   980  		func f68(a,b [2]byte) bool {
   981  		    return a == b
   982  		}`,
   983  		pos: []string{"\tCMPW\t[A-Z]"},
   984  	},
   985  	{
   986  		fn: `
   987  		func f69(a,b [3]uint16) bool {
   988  		    return a == b
   989  		}`,
   990  		pos: []string{"\tCMPL\t[A-Z]"},
   991  	},
   992  	{
   993  		fn: `
   994  		func f70(a,b [15]byte) bool {
   995  		    return a == b
   996  		}`,
   997  		pos: []string{"\tCMPQ\t[A-Z]"},
   998  	},
   999  	{
  1000  		fn: `
  1001  		func f71(a,b unsafe.Pointer) bool { // This was a TODO in mapaccess1_faststr
  1002  		    return *((*[4]byte)(a)) != *((*[4]byte)(b))
  1003  		}`,
  1004  		pos: []string{"\tCMPL\t[A-Z]"},
  1005  	},
  1006  	{
  1007  		// make sure assembly output has matching offset and base register.
  1008  		fn: `
  1009  		func f72(a, b int) int {
  1010  			//go:noinline
  1011  			func() {_, _ = a, b} () // use some frame
  1012  			return b
  1013  		}
  1014  		`,
  1015  		pos: []string{"b\\+40\\(SP\\)"},
  1016  	},
  1017  	{
  1018  		// check load combining
  1019  		fn: `
  1020  		func f73(a, b byte) (byte,byte) {
  1021  		    return f73(f73(a,b))
  1022  		}
  1023  		`,
  1024  		pos: []string{"\tMOVW\t"},
  1025  	},
  1026  	{
  1027  		fn: `
  1028  		func f74(a, b uint16) (uint16,uint16) {
  1029  		    return f74(f74(a,b))
  1030  		}
  1031  		`,
  1032  		pos: []string{"\tMOVL\t"},
  1033  	},
  1034  	{
  1035  		fn: `
  1036  		func f75(a, b uint32) (uint32,uint32) {
  1037  		    return f75(f75(a,b))
  1038  		}
  1039  		`,
  1040  		pos: []string{"\tMOVQ\t"},
  1041  	},
  1042  	{
  1043  		fn: `
  1044  		func f76(a, b uint64) (uint64,uint64) {
  1045  		    return f76(f76(a,b))
  1046  		}
  1047  		`,
  1048  		pos: []string{"\tMOVUPS\t"},
  1049  	},
  1050  	// Make sure we don't put pointers in SSE registers across safe points.
  1051  	{
  1052  		fn: `
  1053  		func $(p, q *[2]*int)  {
  1054  		    a, b := p[0], p[1]
  1055  		    runtime.GC()
  1056  		    q[0], q[1] = a, b
  1057  		}
  1058  		`,
  1059  		neg: []string{"MOVUPS"},
  1060  	},
  1061  	{
  1062  		// check that stack store is optimized away
  1063  		fn: `
  1064  		func $() int {
  1065  			var x int
  1066  			return *(&x)
  1067  		}
  1068  		`,
  1069  		pos: []string{"TEXT\t.*, [$]0-8"},
  1070  	},
  1071  	// math.Abs using integer registers
  1072  	{
  1073  		fn: `
  1074  		func $(x float64) float64 {
  1075  			return math.Abs(x)
  1076  		}
  1077  		`,
  1078  		pos: []string{"\tSHLQ\t[$]1,", "\tSHRQ\t[$]1,"},
  1079  	},
  1080  	// math.Copysign using integer registers
  1081  	{
  1082  		fn: `
  1083  		func $(x, y float64) float64 {
  1084  			return math.Copysign(x, y)
  1085  		}
  1086  		`,
  1087  		pos: []string{"\tSHLQ\t[$]1,", "\tSHRQ\t[$]1,", "\tSHRQ\t[$]63,", "\tSHLQ\t[$]63,", "\tORQ\t"},
  1088  	},
  1089  	// int <-> fp moves
  1090  	{
  1091  		fn: `
  1092  		func $(x float64) uint64 {
  1093  			return math.Float64bits(x+1) + 1
  1094  		}
  1095  		`,
  1096  		pos: []string{"\tMOVQ\tX.*, [^X].*"},
  1097  	},
  1098  	{
  1099  		fn: `
  1100  		func $(x float32) uint32 {
  1101  			return math.Float32bits(x+1) + 1
  1102  		}
  1103  		`,
  1104  		pos: []string{"\tMOVL\tX.*, [^X].*"},
  1105  	},
  1106  	{
  1107  		fn: `
  1108  		func $(x uint64) float64 {
  1109  			return math.Float64frombits(x+1) + 1
  1110  		}
  1111  		`,
  1112  		pos: []string{"\tMOVQ\t[^X].*, X.*"},
  1113  	},
  1114  	{
  1115  		fn: `
  1116  		func $(x uint32) float32 {
  1117  			return math.Float32frombits(x+1) + 1
  1118  		}
  1119  		`,
  1120  		pos: []string{"\tMOVL\t[^X].*, X.*"},
  1121  	},
  1122  }
  1123  
  1124  var linux386Tests = []*asmTest{
  1125  	{
  1126  		fn: `
  1127  		func f0(b []byte) uint32 {
  1128  			return binary.LittleEndian.Uint32(b)
  1129  		}
  1130  		`,
  1131  		pos: []string{"\tMOVL\t\\(.*\\),"},
  1132  	},
  1133  	{
  1134  		fn: `
  1135  		func f1(b []byte, i int) uint32 {
  1136  			return binary.LittleEndian.Uint32(b[i:])
  1137  		}
  1138  		`,
  1139  		pos: []string{"\tMOVL\t\\(.*\\)\\(.*\\*1\\),"},
  1140  	},
  1141  
  1142  	// multiplication merging tests
  1143  	{
  1144  		fn: `
  1145  		func $(n int) int {
  1146  			return 9*n + 14*n
  1147  		}`,
  1148  		pos: []string{"\tIMULL\t[$]23"}, // 23*n
  1149  	},
  1150  	{
  1151  		fn: `
  1152  		func $(a, n int) int {
  1153  			return 19*a + a*n
  1154  		}`,
  1155  		pos: []string{"\tADDL\t[$]19", "\tIMULL"}, // (n+19)*a
  1156  	},
  1157  	{
  1158  		// check that stack store is optimized away
  1159  		fn: `
  1160  		func $() int {
  1161  			var x int
  1162  			return *(&x)
  1163  		}
  1164  		`,
  1165  		pos: []string{"TEXT\t.*, [$]0-4"},
  1166  	},
  1167  	{
  1168  		fn: `
  1169  		func mul3(n int) int {
  1170  			return 23*n - 9*n
  1171  		}`,
  1172  		pos: []string{"\tIMULL\t[$]14"}, // 14*n
  1173  	},
  1174  	{
  1175  		fn: `
  1176  		func mul4(a, n int) int {
  1177  			return n*a - a*19
  1178  		}`,
  1179  		pos: []string{"\tADDL\t[$]-19", "\tIMULL"}, // (n-19)*a
  1180  	},
  1181  }
  1182  
  1183  var linuxS390XTests = []*asmTest{
  1184  	{
  1185  		fn: `
  1186  		func f0(b []byte) uint32 {
  1187  			return binary.LittleEndian.Uint32(b)
  1188  		}
  1189  		`,
  1190  		pos: []string{"\tMOVWBR\t\\(.*\\),"},
  1191  	},
  1192  	{
  1193  		fn: `
  1194  		func f1(b []byte, i int) uint32 {
  1195  			return binary.LittleEndian.Uint32(b[i:])
  1196  		}
  1197  		`,
  1198  		pos: []string{"\tMOVWBR\t\\(.*\\)\\(.*\\*1\\),"},
  1199  	},
  1200  	{
  1201  		fn: `
  1202  		func f2(b []byte) uint64 {
  1203  			return binary.LittleEndian.Uint64(b)
  1204  		}
  1205  		`,
  1206  		pos: []string{"\tMOVDBR\t\\(.*\\),"},
  1207  	},
  1208  	{
  1209  		fn: `
  1210  		func f3(b []byte, i int) uint64 {
  1211  			return binary.LittleEndian.Uint64(b[i:])
  1212  		}
  1213  		`,
  1214  		pos: []string{"\tMOVDBR\t\\(.*\\)\\(.*\\*1\\),"},
  1215  	},
  1216  	{
  1217  		fn: `
  1218  		func f4(b []byte) uint32 {
  1219  			return binary.BigEndian.Uint32(b)
  1220  		}
  1221  		`,
  1222  		pos: []string{"\tMOVWZ\t\\(.*\\),"},
  1223  	},
  1224  	{
  1225  		fn: `
  1226  		func f5(b []byte, i int) uint32 {
  1227  			return binary.BigEndian.Uint32(b[i:])
  1228  		}
  1229  		`,
  1230  		pos: []string{"\tMOVWZ\t\\(.*\\)\\(.*\\*1\\),"},
  1231  	},
  1232  	{
  1233  		fn: `
  1234  		func f6(b []byte) uint64 {
  1235  			return binary.BigEndian.Uint64(b)
  1236  		}
  1237  		`,
  1238  		pos: []string{"\tMOVD\t\\(.*\\),"},
  1239  	},
  1240  	{
  1241  		fn: `
  1242  		func f7(b []byte, i int) uint64 {
  1243  			return binary.BigEndian.Uint64(b[i:])
  1244  		}
  1245  		`,
  1246  		pos: []string{"\tMOVD\t\\(.*\\)\\(.*\\*1\\),"},
  1247  	},
  1248  	{
  1249  		fn: `
  1250  		func f8(x uint64) uint64 {
  1251  			return x<<7 + x>>57
  1252  		}
  1253  		`,
  1254  		pos: []string{"\tRLLG\t[$]7,"},
  1255  	},
  1256  	{
  1257  		fn: `
  1258  		func f9(x uint64) uint64 {
  1259  			return x<<7 | x>>57
  1260  		}
  1261  		`,
  1262  		pos: []string{"\tRLLG\t[$]7,"},
  1263  	},
  1264  	{
  1265  		fn: `
  1266  		func f10(x uint64) uint64 {
  1267  			return x<<7 ^ x>>57
  1268  		}
  1269  		`,
  1270  		pos: []string{"\tRLLG\t[$]7,"},
  1271  	},
  1272  	{
  1273  		fn: `
  1274  		func f11(x uint32) uint32 {
  1275  			return x<<7 + x>>25
  1276  		}
  1277  		`,
  1278  		pos: []string{"\tRLL\t[$]7,"},
  1279  	},
  1280  	{
  1281  		fn: `
  1282  		func f12(x uint32) uint32 {
  1283  			return x<<7 | x>>25
  1284  		}
  1285  		`,
  1286  		pos: []string{"\tRLL\t[$]7,"},
  1287  	},
  1288  	{
  1289  		fn: `
  1290  		func f13(x uint32) uint32 {
  1291  			return x<<7 ^ x>>25
  1292  		}
  1293  		`,
  1294  		pos: []string{"\tRLL\t[$]7,"},
  1295  	},
  1296  	// Fused multiply-add/sub instructions.
  1297  	{
  1298  		fn: `
  1299  		func f14(x, y, z float64) float64 {
  1300  			return x * y + z
  1301  		}
  1302  		`,
  1303  		pos: []string{"\tFMADD\t"},
  1304  	},
  1305  	{
  1306  		fn: `
  1307  		func f15(x, y, z float64) float64 {
  1308  			return x * y - z
  1309  		}
  1310  		`,
  1311  		pos: []string{"\tFMSUB\t"},
  1312  	},
  1313  	{
  1314  		fn: `
  1315  		func f16(x, y, z float32) float32 {
  1316  			return x * y + z
  1317  		}
  1318  		`,
  1319  		pos: []string{"\tFMADDS\t"},
  1320  	},
  1321  	{
  1322  		fn: `
  1323  		func f17(x, y, z float32) float32 {
  1324  			return x * y - z
  1325  		}
  1326  		`,
  1327  		pos: []string{"\tFMSUBS\t"},
  1328  	},
  1329  	// Intrinsic tests for math/bits
  1330  	{
  1331  		fn: `
  1332  		func f18(a uint64) int {
  1333  			return bits.TrailingZeros64(a)
  1334  		}
  1335  		`,
  1336  		pos: []string{"\tFLOGR\t"},
  1337  	},
  1338  	{
  1339  		fn: `
  1340  		func f19(a uint32) int {
  1341  			return bits.TrailingZeros32(a)
  1342  		}
  1343  		`,
  1344  		pos: []string{"\tFLOGR\t", "\tMOVWZ\t"},
  1345  	},
  1346  	{
  1347  		fn: `
  1348  		func f20(a uint16) int {
  1349  			return bits.TrailingZeros16(a)
  1350  		}
  1351  		`,
  1352  		pos: []string{"\tFLOGR\t", "\tOR\t\\$65536,"},
  1353  	},
  1354  	{
  1355  		fn: `
  1356  		func f21(a uint8) int {
  1357  			return bits.TrailingZeros8(a)
  1358  		}
  1359  		`,
  1360  		pos: []string{"\tFLOGR\t", "\tOR\t\\$256,"},
  1361  	},
  1362  	// Intrinsic tests for math/bits
  1363  	{
  1364  		fn: `
  1365  		func f22(a uint64) uint64 {
  1366  			return bits.ReverseBytes64(a)
  1367  		}
  1368  		`,
  1369  		pos: []string{"\tMOVDBR\t"},
  1370  	},
  1371  	{
  1372  		fn: `
  1373  		func f23(a uint32) uint32 {
  1374  			return bits.ReverseBytes32(a)
  1375  		}
  1376  		`,
  1377  		pos: []string{"\tMOVWBR\t"},
  1378  	},
  1379  	{
  1380  		fn: `
  1381  		func f24(a uint64) int {
  1382  			return bits.Len64(a)
  1383  		}
  1384  		`,
  1385  		pos: []string{"\tFLOGR\t"},
  1386  	},
  1387  	{
  1388  		fn: `
  1389  		func f25(a uint32) int {
  1390  			return bits.Len32(a)
  1391  		}
  1392  		`,
  1393  		pos: []string{"\tFLOGR\t"},
  1394  	},
  1395  	{
  1396  		fn: `
  1397  		func f26(a uint16) int {
  1398  			return bits.Len16(a)
  1399  		}
  1400  		`,
  1401  		pos: []string{"\tFLOGR\t"},
  1402  	},
  1403  	{
  1404  		fn: `
  1405  		func f27(a uint8) int {
  1406  			return bits.Len8(a)
  1407  		}
  1408  		`,
  1409  		pos: []string{"\tFLOGR\t"},
  1410  	},
  1411  	{
  1412  		fn: `
  1413  		func f28(a uint) int {
  1414  			return bits.Len(a)
  1415  		}
  1416  		`,
  1417  		pos: []string{"\tFLOGR\t"},
  1418  	},
  1419  	{
  1420  		fn: `
  1421  		func f29(a uint64) int {
  1422  			return bits.LeadingZeros64(a)
  1423  		}
  1424  		`,
  1425  		pos: []string{"\tFLOGR\t"},
  1426  	},
  1427  	{
  1428  		fn: `
  1429  		func f30(a uint32) int {
  1430  			return bits.LeadingZeros32(a)
  1431  		}
  1432  		`,
  1433  		pos: []string{"\tFLOGR\t"},
  1434  	},
  1435  	{
  1436  		fn: `
  1437  		func f31(a uint16) int {
  1438  			return bits.LeadingZeros16(a)
  1439  		}
  1440  		`,
  1441  		pos: []string{"\tFLOGR\t"},
  1442  	},
  1443  	{
  1444  		fn: `
  1445  		func f32(a uint8) int {
  1446  			return bits.LeadingZeros8(a)
  1447  		}
  1448  		`,
  1449  		pos: []string{"\tFLOGR\t"},
  1450  	},
  1451  	{
  1452  		fn: `
  1453  		func f33(a uint) int {
  1454  			return bits.LeadingZeros(a)
  1455  		}
  1456  		`,
  1457  		pos: []string{"\tFLOGR\t"},
  1458  	},
  1459  	{
  1460  		// check that stack store is optimized away
  1461  		fn: `
  1462  		func $() int {
  1463  			var x int
  1464  			return *(&x)
  1465  		}
  1466  		`,
  1467  		pos: []string{"TEXT\t.*, [$]0-8"},
  1468  	},
  1469  }
  1470  
  1471  var linuxARMTests = []*asmTest{
  1472  	{
  1473  		fn: `
  1474  		func f0(x uint32) uint32 {
  1475  			return x<<7 + x>>25
  1476  		}
  1477  		`,
  1478  		pos: []string{"\tMOVW\tR[0-9]+@>25,"},
  1479  	},
  1480  	{
  1481  		fn: `
  1482  		func f1(x uint32) uint32 {
  1483  			return x<<7 | x>>25
  1484  		}
  1485  		`,
  1486  		pos: []string{"\tMOVW\tR[0-9]+@>25,"},
  1487  	},
  1488  	{
  1489  		fn: `
  1490  		func f2(x uint32) uint32 {
  1491  			return x<<7 ^ x>>25
  1492  		}
  1493  		`,
  1494  		pos: []string{"\tMOVW\tR[0-9]+@>25,"},
  1495  	},
  1496  	{
  1497  		fn: `
  1498  		func f3(a uint64) int {
  1499  			return bits.Len64(a)
  1500  		}
  1501  		`,
  1502  		pos: []string{"\tCLZ\t"},
  1503  	},
  1504  	{
  1505  		fn: `
  1506  		func f4(a uint32) int {
  1507  			return bits.Len32(a)
  1508  		}
  1509  		`,
  1510  		pos: []string{"\tCLZ\t"},
  1511  	},
  1512  	{
  1513  		fn: `
  1514  		func f5(a uint16) int {
  1515  			return bits.Len16(a)
  1516  		}
  1517  		`,
  1518  		pos: []string{"\tCLZ\t"},
  1519  	},
  1520  	{
  1521  		fn: `
  1522  		func f6(a uint8) int {
  1523  			return bits.Len8(a)
  1524  		}
  1525  		`,
  1526  		pos: []string{"\tCLZ\t"},
  1527  	},
  1528  	{
  1529  		fn: `
  1530  		func f7(a uint) int {
  1531  			return bits.Len(a)
  1532  		}
  1533  		`,
  1534  		pos: []string{"\tCLZ\t"},
  1535  	},
  1536  	{
  1537  		fn: `
  1538  		func f8(a uint64) int {
  1539  			return bits.LeadingZeros64(a)
  1540  		}
  1541  		`,
  1542  		pos: []string{"\tCLZ\t"},
  1543  	},
  1544  	{
  1545  		fn: `
  1546  		func f9(a uint32) int {
  1547  			return bits.LeadingZeros32(a)
  1548  		}
  1549  		`,
  1550  		pos: []string{"\tCLZ\t"},
  1551  	},
  1552  	{
  1553  		fn: `
  1554  		func f10(a uint16) int {
  1555  			return bits.LeadingZeros16(a)
  1556  		}
  1557  		`,
  1558  		pos: []string{"\tCLZ\t"},
  1559  	},
  1560  	{
  1561  		fn: `
  1562  		func f11(a uint8) int {
  1563  			return bits.LeadingZeros8(a)
  1564  		}
  1565  		`,
  1566  		pos: []string{"\tCLZ\t"},
  1567  	},
  1568  	{
  1569  		fn: `
  1570  		func f12(a uint) int {
  1571  			return bits.LeadingZeros(a)
  1572  		}
  1573  		`,
  1574  		pos: []string{"\tCLZ\t"},
  1575  	},
  1576  	{
  1577  		// make sure assembly output has matching offset and base register.
  1578  		fn: `
  1579  		func f13(a, b int) int {
  1580  			//go:noinline
  1581  			func() {_, _ = a, b} () // use some frame
  1582  			return b
  1583  		}
  1584  		`,
  1585  		pos: []string{"b\\+4\\(FP\\)"},
  1586  	},
  1587  	{
  1588  		// check that stack store is optimized away
  1589  		fn: `
  1590  		func $() int {
  1591  			var x int
  1592  			return *(&x)
  1593  		}
  1594  		`,
  1595  		pos: []string{"TEXT\t.*, [$]-4-4"},
  1596  	},
  1597  }
  1598  
  1599  var linuxARM64Tests = []*asmTest{
  1600  	{
  1601  		fn: `
  1602  		func f0(x uint64) uint64 {
  1603  			return x<<7 + x>>57
  1604  		}
  1605  		`,
  1606  		pos: []string{"\tROR\t[$]57,"},
  1607  	},
  1608  	{
  1609  		fn: `
  1610  		func f1(x uint64) uint64 {
  1611  			return x<<7 | x>>57
  1612  		}
  1613  		`,
  1614  		pos: []string{"\tROR\t[$]57,"},
  1615  	},
  1616  	{
  1617  		fn: `
  1618  		func f2(x uint64) uint64 {
  1619  			return x<<7 ^ x>>57
  1620  		}
  1621  		`,
  1622  		pos: []string{"\tROR\t[$]57,"},
  1623  	},
  1624  	{
  1625  		fn: `
  1626  		func f3(x uint32) uint32 {
  1627  			return x<<7 + x>>25
  1628  		}
  1629  		`,
  1630  		pos: []string{"\tRORW\t[$]25,"},
  1631  	},
  1632  	{
  1633  		fn: `
  1634  		func f4(x uint32) uint32 {
  1635  			return x<<7 | x>>25
  1636  		}
  1637  		`,
  1638  		pos: []string{"\tRORW\t[$]25,"},
  1639  	},
  1640  	{
  1641  		fn: `
  1642  		func f5(x uint32) uint32 {
  1643  			return x<<7 ^ x>>25
  1644  		}
  1645  		`,
  1646  		pos: []string{"\tRORW\t[$]25,"},
  1647  	},
  1648  	{
  1649  		fn: `
  1650  		func f22(a uint64) uint64 {
  1651  			return bits.ReverseBytes64(a)
  1652  		}
  1653  		`,
  1654  		pos: []string{"\tREV\t"},
  1655  	},
  1656  	{
  1657  		fn: `
  1658  		func f23(a uint32) uint32 {
  1659  			return bits.ReverseBytes32(a)
  1660  		}
  1661  		`,
  1662  		pos: []string{"\tREVW\t"},
  1663  	},
  1664  	{
  1665  		fn: `
  1666  		func f24(a uint64) int {
  1667  			return bits.Len64(a)
  1668  		}
  1669  		`,
  1670  		pos: []string{"\tCLZ\t"},
  1671  	},
  1672  	{
  1673  		fn: `
  1674  		func f25(a uint32) int {
  1675  			return bits.Len32(a)
  1676  		}
  1677  		`,
  1678  		pos: []string{"\tCLZ\t"},
  1679  	},
  1680  	{
  1681  		fn: `
  1682  		func f26(a uint16) int {
  1683  			return bits.Len16(a)
  1684  		}
  1685  		`,
  1686  		pos: []string{"\tCLZ\t"},
  1687  	},
  1688  	{
  1689  		fn: `
  1690  		func f27(a uint8) int {
  1691  			return bits.Len8(a)
  1692  		}
  1693  		`,
  1694  		pos: []string{"\tCLZ\t"},
  1695  	},
  1696  	{
  1697  		fn: `
  1698  		func f28(a uint) int {
  1699  			return bits.Len(a)
  1700  		}
  1701  		`,
  1702  		pos: []string{"\tCLZ\t"},
  1703  	},
  1704  	{
  1705  		fn: `
  1706  		func f29(a uint64) int {
  1707  			return bits.LeadingZeros64(a)
  1708  		}
  1709  		`,
  1710  		pos: []string{"\tCLZ\t"},
  1711  	},
  1712  	{
  1713  		fn: `
  1714  		func f30(a uint32) int {
  1715  			return bits.LeadingZeros32(a)
  1716  		}
  1717  		`,
  1718  		pos: []string{"\tCLZ\t"},
  1719  	},
  1720  	{
  1721  		fn: `
  1722  		func f31(a uint16) int {
  1723  			return bits.LeadingZeros16(a)
  1724  		}
  1725  		`,
  1726  		pos: []string{"\tCLZ\t"},
  1727  	},
  1728  	{
  1729  		fn: `
  1730  		func f32(a uint8) int {
  1731  			return bits.LeadingZeros8(a)
  1732  		}
  1733  		`,
  1734  		pos: []string{"\tCLZ\t"},
  1735  	},
  1736  	{
  1737  		fn: `
  1738  		func f33(a uint) int {
  1739  			return bits.LeadingZeros(a)
  1740  		}
  1741  		`,
  1742  		pos: []string{"\tCLZ\t"},
  1743  	},
  1744  	{
  1745  		fn: `
  1746  		func f34(a uint64) uint64 {
  1747  			return a & ((1<<63)-1)
  1748  		}
  1749  		`,
  1750  		pos: []string{"\tAND\t"},
  1751  	},
  1752  	{
  1753  		fn: `
  1754  		func f35(a uint64) uint64 {
  1755  			return a & (1<<63)
  1756  		}
  1757  		`,
  1758  		pos: []string{"\tAND\t"},
  1759  	},
  1760  	{
  1761  		// make sure offsets are folded into load and store.
  1762  		fn: `
  1763  		func f36(_, a [20]byte) (b [20]byte) {
  1764  			b = a
  1765  			return
  1766  		}
  1767  		`,
  1768  		pos: []string{"\tMOVD\t\"\"\\.a\\+[0-9]+\\(FP\\), R[0-9]+", "\tMOVD\tR[0-9]+, \"\"\\.b\\+[0-9]+\\(FP\\)"},
  1769  	},
  1770  	{
  1771  		// check that stack store is optimized away
  1772  		fn: `
  1773  		func $() int {
  1774  			var x int
  1775  			return *(&x)
  1776  		}
  1777  		`,
  1778  		pos: []string{"TEXT\t.*, [$]-8-8"},
  1779  	},
  1780  	{
  1781  		// check that we don't emit comparisons for constant shift
  1782  		fn: `
  1783  //go:nosplit
  1784  		func $(x int) int {
  1785  			return x << 17
  1786  		}
  1787  		`,
  1788  		pos: []string{"LSL\t\\$17"},
  1789  		neg: []string{"CMP"},
  1790  	},
  1791  }
  1792  
  1793  var linuxMIPSTests = []*asmTest{
  1794  	{
  1795  		fn: `
  1796  		func f0(a uint64) int {
  1797  			return bits.Len64(a)
  1798  		}
  1799  		`,
  1800  		pos: []string{"\tCLZ\t"},
  1801  	},
  1802  	{
  1803  		fn: `
  1804  		func f1(a uint32) int {
  1805  			return bits.Len32(a)
  1806  		}
  1807  		`,
  1808  		pos: []string{"\tCLZ\t"},
  1809  	},
  1810  	{
  1811  		fn: `
  1812  		func f2(a uint16) int {
  1813  			return bits.Len16(a)
  1814  		}
  1815  		`,
  1816  		pos: []string{"\tCLZ\t"},
  1817  	},
  1818  	{
  1819  		fn: `
  1820  		func f3(a uint8) int {
  1821  			return bits.Len8(a)
  1822  		}
  1823  		`,
  1824  		pos: []string{"\tCLZ\t"},
  1825  	},
  1826  	{
  1827  		fn: `
  1828  		func f4(a uint) int {
  1829  			return bits.Len(a)
  1830  		}
  1831  		`,
  1832  		pos: []string{"\tCLZ\t"},
  1833  	},
  1834  	{
  1835  		fn: `
  1836  		func f5(a uint64) int {
  1837  			return bits.LeadingZeros64(a)
  1838  		}
  1839  		`,
  1840  		pos: []string{"\tCLZ\t"},
  1841  	},
  1842  	{
  1843  		fn: `
  1844  		func f6(a uint32) int {
  1845  			return bits.LeadingZeros32(a)
  1846  		}
  1847  		`,
  1848  		pos: []string{"\tCLZ\t"},
  1849  	},
  1850  	{
  1851  		fn: `
  1852  		func f7(a uint16) int {
  1853  			return bits.LeadingZeros16(a)
  1854  		}
  1855  		`,
  1856  		pos: []string{"\tCLZ\t"},
  1857  	},
  1858  	{
  1859  		fn: `
  1860  		func f8(a uint8) int {
  1861  			return bits.LeadingZeros8(a)
  1862  		}
  1863  		`,
  1864  		pos: []string{"\tCLZ\t"},
  1865  	},
  1866  	{
  1867  		fn: `
  1868  		func f9(a uint) int {
  1869  			return bits.LeadingZeros(a)
  1870  		}
  1871  		`,
  1872  		pos: []string{"\tCLZ\t"},
  1873  	},
  1874  	{
  1875  		// check that stack store is optimized away
  1876  		fn: `
  1877  		func $() int {
  1878  			var x int
  1879  			return *(&x)
  1880  		}
  1881  		`,
  1882  		pos: []string{"TEXT\t.*, [$]-4-4"},
  1883  	},
  1884  }
  1885  
  1886  var linuxMIPS64Tests = []*asmTest{
  1887  	{
  1888  		// check that we don't emit comparisons for constant shift
  1889  		fn: `
  1890  		func $(x int) int {
  1891  			return x << 17
  1892  		}
  1893  		`,
  1894  		pos: []string{"SLLV\t\\$17"},
  1895  		neg: []string{"SGT"},
  1896  	},
  1897  }
  1898  
  1899  var linuxPPC64LETests = []*asmTest{
  1900  	// Fused multiply-add/sub instructions.
  1901  	{
  1902  		fn: `
  1903  		func f0(x, y, z float64) float64 {
  1904  			return x * y + z
  1905  		}
  1906  		`,
  1907  		pos: []string{"\tFMADD\t"},
  1908  	},
  1909  	{
  1910  		fn: `
  1911  		func f1(x, y, z float64) float64 {
  1912  			return x * y - z
  1913  		}
  1914  		`,
  1915  		pos: []string{"\tFMSUB\t"},
  1916  	},
  1917  	{
  1918  		fn: `
  1919  		func f2(x, y, z float32) float32 {
  1920  			return x * y + z
  1921  		}
  1922  		`,
  1923  		pos: []string{"\tFMADDS\t"},
  1924  	},
  1925  	{
  1926  		fn: `
  1927  		func f3(x, y, z float32) float32 {
  1928  			return x * y - z
  1929  		}
  1930  		`,
  1931  		pos: []string{"\tFMSUBS\t"},
  1932  	},
  1933  	{
  1934  		fn: `
  1935  		func f4(x uint32) uint32 {
  1936  			return x<<7 | x>>25
  1937  		}
  1938  		`,
  1939  		pos: []string{"\tROTLW\t"},
  1940  	},
  1941  	{
  1942  		fn: `
  1943  		func f5(x uint32) uint32 {
  1944  			return x<<7 + x>>25
  1945  		}
  1946  		`,
  1947  		pos: []string{"\tROTLW\t"},
  1948  	},
  1949  	{
  1950  		fn: `
  1951  		func f6(x uint32) uint32 {
  1952  			return x<<7 ^ x>>25
  1953  		}
  1954  		`,
  1955  		pos: []string{"\tROTLW\t"},
  1956  	},
  1957  	{
  1958  		fn: `
  1959  		func f7(x uint64) uint64 {
  1960  			return x<<7 | x>>57
  1961  		}
  1962  		`,
  1963  		pos: []string{"\tROTL\t"},
  1964  	},
  1965  	{
  1966  		fn: `
  1967  		func f8(x uint64) uint64 {
  1968  			return x<<7 + x>>57
  1969  		}
  1970  		`,
  1971  		pos: []string{"\tROTL\t"},
  1972  	},
  1973  	{
  1974  		fn: `
  1975  		func f9(x uint64) uint64 {
  1976  			return x<<7 ^ x>>57
  1977  		}
  1978  		`,
  1979  		pos: []string{"\tROTL\t"},
  1980  	},
  1981  	{
  1982  		// check that stack store is optimized away
  1983  		fn: `
  1984  		func $() int {
  1985  			var x int
  1986  			return *(&x)
  1987  		}
  1988  		`,
  1989  		pos: []string{"TEXT\t.*, [$]0-8"},
  1990  	},
  1991  }
  1992  
  1993  var plan9AMD64Tests = []*asmTest{
  1994  	// We should make sure that the compiler doesn't generate floating point
  1995  	// instructions for non-float operations on Plan 9, because floating point
  1996  	// operations are not allowed in the note handler.
  1997  	// Array zeroing.
  1998  	{
  1999  		fn: `
  2000  		func $() [16]byte {
  2001  			var a [16]byte
  2002  			return a
  2003  		}
  2004  		`,
  2005  		pos: []string{"\tMOVQ\t\\$0, \"\""},
  2006  	},
  2007  	// Array copy.
  2008  	{
  2009  		fn: `
  2010  		func $(a [16]byte) (b [16]byte) {
  2011  			b = a
  2012  			return
  2013  		}
  2014  		`,
  2015  		pos: []string{"\tMOVQ\t\"\"\\.a\\+[0-9]+\\(SP\\), (AX|CX)", "\tMOVQ\t(AX|CX), \"\"\\.b\\+[0-9]+\\(SP\\)"},
  2016  	},
  2017  }
  2018  
  2019  // TestLineNumber checks to make sure the generated assembly has line numbers
  2020  // see issue #16214
  2021  func TestLineNumber(t *testing.T) {
  2022  	testenv.MustHaveGoBuild(t)
  2023  	dir, err := ioutil.TempDir("", "TestLineNumber")
  2024  	if err != nil {
  2025  		t.Fatalf("could not create directory: %v", err)
  2026  	}
  2027  	defer os.RemoveAll(dir)
  2028  
  2029  	src := filepath.Join(dir, "x.go")
  2030  	err = ioutil.WriteFile(src, []byte(issue16214src), 0644)
  2031  	if err != nil {
  2032  		t.Fatalf("could not write file: %v", err)
  2033  	}
  2034  
  2035  	cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-S", "-o", filepath.Join(dir, "out.o"), src)
  2036  	out, err := cmd.CombinedOutput()
  2037  	if err != nil {
  2038  		t.Fatalf("fail to run go tool compile: %v", err)
  2039  	}
  2040  
  2041  	if strings.Contains(string(out), "unknown line number") {
  2042  		t.Errorf("line number missing in assembly:\n%s", out)
  2043  	}
  2044  }
  2045  
  2046  var issue16214src = `
  2047  package main
  2048  
  2049  func Mod32(x uint32) uint32 {
  2050  	return x % 3 // frontend rewrites it as HMUL with 2863311531, the LITERAL node has unknown Pos
  2051  }
  2052  `