@@ -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