1 package compiler
2 3 // This file implements function values and closures. It may need some lowering
4 // in a later step, see func-lowering.go.
5 6 import (
7 "go/types"
8 9 "golang.org/x/tools/go/ssa"
10 "tinygo.org/x/go-llvm"
11 )
12 13 // createFuncValue creates a function value from a raw function pointer with no
14 // context.
15 func (b *builder) createFuncValue(funcPtr, context llvm.Value, sig *types.Signature) llvm.Value {
16 // Closure is: {context, function pointer}
17 funcValueType := b.getFuncType(sig)
18 funcValue := llvm.Undef(funcValueType)
19 funcValue = b.CreateInsertValue(funcValue, context, 0, "")
20 funcValue = b.CreateInsertValue(funcValue, funcPtr, 1, "")
21 return funcValue
22 }
23 24 // extractFuncScalar returns some scalar that can be used in comparisons. It is
25 // a cheap operation.
26 func (b *builder) extractFuncScalar(funcValue llvm.Value) llvm.Value {
27 return b.CreateExtractValue(funcValue, 1, "")
28 }
29 30 // extractFuncContext extracts the context pointer from this function value. It
31 // is a cheap operation.
32 func (b *builder) extractFuncContext(funcValue llvm.Value) llvm.Value {
33 return b.CreateExtractValue(funcValue, 0, "")
34 }
35 36 // decodeFuncValue extracts the context and the function pointer from this func
37 // value.
38 func (b *builder) decodeFuncValue(funcValue llvm.Value) (funcPtr, context llvm.Value) {
39 context = b.CreateExtractValue(funcValue, 0, "")
40 funcPtr = b.CreateExtractValue(funcValue, 1, "")
41 return
42 }
43 44 // getFuncType returns the type of a func value given a signature.
45 func (c *compilerContext) getFuncType(typ *types.Signature) llvm.Type {
46 return c.ctx.StructType([]llvm.Type{c.dataPtrType, c.funcPtrType}, false)
47 }
48 49 // getLLVMFunctionType returns a LLVM function type for a given signature.
50 func (c *compilerContext) getLLVMFunctionType(typ *types.Signature) llvm.Type {
51 // Get the return type.
52 var returnType llvm.Type
53 switch typ.Results().Len() {
54 case 0:
55 // No return values.
56 returnType = c.ctx.VoidType()
57 case 1:
58 // Just one return value.
59 returnType = c.getLLVMType(typ.Results().At(0).Type())
60 default:
61 // Multiple return values. Put them together in a struct.
62 // This appears to be the common way to handle multiple return values in
63 // LLVM.
64 members := make([]llvm.Type, typ.Results().Len())
65 for i := 0; i < typ.Results().Len(); i++ {
66 members[i] = c.getLLVMType(typ.Results().At(i).Type())
67 }
68 returnType = c.ctx.StructType(members, false)
69 }
70 71 // Get the parameter types.
72 var paramTypes []llvm.Type
73 if typ.Recv() != nil {
74 recv := c.getLLVMType(typ.Recv().Type())
75 if recv.StructName() == "runtime._interface" {
76 // This is a call on an interface, not a concrete type.
77 // The receiver is not an interface, but a i8* type.
78 recv = c.dataPtrType
79 }
80 for _, info := range c.expandFormalParamType(recv, "", nil) {
81 paramTypes = append(paramTypes, info.llvmType)
82 }
83 }
84 for i := 0; i < typ.Params().Len(); i++ {
85 subType := c.getLLVMType(typ.Params().At(i).Type())
86 for _, info := range c.expandFormalParamType(subType, "", nil) {
87 paramTypes = append(paramTypes, info.llvmType)
88 }
89 }
90 // All functions take these parameters at the end.
91 paramTypes = append(paramTypes, c.dataPtrType) // context
92 93 // Make a func type out of the signature.
94 return llvm.FunctionType(returnType, paramTypes, false)
95 }
96 97 // parseMakeClosure makes a function value (with context) from the given
98 // closure expression.
99 func (b *builder) parseMakeClosure(expr *ssa.MakeClosure) (llvm.Value, error) {
100 if len(expr.Bindings) == 0 {
101 panic("unexpected: MakeClosure without bound variables")
102 }
103 f := expr.Fn.(*ssa.Function)
104 105 // Collect all bound variables.
106 boundVars := make([]llvm.Value, len(expr.Bindings))
107 for i, binding := range expr.Bindings {
108 // The context stores the bound variables.
109 llvmBoundVar := b.getValue(binding, getPos(expr))
110 boundVars[i] = llvmBoundVar
111 }
112 113 // Store the bound variables in a single object, allocating it on the heap
114 // if necessary.
115 context := b.emitPointerPack(boundVars)
116 117 // Create the closure.
118 _, fn := b.getFunction(f)
119 return b.createFuncValue(fn, context, f.Signature), nil
120 }
121