blob: c4aed84432de5037ecaf0f088835f5e9e9df5ab8 [file] [log] [blame] [edit]
// 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
})
}