Source file src/cmd/compile/internal/test/mulconst_test.go

     1  // Copyright 2020 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 test
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"internal/testenv"
    11  	"os"
    12  	"path/filepath"
    13  	"strings"
    14  	"testing"
    15  )
    16  
    17  func TestConstantMultiplies(t *testing.T) {
    18  	testenv.MustHaveGoRun(t)
    19  
    20  	signs := []string{"", "u"}
    21  	widths := []int{8, 16, 32, 64}
    22  
    23  	// Make test code.
    24  	var code bytes.Buffer
    25  	fmt.Fprintf(&code, "package main\n")
    26  	for _, b := range widths {
    27  		for _, s := range signs {
    28  			fmt.Fprintf(&code, "type test_%s%d struct {\n", s, b)
    29  			fmt.Fprintf(&code, "    m %sint%d\n", s, b)
    30  			fmt.Fprintf(&code, "    f func(%sint%d)%sint%d\n", s, b, s, b)
    31  			fmt.Fprintf(&code, "}\n")
    32  			fmt.Fprintf(&code, "var test_%s%ds []test_%s%d\n", s, b, s, b)
    33  		}
    34  	}
    35  	for _, b := range widths {
    36  		for _, s := range signs {
    37  			lo := -256
    38  			hi := 256
    39  			if b == 8 {
    40  				lo = -128
    41  				hi = 127
    42  			}
    43  			if s == "u" {
    44  				lo = 0
    45  			}
    46  			for i := lo; i <= hi; i++ {
    47  				name := fmt.Sprintf("f_%s%d_%d", s, b, i)
    48  				name = strings.ReplaceAll(name, "-", "n")
    49  				fmt.Fprintf(&code, "func %s(x %sint%d) %sint%d {\n", name, s, b, s, b)
    50  				fmt.Fprintf(&code, "    return x*%d\n", i)
    51  				fmt.Fprintf(&code, "}\n")
    52  				fmt.Fprintf(&code, "func init() {\n")
    53  				fmt.Fprintf(&code, "    test_%s%ds = append(test_%s%ds, test_%s%d{%d, %s})\n", s, b, s, b, s, b, i, name)
    54  				fmt.Fprintf(&code, "}\n")
    55  			}
    56  		}
    57  	}
    58  	fmt.Fprintf(&code, "func main() {\n")
    59  	for _, b := range widths {
    60  		for _, s := range signs {
    61  			lo := -256
    62  			hi := 256
    63  			if s == "u" {
    64  				lo = 0
    65  			}
    66  			fmt.Fprintf(&code, "    for _, tst := range test_%s%ds {\n", s, b)
    67  			fmt.Fprintf(&code, "        for x := %d; x <= %d; x++ {\n", lo, hi)
    68  			fmt.Fprintf(&code, "            y := %sint%d(x)\n", s, b)
    69  			fmt.Fprintf(&code, "            if tst.f(y) != y*tst.m {\n")
    70  			fmt.Fprintf(&code, "                panic(tst.m)\n")
    71  			fmt.Fprintf(&code, "            }\n")
    72  			fmt.Fprintf(&code, "        }\n")
    73  			fmt.Fprintf(&code, "    }\n")
    74  		}
    75  	}
    76  	fmt.Fprintf(&code, "}\n")
    77  
    78  	fmt.Printf("CODE:\n%s\n", string(code.Bytes()))
    79  
    80  	// Make test file
    81  	tmpdir := t.TempDir()
    82  	src := filepath.Join(tmpdir, "x.go")
    83  	err := os.WriteFile(src, code.Bytes(), 0644)
    84  	if err != nil {
    85  		t.Fatalf("write file failed: %v", err)
    86  	}
    87  
    88  	cmd := testenv.Command(t, testenv.GoToolPath(t), "run", src)
    89  	out, err := cmd.CombinedOutput()
    90  	if err != nil {
    91  		t.Fatalf("go run failed: %v\n%s", err, out)
    92  	}
    93  	if len(out) > 0 {
    94  		t.Fatalf("got output when expecting none: %s\n", string(out))
    95  	}
    96  }
    97  
    98  // Benchmark multiplication of an integer by various constants.
    99  //
   100  // The comment above each sub-benchmark provides an example of how the
   101  // target multiplication operation might be implemented using shift
   102  // (multiplication by a power of 2), addition and subtraction
   103  // operations. It is platform-dependent whether these transformations
   104  // are actually applied.
   105  
   106  var (
   107  	mulSinkI32 int32
   108  	mulSinkI64 int64
   109  	mulSinkU32 uint32
   110  	mulSinkU64 uint64
   111  )
   112  
   113  func BenchmarkMulconstI32(b *testing.B) {
   114  	// 3x = 2x + x
   115  	b.Run("3", func(b *testing.B) {
   116  		x := int32(1)
   117  		for i := 0; i < b.N; i++ {
   118  			x *= 3
   119  		}
   120  		mulSinkI32 = x
   121  	})
   122  	// 5x = 4x + x
   123  	b.Run("5", func(b *testing.B) {
   124  		x := int32(1)
   125  		for i := 0; i < b.N; i++ {
   126  			x *= 5
   127  		}
   128  		mulSinkI32 = x
   129  	})
   130  	// 12x = 8x + 4x
   131  	b.Run("12", func(b *testing.B) {
   132  		x := int32(1)
   133  		for i := 0; i < b.N; i++ {
   134  			x *= 12
   135  		}
   136  		mulSinkI32 = x
   137  	})
   138  	// 120x = 128x - 8x
   139  	b.Run("120", func(b *testing.B) {
   140  		x := int32(1)
   141  		for i := 0; i < b.N; i++ {
   142  			x *= 120
   143  		}
   144  		mulSinkI32 = x
   145  	})
   146  	// -120x = 8x - 120x
   147  	b.Run("-120", func(b *testing.B) {
   148  		x := int32(1)
   149  		for i := 0; i < b.N; i++ {
   150  			x *= -120
   151  		}
   152  		mulSinkI32 = x
   153  	})
   154  	// 65537x = 65536x + x
   155  	b.Run("65537", func(b *testing.B) {
   156  		x := int32(1)
   157  		for i := 0; i < b.N; i++ {
   158  			x *= 65537
   159  		}
   160  		mulSinkI32 = x
   161  	})
   162  	// 65538x = 65536x + 2x
   163  	b.Run("65538", func(b *testing.B) {
   164  		x := int32(1)
   165  		for i := 0; i < b.N; i++ {
   166  			x *= 65538
   167  		}
   168  		mulSinkI32 = x
   169  	})
   170  }
   171  
   172  func BenchmarkMulconstI64(b *testing.B) {
   173  	// 3x = 2x + x
   174  	b.Run("3", func(b *testing.B) {
   175  		x := int64(1)
   176  		for i := 0; i < b.N; i++ {
   177  			x *= 3
   178  		}
   179  		mulSinkI64 = x
   180  	})
   181  	// 5x = 4x + x
   182  	b.Run("5", func(b *testing.B) {
   183  		x := int64(1)
   184  		for i := 0; i < b.N; i++ {
   185  			x *= 5
   186  		}
   187  		mulSinkI64 = x
   188  	})
   189  	// 12x = 8x + 4x
   190  	b.Run("12", func(b *testing.B) {
   191  		x := int64(1)
   192  		for i := 0; i < b.N; i++ {
   193  			x *= 12
   194  		}
   195  		mulSinkI64 = x
   196  	})
   197  	// 120x = 128x - 8x
   198  	b.Run("120", func(b *testing.B) {
   199  		x := int64(1)
   200  		for i := 0; i < b.N; i++ {
   201  			x *= 120
   202  		}
   203  		mulSinkI64 = x
   204  	})
   205  	// -120x = 8x - 120x
   206  	b.Run("-120", func(b *testing.B) {
   207  		x := int64(1)
   208  		for i := 0; i < b.N; i++ {
   209  			x *= -120
   210  		}
   211  		mulSinkI64 = x
   212  	})
   213  	// 65537x = 65536x + x
   214  	b.Run("65537", func(b *testing.B) {
   215  		x := int64(1)
   216  		for i := 0; i < b.N; i++ {
   217  			x *= 65537
   218  		}
   219  		mulSinkI64 = x
   220  	})
   221  	// 65538x = 65536x + 2x
   222  	b.Run("65538", func(b *testing.B) {
   223  		x := int64(1)
   224  		for i := 0; i < b.N; i++ {
   225  			x *= 65538
   226  		}
   227  		mulSinkI64 = x
   228  	})
   229  }
   230  
   231  func BenchmarkMulconstU32(b *testing.B) {
   232  	// 3x = 2x + x
   233  	b.Run("3", func(b *testing.B) {
   234  		x := uint32(1)
   235  		for i := 0; i < b.N; i++ {
   236  			x *= 3
   237  		}
   238  		mulSinkU32 = x
   239  	})
   240  	// 5x = 4x + x
   241  	b.Run("5", func(b *testing.B) {
   242  		x := uint32(1)
   243  		for i := 0; i < b.N; i++ {
   244  			x *= 5
   245  		}
   246  		mulSinkU32 = x
   247  	})
   248  	// 12x = 8x + 4x
   249  	b.Run("12", func(b *testing.B) {
   250  		x := uint32(1)
   251  		for i := 0; i < b.N; i++ {
   252  			x *= 12
   253  		}
   254  		mulSinkU32 = x
   255  	})
   256  	// 120x = 128x - 8x
   257  	b.Run("120", func(b *testing.B) {
   258  		x := uint32(1)
   259  		for i := 0; i < b.N; i++ {
   260  			x *= 120
   261  		}
   262  		mulSinkU32 = x
   263  	})
   264  	// 65537x = 65536x + x
   265  	b.Run("65537", func(b *testing.B) {
   266  		x := uint32(1)
   267  		for i := 0; i < b.N; i++ {
   268  			x *= 65537
   269  		}
   270  		mulSinkU32 = x
   271  	})
   272  	// 65538x = 65536x + 2x
   273  	b.Run("65538", func(b *testing.B) {
   274  		x := uint32(1)
   275  		for i := 0; i < b.N; i++ {
   276  			x *= 65538
   277  		}
   278  		mulSinkU32 = x
   279  	})
   280  }
   281  
   282  func BenchmarkMulconstU64(b *testing.B) {
   283  	// 3x = 2x + x
   284  	b.Run("3", func(b *testing.B) {
   285  		x := uint64(1)
   286  		for i := 0; i < b.N; i++ {
   287  			x *= 3
   288  		}
   289  		mulSinkU64 = x
   290  	})
   291  	// 5x = 4x + x
   292  	b.Run("5", func(b *testing.B) {
   293  		x := uint64(1)
   294  		for i := 0; i < b.N; i++ {
   295  			x *= 5
   296  		}
   297  		mulSinkU64 = x
   298  	})
   299  	// 12x = 8x + 4x
   300  	b.Run("12", func(b *testing.B) {
   301  		x := uint64(1)
   302  		for i := 0; i < b.N; i++ {
   303  			x *= 12
   304  		}
   305  		mulSinkU64 = x
   306  	})
   307  	// 120x = 128x - 8x
   308  	b.Run("120", func(b *testing.B) {
   309  		x := uint64(1)
   310  		for i := 0; i < b.N; i++ {
   311  			x *= 120
   312  		}
   313  		mulSinkU64 = x
   314  	})
   315  	// 65537x = 65536x + x
   316  	b.Run("65537", func(b *testing.B) {
   317  		x := uint64(1)
   318  		for i := 0; i < b.N; i++ {
   319  			x *= 65537
   320  		}
   321  		mulSinkU64 = x
   322  	})
   323  	// 65538x = 65536x + 2x
   324  	b.Run("65538", func(b *testing.B) {
   325  		x := uint64(1)
   326  		for i := 0; i < b.N; i++ {
   327  			x *= 65538
   328  		}
   329  		mulSinkU64 = x
   330  	})
   331  }
   332  

View as plain text