| // Copyright 2020 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package test | |
| import ( | |
| "bytes" | |
| "fmt" | |
| "internal/testenv" | |
| "os" | |
| "path/filepath" | |
| "strings" | |
| "testing" | |
| ) | |
| func TestConstantMultiplies(t *testing.T) { | |
| testenv.MustHaveGoRun(t) | |
| signs := []string{"", "u"} | |
| widths := []int{8, 16, 32, 64} | |
| // Make test code. | |
| var code bytes.Buffer | |
| fmt.Fprintf(&code, "package main\n") | |
| for _, b := range widths { | |
| for _, s := range signs { | |
| fmt.Fprintf(&code, "type test_%s%d struct {\n", s, b) | |
| fmt.Fprintf(&code, " m %sint%d\n", s, b) | |
| fmt.Fprintf(&code, " f func(%sint%d)%sint%d\n", s, b, s, b) | |
| fmt.Fprintf(&code, "}\n") | |
| fmt.Fprintf(&code, "var test_%s%ds []test_%s%d\n", s, b, s, b) | |
| } | |
| } | |
| for _, b := range widths { | |
| for _, s := range signs { | |
| lo := -256 | |
| hi := 256 | |
| if b == 8 { | |
| lo = -128 | |
| hi = 127 | |
| } | |
| if s == "u" { | |
| lo = 0 | |
| } | |
| for i := lo; i <= hi; i++ { | |
| name := fmt.Sprintf("f_%s%d_%d", s, b, i) | |
| name = strings.ReplaceAll(name, "-", "n") | |
| fmt.Fprintf(&code, "func %s(x %sint%d) %sint%d {\n", name, s, b, s, b) | |
| fmt.Fprintf(&code, " return x*%d\n", i) | |
| fmt.Fprintf(&code, "}\n") | |
| fmt.Fprintf(&code, "func init() {\n") | |
| fmt.Fprintf(&code, " test_%s%ds = append(test_%s%ds, test_%s%d{%d, %s})\n", s, b, s, b, s, b, i, name) | |
| fmt.Fprintf(&code, "}\n") | |
| } | |
| } | |
| } | |
| fmt.Fprintf(&code, "func main() {\n") | |
| for _, b := range widths { | |
| for _, s := range signs { | |
| lo := -256 | |
| hi := 256 | |
| if s == "u" { | |
| lo = 0 | |
| } | |
| fmt.Fprintf(&code, " for _, tst := range test_%s%ds {\n", s, b) | |
| fmt.Fprintf(&code, " for x := %d; x <= %d; x++ {\n", lo, hi) | |
| fmt.Fprintf(&code, " y := %sint%d(x)\n", s, b) | |
| fmt.Fprintf(&code, " if tst.f(y) != y*tst.m {\n") | |
| fmt.Fprintf(&code, " panic(tst.m)\n") | |
| fmt.Fprintf(&code, " }\n") | |
| fmt.Fprintf(&code, " }\n") | |
| fmt.Fprintf(&code, " }\n") | |
| } | |
| } | |
| fmt.Fprintf(&code, "}\n") | |
| t.Logf("CODE:\n%s\n", string(code.Bytes())) | |
| // Make test file | |
| tmpdir := t.TempDir() | |
| src := filepath.Join(tmpdir, "x.go") | |
| err := os.WriteFile(src, code.Bytes(), 0644) | |
| if err != nil { | |
| t.Fatalf("write file failed: %v", err) | |
| } | |
| cmd := testenv.Command(t, testenv.GoToolPath(t), "run", src) | |
| out, err := cmd.CombinedOutput() | |
| if err != nil { | |
| t.Fatalf("go run failed: %v\n%s", err, out) | |
| } | |
| if len(out) > 0 { | |
| t.Fatalf("got output when expecting none: %s\n", string(out)) | |
| } | |
| } | |
| // Benchmark multiplication of an integer by various constants. | |
| // | |
| // The comment above each sub-benchmark provides an example of how the | |
| // target multiplication operation might be implemented using shift | |
| // (multiplication by a power of 2), addition and subtraction | |
| // operations. It is platform-dependent whether these transformations | |
| // are actually applied. | |
| var ( | |
| mulSinkI32 int32 | |
| mulSinkI64 int64 | |
| mulSinkU32 uint32 | |
| mulSinkU64 uint64 | |
| ) | |
| func BenchmarkMulconstI32(b *testing.B) { | |
| // 3x = 2x + x | |
| b.Run("3", func(b *testing.B) { | |
| x := int32(1) | |
| for i := 0; i < b.N; i++ { | |
| x *= 3 | |
| } | |
| mulSinkI32 = x | |
| }) | |
| // 5x = 4x + x | |
| b.Run("5", func(b *testing.B) { | |
| x := int32(1) | |
| for i := 0; i < b.N; i++ { | |
| x *= 5 | |
| } | |
| mulSinkI32 = x | |
| }) | |
| // 12x = 8x + 4x | |
| b.Run("12", func(b *testing.B) { | |
| x := int32(1) | |
| for i := 0; i < b.N; i++ { | |
| x *= 12 | |
| } | |
| mulSinkI32 = x | |
| }) | |
| // 120x = 128x - 8x | |
| b.Run("120", func(b *testing.B) { | |
| x := int32(1) | |
| for i := 0; i < b.N; i++ { | |
| x *= 120 | |
| } | |
| mulSinkI32 = x | |
| }) | |
| // -120x = 8x - 128x | |
| b.Run("-120", func(b *testing.B) { | |
| x := int32(1) | |
| for i := 0; i < b.N; i++ { | |
| x *= -120 | |
| } | |
| mulSinkI32 = x | |
| }) | |
| // 65537x = 65536x + x | |
| b.Run("65537", func(b *testing.B) { | |
| x := int32(1) | |
| for i := 0; i < b.N; i++ { | |
| x *= 65537 | |
| } | |
| mulSinkI32 = x | |
| }) | |
| // 65538x = 65536x + 2x | |
| b.Run("65538", func(b *testing.B) { | |
| x := int32(1) | |
| for i := 0; i < b.N; i++ { | |
| x *= 65538 | |
| } | |
| mulSinkI32 = x | |
| }) | |
| } | |
| func BenchmarkMulconstI64(b *testing.B) { | |
| // 3x = 2x + x | |
| b.Run("3", func(b *testing.B) { | |
| x := int64(1) | |
| for i := 0; i < b.N; i++ { | |
| x *= 3 | |
| } | |
| mulSinkI64 = x | |
| }) | |
| // 5x = 4x + x | |
| b.Run("5", func(b *testing.B) { | |
| x := int64(1) | |
| for i := 0; i < b.N; i++ { | |
| x *= 5 | |
| } | |
| mulSinkI64 = x | |
| }) | |
| // 12x = 8x + 4x | |
| b.Run("12", func(b *testing.B) { | |
| x := int64(1) | |
| for i := 0; i < b.N; i++ { | |
| x *= 12 | |
| } | |
| mulSinkI64 = x | |
| }) | |
| // 120x = 128x - 8x | |
| b.Run("120", func(b *testing.B) { | |
| x := int64(1) | |
| for i := 0; i < b.N; i++ { | |
| x *= 120 | |
| } | |
| mulSinkI64 = x | |
| }) | |
| // -120x = 8x - 128x | |
| b.Run("-120", func(b *testing.B) { | |
| x := int64(1) | |
| for i := 0; i < b.N; i++ { | |
| x *= -120 | |
| } | |
| mulSinkI64 = x | |
| }) | |
| // 65537x = 65536x + x | |
| b.Run("65537", func(b *testing.B) { | |
| x := int64(1) | |
| for i := 0; i < b.N; i++ { | |
| x *= 65537 | |
| } | |
| mulSinkI64 = x | |
| }) | |
| // 65538x = 65536x + 2x | |
| b.Run("65538", func(b *testing.B) { | |
| x := int64(1) | |
| for i := 0; i < b.N; i++ { | |
| x *= 65538 | |
| } | |
| mulSinkI64 = x | |
| }) | |
| } | |
| func BenchmarkMulconstU32(b *testing.B) { | |
| // 3x = 2x + x | |
| b.Run("3", func(b *testing.B) { | |
| x := uint32(1) | |
| for i := 0; i < b.N; i++ { | |
| x *= 3 | |
| } | |
| mulSinkU32 = x | |
| }) | |
| // 5x = 4x + x | |
| b.Run("5", func(b *testing.B) { | |
| x := uint32(1) | |
| for i := 0; i < b.N; i++ { | |
| x *= 5 | |
| } | |
| mulSinkU32 = x | |
| }) | |
| // 12x = 8x + 4x | |
| b.Run("12", func(b *testing.B) { | |
| x := uint32(1) | |
| for i := 0; i < b.N; i++ { | |
| x *= 12 | |
| } | |
| mulSinkU32 = x | |
| }) | |
| // 120x = 128x - 8x | |
| b.Run("120", func(b *testing.B) { | |
| x := uint32(1) | |
| for i := 0; i < b.N; i++ { | |
| x *= 120 | |
| } | |
| mulSinkU32 = x | |
| }) | |
| // 65537x = 65536x + x | |
| b.Run("65537", func(b *testing.B) { | |
| x := uint32(1) | |
| for i := 0; i < b.N; i++ { | |
| x *= 65537 | |
| } | |
| mulSinkU32 = x | |
| }) | |
| // 65538x = 65536x + 2x | |
| b.Run("65538", func(b *testing.B) { | |
| x := uint32(1) | |
| for i := 0; i < b.N; i++ { | |
| x *= 65538 | |
| } | |
| mulSinkU32 = x | |
| }) | |
| } | |
| func BenchmarkMulconstU64(b *testing.B) { | |
| // 3x = 2x + x | |
| b.Run("3", func(b *testing.B) { | |
| x := uint64(1) | |
| for i := 0; i < b.N; i++ { | |
| x *= 3 | |
| } | |
| mulSinkU64 = x | |
| }) | |
| // 5x = 4x + x | |
| b.Run("5", func(b *testing.B) { | |
| x := uint64(1) | |
| for i := 0; i < b.N; i++ { | |
| x *= 5 | |
| } | |
| mulSinkU64 = x | |
| }) | |
| // 12x = 8x + 4x | |
| b.Run("12", func(b *testing.B) { | |
| x := uint64(1) | |
| for i := 0; i < b.N; i++ { | |
| x *= 12 | |
| } | |
| mulSinkU64 = x | |
| }) | |
| // 120x = 128x - 8x | |
| b.Run("120", func(b *testing.B) { | |
| x := uint64(1) | |
| for i := 0; i < b.N; i++ { | |
| x *= 120 | |
| } | |
| mulSinkU64 = x | |
| }) | |
| // 65537x = 65536x + x | |
| b.Run("65537", func(b *testing.B) { | |
| x := uint64(1) | |
| for i := 0; i < b.N; i++ { | |
| x *= 65537 | |
| } | |
| mulSinkU64 = x | |
| }) | |
| // 65538x = 65536x + 2x | |
| b.Run("65538", func(b *testing.B) { | |
| x := uint64(1) | |
| for i := 0; i < b.N; i++ { | |
| x *= 65538 | |
| } | |
| mulSinkU64 = x | |
| }) | |
| } |