func.go raw

   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