diff options
author | Ayke van Laethem <[email protected]> | 2023-09-25 13:04:28 +0200 |
---|---|---|
committer | Ayke van Laethem <[email protected]> | 2023-09-25 16:51:01 +0200 |
commit | 34f302e0645535f2a52dacf2b850d9a10cc4b9b6 (patch) | |
tree | f31202635b6e31c1702fcfc8edd15aab10e51220 | |
parent | 6ef8fcd5379b9610c518ab893e878a4c9b37ba08 (diff) | |
download | tinygo-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.go | 29 | ||||
-rw-r--r-- | compiler/compiler.go | 3 | ||||
-rw-r--r-- | compiler/compiler_test.go | 4 | ||||
-rw-r--r-- | transform/transform_test.go | 4 |
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) |