mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-07-26 06:38:42 +00:00
5ec2632461
getFunction and getLLVMFunctionType duplicate the construction of LLVM result types for functions with zero, one, or multiple results. Move this code to getLLVMResultType. Also split the existing parameter expansion code into expandDirectFormalParamType so callers can request the current flattened parameter types directly.
118 lines
3.8 KiB
Go
118 lines
3.8 KiB
Go
package compiler
|
|
|
|
// This file implements function values and closures. It may need some lowering
|
|
// in a later step, see func-lowering.go.
|
|
|
|
import (
|
|
"go/types"
|
|
|
|
"golang.org/x/tools/go/ssa"
|
|
"tinygo.org/x/go-llvm"
|
|
)
|
|
|
|
func (c *compilerContext) getLLVMResultType(sig *types.Signature) llvm.Type {
|
|
switch sig.Results().Len() {
|
|
case 0:
|
|
return c.ctx.VoidType()
|
|
case 1:
|
|
return c.getLLVMType(sig.Results().At(0).Type())
|
|
default:
|
|
results := make([]llvm.Type, sig.Results().Len())
|
|
for i := range results {
|
|
results[i] = c.getLLVMType(sig.Results().At(i).Type())
|
|
}
|
|
return c.ctx.StructType(results, false)
|
|
}
|
|
}
|
|
|
|
// createFuncValue creates a function value from a raw function pointer with no
|
|
// context.
|
|
func (b *builder) createFuncValue(funcPtr, context llvm.Value, sig *types.Signature) llvm.Value {
|
|
// Closure is: {context, function pointer}
|
|
funcValueType := b.getFuncType(sig)
|
|
funcValue := llvm.Undef(funcValueType)
|
|
funcValue = b.CreateInsertValue(funcValue, context, 0, "")
|
|
funcValue = b.CreateInsertValue(funcValue, funcPtr, 1, "")
|
|
return funcValue
|
|
}
|
|
|
|
// extractFuncScalar returns some scalar that can be used in comparisons. It is
|
|
// a cheap operation.
|
|
func (b *builder) extractFuncScalar(funcValue llvm.Value) llvm.Value {
|
|
return b.CreateExtractValue(funcValue, 1, "")
|
|
}
|
|
|
|
// extractFuncContext extracts the context pointer from this function value. It
|
|
// is a cheap operation.
|
|
func (b *builder) extractFuncContext(funcValue llvm.Value) llvm.Value {
|
|
return b.CreateExtractValue(funcValue, 0, "")
|
|
}
|
|
|
|
// decodeFuncValue extracts the context and the function pointer from this func
|
|
// value.
|
|
func (b *builder) decodeFuncValue(funcValue llvm.Value) (funcPtr, context llvm.Value) {
|
|
context = b.CreateExtractValue(funcValue, 0, "")
|
|
funcPtr = b.CreateExtractValue(funcValue, 1, "")
|
|
return
|
|
}
|
|
|
|
// getFuncType returns the type of a func value given a signature.
|
|
func (c *compilerContext) getFuncType(typ *types.Signature) llvm.Type {
|
|
return c.ctx.StructType([]llvm.Type{c.dataPtrType, c.funcPtrType}, false)
|
|
}
|
|
|
|
// getLLVMFunctionType returns a LLVM function type for a given signature.
|
|
func (c *compilerContext) getLLVMFunctionType(typ *types.Signature) llvm.Type {
|
|
returnType := c.getLLVMResultType(typ)
|
|
|
|
// Get the parameter types.
|
|
var paramTypes []llvm.Type
|
|
if typ.Recv() != nil {
|
|
recv := c.getLLVMType(typ.Recv().Type())
|
|
if recv.StructName() == "runtime._interface" {
|
|
// This is a call on an interface, not a concrete type.
|
|
// The receiver is not an interface, but a i8* type.
|
|
recv = c.dataPtrType
|
|
}
|
|
for _, info := range c.expandFormalParamType(recv, "", nil) {
|
|
paramTypes = append(paramTypes, info.llvmType)
|
|
}
|
|
}
|
|
for v := range typ.Params().Variables() {
|
|
subType := c.getLLVMType(v.Type())
|
|
for _, info := range c.expandFormalParamType(subType, "", nil) {
|
|
paramTypes = append(paramTypes, info.llvmType)
|
|
}
|
|
}
|
|
// All functions take these parameters at the end.
|
|
paramTypes = append(paramTypes, c.dataPtrType) // context
|
|
|
|
// Make a func type out of the signature.
|
|
return llvm.FunctionType(returnType, paramTypes, false)
|
|
}
|
|
|
|
// parseMakeClosure makes a function value (with context) from the given
|
|
// closure expression.
|
|
func (b *builder) parseMakeClosure(expr *ssa.MakeClosure) (llvm.Value, error) {
|
|
if len(expr.Bindings) == 0 {
|
|
panic("unexpected: MakeClosure without bound variables")
|
|
}
|
|
f := expr.Fn.(*ssa.Function)
|
|
|
|
// Collect all bound variables.
|
|
boundVars := make([]llvm.Value, len(expr.Bindings))
|
|
for i, binding := range expr.Bindings {
|
|
// The context stores the bound variables.
|
|
llvmBoundVar := b.getValue(binding, getPos(expr))
|
|
boundVars[i] = llvmBoundVar
|
|
}
|
|
|
|
// Store the bound variables in a single object, allocating it on the heap
|
|
// if necessary.
|
|
context := b.emitPointerPack(boundVars, expr.Pos())
|
|
|
|
// Create the closure.
|
|
_, fn := b.getFunction(f)
|
|
return b.createFuncValue(fn, context, f.Signature), nil
|
|
}
|