| // 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") |
| |
| fmt.Printf("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 - 120x |
| 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 - 120x |
| 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 |
| }) |
| } |