Skip to content

Commit c1521fe

Browse files
aykevldeadprogram
authored andcommitted
compiler: refactor starting new goroutines
1 parent 405ec2a commit c1521fe

File tree

2 files changed

+25
-28
lines changed

2 files changed

+25
-28
lines changed

compiler/compiler.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,7 +1071,7 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) {
10711071
panic("StaticCallee returned an unexpected value")
10721072
}
10731073
params = append(params, context) // context parameter
1074-
c.emitStartGoroutine(calleeFn.LLVMFn, params)
1074+
frame.createGoInstruction(calleeFn.LLVMFn, params)
10751075
} else if !instr.Call.IsInvoke() {
10761076
// This is a function pointer.
10771077
// At the moment, two extra params are passed to the newly started
@@ -1089,7 +1089,7 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) {
10891089
default:
10901090
panic("unknown scheduler type")
10911091
}
1092-
c.emitStartGoroutine(funcPtr, params)
1092+
frame.createGoInstruction(funcPtr, params)
10931093
} else {
10941094
c.addError(instr.Pos(), "todo: go on interface call")
10951095
}

compiler/goroutine.go

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,30 @@ package compiler
33
// This file implements the 'go' keyword to start a new goroutine. See
44
// goroutine-lowering.go for more details.
55

6-
import "tinygo.org/x/go-llvm"
6+
import (
7+
"github.com/tinygo-org/tinygo/compiler/llvmutil"
8+
"tinygo.org/x/go-llvm"
9+
)
710

