func.go raw

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