// tupleType returns a struct type with anonymous // fields with the specified types. func tupleType(fieldTypes ...types.Type) types.Type { vars := make([]*types.Var, len(fieldTypes)) for i, t := range fieldTypes { vars[i] = types.NewParam(0, nil, fmt.Sprintf("f%d", i), t) } return types.NewStruct(vars, nil) }
// ResultList = Type | ParamList . func (p *parser) parseResultList(pkg *types.Package) *types.Tuple { switch p.tok { case '<': return types.NewTuple(types.NewParam(token.NoPos, pkg, "", p.parseType(pkg))) case '(': params, _ := p.parseParamList(pkg) return params default: return nil } }
// Param = Name ["..."] Type . func (p *parser) parseParam(pkg *types.Package) (param *types.Var, isVariadic bool) { name := p.parseName() if p.tok == '.' { p.next() p.expect('.') p.expect('.') isVariadic = true } typ := p.parseType(pkg) if isVariadic { typ = types.NewSlice(typ) } param = types.NewParam(token.NoPos, pkg, name, typ) return }
// newVar creates a 'var' for use in a types.Tuple. func newVar(name string, typ types.Type) *types.Var { return types.NewParam(token.NoPos, nil, name, typ) }
// prepareCall returns the evaluated function and arguments. // // For builtins that may not be used in go/defer, prepareCall // will emits inline code. In this case, prepareCall returns // nil for fn and args, and returns a non-nil value for result. func (fr *frame) prepareCall(instr ssa.CallInstruction) (fn *LLVMValue, args []*LLVMValue, result *LLVMValue) { call := instr.Common() args = make([]*LLVMValue, len(call.Args)) for i, arg := range call.Args { args[i] = fr.value(arg) } if call.IsInvoke() { fn := fr.interfaceMethod(fr.value(call.Value), call.Method) return fn, args, nil } switch v := call.Value.(type) { case *ssa.Builtin: // handled below case *ssa.Function: // Function handled specially; value() will convert // a function to one with a context argument. fn = fr.resolveFunction(v) pair := llvm.ConstNull(fr.llvmtypes.ToLLVM(fn.Type())) pair = llvm.ConstInsertValue(pair, fn.LLVMValue(), []uint32{0}) fn = fr.NewValue(pair, fn.Type()) return fn, args, nil default: fn = fr.value(call.Value) return fn, args, nil } // Builtins may only be used in calls (i.e. can't be assigned), // and only print[ln], panic and recover may be used in go/defer. builtin := call.Value.(*ssa.Builtin) switch builtin.Name() { case "print", "println": // print/println generates a call-site specific anonymous // function to print the values. It's not inline because // print/println may be deferred. params := make([]*types.Var, len(call.Args)) for i, arg := range call.Args { // make sure to use args[i].Type(), not call.Args[i].Type(), // as the evaluated expression converts untyped. params[i] = types.NewParam(arg.Pos(), nil, arg.Name(), args[i].Type()) } sig := types.NewSignature(nil, nil, types.NewTuple(params...), nil, false) llfntyp := fr.llvmtypes.ToLLVM(sig) llfnptr := llvm.AddFunction(fr.module.Module, "", llfntyp.StructElementTypes()[0].ElementType()) currBlock := fr.builder.GetInsertBlock() entry := llvm.AddBasicBlock(llfnptr, "entry") fr.builder.SetInsertPointAtEnd(entry) internalArgs := make([]Value, len(args)) for i, arg := range args { internalArgs[i] = fr.NewValue(llfnptr.Param(i), arg.Type()) } fr.printValues(builtin.Name() == "println", internalArgs...) fr.builder.CreateRetVoid() fr.builder.SetInsertPointAtEnd(currBlock) return fr.NewValue(llfnptr, sig), args, nil case "panic": panic("TODO: panic") case "recover": // TODO(axw) determine number of frames to skip in pc check indirect := fr.NewValue(llvm.ConstNull(llvm.Int32Type()), types.Typ[types.Int32]) return fr.runtime.recover_, []*LLVMValue{indirect}, nil case "append": return nil, nil, fr.callAppend(args[0], args[1]) case "close": return fr.runtime.chanclose, args, nil case "cap": return nil, nil, fr.callCap(args[0]) case "len": return nil, nil, fr.callLen(args[0]) case "copy": return nil, nil, fr.callCopy(args[0], args[1]) case "delete": fr.callDelete(args[0], args[1]) return nil, nil, nil case "real": return nil, nil, args[0].extractComplexComponent(0) case "imag": return nil, nil, args[0].extractComplexComponent(1) case "complex": r := args[0].LLVMValue() i := args[1].LLVMValue() typ := instr.Value().Type() cmplx := llvm.Undef(fr.llvmtypes.ToLLVM(typ)) cmplx = fr.builder.CreateInsertValue(cmplx, r, 0, "") cmplx = fr.builder.CreateInsertValue(cmplx, i, 1, "") return nil, nil, fr.NewValue(cmplx, typ) default: panic("unimplemented: " + builtin.Name()) } }
func (c *compiler) VisitFuncLit(lit *ast.FuncLit) Value { ftyp := c.typeinfo.Types[lit].(*types.Signature) // Walk the function literal, promoting stack vars not defined // in the function literal, and storing the ident's for non-const // values not declared in the function literal. // // (First, set a dummy "stack" value for the params and results.) var dummyfunc LLVMValue dummyfunc.stack = &dummyfunc paramVars := ftyp.Params() resultVars := ftyp.Results() c.functions.push(&function{ LLVMValue: &dummyfunc, results: resultVars, }) v := &identVisitor{compiler: c} ast.Walk(v, lit.Body) c.functions.pop() // Create closure by adding a context parameter to the function, // and bind it with the values of the stack vars found in the // step above. origfnpairtyp := c.types.ToLLVM(ftyp) fnpairtyp := origfnpairtyp fntyp := origfnpairtyp.StructElementTypes()[0].ElementType() if v.captures != nil { // Add the additional context param. ctxfields := make([]*types.Var, len(v.captures)) for i, capturevar := range v.captures { p := capturevar.Pkg() n := capturevar.Name() t := types.NewPointer(capturevar.Type()) ctxfields[i] = types.NewParam(token.NoPos, p, n, t) } ctxtyp := types.NewPointer(types.NewStruct(ctxfields, nil)) llvmctxtyp := c.types.ToLLVM(ctxtyp) rettyp := fntyp.ReturnType() paramtyps := append([]llvm.Type{llvmctxtyp}, fntyp.ParamTypes()...) vararg := fntyp.IsFunctionVarArg() fntyp = llvm.FunctionType(rettyp, paramtyps, vararg) opaqueptrtyp := origfnpairtyp.StructElementTypes()[1] elttyps := []llvm.Type{llvm.PointerType(fntyp, 0), opaqueptrtyp} fnpairtyp = llvm.StructType(elttyps, false) } fnptr := llvm.AddFunction(c.module.Module, "", fntyp) fnvalue := llvm.ConstNull(fnpairtyp) fnvalue = llvm.ConstInsertValue(fnvalue, fnptr, []uint32{0}) currBlock := c.builder.GetInsertBlock() f := c.NewValue(fnvalue, ftyp) captureVars := types.NewTuple(v.captures...) c.buildFunction(f, captureVars, paramVars, resultVars, lit.Body) // Closure? Bind values to a context block. if v.captures != nil { // Store the free variables in the heap allocated block. block := c.createTypeMalloc(fntyp.ParamTypes()[0].ElementType()) for i, contextvar := range v.captures { value := c.objectdata[contextvar].Value blockPtr := c.builder.CreateStructGEP(block, i, "") c.builder.CreateStore(value.pointer.LLVMValue(), blockPtr) } // Cast the function pointer type back to the original // type, without the context parameter. fnptr = llvm.ConstBitCast(fnptr, origfnpairtyp.StructElementTypes()[0]) fnvalue = llvm.Undef(origfnpairtyp) fnvalue = llvm.ConstInsertValue(fnvalue, fnptr, []uint32{0}) // Set the context value. i8ptr := llvm.PointerType(llvm.Int8Type(), 0) block = c.builder.CreateBitCast(block, i8ptr, "") fnvalue = c.builder.CreateInsertValue(fnvalue, block, 1, "") f.value = fnvalue } else { c.builder.SetInsertPointAtEnd(currBlock) } return f }