8-
// emitStartGoroutine starts a new goroutine with the provided function pointer
11+
// createGoInstruction starts a new goroutine with the provided function pointer
912
// and parameters.
1013
// In general, you should pass all regular parameters plus the context parameter.
1114
// There is one exception: the task-based scheduler needs to have the function
1215
// pointer passed in as a parameter too in addition to the context.
1316
//
1417
// Because a go statement doesn't return anything, return undef.
15-
func (c *Compiler) emitStartGoroutine(funcPtr llvm.Value, params []llvm.Value) llvm.Value {
16-
paramBundle := c.emitPointerPack(params)
18+
func (b *builder) createGoInstruction(funcPtr llvm.Value, params []llvm.Value) llvm.Value {
19+
paramBundle := b.emitPointerPack(params)
1720
var callee llvm.Value
18-
switch c.Scheduler() {
21+
switch b.Scheduler() {
1922
case "none", "tasks":
20-
callee = c.createGoroutineStartWrapper(funcPtr)
23+
callee = b.createGoroutineStartWrapper(funcPtr)
2124
case "coroutines":
22-
callee = c.builder.CreatePtrToInt(funcPtr, c.uintptrType, "")
25+
callee = b.CreatePtrToInt(funcPtr, b.uintptrType, "")
2326
default:
2427
panic("unreachable")
2528
}
26-
c.createCall(c.mod.NamedFunction("internal/task.start"), []llvm.Value{callee, paramBundle, llvm.Undef(c.i8ptrType), llvm.ConstPointerNull(c.i8ptrType)}, "")
29+
b.createCall(b.mod.NamedFunction("internal/task.start"), []llvm.Value{callee, paramBundle, llvm.Undef(b.i8ptrType), llvm.ConstPointerNull(b.i8ptrType)}, "")
2730
return llvm.Undef(funcPtr.Type().ElementType().ReturnType())
2831
}
2932

@@ -45,36 +48,34 @@ func (c *Compiler) emitStartGoroutine(funcPtr llvm.Value, params []llvm.Value) l
4548
// allows a single (pointer) argument to the newly started goroutine. Also, it
4649
// ignores the return value because newly started goroutines do not have a
4750
// return value.
48-
func (c *Compiler) createGoroutineStartWrapper(fn llvm.Value) llvm.Value {
51+
func (c *compilerContext) createGoroutineStartWrapper(fn llvm.Value) llvm.Value {
4952
var wrapper llvm.Value
5053

54+
builder := c.ctx.NewBuilder()
55+
5156
if !fn.IsAFunction().IsNil() {
5257
// See whether this wrapper has already been created. If so, return it.
5358
name := fn.Name()
5459
wrapper = c.mod.NamedFunction(name + "$gowrapper")
5560
if !wrapper.IsNil() {
56-
return c.builder.CreatePtrToInt(wrapper, c.uintptrType, "")
61+
return llvm.ConstPtrToInt(wrapper, c.uintptrType)
5762
}
5863

59-
// Save the current position in the IR builder.
60-
currentBlock := c.builder.GetInsertBlock()
61-
defer c.builder.SetInsertPointAtEnd(currentBlock)
62-
6364
// Create the wrapper.
6465
wrapperType := llvm.FunctionType(c.ctx.VoidType(), []llvm.Type{c.i8ptrType}, false)
6566
wrapper = llvm.AddFunction(c.mod, name+"$gowrapper", wrapperType)
6667
wrapper.SetLinkage(llvm.PrivateLinkage)
6768
wrapper.SetUnnamedAddr(true)
6869
entry := c.ctx.AddBasicBlock(wrapper, "entry")
69-
c.builder.SetInsertPointAtEnd(entry)
70+
builder.SetInsertPointAtEnd(entry)
7071

7172
// Create the list of params for the call.
7273
paramTypes := fn.Type().ElementType().ParamTypes()
73-
params := c.emitPointerUnpack(wrapper.Param(0), paramTypes[:len(paramTypes)-1])
74+
params := llvmutil.EmitPointerUnpack(builder, c.mod, wrapper.Param(0), paramTypes[:len(paramTypes)-1])
7475
params = append(params, llvm.Undef(c.i8ptrType))
7576

7677
// Create the call.
77-
c.builder.CreateCall(fn, params, "")
78+
builder.CreateCall(fn, params, "")
7879

7980
} else {
8081
// For a function pointer like this:
@@ -94,22 +95,18 @@ func (c *Compiler) createGoroutineStartWrapper(fn llvm.Value) llvm.Value {
9495
// With a bit of luck, identical wrapper functions like these can be
9596
// merged into one.
9697

97-
// Save the current position in the IR builder.
98-
currentBlock := c.builder.GetInsertBlock()
99-
defer c.builder.SetInsertPointAtEnd(currentBlock)
100-
10198
// Create the wrapper.
10299
wrapperType := llvm.FunctionType(c.ctx.VoidType(), []llvm.Type{c.i8ptrType}, false)
103100
wrapper = llvm.AddFunction(c.mod, ".gowrapper", wrapperType)
104101
wrapper.SetLinkage(llvm.InternalLinkage)
105102
wrapper.SetUnnamedAddr(true)
106103
entry := c.ctx.AddBasicBlock(wrapper, "entry")
107-
c.builder.SetInsertPointAtEnd(entry)
104+
builder.SetInsertPointAtEnd(entry)
108105

109106
// Get the list of parameters, with the extra parameters at the end.
110107
paramTypes := fn.Type().ElementType().ParamTypes()
111108
paramTypes[len(paramTypes)-1] = fn.Type() // the last element is the function pointer
112-
params := c.emitPointerUnpack(wrapper.Param(0), paramTypes)
109+
params := llvmutil.EmitPointerUnpack(builder, c.mod, wrapper.Param(0), paramTypes)
113110

114111
// Get the function pointer.
115112
fnPtr := params[len(params)-1]
@@ -119,13 +116,13 @@ func (c *Compiler) createGoroutineStartWrapper(fn llvm.Value) llvm.Value {
119116
params[len(params)-1] = llvm.Undef(c.i8ptrType)
120117

121118
// Create the call.
122-
c.builder.CreateCall(fnPtr, params, "")
119+
builder.CreateCall(fnPtr, params, "")
123120
}
124121

125122
// Finish the function. Every basic block must end in a terminator, and
126123
// because goroutines never return a value we can simply return void.
127-
c.builder.CreateRetVoid()
124+
builder.CreateRetVoid()
128125

129126
// Return a ptrtoint of the wrapper, not the function itself.
130-
return c.builder.CreatePtrToInt(wrapper, c.uintptrType, "")
127+
return builder.CreatePtrToInt(wrapper, c.uintptrType, "")
131128
}

0 commit comments

Comments
 (0)