mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-11 14:33:41 +00:00
refactor coroutine lowering and tasks
This commit is contained in:
+14
-15
@@ -40,24 +40,22 @@ const tinygoPath = "github.com/tinygo-org/tinygo"
|
||||
var functionsUsedInTransforms = []string{
|
||||
"runtime.alloc",
|
||||
"runtime.free",
|
||||
"runtime.scheduler",
|
||||
"runtime.nilPanic",
|
||||
}
|
||||
|
||||
var taskFunctionsUsedInTransforms = []string{
|
||||
"runtime.startGoroutine",
|
||||
}
|
||||
var taskFunctionsUsedInTransforms = []string{}
|
||||
|
||||
var coroFunctionsUsedInTransforms = []string{
|
||||
"runtime.avrSleep",
|
||||
"runtime.getFakeCoroutine",
|
||||
"runtime.setTaskStatePtr",
|
||||
"runtime.getTaskStatePtr",
|
||||
"runtime.activateTask",
|
||||
"runtime.noret",
|
||||
"runtime.getParentHandle",
|
||||
"runtime.getCoroutine",
|
||||
"runtime.llvmCoroRefHolder",
|
||||
"internal/task.start",
|
||||
"internal/task.Pause",
|
||||
"internal/task.fake",
|
||||
"internal/task.Current",
|
||||
"internal/task.createTask",
|
||||
"(*internal/task.Task).setState",
|
||||
"(*internal/task.Task).returnTo",
|
||||
"(*internal/task.Task).returnCurrent",
|
||||
"(*internal/task.Task).setReturnPtr",
|
||||
"(*internal/task.Task).getReturnPtr",
|
||||
}
|
||||
|
||||
type Compiler struct {
|
||||
@@ -162,6 +160,7 @@ func (c *Compiler) Module() llvm.Module {
|
||||
func (c *Compiler) getFunctionsUsedInTransforms() []string {
|
||||
fnused := functionsUsedInTransforms
|
||||
switch c.Scheduler() {
|
||||
case "none":
|
||||
case "coroutines":
|
||||
fnused = append(append([]string{}, fnused...), coroFunctionsUsedInTransforms...)
|
||||
case "tasks":
|
||||
@@ -218,7 +217,7 @@ func (c *Compiler) Compile(mainPath string) []error {
|
||||
path = path[len(tinygoPath+"/src/"):]
|
||||
}
|
||||
switch path {
|
||||
case "machine", "os", "reflect", "runtime", "runtime/interrupt", "runtime/volatile", "sync", "testing", "internal/reflectlite":
|
||||
case "machine", "os", "reflect", "runtime", "runtime/interrupt", "runtime/volatile", "sync", "testing", "internal/reflectlite", "internal/task":
|
||||
return path
|
||||
default:
|
||||
if strings.HasPrefix(path, "device/") || strings.HasPrefix(path, "examples/") {
|
||||
@@ -1095,7 +1094,7 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) {
|
||||
funcPtr, context := c.decodeFuncValue(c.getValue(frame, instr.Call.Value), instr.Call.Value.Type().(*types.Signature))
|
||||
params = append(params, context) // context parameter
|
||||
switch c.Scheduler() {
|
||||
case "coroutines":
|
||||
case "none", "coroutines":
|
||||
// There are no additional parameters needed for the goroutine start operation.
|
||||
case "tasks":
|
||||
// Add the function pointer as a parameter to start the goroutine.
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ func (c *Compiler) funcImplementation() funcValueImplementation {
|
||||
// Always pick the switch implementation, as it allows the use of blocking
|
||||
// inside a function that is used as a func value.
|
||||
switch c.Scheduler() {
|
||||
case "coroutines":
|
||||
case "none", "coroutines":
|
||||
return funcValueSwitch
|
||||
case "tasks":
|
||||
return funcValueDoubleword
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+6
-13
@@ -13,24 +13,17 @@ import "tinygo.org/x/go-llvm"
|
||||
//
|
||||
// Because a go statement doesn't return anything, return undef.
|
||||
func (c *Compiler) emitStartGoroutine(funcPtr llvm.Value, params []llvm.Value) llvm.Value {
|
||||
paramBundle := c.emitPointerPack(params)
|
||||
var callee llvm.Value
|
||||
switch c.Scheduler() {
|
||||
case "tasks":
|
||||
paramBundle := c.emitPointerPack(params)
|
||||
paramBundle = c.builder.CreatePtrToInt(paramBundle, c.uintptrType, "")
|
||||
|
||||
calleeValue := c.createGoroutineStartWrapper(funcPtr)
|
||||
c.createRuntimeCall("startGoroutine", []llvm.Value{calleeValue, paramBundle}, "")
|
||||
case "none", "tasks":
|
||||
callee = c.createGoroutineStartWrapper(funcPtr)
|
||||
case "coroutines":
|
||||
// We roundtrip through runtime.makeGoroutine as a signal (to find these
|
||||
// calls) and to break any optimizations LLVM will try to do: they are
|
||||
// invalid if we called this as a regular function to be updated later.
|
||||
calleeValue := c.builder.CreatePtrToInt(funcPtr, c.uintptrType, "")
|
||||
calleeValue = c.createRuntimeCall("makeGoroutine", []llvm.Value{calleeValue}, "")
|
||||
calleeValue = c.builder.CreateIntToPtr(calleeValue, funcPtr.Type(), "")
|
||||
c.createCall(calleeValue, append(params, llvm.ConstPointerNull(c.i8ptrType)), "")
|
||||
callee = c.builder.CreatePtrToInt(funcPtr, c.uintptrType, "")
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
c.createCall(c.mod.NamedFunction("internal/task.start"), []llvm.Value{callee, paramBundle, llvm.Undef(c.i8ptrType), llvm.ConstPointerNull(c.i8ptrType)}, "")
|
||||
return llvm.Undef(funcPtr.Type().ElementType().ReturnType())
|
||||
}
|
||||
|
||||
|
||||
+27
-8
@@ -31,6 +31,9 @@ func (c *Compiler) Optimize(optLevel, sizeLevel int, inlinerThreshold uint) []er
|
||||
}
|
||||
}
|
||||
|
||||
// Replace callMain placeholder with actual main function.
|
||||
c.mod.NamedFunction("runtime.callMain").ReplaceAllUsesWith(c.mod.NamedFunction(c.ir.MainPkg().Pkg.Path() + ".main"))
|
||||
|
||||
// Run function passes for each function.
|
||||
funcPasses := llvm.NewFunctionPassManagerForModule(c.mod)
|
||||
defer funcPasses.Dispose()
|
||||
@@ -92,25 +95,41 @@ func (c *Compiler) Optimize(optLevel, sizeLevel int, inlinerThreshold uint) []er
|
||||
}
|
||||
}
|
||||
|
||||
err := c.LowerGoroutines()
|
||||
if err != nil {
|
||||
return []error{err}
|
||||
}
|
||||
} else {
|
||||
// Must be run at any optimization level.
|
||||
transform.LowerInterfaces(c.mod)
|
||||
if c.funcImplementation() == funcValueSwitch {
|
||||
transform.LowerFuncValues(c.mod)
|
||||
}
|
||||
err := c.LowerGoroutines()
|
||||
if err != nil {
|
||||
return []error{err}
|
||||
}
|
||||
errs := transform.LowerInterrupts(c.mod)
|
||||
if len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
}
|
||||
|
||||
// Lower async implementations.
|
||||
switch c.Scheduler() {
|
||||
case "coroutines":
|
||||
// Lower async as coroutines.
|
||||
err := transform.LowerCoroutines(c.mod, c.NeedsStackObjects())
|
||||
if err != nil {
|
||||
return []error{err}
|
||||
}
|
||||
case "tasks":
|
||||
// No transformations necessary.
|
||||
case "none":
|
||||
// Check for any goroutine starts.
|
||||
if start := c.mod.NamedFunction("internal/task.start"); !start.IsNil() && len(getUses(start)) > 0 {
|
||||
errs := []error{}
|
||||
for _, call := range getUses(start) {
|
||||
errs = append(errs, errorAt(call, "attempted to start a goroutine without a scheduler"))
|
||||
}
|
||||
return errs
|
||||
}
|
||||
default:
|
||||
return []error{errors.New("invalid scheduler")}
|
||||
}
|
||||
|
||||
if c.VerifyIR() {
|
||||
if errs := c.checkModule(); errs != nil {
|
||||
return errs
|
||||
|
||||
Reference in New Issue
Block a user