builder: run interp per package

This results in a significant speedup in some cases. For example, this
runs over twice as fast with a warm cache:

    tinygo build -o test.elf ./testdata/stdlib.go

This should help a lot with edit-compile-test cycles, that typically
only modify a single package.

This required some changes to the interp package to deal with globals
created in a previous run of the interp package and to deal with
external globals (that can't be loaded from or stored to).
This commit is contained in:
Ayke van Laethem
2021-03-29 23:51:56 +02:00
committed by Ron Evans
parent 35bf0746a1
commit 312f5d3833
5 changed files with 188 additions and 10 deletions
+28 -2
View File
@@ -55,6 +55,7 @@ type BuildResult struct {
type packageAction struct {
ImportPath string
CompilerVersion int // compiler.Version
InterpVersion int // interp.Version
LLVMVersion string
Config *compiler.Config
CFlags []string
@@ -135,6 +136,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
actionID := packageAction{
ImportPath: pkg.ImportPath,
CompilerVersion: compiler.Version,
InterpVersion: interp.Version,
LLVMVersion: llvm.Version,
Config: compilerConfig,
CFlags: pkg.CFlags,
@@ -190,6 +192,21 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
return errors.New("verification error after compiling package " + pkg.ImportPath)
}
// Try to interpret package initializers at compile time.
// It may only be possible to do this partially, in which case
// it is completed after all IR files are linked.
pkgInit := mod.NamedFunction(pkg.Pkg.Path() + ".init")
if pkgInit.IsNil() {
panic("init not found for " + pkg.Pkg.Path())
}
err := interp.RunFunc(pkgInit, config.DumpSSA())
if err != nil {
return err
}
if err := llvm.VerifyModule(mod, llvm.PrintMessageAction); err != nil {
return errors.New("verification error after interpreting " + pkgInit.Name())
}
// Serialize the LLVM module as a bitcode file.
// Write to a temporary path that is renamed to the destination
// file to avoid race conditions with other TinyGo invocatiosn
@@ -575,8 +592,17 @@ func optimizeProgram(mod llvm.Module, config *compileopts.Config) error {
if err != nil {
return err
}
if err := llvm.VerifyModule(mod, llvm.PrintMessageAction); err != nil {
return errors.New("verification error after interpreting runtime.initAll")
if config.VerifyIR() {
// Only verify if we really need it.
// The IR has already been verified before writing the bitcode to disk
// and the interp function above doesn't need to do a lot as most of the
// package initializers have already run. Additionally, verifying this
// linked IR is _expensive_ because dead code hasn't been removed yet,
// easily costing a few hundred milliseconds. Therefore, only do it when
// specifically requested.
if err := llvm.VerifyModule(mod, llvm.PrintMessageAction); err != nil {
return errors.New("verification error after interpreting runtime.initAll")
}
}
if config.GOOS() != "darwin" {