blob: 07e8eea1b882755061672aef7ae0fb2890382976 [file] [log] [blame]
// Copyright 2017 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 gc
import (
"bytes"
"internal/testenv"
"os/exec"
"testing"
)
// TestIntendedInlining tests that specific runtime functions are inlined.
// This allows refactoring for code clarity and re-use without fear that
// changes to the compiler will cause silent performance regressions.
func TestIntendedInlining(t *testing.T) {
if testing.Short() && testenv.Builder() == "" {
t.Skip("skipping in short mode")
}
testenv.MustHaveGoRun(t)
t.Parallel()
// want is the list of function names (by package) that should
// be inlined.
want := map[string][]string{
"runtime": {
"tophash",
"add",
"addb",
"subtractb",
"(*bmap).keys",
"bucketShift",
"bucketMask",
"fastrand",
"noescape",
// TODO: These were modified at some point to be
// made inlineable, but have since been broken.
// "nextFreeFast",
},
"unicode/utf8": {
"FullRune",
"FullRuneInString",
"RuneLen",
"ValidRune",
},
}
m := make(map[string]bool)
pkgs := make([]string, 0, len(want))
for pname, fnames := range want {
pkgs = append(pkgs, pname)
for _, fname := range fnames {
m[pname+"."+fname] = true
}
}
args := append([]string{"build", "-a", "-gcflags=-m"}, pkgs...)
cmd := testenv.CleanCmdEnv(exec.Command(testenv.GoToolPath(t), args...))
out, err := cmd.CombinedOutput()
if err != nil {
t.Logf("%s", out)
t.Fatal(err)
}
lines := bytes.Split(out, []byte{'\n'})
curPkg := ""
for _, l := range lines {
if bytes.HasPrefix(l, []byte("# ")) {
curPkg = string(l[2:])
}
f := bytes.Split(l, []byte(": can inline "))
if len(f) < 2 {
continue
}
fn := bytes.TrimSpace(f[1])
delete(m, curPkg+"."+string(fn))
}
for s := range m {
t.Errorf("function %s not inlined", s)
}
}