aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAyke van Laethem <[email protected]>2023-09-25 13:04:28 +0200
committerAyke van Laethem <[email protected]>2023-09-25 16:51:01 +0200
commit34f302e0645535f2a52dacf2b850d9a10cc4b9b6 (patch)
treef31202635b6e31c1702fcfc8edd15aab10e51220
parent6ef8fcd5379b9610c518ab893e878a4c9b37ba08 (diff)
downloadtinygo-build-ssa-in-jobs.tar.gz
tinygo-build-ssa-in-jobs.zip
builder: do Go SSA build in a separate jobbuild-ssa-in-jobs
This means it can run in parallel with other jobs - although it can't run in parallel with itself. This is an imperfect solution that is a slight improvement in compile time over building the SSA sequentially while buliding the jobs graph. But it paves the way for more efficient solutions.
-rw-r--r--builder/build.go29
-rw-r--r--compiler/compiler.go3
-rw-r--r--compiler/compiler_test.go4
-rw-r--r--transform/transform_test.go4
4 files changed, 32 insertions, 8 deletions
diff --git a/builder/build.go b/builder/build.go
index dc360b92e..9036d113a 100644
--- a/builder/build.go
+++ b/builder/build.go
@@ -23,6 +23,7 @@ import (
"sort"
"strconv"
"strings"
+ "sync"
"github.com/gofrs/flock"
"github.com/tinygo-org/tinygo/compileopts"
@@ -216,6 +217,8 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
// Packages that have a cache hit will not be compiled again.
var packageJobs []*compileJob
packageActionIDJobs := make(map[string]*compileJob)
+ ssaJobs := make(map[string]*compileJob)
+ var ssaLock sync.Mutex
if config.Options.GlobalValues == nil {
config.Options.GlobalValues = make(map[string]map[string]string)
@@ -292,7 +295,9 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
// Action ID jobs need to know the action ID of all the jobs the package
// imports.
+ // Also, we need to know the Go SSA job dependencies for this package.
var importedPackages []*compileJob
+ var ssaJobDependencies []*compileJob
for _, imported := range pkg.Pkg.Imports() {
job, ok := packageActionIDJobs[imported.Path()]
if !ok {
@@ -300,6 +305,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
}
importedPackages = append(importedPackages, job)
actionIDDependencies = append(actionIDDependencies, job)
+ ssaJobDependencies = append(ssaJobDependencies, ssaJobs[imported.Path()])
}
// Create a job that will calculate the action ID for a package compile
@@ -344,15 +350,32 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
}
packageActionIDJobs[pkg.ImportPath] = packageActionIDJob
- // Build the SSA for the given package.
+ // Build the Go SSA for the given package.
ssaPkg := program.Package(pkg.Pkg)
- ssaPkg.Build()
+ ssaJob := &compileJob{
+ description: "build Go SSA for package " + pkg.ImportPath,
+ dependencies: append([]*compileJob{packageActionIDJob}, ssaJobDependencies...),
+ run: func(job *compileJob) (err error) {
+ // Make sure only a single SSA build is running at a time. I
+ // believe this should not be required (I believe there is a
+ // race condition in the x/tools/go/ssa package), but for now
+ // this is needed to avoid race conditions.
+ ssaLock.Lock()
+ defer ssaLock.Unlock()
+
+ // Do the Go SSA build.
+ ssaPkg.Build()
+
+ return nil
+ },
+ }
+ ssaJobs[pkg.ImportPath] = ssaJob
// Now create the job to actually build the package. It will exit early
// if the package is already compiled.
job := &compileJob{
description: "compile package " + pkg.ImportPath,
- dependencies: []*compileJob{packageActionIDJob},
+ dependencies: []*compileJob{ssaJob, packageActionIDJob},
run: func(job *compileJob) error {
job.result = filepath.Join(cacheDir, "pkg-"+packageActionIDJob.result+".bc")
// Acquire a lock (if supported).
diff --git a/compiler/compiler.go b/compiler/compiler.go
index cb3a892a8..2ff1ebe26 100644
--- a/compiler/compiler.go
+++ b/compiler/compiler.go
@@ -281,9 +281,6 @@ func CompilePackage(moduleName string, pkg *loader.Package, ssaPkg *ssa.Package,
c.runtimePkg = ssaPkg.Prog.ImportedPackage("runtime").Pkg
c.program = ssaPkg.Prog
- // Convert AST to SSA.
- ssaPkg.Build()
-
// Initialize debug information.
if c.Debug {
c.cu = c.dibuilder.CreateCompileUnit(llvm.DICompileUnit{
diff --git a/compiler/compiler_test.go b/compiler/compiler_test.go
index 92ce31b01..5450848c1 100644
--- a/compiler/compiler_test.go
+++ b/compiler/compiler_test.go
@@ -259,5 +259,7 @@ func testCompilePackage(t *testing.T, options *compileopts.Options, file string)
// Compile AST to IR.
program := lprogram.LoadSSA()
pkg := lprogram.MainPkg()
- return CompilePackage(file, pkg, program.Package(pkg.Pkg), machine, compilerConfig, false)
+ ssaPkg := program.Package(pkg.Pkg)
+ ssaPkg.Build()
+ return CompilePackage(file, pkg, ssaPkg, machine, compilerConfig, false)
}
diff --git a/transform/transform_test.go b/transform/transform_test.go
index 4cab255e6..98a1aab2d 100644
--- a/transform/transform_test.go
+++ b/transform/transform_test.go
@@ -159,7 +159,9 @@ func compileGoFileForTesting(t *testing.T, filename string) llvm.Module {
// Compile AST to IR.
program := lprogram.LoadSSA()
pkg := lprogram.MainPkg()
- mod, errs := compiler.CompilePackage(filename, pkg, program.Package(pkg.Pkg), machine, compilerConfig, false)
+ ssaPkg := program.Package(pkg.Pkg)
+ ssaPkg.Build()
+ mod, errs := compiler.CompilePackage(filename, pkg, ssaPkg, machine, compilerConfig, false)
if errs != nil {
for _, err := range errs {
t.Error(err)