mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-07-31 09:07:46 +00:00
c466465c32
This flag, if set, is a regexp for function names. If there are heap allocations in the matching function names, these heap allocations will be printed with an explanation why the heap allocation exists (and why the object can't be stack allocated).
130 lines
3.4 KiB
Go
130 lines
3.4 KiB
Go
package transform_test
|
|
|
|
import (
|
|
"go/token"
|
|
"go/types"
|
|
"io/ioutil"
|
|
"path/filepath"
|
|
"regexp"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/tinygo-org/tinygo/compileopts"
|
|
"github.com/tinygo-org/tinygo/compiler"
|
|
"github.com/tinygo-org/tinygo/loader"
|
|
"github.com/tinygo-org/tinygo/transform"
|
|
"tinygo.org/x/go-llvm"
|
|
)
|
|
|
|
func TestAllocs(t *testing.T) {
|
|
t.Parallel()
|
|
testTransform(t, "testdata/allocs", func(mod llvm.Module) {
|
|
transform.OptimizeAllocs(mod, nil, nil)
|
|
})
|
|
}
|
|
|
|
type allocsTestOutput struct {
|
|
filename string
|
|
line int
|
|
msg string
|
|
}
|
|
|
|
func (out allocsTestOutput) String() string {
|
|
return out.filename + ":" + strconv.Itoa(out.line) + ": " + out.msg
|
|
}
|
|
|
|
// Test with a Go file as input (for more accurate tests).
|
|
func TestAllocs2(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
target, err := compileopts.LoadTarget("i686--linux")
|
|
if err != nil {
|
|
t.Fatal("failed to load target:", err)
|
|
}
|
|
config := &compileopts.Config{
|
|
Options: &compileopts.Options{},
|
|
Target: target,
|
|
}
|
|
compilerConfig := &compiler.Config{
|
|
Triple: config.Triple(),
|
|
GOOS: config.GOOS(),
|
|
GOARCH: config.GOARCH(),
|
|
CodeModel: config.CodeModel(),
|
|
RelocationModel: config.RelocationModel(),
|
|
Scheduler: config.Scheduler(),
|
|
FuncImplementation: config.FuncImplementation(),
|
|
AutomaticStackSize: config.AutomaticStackSize(),
|
|
Debug: true,
|
|
}
|
|
machine, err := compiler.NewTargetMachine(compilerConfig)
|
|
if err != nil {
|
|
t.Fatal("failed to create target machine:", err)
|
|
}
|
|
|
|
// Load entire program AST into memory.
|
|
lprogram, err := loader.Load(config, []string{"./testdata/allocs2.go"}, config.ClangHeaders, types.Config{
|
|
Sizes: compiler.Sizes(machine),
|
|
})
|
|
if err != nil {
|
|
t.Fatal("failed to create target machine:", err)
|
|
}
|
|
err = lprogram.Parse()
|
|
if err != nil {
|
|
t.Fatal("could not parse", err)
|
|
}
|
|
|
|
// Compile AST to IR.
|
|
program := lprogram.LoadSSA()
|
|
pkg := lprogram.MainPkg()
|
|
mod, errs := compiler.CompilePackage("allocs2.go", pkg, program.Package(pkg.Pkg), machine, compilerConfig, false)
|
|
if errs != nil {
|
|
for _, err := range errs {
|
|
t.Error(err)
|
|
}
|
|
return
|
|
}
|
|
|
|
// Run functionattrs pass, which is necessary for escape analysis.
|
|
pm := llvm.NewPassManager()
|
|
defer pm.Dispose()
|
|
pm.AddInstructionCombiningPass()
|
|
pm.AddFunctionAttrsPass()
|
|
pm.Run(mod)
|
|
|
|
// Run heap to stack transform.
|
|
var testOutputs []allocsTestOutput
|
|
transform.OptimizeAllocs(mod, regexp.MustCompile("."), func(pos token.Position, msg string) {
|
|
testOutputs = append(testOutputs, allocsTestOutput{
|
|
filename: filepath.Base(pos.Filename),
|
|
line: pos.Line,
|
|
msg: msg,
|
|
})
|
|
})
|
|
sort.Slice(testOutputs, func(i, j int) bool {
|
|
return testOutputs[i].line < testOutputs[j].line
|
|
})
|
|
testOutput := ""
|
|
for _, out := range testOutputs {
|
|
testOutput += out.String() + "\n"
|
|
}
|
|
|
|
// Load expected test output (the OUT: lines).
|
|
testInput, err := ioutil.ReadFile("./testdata/allocs2.go")
|
|
if err != nil {
|
|
t.Fatal("could not read test input:", err)
|
|
}
|
|
var expectedTestOutput string
|
|
for i, line := range strings.Split(strings.ReplaceAll(string(testInput), "\r\n", "\n"), "\n") {
|
|
if idx := strings.Index(line, " // OUT: "); idx > 0 {
|
|
msg := line[idx+len(" // OUT: "):]
|
|
expectedTestOutput += "allocs2.go:" + strconv.Itoa(i+1) + ": " + msg + "\n"
|
|
}
|
|
}
|
|
|
|
if testOutput != expectedTestOutput {
|
|
t.Errorf("output does not match expected output:\n%s", testOutput)
|
|
}
|
|
}
|