github.com/goproxy0/go@v0.0.0-20171111080102-49cc0c489d2c/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", "math/bits"},
   240  		tests:   linuxS390XTests,
   241  	},
   242  	{
   243  		arch:    "arm",
   244  		os:      "linux",
   245  		imports: []string{"math/bits", "runtime"},
   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  		imports: []string{"encoding/binary", "math", "math/bits"},
   269  		tests:   linuxPPC64LETests,
   270  	},
   271  	{
   272  		arch:  "amd64",
   273  		os:    "plan9",
   274  		tests: plan9AMD64Tests,
   275  	},
   276  }
   277  
   278  var linuxAMD64Tests = []*asmTest{
   279  	// multiplication by powers of two
   280  	{
   281  		fn: `
   282  		func $(n int) int {
   283  			return n * 64
   284  		}
   285  		`,
   286  		pos: []string{"\tSHLQ\t\\$6,"},
   287  		neg: []string{"IMULQ"},
   288  	},
   289  	{
   290  		fn: `
   291  		func $(n int) int {
   292  			return -128*n
   293  		}
   294  		`,
   295  		pos: []string{"SHLQ"},
   296  		neg: []string{"IMULQ"},
   297  	},
   298  
   299  	{
   300  		fn: `
   301  		func $(x int) int {
   302  			return x * 96
   303  		}
   304  		`,
   305  		pos: []string{"\tSHLQ\t\\$5,", "\tLEAQ\t\\(.*\\)\\(.*\\*2\\),"},
   306  	},
   307  	// Load-combining tests.
   308  	{
   309  		fn: `
   310  		func f2(b []byte) uint64 {
   311  			return binary.LittleEndian.Uint64(b)
   312  		}
   313  		`,
   314  		pos: []string{"\tMOVQ\t\\(.*\\),"},
   315  	},
   316  	{
   317  		fn: `
   318  		func f3(b []byte, i int) uint64 {
   319  			return binary.LittleEndian.Uint64(b[i:])
   320  		}
   321  		`,
   322  		pos: []string{"\tMOVQ\t\\(.*\\)\\(.*\\*1\\),"},
   323  	},
   324  	{
   325  		fn: `
   326  		func f4(b []byte) uint32 {
   327  			return binary.LittleEndian.Uint32(b)
   328  		}
   329  		`,
   330  		pos: []string{"\tMOVL\t\\(.*\\),"},
   331  	},
   332  	{
   333  		fn: `
   334  		func f5(b []byte, i int) uint32 {
   335  			return binary.LittleEndian.Uint32(b[i:])
   336  		}
   337  		`,
   338  		pos: []string{"\tMOVL\t\\(.*\\)\\(.*\\*1\\),"},
   339  	},
   340  	{
   341  		fn: `
   342  		func f6(b []byte) uint64 {
   343  			return binary.BigEndian.Uint64(b)
   344  		}
   345  		`,
   346  		pos: []string{"\tBSWAPQ\t"},
   347  	},
   348  	{
   349  		fn: `
   350  		func f7(b []byte, i int) uint64 {
   351  			return binary.BigEndian.Uint64(b[i:])
   352  		}
   353  		`,
   354  		pos: []string{"\tBSWAPQ\t"},
   355  	},
   356  	{
   357  		fn: `
   358  		func f8(b []byte, v uint64) {
   359  			binary.BigEndian.PutUint64(b, v)
   360  		}
   361  		`,
   362  		pos: []string{"\tBSWAPQ\t"},
   363  	},
   364  	{
   365  		fn: `
   366  		func f9(b []byte, i int, v uint64) {
   367  			binary.BigEndian.PutUint64(b[i:], v)
   368  		}
   369  		`,
   370  		pos: []string{"\tBSWAPQ\t"},
   371  	},
   372  	{
   373  		fn: `
   374  		func f10(b []byte) uint32 {
   375  			return binary.BigEndian.Uint32(b)
   376  		}
   377  		`,
   378  		pos: []string{"\tBSWAPL\t"},
   379  	},
   380  	{
   381  		fn: `
   382  		func f11(b []byte, i int) uint32 {
   383  			return binary.BigEndian.Uint32(b[i:])
   384  		}
   385  		`,
   386  		pos: []string{"\tBSWAPL\t"},
   387  	},
   388  	{
   389  		fn: `
   390  		func f12(b []byte, v uint32) {
   391  			binary.BigEndian.PutUint32(b, v)
   392  		}
   393  		`,
   394  		pos: []string{"\tBSWAPL\t"},
   395  	},
   396  	{
   397  		fn: `
   398  		func f13(b []byte, i int, v uint32) {
   399  			binary.BigEndian.PutUint32(b[i:], v)
   400  		}
   401  		`,
   402  		pos: []string{"\tBSWAPL\t"},
   403  	},
   404  	{
   405  		fn: `
   406  		func f14(b []byte) uint16 {
   407  			return binary.BigEndian.Uint16(b)
   408  		}
   409  		`,
   410  		pos: []string{"\tROLW\t\\$8,"},
   411  	},
   412  	{
   413  		fn: `
   414  		func f15(b []byte, i int) uint16 {
   415  			return binary.BigEndian.Uint16(b[i:])
   416  		}
   417  		`,
   418  		pos: []string{"\tROLW\t\\$8,"},
   419  	},
   420  	{
   421  		fn: `
   422  		func f16(b []byte, v uint16) {
   423  			binary.BigEndian.PutUint16(b, v)
   424  		}
   425  		`,
   426  		pos: []string{"\tROLW\t\\$8,"},
   427  	},
   428  	{
   429  		fn: `
   430  		func f17(b []byte, i int, v uint16) {
   431  			binary.BigEndian.PutUint16(b[i:], v)
   432  		}
   433  		`,
   434  		pos: []string{"\tROLW\t\\$8,"},
   435  	},
   436  	// Structure zeroing.  See issue #18370.
   437  	{
   438  		fn: `
   439  		type T1 struct {
   440  			a, b, c int
   441  		}
   442  		func $(t *T1) {
   443  			*t = T1{}
   444  		}
   445  		`,
   446  		pos: []string{"\tXORPS\tX., X", "\tMOVUPS\tX., \\(.*\\)", "\tMOVQ\t\\$0, 16\\(.*\\)"},
   447  	},
   448  	// SSA-able composite literal initialization. Issue 18872.
   449  	{
   450  		fn: `
   451  		type T18872 struct {
   452  			a, b, c, d int
   453  		}
   454  
   455  		func f18872(p *T18872) {
   456  			*p = T18872{1, 2, 3, 4}
   457  		}
   458  		`,
   459  		pos: []string{"\tMOVQ\t[$]1", "\tMOVQ\t[$]2", "\tMOVQ\t[$]3", "\tMOVQ\t[$]4"},
   460  	},
   461  	// Also test struct containing pointers (this was special because of write barriers).
   462  	{
   463  		fn: `
   464  		type T2 struct {
   465  			a, b, c *int
   466  		}
   467  		func f19(t *T2) {
   468  			*t = T2{}
   469  		}
   470  		`,
   471  		pos: []string{"\tXORPS\tX., X", "\tMOVUPS\tX., \\(.*\\)", "\tMOVQ\t\\$0, 16\\(.*\\)", "\tCALL\truntime\\.(writebarrierptr|gcWriteBarrier)\\(SB\\)"},
   472  	},
   473  	// Rotate tests
   474  	{
   475  		fn: `
   476  		func f20(x uint64) uint64 {
   477  			return x<<7 | x>>57
   478  		}
   479  		`,
   480  		pos: []string{"\tROLQ\t[$]7,"},
   481  	},
   482  	{
   483  		fn: `
   484  		func f21(x uint64) uint64 {
   485  			return x<<7 + x>>57
   486  		}
   487  		`,
   488  		pos: []string{"\tROLQ\t[$]7,"},
   489  	},
   490  	{
   491  		fn: `
   492  		func f22(x uint64) uint64 {
   493  			return x<<7 ^ x>>57
   494  		}
   495  		`,
   496  		pos: []string{"\tROLQ\t[$]7,"},
   497  	},
   498  	{
   499  		fn: `
   500  		func f23(x uint32) uint32 {
   501  			return x<<7 + x>>25
   502  		}
   503  		`,
   504  		pos: []string{"\tROLL\t[$]7,"},
   505  	},
   506  	{
   507  		fn: `
   508  		func f24(x uint32) uint32 {
   509  			return x<<7 | x>>25
   510  		}
   511  		`,
   512  		pos: []string{"\tROLL\t[$]7,"},
   513  	},
   514  	{
   515  		fn: `
   516  		func f25(x uint32) uint32 {
   517  			return x<<7 ^ x>>25
   518  		}
   519  		`,
   520  		pos: []string{"\tROLL\t[$]7,"},
   521  	},
   522  	{
   523  		fn: `
   524  		func f26(x uint16) uint16 {
   525  			return x<<7 + x>>9
   526  		}
   527  		`,
   528  		pos: []string{"\tROLW\t[$]7,"},
   529  	},
   530  	{
   531  		fn: `
   532  		func f27(x uint16) uint16 {
   533  			return x<<7 | x>>9
   534  		}
   535  		`,
   536  		pos: []string{"\tROLW\t[$]7,"},
   537  	},
   538  	{
   539  		fn: `
   540  		func f28(x uint16) uint16 {
   541  			return x<<7 ^ x>>9
   542  		}
   543  		`,
   544  		pos: []string{"\tROLW\t[$]7,"},
   545  	},
   546  	{
   547  		fn: `
   548  		func f29(x uint8) uint8 {
   549  			return x<<7 + x>>1
   550  		}
   551  		`,
   552  		pos: []string{"\tROLB\t[$]7,"},
   553  	},
   554  	{
   555  		fn: `
   556  		func f30(x uint8) uint8 {
   557  			return x<<7 | x>>1
   558  		}
   559  		`,
   560  		pos: []string{"\tROLB\t[$]7,"},
   561  	},
   562  	{
   563  		fn: `
   564  		func f31(x uint8) uint8 {
   565  			return x<<7 ^ x>>1
   566  		}
   567  		`,
   568  		pos: []string{"\tROLB\t[$]7,"},
   569  	},
   570  	// Rotate after inlining (see issue 18254).
   571  	{
   572  		fn: `
   573  		func f32(x uint32) uint32 {
   574  			return g(x, 7)
   575  		}
   576  		func g(x uint32, k uint) uint32 {
   577  			return x<<k | x>>(32-k)
   578  		}
   579  		`,
   580  		pos: []string{"\tROLL\t[$]7,"},
   581  	},
   582  	{
   583  		fn: `
   584  		func f33(m map[int]int) int {
   585  			return m[5]
   586  		}
   587  		`,
   588  		pos: []string{"\tMOVQ\t[$]5,"},
   589  	},
   590  	// Direct use of constants in fast map access calls. Issue 19015.
   591  	{
   592  		fn: `
   593  		func f34(m map[int]int) bool {
   594  			_, ok := m[5]
   595  			return ok
   596  		}
   597  		`,
   598  		pos: []string{"\tMOVQ\t[$]5,"},
   599  	},
   600  	{
   601  		fn: `
   602  		func f35(m map[string]int) int {
   603  			return m["abc"]
   604  		}
   605  		`,
   606  		pos: []string{"\"abc\""},
   607  	},
   608  	{
   609  		fn: `
   610  		func f36(m map[string]int) bool {
   611  			_, ok := m["abc"]
   612  			return ok
   613  		}
   614  		`,
   615  		pos: []string{"\"abc\""},
   616  	},
   617  	// Bit test ops on amd64, issue 18943.
   618  	{
   619  		fn: `
   620  		func f37(a, b uint64) int {
   621  			if a&(1<<(b&63)) != 0 {
   622  				return 1
   623  			}
   624  			return -1
   625  		}
   626  		`,
   627  		pos: []string{"\tBTQ\t"},
   628  	},
   629  	{
   630  		fn: `
   631  		func f38(a, b uint64) bool {
   632  			return a&(1<<(b&63)) != 0
   633  		}
   634  		`,
   635  		pos: []string{"\tBTQ\t"},
   636  	},
   637  	{
   638  		fn: `
   639  		func f39(a uint64) int {
   640  			if a&(1<<60) != 0 {
   641  				return 1
   642  			}
   643  			return -1
   644  		}
   645  		`,
   646  		pos: []string{"\tBTQ\t\\$60"},
   647  	},
   648  	{
   649  		fn: `
   650  		func f40(a uint64) bool {
   651  			return a&(1<<60) != 0
   652  		}
   653  		`,
   654  		pos: []string{"\tBTQ\t\\$60"},
   655  	},
   656  	// Intrinsic tests for math/bits
   657  	{
   658  		fn: `
   659  		func f41(a uint64) int {
   660  			return bits.TrailingZeros64(a)
   661  		}
   662  		`,
   663  		pos: []string{"\tBSFQ\t", "\tMOVL\t\\$64,", "\tCMOVQEQ\t"},
   664  	},
   665  	{
   666  		fn: `
   667  		func f42(a uint32) int {
   668  			return bits.TrailingZeros32(a)
   669  		}
   670  		`,
   671  		pos: []string{"\tBSFQ\t", "\tORQ\t[^$]", "\tMOVQ\t\\$4294967296,"},
   672  	},
   673  	{
   674  		fn: `
   675  		func f43(a uint16) int {
   676  			return bits.TrailingZeros16(a)
   677  		}
   678  		`,
   679  		pos: []string{"\tBSFQ\t", "\tORQ\t\\$65536,"},
   680  	},
   681  	{
   682  		fn: `
   683  		func f44(a uint8) int {
   684  			return bits.TrailingZeros8(a)
   685  		}
   686  		`,
   687  		pos: []string{"\tBSFQ\t", "\tORQ\t\\$256,"},
   688  	},
   689  	{
   690  		fn: `
   691  		func f45(a uint64) uint64 {
   692  			return bits.ReverseBytes64(a)
   693  		}
   694  		`,
   695  		pos: []string{"\tBSWAPQ\t"},
   696  	},
   697  	{
   698  		fn: `
   699  		func f46(a uint32) uint32 {
   700  			return bits.ReverseBytes32(a)
   701  		}
   702  		`,
   703  		pos: []string{"\tBSWAPL\t"},
   704  	},
   705  	{
   706  		fn: `
   707  		func f47(a uint16) uint16 {
   708  			return bits.ReverseBytes16(a)
   709  		}
   710  		`,
   711  		pos: []string{"\tROLW\t\\$8,"},
   712  	},
   713  	{
   714  		fn: `
   715  		func f48(a uint64) int {
   716  			return bits.Len64(a)
   717  		}
   718  		`,
   719  		pos: []string{"\tBSRQ\t"},
   720  	},
   721  	{
   722  		fn: `
   723  		func f49(a uint32) int {
   724  			return bits.Len32(a)
   725  		}
   726  		`,
   727  		pos: []string{"\tBSRQ\t"},
   728  	},
   729  	{
   730  		fn: `
   731  		func f50(a uint16) int {
   732  			return bits.Len16(a)
   733  		}
   734  		`,
   735  		pos: []string{"\tBSRQ\t"},
   736  	},
   737  	/* see ssa.go
   738  	{
   739  		fn:`
   740  		func f51(a uint8) int {
   741  			return bits.Len8(a)
   742  		}
   743  		`,
   744  		pos:[]string{"\tBSRQ\t"},
   745  	},
   746  	*/
   747  	{
   748  		fn: `
   749  		func f52(a uint) int {
   750  			return bits.Len(a)
   751  		}
   752  		`,
   753  		pos: []string{"\tBSRQ\t"},
   754  	},
   755  	{
   756  		fn: `
   757  		func f53(a uint64) int {
   758  			return bits.LeadingZeros64(a)
   759  		}
   760  		`,
   761  		pos: []string{"\tBSRQ\t"},
   762  	},
   763  	{
   764  		fn: `
   765  		func f54(a uint32) int {
   766  			return bits.LeadingZeros32(a)
   767  		}
   768  		`,
   769  		pos: []string{"\tBSRQ\t"},
   770  	},
   771  	{
   772  		fn: `
   773  		func f55(a uint16) int {
   774  			return bits.LeadingZeros16(a)
   775  		}
   776  		`,
   777  		pos: []string{"\tBSRQ\t"},
   778  	},
   779  	/* see ssa.go
   780  	{
   781  		fn:`
   782  		func f56(a uint8) int {
   783  			return bits.LeadingZeros8(a)
   784  		}
   785  		`,
   786  		pos:[]string{"\tBSRQ\t"},
   787  	},
   788  	*/
   789  	{
   790  		fn: `
   791  		func f57(a uint) int {
   792  			return bits.LeadingZeros(a)
   793  		}
   794  		`,
   795  		pos: []string{"\tBSRQ\t"},
   796  	},
   797  	{
   798  		fn: `
   799  		func pop1(x uint64) int {
   800  			return bits.OnesCount64(x)
   801  		}`,
   802  		pos: []string{"\tPOPCNTQ\t", "support_popcnt"},
   803  	},
   804  	{
   805  		fn: `
   806  		func pop2(x uint32) int {
   807  			return bits.OnesCount32(x)
   808  		}`,
   809  		pos: []string{"\tPOPCNTL\t", "support_popcnt"},
   810  	},
   811  	{
   812  		fn: `
   813  		func pop3(x uint16) int {
   814  			return bits.OnesCount16(x)
   815  		}`,
   816  		pos: []string{"\tPOPCNTL\t", "support_popcnt"},
   817  	},
   818  	{
   819  		fn: `
   820  		func pop4(x uint) int {
   821  			return bits.OnesCount(x)
   822  		}`,
   823  		pos: []string{"\tPOPCNTQ\t", "support_popcnt"},
   824  	},
   825  	// multiplication merging tests
   826  	{
   827  		fn: `
   828  		func mul1(n int) int {
   829  			return 15*n + 31*n
   830  		}`,
   831  		pos: []string{"\tIMULQ\t[$]46"}, // 46*n
   832  	},
   833  	{
   834  		fn: `
   835  		func mul2(n int) int {
   836  			return 5*n + 7*(n+1) + 11*(n+2)
   837  		}`,
   838  		pos: []string{"\tIMULQ\t[$]23", "\tADDQ\t[$]29"}, // 23*n + 29
   839  	},
   840  	{
   841  		fn: `
   842  		func mul3(a, n int) int {
   843  			return a*n + 19*n
   844  		}`,
   845  		pos: []string{"\tADDQ\t[$]19", "\tIMULQ"}, // (a+19)*n
   846  	},
   847  	{
   848  		fn: `
   849  		func mul4(n int) int {
   850  			return 23*n - 9*n
   851  		}`,
   852  		pos: []string{"\tIMULQ\t[$]14"}, // 14*n
   853  	},
   854  	{
   855  		fn: `
   856  		func mul5(a, n int) int {
   857  			return a*n - 19*n
   858  		}`,
   859  		pos: []string{"\tADDQ\t[$]-19", "\tIMULQ"}, // (a-19)*n
   860  	},
   861  
   862  	// see issue 19595.
   863  	// We want to merge load+op in f58, but not in f59.
   864  	{
   865  		fn: `
   866  		func f58(p, q *int) {
   867  			x := *p
   868  			*q += x
   869  		}`,
   870  		pos: []string{"\tADDQ\t\\("},
   871  	},
   872  	{
   873  		fn: `
   874  		func f59(p, q *int) {
   875  			x := *p
   876  			for i := 0; i < 10; i++ {
   877  				*q += x
   878  			}
   879  		}`,
   880  		pos: []string{"\tADDQ\t[A-Z]"},
   881  	},
   882  	// Floating-point strength reduction
   883  	{
   884  		fn: `
   885  		func f60(f float64) float64 {
   886  			return f * 2.0
   887  		}`,
   888  		pos: []string{"\tADDSD\t"},
   889  	},
   890  	{
   891  		fn: `
   892  		func f62(f float64) float64 {
   893  			return f / 16.0
   894  		}`,
   895  		pos: []string{"\tMULSD\t"},
   896  	},
   897  	{
   898  		fn: `
   899  		func f63(f float64) float64 {
   900  			return f / 0.125
   901  		}`,
   902  		pos: []string{"\tMULSD\t"},
   903  	},
   904  	{
   905  		fn: `
   906  		func f64(f float64) float64 {
   907  			return f / 0.5
   908  		}`,
   909  		pos: []string{"\tADDSD\t"},
   910  	},
   911  	// Check that compare to constant string uses 2/4/8 byte compares
   912  	{
   913  		fn: `
   914  		func f65(a string) bool {
   915  		    return a == "xx"
   916  		}`,
   917  		pos: []string{"\tCMPW\t[A-Z]"},
   918  	},
   919  	{
   920  		fn: `
   921  		func f66(a string) bool {
   922  		    return a == "xxxx"
   923  		}`,
   924  		pos: []string{"\tCMPL\t[A-Z]"},
   925  	},
   926  	{
   927  		fn: `
   928  		func f67(a string) bool {
   929  		    return a == "xxxxxxxx"
   930  		}`,
   931  		pos: []string{"\tCMPQ\t[A-Z]"},
   932  	},
   933  	// Non-constant rotate
   934  	{
   935  		fn: `func rot64l(x uint64, y int) uint64 {
   936  			z := uint(y & 63)
   937  			return x << z | x >> (64-z)
   938  		}`,
   939  		pos: []string{"\tROLQ\t"},
   940  	},
   941  	{
   942  		fn: `func rot64r(x uint64, y int) uint64 {
   943  			z := uint(y & 63)
   944  			return x >> z | x << (64-z)
   945  		}`,
   946  		pos: []string{"\tRORQ\t"},
   947  	},
   948  	{
   949  		fn: `func rot32l(x uint32, y int) uint32 {
   950  			z := uint(y & 31)
   951  			return x << z | x >> (32-z)
   952  		}`,
   953  		pos: []string{"\tROLL\t"},
   954  	},
   955  	{
   956  		fn: `func rot32r(x uint32, y int) uint32 {
   957  			z := uint(y & 31)
   958  			return x >> z | x << (32-z)
   959  		}`,
   960  		pos: []string{"\tRORL\t"},
   961  	},
   962  	{
   963  		fn: `func rot16l(x uint16, y int) uint16 {
   964  			z := uint(y & 15)
   965  			return x << z | x >> (16-z)
   966  		}`,
   967  		pos: []string{"\tROLW\t"},
   968  	},
   969  	{
   970  		fn: `func rot16r(x uint16, y int) uint16 {
   971  			z := uint(y & 15)
   972  			return x >> z | x << (16-z)
   973  		}`,
   974  		pos: []string{"\tRORW\t"},
   975  	},
   976  	{
   977  		fn: `func rot8l(x uint8, y int) uint8 {
   978  			z := uint(y & 7)
   979  			return x << z | x >> (8-z)
   980  		}`,
   981  		pos: []string{"\tROLB\t"},
   982  	},
   983  	{
   984  		fn: `func rot8r(x uint8, y int) uint8 {
   985  			z := uint(y & 7)
   986  			return x >> z | x << (8-z)
   987  		}`,
   988  		pos: []string{"\tRORB\t"},
   989  	},
   990  	// Check that array compare uses 2/4/8 byte compares
   991  	{
   992  		fn: `
   993  		func f68(a,b [2]byte) bool {
   994  		    return a == b
   995  		}`,
   996  		pos: []string{"\tCMPW\t[A-Z]"},
   997  	},
   998  	{
   999  		fn: `
  1000  		func f69(a,b [3]uint16) bool {
  1001  		    return a == b
  1002  		}`,
  1003  		pos: []string{"\tCMPL\t[A-Z]"},
  1004  	},
  1005  	{
  1006  		fn: `
  1007  		func f70(a,b [15]byte) bool {
  1008  		    return a == b
  1009  		}`,
  1010  		pos: []string{"\tCMPQ\t[A-Z]"},
  1011  	},
  1012  	{
  1013  		fn: `
  1014  		func f71(a,b unsafe.Pointer) bool { // This was a TODO in mapaccess1_faststr
  1015  		    return *((*[4]byte)(a)) != *((*[4]byte)(b))
  1016  		}`,
  1017  		pos: []string{"\tCMPL\t[A-Z]"},
  1018  	},
  1019  	{
  1020  		// make sure assembly output has matching offset and base register.
  1021  		fn: `
  1022  		func f72(a, b int) int {
  1023  			runtime.GC() // use some frame
  1024  			return b
  1025  		}
  1026  		`,
  1027  		pos: []string{"b\\+24\\(SP\\)"},
  1028  	},
  1029  	{
  1030  		// check load combining
  1031  		fn: `
  1032  		func f73(a, b byte) (byte,byte) {
  1033  		    return f73(f73(a,b))
  1034  		}
  1035  		`,
  1036  		pos: []string{"\tMOVW\t"},
  1037  	},
  1038  	{
  1039  		fn: `
  1040  		func f74(a, b uint16) (uint16,uint16) {
  1041  		    return f74(f74(a,b))
  1042  		}
  1043  		`,
  1044  		pos: []string{"\tMOVL\t"},
  1045  	},
  1046  	{
  1047  		fn: `
  1048  		func f75(a, b uint32) (uint32,uint32) {
  1049  		    return f75(f75(a,b))
  1050  		}
  1051  		`,
  1052  		pos: []string{"\tMOVQ\t"},
  1053  	},
  1054  	{
  1055  		fn: `
  1056  		func f76(a, b uint64) (uint64,uint64) {
  1057  		    return f76(f76(a,b))
  1058  		}
  1059  		`,
  1060  		pos: []string{"\tMOVUPS\t"},
  1061  	},
  1062  	// Make sure we don't put pointers in SSE registers across safe points.
  1063  	{
  1064  		fn: `
  1065  		func $(p, q *[2]*int)  {
  1066  		    a, b := p[0], p[1]
  1067  		    runtime.GC()
  1068  		    q[0], q[1] = a, b
  1069  		}
  1070  		`,
  1071  		neg: []string{"MOVUPS"},
  1072  	},
  1073  	{
  1074  		// check that stack store is optimized away
  1075  		fn: `
  1076  		func $() int {
  1077  			var x int
  1078  			return *(&x)
  1079  		}
  1080  		`,
  1081  		pos: []string{"TEXT\t.*, [$]0-8"},
  1082  	},
  1083  	// math.Abs using integer registers
  1084  	{
  1085  		fn: `
  1086  		func $(x float64) float64 {
  1087  			return math.Abs(x)
  1088  		}
  1089  		`,
  1090  		pos: []string{"\tSHLQ\t[$]1,", "\tSHRQ\t[$]1,"},
  1091  	},
  1092  	// math.Copysign using integer registers
  1093  	{
  1094  		fn: `
  1095  		func $(x, y float64) float64 {
  1096  			return math.Copysign(x, y)
  1097  		}
  1098  		`,
  1099  		pos: []string{"\tSHLQ\t[$]1,", "\tSHRQ\t[$]1,", "\tSHRQ\t[$]63,", "\tSHLQ\t[$]63,", "\tORQ\t"},
  1100  	},
  1101  	// int <-> fp moves
  1102  	{
  1103  		fn: `
  1104  		func $(x float64) uint64 {
  1105  			return math.Float64bits(x+1) + 1
  1106  		}
  1107  		`,
  1108  		pos: []string{"\tMOVQ\tX.*, [^X].*"},
  1109  	},
  1110  	{
  1111  		fn: `
  1112  		func $(x float32) uint32 {
  1113  			return math.Float32bits(x+1) + 1
  1114  		}
  1115  		`,
  1116  		pos: []string{"\tMOVL\tX.*, [^X].*"},
  1117  	},
  1118  	{
  1119  		fn: `
  1120  		func $(x uint64) float64 {
  1121  			return math.Float64frombits(x+1) + 1
  1122  		}
  1123  		`,
  1124  		pos: []string{"\tMOVQ\t[^X].*, X.*"},
  1125  	},
  1126  	{
  1127  		fn: `
  1128  		func $(x uint32) float32 {
  1129  			return math.Float32frombits(x+1) + 1
  1130  		}
  1131  		`,
  1132  		pos: []string{"\tMOVL\t[^X].*, X.*"},
  1133  	},
  1134  	{
  1135  		fn: `
  1136  		func $(x uint32) bool {
  1137  			return x > 4
  1138  		}
  1139  		`,
  1140  		pos: []string{"\tSETHI\t\\("},
  1141  	},
  1142  	// Check that len() and cap() div by a constant power of two
  1143  	// are compiled into SHRQ.
  1144  	{
  1145  		fn: `
  1146  		func $(a []int) int {
  1147  			return len(a) / 1024
  1148  		}
  1149  		`,
  1150  		pos: []string{"\tSHRQ\t\\$10,"},
  1151  	},
  1152  	{
  1153  		fn: `
  1154  		func $(s string) int {
  1155  			return len(s) / (4097 >> 1)
  1156  		}
  1157  		`,
  1158  		pos: []string{"\tSHRQ\t\\$11,"},
  1159  	},
  1160  	{
  1161  		fn: `
  1162  		func $(a []int) int {
  1163  			return cap(a) / ((1 << 11) + 2048)
  1164  		}
  1165  		`,
  1166  		pos: []string{"\tSHRQ\t\\$12,"},
  1167  	},
  1168  	// Check that len() and cap() mod by a constant power of two
  1169  	// are compiled into ANDQ.
  1170  	{
  1171  		fn: `
  1172  		func $(a []int) int {
  1173  			return len(a) % 1024
  1174  		}
  1175  		`,
  1176  		pos: []string{"\tANDQ\t\\$1023,"},
  1177  	},
  1178  	{
  1179  		fn: `
  1180  		func $(s string) int {
  1181  			return len(s) % (4097 >> 1)
  1182  		}
  1183  		`,
  1184  		pos: []string{"\tANDQ\t\\$2047,"},
  1185  	},
  1186  	{
  1187  		fn: `
  1188  		func $(a []int) int {
  1189  			return cap(a) % ((1 << 11) + 2048)
  1190  		}
  1191  		`,
  1192  		pos: []string{"\tANDQ\t\\$4095,"},
  1193  	},
  1194  	{
  1195  		// Test that small memmove was replaced with direct movs
  1196  		fn: `
  1197                  func $() {
  1198                         x := [...]byte{1, 2, 3, 4, 5, 6, 7}
  1199                         copy(x[1:], x[:])
  1200                  }
  1201  		`,
  1202  		neg: []string{"memmove"},
  1203  	},
  1204  	{
  1205  		// Same as above but with different size
  1206  		fn: `
  1207                  func $() {
  1208                         x := [...]byte{1, 2, 3, 4}
  1209                         copy(x[1:], x[:])
  1210                  }
  1211  		`,
  1212  		neg: []string{"memmove"},
  1213  	},
  1214  	{
  1215  		// Same as above but with different size
  1216  		fn: `
  1217                  func $() {
  1218                         x := [...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
  1219                         copy(x[1:], x[:])
  1220                  }
  1221  		`,
  1222  		neg: []string{"memmove"},
  1223  	},
  1224  }
  1225  
  1226  var linux386Tests = []*asmTest{
  1227  	{
  1228  		fn: `
  1229  		func f0(b []byte) uint32 {
  1230  			return binary.LittleEndian.Uint32(b)
  1231  		}
  1232  		`,
  1233  		pos: []string{"\tMOVL\t\\(.*\\),"},
  1234  	},
  1235  	{
  1236  		fn: `
  1237  		func f1(b []byte, i int) uint32 {
  1238  			return binary.LittleEndian.Uint32(b[i:])
  1239  		}
  1240  		`,
  1241  		pos: []string{"\tMOVL\t\\(.*\\)\\(.*\\*1\\),"},
  1242  	},
  1243  
  1244  	// multiplication by powers of two
  1245  	{
  1246  		fn: `
  1247  		func $(n int) int {
  1248  			return 32*n
  1249  		}
  1250  		`,
  1251  		pos: []string{"SHLL"},
  1252  		neg: []string{"IMULL"},
  1253  	},
  1254  	{
  1255  		fn: `
  1256  		func $(n int) int {
  1257  			return -64*n
  1258  		}
  1259  		`,
  1260  		pos: []string{"SHLL"},
  1261  		neg: []string{"IMULL"},
  1262  	},
  1263  
  1264  	// multiplication merging tests
  1265  	{
  1266  		fn: `
  1267  		func $(n int) int {
  1268  			return 9*n + 14*n
  1269  		}`,
  1270  		pos: []string{"\tIMULL\t[$]23"}, // 23*n
  1271  	},
  1272  	{
  1273  		fn: `
  1274  		func $(a, n int) int {
  1275  			return 19*a + a*n
  1276  		}`,
  1277  		pos: []string{"\tADDL\t[$]19", "\tIMULL"}, // (n+19)*a
  1278  	},
  1279  	{
  1280  		// check that stack store is optimized away
  1281  		fn: `
  1282  		func $() int {
  1283  			var x int
  1284  			return *(&x)
  1285  		}
  1286  		`,
  1287  		pos: []string{"TEXT\t.*, [$]0-4"},
  1288  	},
  1289  	{
  1290  		fn: `
  1291  		func mul3(n int) int {
  1292  			return 23*n - 9*n
  1293  		}`,
  1294  		pos: []string{"\tIMULL\t[$]14"}, // 14*n
  1295  	},
  1296  	{
  1297  		fn: `
  1298  		func mul4(a, n int) int {
  1299  			return n*a - a*19
  1300  		}`,
  1301  		pos: []string{"\tADDL\t[$]-19", "\tIMULL"}, // (n-19)*a
  1302  	},
  1303  	// Check that len() and cap() div by a constant power of two
  1304  	// are compiled into SHRL.
  1305  	{
  1306  		fn: `
  1307  		func $(a []int) int {
  1308  			return len(a) / 1024
  1309  		}
  1310  		`,
  1311  		pos: []string{"\tSHRL\t\\$10,"},
  1312  	},
  1313  	{
  1314  		fn: `
  1315  		func $(s string) int {
  1316  			return len(s) / (4097 >> 1)
  1317  		}
  1318  		`,
  1319  		pos: []string{"\tSHRL\t\\$11,"},
  1320  	},
  1321  	{
  1322  		fn: `
  1323  		func $(a []int) int {
  1324  			return cap(a) / ((1 << 11) + 2048)
  1325  		}
  1326  		`,
  1327  		pos: []string{"\tSHRL\t\\$12,"},
  1328  	},
  1329  	// Check that len() and cap() mod by a constant power of two
  1330  	// are compiled into ANDL.
  1331  	{
  1332  		fn: `
  1333  		func $(a []int) int {
  1334  			return len(a) % 1024
  1335  		}
  1336  		`,
  1337  		pos: []string{"\tANDL\t\\$1023,"},
  1338  	},
  1339  	{
  1340  		fn: `
  1341  		func $(s string) int {
  1342  			return len(s) % (4097 >> 1)
  1343  		}
  1344  		`,
  1345  		pos: []string{"\tANDL\t\\$2047,"},
  1346  	},
  1347  	{
  1348  		fn: `
  1349  		func $(a []int) int {
  1350  			return cap(a) % ((1 << 11) + 2048)
  1351  		}
  1352  		`,
  1353  		pos: []string{"\tANDL\t\\$4095,"},
  1354  	},
  1355  	{
  1356  		// Test that small memmove was replaced with direct movs
  1357  		fn: `
  1358                  func $() {
  1359                         x := [...]byte{1, 2, 3, 4, 5, 6, 7}
  1360                         copy(x[1:], x[:])
  1361                  }
  1362  		`,
  1363  		neg: []string{"memmove"},
  1364  	},
  1365  	{
  1366  		// Same as above but with different size
  1367  		fn: `
  1368                  func $() {
  1369                         x := [...]byte{1, 2, 3, 4}
  1370                         copy(x[1:], x[:])
  1371                  }
  1372  		`,
  1373  		neg: []string{"memmove"},
  1374  	},
  1375  }
  1376  
  1377  var linuxS390XTests = []*asmTest{
  1378  	{
  1379  		fn: `
  1380  		func f0(b []byte) uint32 {
  1381  			return binary.LittleEndian.Uint32(b)
  1382  		}
  1383  		`,
  1384  		pos: []string{"\tMOVWBR\t\\(.*\\),"},
  1385  	},
  1386  	{
  1387  		fn: `
  1388  		func f1(b []byte, i int) uint32 {
  1389  			return binary.LittleEndian.Uint32(b[i:])
  1390  		}
  1391  		`,
  1392  		pos: []string{"\tMOVWBR\t\\(.*\\)\\(.*\\*1\\),"},
  1393  	},
  1394  	{
  1395  		fn: `
  1396  		func f2(b []byte) uint64 {
  1397  			return binary.LittleEndian.Uint64(b)
  1398  		}
  1399  		`,
  1400  		pos: []string{"\tMOVDBR\t\\(.*\\),"},
  1401  	},
  1402  	{
  1403  		fn: `
  1404  		func f3(b []byte, i int) uint64 {
  1405  			return binary.LittleEndian.Uint64(b[i:])
  1406  		}
  1407  		`,
  1408  		pos: []string{"\tMOVDBR\t\\(.*\\)\\(.*\\*1\\),"},
  1409  	},
  1410  	{
  1411  		fn: `
  1412  		func f4(b []byte) uint32 {
  1413  			return binary.BigEndian.Uint32(b)
  1414  		}
  1415  		`,
  1416  		pos: []string{"\tMOVWZ\t\\(.*\\),"},
  1417  	},
  1418  	{
  1419  		fn: `
  1420  		func f5(b []byte, i int) uint32 {
  1421  			return binary.BigEndian.Uint32(b[i:])
  1422  		}
  1423  		`,
  1424  		pos: []string{"\tMOVWZ\t\\(.*\\)\\(.*\\*1\\),"},
  1425  	},
  1426  	{
  1427  		fn: `
  1428  		func f6(b []byte) uint64 {
  1429  			return binary.BigEndian.Uint64(b)
  1430  		}
  1431  		`,
  1432  		pos: []string{"\tMOVD\t\\(.*\\),"},
  1433  	},
  1434  	{
  1435  		fn: `
  1436  		func f7(b []byte, i int) uint64 {
  1437  			return binary.BigEndian.Uint64(b[i:])
  1438  		}
  1439  		`,
  1440  		pos: []string{"\tMOVD\t\\(.*\\)\\(.*\\*1\\),"},
  1441  	},
  1442  	{
  1443  		fn: `
  1444  		func f8(x uint64) uint64 {
  1445  			return x<<7 + x>>57
  1446  		}
  1447  		`,
  1448  		pos: []string{"\tRLLG\t[$]7,"},
  1449  	},
  1450  	{
  1451  		fn: `
  1452  		func f9(x uint64) uint64 {
  1453  			return x<<7 | x>>57
  1454  		}
  1455  		`,
  1456  		pos: []string{"\tRLLG\t[$]7,"},
  1457  	},
  1458  	{
  1459  		fn: `
  1460  		func f10(x uint64) uint64 {
  1461  			return x<<7 ^ x>>57
  1462  		}
  1463  		`,
  1464  		pos: []string{"\tRLLG\t[$]7,"},
  1465  	},
  1466  	{
  1467  		fn: `
  1468  		func f11(x uint32) uint32 {
  1469  			return x<<7 + x>>25
  1470  		}
  1471  		`,
  1472  		pos: []string{"\tRLL\t[$]7,"},
  1473  	},
  1474  	{
  1475  		fn: `
  1476  		func f12(x uint32) uint32 {
  1477  			return x<<7 | x>>25
  1478  		}
  1479  		`,
  1480  		pos: []string{"\tRLL\t[$]7,"},
  1481  	},
  1482  	{
  1483  		fn: `
  1484  		func f13(x uint32) uint32 {
  1485  			return x<<7 ^ x>>25
  1486  		}
  1487  		`,
  1488  		pos: []string{"\tRLL\t[$]7,"},
  1489  	},
  1490  	// Fused multiply-add/sub instructions.
  1491  	{
  1492  		fn: `
  1493  		func f14(x, y, z float64) float64 {
  1494  			return x * y + z
  1495  		}
  1496  		`,
  1497  		pos: []string{"\tFMADD\t"},
  1498  	},
  1499  	{
  1500  		fn: `
  1501  		func f15(x, y, z float64) float64 {
  1502  			return x * y - z
  1503  		}
  1504  		`,
  1505  		pos: []string{"\tFMSUB\t"},
  1506  	},
  1507  	{
  1508  		fn: `
  1509  		func f16(x, y, z float32) float32 {
  1510  			return x * y + z
  1511  		}
  1512  		`,
  1513  		pos: []string{"\tFMADDS\t"},
  1514  	},
  1515  	{
  1516  		fn: `
  1517  		func f17(x, y, z float32) float32 {
  1518  			return x * y - z
  1519  		}
  1520  		`,
  1521  		pos: []string{"\tFMSUBS\t"},
  1522  	},
  1523  	// Intrinsic tests for math/bits
  1524  	{
  1525  		fn: `
  1526  		func f18(a uint64) int {
  1527  			return bits.TrailingZeros64(a)
  1528  		}
  1529  		`,
  1530  		pos: []string{"\tFLOGR\t"},
  1531  	},
  1532  	{
  1533  		fn: `
  1534  		func f19(a uint32) int {
  1535  			return bits.TrailingZeros32(a)
  1536  		}
  1537  		`,
  1538  		pos: []string{"\tFLOGR\t", "\tMOVWZ\t"},
  1539  	},
  1540  	{
  1541  		fn: `
  1542  		func f20(a uint16) int {
  1543  			return bits.TrailingZeros16(a)
  1544  		}
  1545  		`,
  1546  		pos: []string{"\tFLOGR\t", "\tOR\t\\$65536,"},
  1547  	},
  1548  	{
  1549  		fn: `
  1550  		func f21(a uint8) int {
  1551  			return bits.TrailingZeros8(a)
  1552  		}
  1553  		`,
  1554  		pos: []string{"\tFLOGR\t", "\tOR\t\\$256,"},
  1555  	},
  1556  	// Intrinsic tests for math/bits
  1557  	{
  1558  		fn: `
  1559  		func f22(a uint64) uint64 {
  1560  			return bits.ReverseBytes64(a)
  1561  		}
  1562  		`,
  1563  		pos: []string{"\tMOVDBR\t"},
  1564  	},
  1565  	{
  1566  		fn: `
  1567  		func f23(a uint32) uint32 {
  1568  			return bits.ReverseBytes32(a)
  1569  		}
  1570  		`,
  1571  		pos: []string{"\tMOVWBR\t"},
  1572  	},
  1573  	{
  1574  		fn: `
  1575  		func f24(a uint64) int {
  1576  			return bits.Len64(a)
  1577  		}
  1578  		`,
  1579  		pos: []string{"\tFLOGR\t"},
  1580  	},
  1581  	{
  1582  		fn: `
  1583  		func f25(a uint32) int {
  1584  			return bits.Len32(a)
  1585  		}
  1586  		`,
  1587  		pos: []string{"\tFLOGR\t"},
  1588  	},
  1589  	{
  1590  		fn: `
  1591  		func f26(a uint16) int {
  1592  			return bits.Len16(a)
  1593  		}
  1594  		`,
  1595  		pos: []string{"\tFLOGR\t"},
  1596  	},
  1597  	{
  1598  		fn: `
  1599  		func f27(a uint8) int {
  1600  			return bits.Len8(a)
  1601  		}
  1602  		`,
  1603  		pos: []string{"\tFLOGR\t"},
  1604  	},
  1605  	{
  1606  		fn: `
  1607  		func f28(a uint) int {
  1608  			return bits.Len(a)
  1609  		}
  1610  		`,
  1611  		pos: []string{"\tFLOGR\t"},
  1612  	},
  1613  	{
  1614  		fn: `
  1615  		func f29(a uint64) int {
  1616  			return bits.LeadingZeros64(a)
  1617  		}
  1618  		`,
  1619  		pos: []string{"\tFLOGR\t"},
  1620  	},
  1621  	{
  1622  		fn: `
  1623  		func f30(a uint32) int {
  1624  			return bits.LeadingZeros32(a)
  1625  		}
  1626  		`,
  1627  		pos: []string{"\tFLOGR\t"},
  1628  	},
  1629  	{
  1630  		fn: `
  1631  		func f31(a uint16) int {
  1632  			return bits.LeadingZeros16(a)
  1633  		}
  1634  		`,
  1635  		pos: []string{"\tFLOGR\t"},
  1636  	},
  1637  	{
  1638  		fn: `
  1639  		func f32(a uint8) int {
  1640  			return bits.LeadingZeros8(a)
  1641  		}
  1642  		`,
  1643  		pos: []string{"\tFLOGR\t"},
  1644  	},
  1645  	{
  1646  		fn: `
  1647  		func f33(a uint) int {
  1648  			return bits.LeadingZeros(a)
  1649  		}
  1650  		`,
  1651  		pos: []string{"\tFLOGR\t"},
  1652  	},
  1653  	// Intrinsic tests for math.
  1654  	{
  1655  		fn: `
  1656  		func ceil(x float64) float64 {
  1657  			return math.Ceil(x)
  1658  		}
  1659  		`,
  1660  		pos: []string{"\tFIDBR\t[$]6"},
  1661  	},
  1662  	{
  1663  		fn: `
  1664  		func floor(x float64) float64 {
  1665  			return math.Floor(x)
  1666  		}
  1667  		`,
  1668  		pos: []string{"\tFIDBR\t[$]7"},
  1669  	},
  1670  	{
  1671  		fn: `
  1672  		func round(x float64) float64 {
  1673  			return math.Round(x)
  1674  		}
  1675  		`,
  1676  		pos: []string{"\tFIDBR\t[$]1"},
  1677  	},
  1678  	{
  1679  		fn: `
  1680  		func trunc(x float64) float64 {
  1681  			return math.Trunc(x)
  1682  		}
  1683  		`,
  1684  		pos: []string{"\tFIDBR\t[$]5"},
  1685  	},
  1686  	{
  1687  		fn: `
  1688  		func roundToEven(x float64) float64 {
  1689  			return math.RoundToEven(x)
  1690  		}
  1691  		`,
  1692  		pos: []string{"\tFIDBR\t[$]4"},
  1693  	},
  1694  	{
  1695  		// check that stack store is optimized away
  1696  		fn: `
  1697  		func $() int {
  1698  			var x int
  1699  			return *(&x)
  1700  		}
  1701  		`,
  1702  		pos: []string{"TEXT\t.*, [$]0-8"},
  1703  	},
  1704  	// Constant propagation through raw bits conversions.
  1705  	{
  1706  		// uint32 constant converted to float32 constant
  1707  		fn: `
  1708  		func $(x float32) float32 {
  1709  			if x > math.Float32frombits(0x3f800000) {
  1710  				return -x
  1711  			}
  1712  			return x
  1713  		}
  1714  		`,
  1715  		pos: []string{"\tFMOVS\t[$]f32.3f800000\\(SB\\)"},
  1716  	},
  1717  	{
  1718  		// float32 constant converted to uint32 constant
  1719  		fn: `
  1720  		func $(x uint32) uint32 {
  1721  			if x > math.Float32bits(1) {
  1722  				return -x
  1723  			}
  1724  			return x
  1725  		}
  1726  		`,
  1727  		neg: []string{"\tFMOVS\t"},
  1728  	},
  1729  	// Constant propagation through float comparisons.
  1730  	{
  1731  		fn: `
  1732  		func $() bool {
  1733  			return 0.5 == float64(uint32(1)) ||
  1734  				1.5 > float64(uint64(1<<63)) ||
  1735  				math.NaN() == math.NaN()
  1736  		}
  1737  		`,
  1738  		pos: []string{"\tMOV(B|BZ|D)\t[$]0,"},
  1739  		neg: []string{"\tFCMPU\t", "\tMOV(B|BZ|D)\t[$]1,"},
  1740  	},
  1741  	{
  1742  		fn: `
  1743  		func $() bool {
  1744  			return float32(0.5) <= float32(int64(1)) &&
  1745  				float32(1.5) >= float32(int32(-1<<31)) &&
  1746  				float32(math.NaN()) != float32(math.NaN())
  1747  		}
  1748  		`,
  1749  		pos: []string{"\tMOV(B|BZ|D)\t[$]1,"},
  1750  		neg: []string{"\tCEBR\t", "\tMOV(B|BZ|D)\t[$]0,"},
  1751  	},
  1752  	// math tests
  1753  	{
  1754  		fn: `
  1755  		func $(x float64) float64 {
  1756  			return math.Abs(x)
  1757  		}
  1758  		`,
  1759  		pos: []string{"\tLPDFR\t"},
  1760  		neg: []string{"\tMOVD\t"}, // no integer loads/stores
  1761  	},
  1762  	{
  1763  		fn: `
  1764  		func $(x float32) float32 {
  1765  			return float32(math.Abs(float64(x)))
  1766  		}
  1767  		`,
  1768  		pos: []string{"\tLPDFR\t"},
  1769  		neg: []string{"\tLDEBR\t", "\tLEDBR\t"}, // no float64 conversion
  1770  	},
  1771  	{
  1772  		fn: `
  1773  		func $(x float64) float64 {
  1774  			return math.Float64frombits(math.Float64bits(x)|1<<63)
  1775  		}
  1776  		`,
  1777  		pos: []string{"\tLNDFR\t"},
  1778  		neg: []string{"\tMOVD\t"}, // no integer loads/stores
  1779  	},
  1780  	{
  1781  		fn: `
  1782  		func $(x float64) float64 {
  1783  			return -math.Abs(x)
  1784  		}
  1785  		`,
  1786  		pos: []string{"\tLNDFR\t"},
  1787  		neg: []string{"\tMOVD\t"}, // no integer loads/stores
  1788  	},
  1789  	{
  1790  		fn: `
  1791  		func $(x, y float64) float64 {
  1792  			return math.Copysign(x, y)
  1793  		}
  1794  		`,
  1795  		pos: []string{"\tCPSDR\t"},
  1796  		neg: []string{"\tMOVD\t"}, // no integer loads/stores
  1797  	},
  1798  	{
  1799  		fn: `
  1800  		func $(x float64) float64 {
  1801  			return math.Copysign(x, -1)
  1802  		}
  1803  		`,
  1804  		pos: []string{"\tLNDFR\t"},
  1805  		neg: []string{"\tMOVD\t"}, // no integer loads/stores
  1806  	},
  1807  	{
  1808  		fn: `
  1809  		func $(x float64) float64 {
  1810  			return math.Copysign(-1, x)
  1811  		}
  1812  		`,
  1813  		pos: []string{"\tCPSDR\t"},
  1814  		neg: []string{"\tMOVD\t"}, // no integer loads/stores
  1815  	},
  1816  }
  1817  
  1818  var linuxARMTests = []*asmTest{
  1819  	// multiplication by powers of two
  1820  	{
  1821  		fn: `
  1822  		func $(n int) int {
  1823  			return 16*n
  1824  		}
  1825  		`,
  1826  		pos: []string{"\tSLL\t[$]4"},
  1827  		neg: []string{"\tMUL\t"},
  1828  	},
  1829  	{
  1830  		fn: `
  1831  		func $(n int) int {
  1832  			return -32*n
  1833  		}
  1834  		`,
  1835  		pos: []string{"\tSLL\t[$]5"},
  1836  		neg: []string{"\tMUL\t"},
  1837  	},
  1838  
  1839  	{
  1840  		fn: `
  1841  		func f0(x uint32) uint32 {
  1842  			return x<<7 + x>>25
  1843  		}
  1844  		`,
  1845  		pos: []string{"\tMOVW\tR[0-9]+@>25,"},
  1846  	},
  1847  	{
  1848  		fn: `
  1849  		func f1(x uint32) uint32 {
  1850  			return x<<7 | x>>25
  1851  		}
  1852  		`,
  1853  		pos: []string{"\tMOVW\tR[0-9]+@>25,"},
  1854  	},
  1855  	{
  1856  		fn: `
  1857  		func f2(x uint32) uint32 {
  1858  			return x<<7 ^ x>>25
  1859  		}
  1860  		`,
  1861  		pos: []string{"\tMOVW\tR[0-9]+@>25,"},
  1862  	},
  1863  	{
  1864  		fn: `
  1865  		func f3(a uint64) int {
  1866  			return bits.Len64(a)
  1867  		}
  1868  		`,
  1869  		pos: []string{"\tCLZ\t"},
  1870  	},
  1871  	{
  1872  		fn: `
  1873  		func f4(a uint32) int {
  1874  			return bits.Len32(a)
  1875  		}
  1876  		`,
  1877  		pos: []string{"\tCLZ\t"},
  1878  	},
  1879  	{
  1880  		fn: `
  1881  		func f5(a uint16) int {
  1882  			return bits.Len16(a)
  1883  		}
  1884  		`,
  1885  		pos: []string{"\tCLZ\t"},
  1886  	},
  1887  	{
  1888  		fn: `
  1889  		func f6(a uint8) int {
  1890  			return bits.Len8(a)
  1891  		}
  1892  		`,
  1893  		pos: []string{"\tCLZ\t"},
  1894  	},
  1895  	{
  1896  		fn: `
  1897  		func f7(a uint) int {
  1898  			return bits.Len(a)
  1899  		}
  1900  		`,
  1901  		pos: []string{"\tCLZ\t"},
  1902  	},
  1903  	{
  1904  		fn: `
  1905  		func f8(a uint64) int {
  1906  			return bits.LeadingZeros64(a)
  1907  		}
  1908  		`,
  1909  		pos: []string{"\tCLZ\t"},
  1910  	},
  1911  	{
  1912  		fn: `
  1913  		func f9(a uint32) int {
  1914  			return bits.LeadingZeros32(a)
  1915  		}
  1916  		`,
  1917  		pos: []string{"\tCLZ\t"},
  1918  	},
  1919  	{
  1920  		fn: `
  1921  		func f10(a uint16) int {
  1922  			return bits.LeadingZeros16(a)
  1923  		}
  1924  		`,
  1925  		pos: []string{"\tCLZ\t"},
  1926  	},
  1927  	{
  1928  		fn: `
  1929  		func f11(a uint8) int {
  1930  			return bits.LeadingZeros8(a)
  1931  		}
  1932  		`,
  1933  		pos: []string{"\tCLZ\t"},
  1934  	},
  1935  	{
  1936  		fn: `
  1937  		func f12(a uint) int {
  1938  			return bits.LeadingZeros(a)
  1939  		}
  1940  		`,
  1941  		pos: []string{"\tCLZ\t"},
  1942  	},
  1943  	{
  1944  		// make sure assembly output has matching offset and base register.
  1945  		fn: `
  1946  		func f13(a, b int) int {
  1947  			runtime.GC() // use some frame
  1948  			return b
  1949  		}
  1950  		`,
  1951  		pos: []string{"b\\+4\\(FP\\)"},
  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.*, [$]-4-4"},
  1962  	},
  1963  }
  1964  
  1965  var linuxARM64Tests = []*asmTest{
  1966  	// multiplication by powers of two
  1967  	{
  1968  		fn: `
  1969  		func $(n int) int {
  1970  			return 64*n
  1971  		}
  1972  		`,
  1973  		pos: []string{"\tLSL\t[$]6"},
  1974  		neg: []string{"\tMUL\t"},
  1975  	},
  1976  	{
  1977  		fn: `
  1978  		func $(n int) int {
  1979  			return -128*n
  1980  		}
  1981  		`,
  1982  		pos: []string{"\tLSL\t[$]7"},
  1983  		neg: []string{"\tMUL\t"},
  1984  	},
  1985  
  1986  	{
  1987  		fn: `
  1988  		func f0(x uint64) uint64 {
  1989  			return x<<7 + x>>57
  1990  		}
  1991  		`,
  1992  		pos: []string{"\tROR\t[$]57,"},
  1993  	},
  1994  	{
  1995  		fn: `
  1996  		func f1(x uint64) uint64 {
  1997  			return x<<7 | x>>57
  1998  		}
  1999  		`,
  2000  		pos: []string{"\tROR\t[$]57,"},
  2001  	},
  2002  	{
  2003  		fn: `
  2004  		func f2(x uint64) uint64 {
  2005  			return x<<7 ^ x>>57
  2006  		}
  2007  		`,
  2008  		pos: []string{"\tROR\t[$]57,"},
  2009  	},
  2010  	{
  2011  		fn: `
  2012  		func f3(x uint32) uint32 {
  2013  			return x<<7 + x>>25
  2014  		}
  2015  		`,
  2016  		pos: []string{"\tRORW\t[$]25,"},
  2017  	},
  2018  	{
  2019  		fn: `
  2020  		func f4(x uint32) uint32 {
  2021  			return x<<7 | x>>25
  2022  		}
  2023  		`,
  2024  		pos: []string{"\tRORW\t[$]25,"},
  2025  	},
  2026  	{
  2027  		fn: `
  2028  		func f5(x uint32) uint32 {
  2029  			return x<<7 ^ x>>25
  2030  		}
  2031  		`,
  2032  		pos: []string{"\tRORW\t[$]25,"},
  2033  	},
  2034  	{
  2035  		fn: `
  2036  		func f22(a uint64) uint64 {
  2037  			return bits.ReverseBytes64(a)
  2038  		}
  2039  		`,
  2040  		pos: []string{"\tREV\t"},
  2041  	},
  2042  	{
  2043  		fn: `
  2044  		func f23(a uint32) uint32 {
  2045  			return bits.ReverseBytes32(a)
  2046  		}
  2047  		`,
  2048  		pos: []string{"\tREVW\t"},
  2049  	},
  2050  	{
  2051  		fn: `
  2052  		func f24(a uint64) int {
  2053  			return bits.Len64(a)
  2054  		}
  2055  		`,
  2056  		pos: []string{"\tCLZ\t"},
  2057  	},
  2058  	{
  2059  		fn: `
  2060  		func f25(a uint32) int {
  2061  			return bits.Len32(a)
  2062  		}
  2063  		`,
  2064  		pos: []string{"\tCLZ\t"},
  2065  	},
  2066  	{
  2067  		fn: `
  2068  		func f26(a uint16) int {
  2069  			return bits.Len16(a)
  2070  		}
  2071  		`,
  2072  		pos: []string{"\tCLZ\t"},
  2073  	},
  2074  	{
  2075  		fn: `
  2076  		func f27(a uint8) int {
  2077  			return bits.Len8(a)
  2078  		}
  2079  		`,
  2080  		pos: []string{"\tCLZ\t"},
  2081  	},
  2082  	{
  2083  		fn: `
  2084  		func f28(a uint) int {
  2085  			return bits.Len(a)
  2086  		}
  2087  		`,
  2088  		pos: []string{"\tCLZ\t"},
  2089  	},
  2090  	{
  2091  		fn: `
  2092  		func f29(a uint64) int {
  2093  			return bits.LeadingZeros64(a)
  2094  		}
  2095  		`,
  2096  		pos: []string{"\tCLZ\t"},
  2097  	},
  2098  	{
  2099  		fn: `
  2100  		func f30(a uint32) int {
  2101  			return bits.LeadingZeros32(a)
  2102  		}
  2103  		`,
  2104  		pos: []string{"\tCLZ\t"},
  2105  	},
  2106  	{
  2107  		fn: `
  2108  		func f31(a uint16) int {
  2109  			return bits.LeadingZeros16(a)
  2110  		}
  2111  		`,
  2112  		pos: []string{"\tCLZ\t"},
  2113  	},
  2114  	{
  2115  		fn: `
  2116  		func f32(a uint8) int {
  2117  			return bits.LeadingZeros8(a)
  2118  		}
  2119  		`,
  2120  		pos: []string{"\tCLZ\t"},
  2121  	},
  2122  	{
  2123  		fn: `
  2124  		func f33(a uint) int {
  2125  			return bits.LeadingZeros(a)
  2126  		}
  2127  		`,
  2128  		pos: []string{"\tCLZ\t"},
  2129  	},
  2130  	{
  2131  		fn: `
  2132  		func f34(a uint64) uint64 {
  2133  			return a & ((1<<63)-1)
  2134  		}
  2135  		`,
  2136  		pos: []string{"\tAND\t"},
  2137  	},
  2138  	{
  2139  		fn: `
  2140  		func f35(a uint64) uint64 {
  2141  			return a & (1<<63)
  2142  		}
  2143  		`,
  2144  		pos: []string{"\tAND\t"},
  2145  	},
  2146  	{
  2147  		// make sure offsets are folded into load and store.
  2148  		fn: `
  2149  		func f36(_, a [20]byte) (b [20]byte) {
  2150  			b = a
  2151  			return
  2152  		}
  2153  		`,
  2154  		pos: []string{"\tMOVD\t\"\"\\.a\\+[0-9]+\\(FP\\), R[0-9]+", "\tMOVD\tR[0-9]+, \"\"\\.b\\+[0-9]+\\(FP\\)"},
  2155  	},
  2156  	{
  2157  		// check that stack store is optimized away
  2158  		fn: `
  2159  		func $() int {
  2160  			var x int
  2161  			return *(&x)
  2162  		}
  2163  		`,
  2164  		pos: []string{"TEXT\t.*, [$]-8-8"},
  2165  	},
  2166  	{
  2167  		// check that we don't emit comparisons for constant shift
  2168  		fn: `
  2169  //go:nosplit
  2170  		func $(x int) int {
  2171  			return x << 17
  2172  		}
  2173  		`,
  2174  		pos: []string{"LSL\t\\$17"},
  2175  		neg: []string{"CMP"},
  2176  	},
  2177  }
  2178  
  2179  var linuxMIPSTests = []*asmTest{
  2180  	{
  2181  		fn: `
  2182  		func f0(a uint64) int {
  2183  			return bits.Len64(a)
  2184  		}
  2185  		`,
  2186  		pos: []string{"\tCLZ\t"},
  2187  	},
  2188  	{
  2189  		fn: `
  2190  		func f1(a uint32) int {
  2191  			return bits.Len32(a)
  2192  		}
  2193  		`,
  2194  		pos: []string{"\tCLZ\t"},
  2195  	},
  2196  	{
  2197  		fn: `
  2198  		func f2(a uint16) int {
  2199  			return bits.Len16(a)
  2200  		}
  2201  		`,
  2202  		pos: []string{"\tCLZ\t"},
  2203  	},
  2204  	{
  2205  		fn: `
  2206  		func f3(a uint8) int {
  2207  			return bits.Len8(a)
  2208  		}
  2209  		`,
  2210  		pos: []string{"\tCLZ\t"},
  2211  	},
  2212  	{
  2213  		fn: `
  2214  		func f4(a uint) int {
  2215  			return bits.Len(a)
  2216  		}
  2217  		`,
  2218  		pos: []string{"\tCLZ\t"},
  2219  	},
  2220  	{
  2221  		fn: `
  2222  		func f5(a uint64) int {
  2223  			return bits.LeadingZeros64(a)
  2224  		}
  2225  		`,
  2226  		pos: []string{"\tCLZ\t"},
  2227  	},
  2228  	{
  2229  		fn: `
  2230  		func f6(a uint32) int {
  2231  			return bits.LeadingZeros32(a)
  2232  		}
  2233  		`,
  2234  		pos: []string{"\tCLZ\t"},
  2235  	},
  2236  	{
  2237  		fn: `
  2238  		func f7(a uint16) int {
  2239  			return bits.LeadingZeros16(a)
  2240  		}
  2241  		`,
  2242  		pos: []string{"\tCLZ\t"},
  2243  	},
  2244  	{
  2245  		fn: `
  2246  		func f8(a uint8) int {
  2247  			return bits.LeadingZeros8(a)
  2248  		}
  2249  		`,
  2250  		pos: []string{"\tCLZ\t"},
  2251  	},
  2252  	{
  2253  		fn: `
  2254  		func f9(a uint) int {
  2255  			return bits.LeadingZeros(a)
  2256  		}
  2257  		`,
  2258  		pos: []string{"\tCLZ\t"},
  2259  	},
  2260  	{
  2261  		// check that stack store is optimized away
  2262  		fn: `
  2263  		func $() int {
  2264  			var x int
  2265  			return *(&x)
  2266  		}
  2267  		`,
  2268  		pos: []string{"TEXT\t.*, [$]-4-4"},
  2269  	},
  2270  }
  2271  
  2272  var linuxMIPS64Tests = []*asmTest{
  2273  	{
  2274  		// check that we don't emit comparisons for constant shift
  2275  		fn: `
  2276  		func $(x int) int {
  2277  			return x << 17
  2278  		}
  2279  		`,
  2280  		pos: []string{"SLLV\t\\$17"},
  2281  		neg: []string{"SGT"},
  2282  	},
  2283  }
  2284  
  2285  var linuxPPC64LETests = []*asmTest{
  2286  	// Fused multiply-add/sub instructions.
  2287  	{
  2288  		fn: `
  2289  		func f0(x, y, z float64) float64 {
  2290  			return x * y + z
  2291  		}
  2292  		`,
  2293  		pos: []string{"\tFMADD\t"},
  2294  	},
  2295  	{
  2296  		fn: `
  2297  		func f1(x, y, z float64) float64 {
  2298  			return x * y - z
  2299  		}
  2300  		`,
  2301  		pos: []string{"\tFMSUB\t"},
  2302  	},
  2303  	{
  2304  		fn: `
  2305  		func f2(x, y, z float32) float32 {
  2306  			return x * y + z
  2307  		}
  2308  		`,
  2309  		pos: []string{"\tFMADDS\t"},
  2310  	},
  2311  	{
  2312  		fn: `
  2313  		func f3(x, y, z float32) float32 {
  2314  			return x * y - z
  2315  		}
  2316  		`,
  2317  		pos: []string{"\tFMSUBS\t"},
  2318  	},
  2319  	{
  2320  		fn: `
  2321  		func f4(x uint32) uint32 {
  2322  			return x<<7 | x>>25
  2323  		}
  2324  		`,
  2325  		pos: []string{"\tROTLW\t"},
  2326  	},
  2327  	{
  2328  		fn: `
  2329  		func f5(x uint32) uint32 {
  2330  			return x<<7 + x>>25
  2331  		}
  2332  		`,
  2333  		pos: []string{"\tROTLW\t"},
  2334  	},
  2335  	{
  2336  		fn: `
  2337  		func f6(x uint32) uint32 {
  2338  			return x<<7 ^ x>>25
  2339  		}
  2340  		`,
  2341  		pos: []string{"\tROTLW\t"},
  2342  	},
  2343  	{
  2344  		fn: `
  2345  		func f7(x uint64) uint64 {
  2346  			return x<<7 | x>>57
  2347  		}
  2348  		`,
  2349  		pos: []string{"\tROTL\t"},
  2350  	},
  2351  	{
  2352  		fn: `
  2353  		func f8(x uint64) uint64 {
  2354  			return x<<7 + x>>57
  2355  		}
  2356  		`,
  2357  		pos: []string{"\tROTL\t"},
  2358  	},
  2359  	{
  2360  		fn: `
  2361  		func f9(x uint64) uint64 {
  2362  			return x<<7 ^ x>>57
  2363  		}
  2364  		`,
  2365  		pos: []string{"\tROTL\t"},
  2366  	},
  2367  	{
  2368  		fn: `
  2369  		func f10(a uint32) uint32 {
  2370  			return bits.RotateLeft32(a, 9)
  2371  		}
  2372  		`,
  2373  		pos: []string{"\tROTLW\t"},
  2374  	},
  2375  	{
  2376  		fn: `
  2377  		func f11(a uint64) uint64 {
  2378  			return bits.RotateLeft64(a, 37)
  2379  		}
  2380  		`,
  2381  		pos: []string{"\tROTL\t"},
  2382  	},
  2383  
  2384  	{
  2385  		fn: `
  2386                  func f12(a, b float64) float64 {
  2387                          return math.Copysign(a, b)
  2388                  }
  2389                  `,
  2390  		pos: []string{"\tFCPSGN\t"},
  2391  	},
  2392  
  2393  	{
  2394  		fn: `
  2395                  func f13(a float64) float64 {
  2396                          return math.Abs(a)
  2397                  }
  2398                  `,
  2399  		pos: []string{"\tFABS\t"},
  2400  	},
  2401  
  2402  	{
  2403  		fn: `
  2404  		func f14(b []byte) uint16 {
  2405  			return binary.LittleEndian.Uint16(b)
  2406  	}
  2407  		`,
  2408  		pos: []string{"\tMOVHZ\t"},
  2409  	},
  2410  	{
  2411  		fn: `
  2412  		func f15(b []byte) uint32 {
  2413  			return binary.LittleEndian.Uint32(b)
  2414  		}
  2415  		`,
  2416  		pos: []string{"\tMOVWZ\t"},
  2417  	},
  2418  
  2419  	{
  2420  		fn: `
  2421  		func f16(b []byte) uint64 {
  2422  			return binary.LittleEndian.Uint64(b)
  2423  		}
  2424  		`,
  2425  		pos: []string{"\tMOVD\t"},
  2426  		neg: []string{"MOVBZ", "MOVHZ", "MOVWZ"},
  2427  	},
  2428  
  2429  	{
  2430  		fn: `
  2431  		func f17(b []byte, v uint16) {
  2432  			binary.LittleEndian.PutUint16(b, v)
  2433  		}
  2434  		`,
  2435  		pos: []string{"\tMOVH\t"},
  2436  	},
  2437  
  2438  	{
  2439  		fn: `
  2440  		func f18(b []byte, v uint32) {
  2441  			binary.LittleEndian.PutUint32(b, v)
  2442  		}
  2443  		`,
  2444  		pos: []string{"\tMOVW\t"},
  2445  	},
  2446  
  2447  	{
  2448  		fn: `
  2449  		func f19(b []byte, v uint64) {
  2450  			binary.LittleEndian.PutUint64(b, v)
  2451  		}
  2452  		`,
  2453  		pos: []string{"\tMOVD\t"},
  2454  		neg: []string{"MOVB", "MOVH", "MOVW"},
  2455  	},
  2456  
  2457  	{
  2458  		// check that stack store is optimized away
  2459  		fn: `
  2460  		func $() int {
  2461  			var x int
  2462  			return *(&x)
  2463  		}
  2464  		`,
  2465  		pos: []string{"TEXT\t.*, [$]0-8"},
  2466  	},
  2467  	// Constant propagation through raw bits conversions.
  2468  	{
  2469  		// uint32 constant converted to float32 constant
  2470  		fn: `
  2471  		func $(x float32) float32 {
  2472  			if x > math.Float32frombits(0x3f800000) {
  2473  				return -x
  2474  			}
  2475  			return x
  2476  		}
  2477  		`,
  2478  		pos: []string{"\tFMOVS\t[$]f32.3f800000\\(SB\\)"},
  2479  	},
  2480  	{
  2481  		// float32 constant converted to uint32 constant
  2482  		fn: `
  2483  		func $(x uint32) uint32 {
  2484  			if x > math.Float32bits(1) {
  2485  				return -x
  2486  			}
  2487  			return x
  2488  		}
  2489  		`,
  2490  		neg: []string{"\tFMOVS\t"},
  2491  	},
  2492  }
  2493  
  2494  var plan9AMD64Tests = []*asmTest{
  2495  	// We should make sure that the compiler doesn't generate floating point
  2496  	// instructions for non-float operations on Plan 9, because floating point
  2497  	// operations are not allowed in the note handler.
  2498  	// Array zeroing.
  2499  	{
  2500  		fn: `
  2501  		func $() [16]byte {
  2502  			var a [16]byte
  2503  			return a
  2504  		}
  2505  		`,
  2506  		pos: []string{"\tMOVQ\t\\$0, \"\""},
  2507  	},
  2508  	// Array copy.
  2509  	{
  2510  		fn: `
  2511  		func $(a [16]byte) (b [16]byte) {
  2512  			b = a
  2513  			return
  2514  		}
  2515  		`,
  2516  		pos: []string{"\tMOVQ\t\"\"\\.a\\+[0-9]+\\(SP\\), (AX|CX)", "\tMOVQ\t(AX|CX), \"\"\\.b\\+[0-9]+\\(SP\\)"},
  2517  	},
  2518  }
  2519  
  2520  // TestLineNumber checks to make sure the generated assembly has line numbers
  2521  // see issue #16214
  2522  func TestLineNumber(t *testing.T) {
  2523  	testenv.MustHaveGoBuild(t)
  2524  	dir, err := ioutil.TempDir("", "TestLineNumber")
  2525  	if err != nil {
  2526  		t.Fatalf("could not create directory: %v", err)
  2527  	}
  2528  	defer os.RemoveAll(dir)
  2529  
  2530  	src := filepath.Join(dir, "x.go")
  2531  	err = ioutil.WriteFile(src, []byte(issue16214src), 0644)
  2532  	if err != nil {
  2533  		t.Fatalf("could not write file: %v", err)
  2534  	}
  2535  
  2536  	cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-S", "-o", filepath.Join(dir, "out.o"), src)
  2537  	out, err := cmd.CombinedOutput()
  2538  	if err != nil {
  2539  		t.Fatalf("fail to run go tool compile: %v", err)
  2540  	}
  2541  
  2542  	if strings.Contains(string(out), "unknown line number") {
  2543  		t.Errorf("line number missing in assembly:\n%s", out)
  2544  	}
  2545  }
  2546  
  2547  var issue16214src = `
  2548  package main
  2549  
  2550  func Mod32(x uint32) uint32 {
  2551  	return x % 3 // frontend rewrites it as HMUL with 2863311531, the LITERAL node has unknown Pos
  2552  }
  2553  `