all: rewrite goroutine lowering

Before this commit, goroutine support was spread through the compiler.
This commit changes this support, so that the compiler itself only
generates simple intrinsics and leaves the real support to a compiler
pass that runs as one of the TinyGo-specific optimization passes.

The biggest change, that was done together with the rewrite, was support
for goroutines in WebAssembly for JavaScript. The challenge in
JavaScript is that in general no blocking operations are allowed, which
means that programs that call time.Sleep() but do not start goroutines
also have to be scheduled by the scheduler.
This commit is contained in:
Ayke van Laethem
2019-01-10 16:54:09 +01:00
parent 072ef603fe
commit 602c264749
24 changed files with 807 additions and 483 deletions
+16 -15
View File
@@ -52,9 +52,18 @@ func (c *Compiler) Optimize(optLevel, sizeLevel int, inlinerThreshold uint) erro
// Run TinyGo-specific interprocedural optimizations.
c.OptimizeAllocs()
c.OptimizeStringToBytes()
err := c.LowerGoroutines()
if err != nil {
return err
}
} else {
// Must be run at any optimization level.
c.LowerInterfaces()
err := c.LowerGoroutines()
if err != nil {
return err
}
}
if err := c.Verify(); err != nil {
return errors.New("optimizations caused a verification failure")
@@ -70,6 +79,13 @@ func (c *Compiler) Optimize(optLevel, sizeLevel int, inlinerThreshold uint) erro
}
}
// Run function passes again, because without it, llvm.coro.size.i32()
// doesn't get lowered.
for fn := c.mod.FirstFunction(); !fn.IsNil(); fn = llvm.NextFunction(fn) {
funcPasses.RunFunc(fn)
}
funcPasses.FinalizeFunc()
// Run module passes.
modPasses := llvm.NewPassManager()
defer modPasses.Dispose()
@@ -324,18 +340,3 @@ func (c *Compiler) hasFlag(call, param llvm.Value, kind string) bool {
}
return true
}
// Return a list of values (actually, instructions) where this value is used as
// an operand.
func getUses(value llvm.Value) []llvm.Value {
if value.IsNil() {
return nil
}
var uses []llvm.Value
use := value.FirstUse()
for !use.IsNil() {
uses = append(uses, use.User())
use = use.NextUse()
}
return uses
}