func (c *compiler) VisitIfStmt(stmt *ast.IfStmt) { currBlock := c.builder.GetInsertBlock() resumeBlock := llvm.AddBasicBlock(currBlock.Parent(), "endif") resumeBlock.MoveAfter(currBlock) defer c.builder.SetInsertPointAtEnd(resumeBlock) var ifBlock, elseBlock llvm.BasicBlock if stmt.Else != nil { elseBlock = llvm.InsertBasicBlock(resumeBlock, "else") ifBlock = llvm.InsertBasicBlock(elseBlock, "if") } else { ifBlock = llvm.InsertBasicBlock(resumeBlock, "if") } if stmt.Else == nil { elseBlock = resumeBlock } if stmt.Init != nil { c.VisitStmt(stmt.Init) } cond_val := c.VisitExpr(stmt.Cond) c.builder.CreateCondBr(cond_val.LLVMValue(), ifBlock, elseBlock) c.builder.SetInsertPointAtEnd(ifBlock) c.VisitBlockStmt(stmt.Body, false) c.maybeImplicitBranch(resumeBlock) if stmt.Else != nil { c.builder.SetInsertPointAtEnd(elseBlock) c.VisitStmt(stmt.Else) c.maybeImplicitBranch(resumeBlock) } }
// Binary logical operators are handled specially, outside of the Value // type, because of the need to perform lazy evaluation. // // Binary logical operators are implemented using a Phi node, which takes // on the appropriate value depending on which basic blocks branch to it. func (c *compiler) compileLogicalOp(op token.Token, lhs Value, rhsFunc func() Value) Value { lhsBlock := c.builder.GetInsertBlock() resultBlock := llvm.AddBasicBlock(lhsBlock.Parent(), "") resultBlock.MoveAfter(lhsBlock) rhsBlock := llvm.InsertBasicBlock(resultBlock, "") falseBlock := llvm.InsertBasicBlock(resultBlock, "") if op == token.LOR { c.builder.CreateCondBr(lhs.LLVMValue(), resultBlock, rhsBlock) } else { c.builder.CreateCondBr(lhs.LLVMValue(), rhsBlock, falseBlock) } c.builder.SetInsertPointAtEnd(rhsBlock) rhs := rhsFunc() rhsBlock = c.builder.GetInsertBlock() // rhsFunc may create blocks c.builder.CreateCondBr(rhs.LLVMValue(), resultBlock, falseBlock) c.builder.SetInsertPointAtEnd(falseBlock) c.builder.CreateBr(resultBlock) c.builder.SetInsertPointAtEnd(resultBlock) result := c.builder.CreatePHI(llvm.Int1Type(), "") trueValue := llvm.ConstAllOnes(llvm.Int1Type()) falseValue := llvm.ConstNull(llvm.Int1Type()) var values []llvm.Value var blocks []llvm.BasicBlock if op == token.LOR { values = []llvm.Value{trueValue, trueValue, falseValue} blocks = []llvm.BasicBlock{lhsBlock, rhsBlock, falseBlock} } else { values = []llvm.Value{trueValue, falseValue} blocks = []llvm.BasicBlock{rhsBlock, falseBlock} } result.AddIncoming(values, blocks) return c.NewLLVMValue(result, types.Bool) }
// contextFunction creates a wrapper function that // has the same signature as the specified function, // but has an additional first parameter that accepts // and ignores the function context value. // // contextFunction must be called with a global function // pointer. func contextFunction(c *compiler, f *LLVMValue) *LLVMValue { defer c.builder.SetInsertPointAtEnd(c.builder.GetInsertBlock()) resultType := c.llvmtypes.ToLLVM(f.Type()) fnptr := f.LLVMValue() contextType := resultType.StructElementTypes()[1] llfntyp := fnptr.Type().ElementType() llfntyp = llvm.FunctionType( llfntyp.ReturnType(), append([]llvm.Type{contextType}, llfntyp.ParamTypes()...), llfntyp.IsFunctionVarArg(), ) wrapper := llvm.AddFunction(c.module.Module, fnptr.Name()+".ctx", llfntyp) wrapper.SetLinkage(llvm.PrivateLinkage) entry := llvm.AddBasicBlock(wrapper, "entry") c.builder.SetInsertPointAtEnd(entry) args := make([]llvm.Value, len(llfntyp.ParamTypes())-1) for i := range args { args[i] = wrapper.Param(i + 1) } result := c.builder.CreateCall(fnptr, args, "") switch nresults := f.Type().(*types.Signature).Results().Len(); nresults { case 0: c.builder.CreateRetVoid() case 1: c.builder.CreateRet(result) default: results := make([]llvm.Value, nresults) for i := range results { results[i] = c.builder.CreateExtractValue(result, i, "") } c.builder.CreateAggregateRet(results) } return c.NewValue(wrapper, f.Type()) }
func (c *compiler) defineMemcpyFunction(fn llvm.Value) { entry := llvm.AddBasicBlock(fn, "entry") c.builder.SetInsertPointAtEnd(entry) dst, src, size := fn.Param(0), fn.Param(1), fn.Param(2) pint8 := llvm.PointerType(llvm.Int8Type(), 0) dst = c.builder.CreateIntToPtr(dst, pint8, "") src = c.builder.CreateIntToPtr(src, pint8, "") sizeType := size.Type() sizeBits := sizeType.IntTypeWidth() memcpyName := "llvm.memcpy.p0i8.p0i8.i" + strconv.Itoa(sizeBits) memcpy := c.module.NamedFunction(memcpyName) if memcpy.IsNil() { paramtypes := []llvm.Type{ pint8, pint8, size.Type(), llvm.Int32Type(), llvm.Int1Type()} memcpyType := llvm.FunctionType(llvm.VoidType(), paramtypes, false) memcpy = llvm.AddFunction(c.module.Module, memcpyName, memcpyType) } args := []llvm.Value{ dst, src, size, llvm.ConstInt(llvm.Int32Type(), 1, false), // single byte alignment llvm.ConstInt(llvm.Int1Type(), 0, false), // not volatile } c.builder.CreateCall(memcpy, args, "") c.builder.CreateRetVoid() }
func (c *compiler) defineFreeFunction(fn llvm.Value) { entry := llvm.AddBasicBlock(fn, "entry") c.builder.SetInsertPointAtEnd(entry) ptr := fn.FirstParam() ptrtyp := llvm.PointerType(llvm.Int8Type(), 0) c.builder.CreateFree(c.builder.CreateIntToPtr(ptr, ptrtyp, "")) c.builder.CreateRetVoid() }
// promoteMethod promotes a named type's method to another type // which has embedded the named type. func (c *compiler) promoteMethod(m *types.Func, recv types.Type, indices []int) types.Object { var pkg *types.Package if recv, ok := recv.(*types.Named); ok { pkg = c.objectdata[recv.Obj()].Package } recvvar := types.NewVar(pkg, "", recv) sig := m.Type().(*types.Signature) sig = types.NewSignature(recvvar, sig.Params(), sig.Results(), sig.IsVariadic()) f := &synthFunc{pkg: pkg, name: m.Name(), typ: sig} ident := ast.NewIdent(f.Name()) var isptr bool if ptr, ok := recv.(*types.Pointer); ok { isptr = true recv = ptr.Elem() } c.objects[ident] = f c.objectdata[f] = &ObjectData{Ident: ident, Package: pkg} if pkg == nil || pkg == c.pkg { if currblock := c.builder.GetInsertBlock(); !currblock.IsNil() { defer c.builder.SetInsertPointAtEnd(currblock) } llvmfn := c.Resolve(ident).LLVMValue() llvmfn = c.builder.CreateExtractValue(llvmfn, 0, "") llvmfn.SetLinkage(llvm.LinkOnceODRLinkage) entry := llvm.AddBasicBlock(llvmfn, "entry") c.builder.SetInsertPointAtEnd(entry) realfn := c.Resolve(c.objectdata[m].Ident).LLVMValue() realfn = c.builder.CreateExtractValue(realfn, 0, "") args := llvmfn.Params() recvarg := args[0] if !isptr { ptr := c.builder.CreateAlloca(recvarg.Type(), "") c.builder.CreateStore(recvarg, ptr) recvarg = ptr } for _, i := range indices { if i == -1 { recvarg = c.builder.CreateLoad(recvarg, "") } else { recvarg = c.builder.CreateStructGEP(recvarg, i, "") } } args[0] = recvarg result := c.builder.CreateCall(realfn, args, "") if sig.Results().Len() == 0 { c.builder.CreateRetVoid() } else { c.builder.CreateRet(result) } } return f }
func (c *compiler) VisitForStmt(stmt *ast.ForStmt) { currBlock := c.builder.GetInsertBlock() doneBlock := llvm.AddBasicBlock(currBlock.Parent(), "done") doneBlock.MoveAfter(currBlock) loopBlock := llvm.InsertBasicBlock(doneBlock, "loop") defer c.builder.SetInsertPointAtEnd(doneBlock) condBlock := loopBlock if stmt.Cond != nil { condBlock = llvm.InsertBasicBlock(loopBlock, "cond") } postBlock := condBlock if stmt.Post != nil { postBlock = llvm.InsertBasicBlock(doneBlock, "post") } if c.lastlabel != nil { labelData := c.labelData(c.lastlabel) labelData.Break = doneBlock labelData.Continue = postBlock c.lastlabel = nil } c.breakblocks = append(c.breakblocks, doneBlock) c.continueblocks = append(c.continueblocks, postBlock) defer func() { c.breakblocks = c.breakblocks[:len(c.breakblocks)-1] c.continueblocks = c.continueblocks[:len(c.continueblocks)-1] }() // Is there an initializer? Create a new scope and visit the statement. if stmt.Init != nil { c.VisitStmt(stmt.Init) } // Start the loop. if stmt.Cond != nil { c.builder.CreateBr(condBlock) c.builder.SetInsertPointAtEnd(condBlock) condVal := c.VisitExpr(stmt.Cond) c.builder.CreateCondBr(condVal.LLVMValue(), loopBlock, doneBlock) } else { c.builder.CreateBr(loopBlock) } // Post. if stmt.Post != nil { c.builder.SetInsertPointAtEnd(postBlock) c.VisitStmt(stmt.Post) c.builder.CreateBr(condBlock) } // Loop body. c.builder.SetInsertPointAtEnd(loopBlock) c.VisitBlockStmt(stmt.Body, false) c.maybeImplicitBranch(postBlock) }
func (c *compiler) createMainFunction() error { // In a PNaCl program (plugin), there should not be a "main.main"; // instead, we expect a "main.CreateModule" function. // See pkg/nacl/ppapi/ppapi.go for more details. mainMain := c.module.NamedFunction("main.main") if c.pnacl { // PNaCl's libppapi_stub.a implements "main", which simply // calls through to PpapiPluginMain. We define our own "main" // so that we can capture argc/argv. if !mainMain.IsNil() { return fmt.Errorf("Found main.main") } pluginMain := c.NamedFunction("PpapiPluginMain", "func() int32") // Synthesise a main which has no return value. We could cast // PpapiPluginMain, but this is potentially unsafe as its // calling convention is unspecified. ftyp := llvm.FunctionType(llvm.VoidType(), nil, false) mainMain = llvm.AddFunction(c.module.Module, "main.main", ftyp) entry := llvm.AddBasicBlock(mainMain, "entry") c.builder.SetInsertPointAtEnd(entry) c.builder.CreateCall(pluginMain, nil, "") c.builder.CreateRetVoid() } else { mainMain = c.module.NamedFunction("main.main") } if mainMain.IsNil() { return fmt.Errorf("Could not find main.main") } // runtime.main is called by main, with argc, argv, argp, // and a pointer to main.main, which must be a niladic // function with no result. runtimeMain := c.NamedFunction("runtime.main", "func(int32, **byte, **byte, *int8) int32") main := c.NamedFunction("main", "func(int32, **byte, **byte) int32") c.builder.SetCurrentDebugLocation(c.debug_info.MDNode(nil)) entry := llvm.AddBasicBlock(main, "entry") c.builder.SetInsertPointAtEnd(entry) mainMain = c.builder.CreateBitCast(mainMain, runtimeMain.Type().ElementType().ParamTypes()[3], "") args := []llvm.Value{main.Param(0), main.Param(1), main.Param(2), mainMain} result := c.builder.CreateCall(runtimeMain, args, "") c.builder.CreateRet(result) return nil }
func (c *compiler) defineMallocFunction(fn llvm.Value) { entry := llvm.AddBasicBlock(fn, "entry") c.builder.SetInsertPointAtEnd(entry) size := fn.FirstParam() ptr := c.builder.CreateArrayMalloc(llvm.Int8Type(), size, "") // XXX memset to zero, or leave that to Go runtime code? fn_type := fn.Type().ElementType() result := c.builder.CreatePtrToInt(ptr, fn_type.ReturnType(), "") c.builder.CreateRet(result) }
func (c *compiler) labelData(label *ast.Ident) *LabelData { data, ok := label.Obj.Data.(*LabelData) if !ok { bb := c.builder.GetInsertBlock() data = &LabelData{} data.Goto = llvm.AddBasicBlock(bb.Parent(), label.Name) label.Obj.Data = data } return data }
func (c *compiler) VisitLabeledStmt(stmt *ast.LabeledStmt) { currBlock := c.builder.GetInsertBlock() labeledBlock, _ := stmt.Label.Obj.Data.(llvm.BasicBlock) if labeledBlock.IsNil() { labeledBlock = llvm.AddBasicBlock(currBlock.Parent(), stmt.Label.Name) stmt.Label.Obj.Data = labeledBlock } labeledBlock.MoveAfter(currBlock) c.builder.CreateBr(labeledBlock) c.builder.SetInsertPointAtEnd(labeledBlock) c.VisitStmt(stmt.Stmt) }
func (c *compiler) VisitForStmt(stmt *ast.ForStmt) { curr_block := c.builder.GetInsertBlock() var cond_block, loop_block, done_block llvm.BasicBlock if stmt.Cond != nil { cond_block = llvm.AddBasicBlock(curr_block.Parent(), "cond") } loop_block = llvm.AddBasicBlock(curr_block.Parent(), "loop") done_block = llvm.AddBasicBlock(curr_block.Parent(), "done") // Is there an initializer? Create a new scope and visit the statement. if stmt.Init != nil { c.PushScope() c.VisitStmt(stmt.Init) defer c.PopScope() } // Start the loop. if stmt.Cond != nil { c.builder.CreateBr(cond_block) c.builder.SetInsertPointAtEnd(cond_block) cond_val := c.VisitExpr(stmt.Cond) c.builder.CreateCondBr( cond_val.LLVMValue(), loop_block, done_block) } else { c.builder.CreateBr(loop_block) } // Loop body. c.builder.SetInsertPointAtEnd(loop_block) c.VisitBlockStmt(stmt.Body) if stmt.Post != nil { c.VisitStmt(stmt.Post) } if stmt.Cond != nil { c.builder.CreateBr(cond_block) } else { c.builder.CreateBr(loop_block) } c.builder.SetInsertPointAtEnd(done_block) }
func (c *compiler) VisitForStmt(stmt *ast.ForStmt) { currBlock := c.builder.GetInsertBlock() doneBlock := llvm.AddBasicBlock(currBlock.Parent(), "done") doneBlock.MoveAfter(currBlock) loopBlock := llvm.InsertBasicBlock(doneBlock, "loop") defer c.builder.SetInsertPointAtEnd(doneBlock) condBlock := loopBlock if stmt.Cond != nil { condBlock = llvm.InsertBasicBlock(loopBlock, "cond") } postBlock := condBlock if stmt.Post != nil { postBlock = llvm.InsertBasicBlock(doneBlock, "post") } // Is there an initializer? Create a new scope and visit the statement. if stmt.Init != nil { c.PushScope() c.VisitStmt(stmt.Init) defer c.PopScope() } // Start the loop. if stmt.Cond != nil { c.builder.CreateBr(condBlock) c.builder.SetInsertPointAtEnd(condBlock) condVal := c.VisitExpr(stmt.Cond) c.builder.CreateCondBr(condVal.LLVMValue(), loopBlock, doneBlock) } else { c.builder.CreateBr(loopBlock) } // Post. if stmt.Post != nil { c.builder.SetInsertPointAtEnd(postBlock) c.VisitStmt(stmt.Post) c.builder.CreateBr(condBlock) } // Loop body. c.builder.SetInsertPointAtEnd(loopBlock) c.VisitBlockStmt(stmt.Body) c.maybeImplicitBranch(postBlock) }
func (c *compiler) buildPtrRecvFunction(fn llvm.Value) llvm.Value { defer c.builder.SetInsertPointAtEnd(c.builder.GetInsertBlock()) ifname := "*" + fn.Name() ifn := c.module.Module.NamedFunction(ifname) fntyp := fn.Type().ElementType() entry := llvm.AddBasicBlock(ifn, "entry") c.builder.SetInsertPointAtEnd(entry) args := ifn.Params() args[0] = c.builder.CreateLoad(args[0], "recv") result := c.builder.CreateCall(fn, args, "") if fntyp.ReturnType().TypeKind() == llvm.VoidTypeKind { c.builder.CreateRetVoid() } else { c.builder.CreateRet(result) } return ifn }
func (c *compiler) VisitIfStmt(stmt *ast.IfStmt) { curr_block := c.builder.GetInsertBlock() resume_block := llvm.AddBasicBlock(curr_block.Parent(), "endif") resume_block.MoveAfter(curr_block) var if_block, else_block llvm.BasicBlock if stmt.Else != nil { else_block = llvm.InsertBasicBlock(resume_block, "else") if_block = llvm.InsertBasicBlock(else_block, "if") } else { if_block = llvm.InsertBasicBlock(resume_block, "if") } if stmt.Else == nil { else_block = resume_block } if stmt.Init != nil { c.PushScope() c.VisitStmt(stmt.Init) defer c.PopScope() } cond_val := c.VisitExpr(stmt.Cond) c.builder.CreateCondBr(cond_val.LLVMValue(), if_block, else_block) c.builder.SetInsertPointAtEnd(if_block) c.VisitBlockStmt(stmt.Body) if in := if_block.LastInstruction(); in.IsNil() || in.IsATerminatorInst().IsNil() { c.builder.CreateBr(resume_block) } if stmt.Else != nil { c.builder.SetInsertPointAtEnd(else_block) c.VisitStmt(stmt.Else) if in := else_block.LastInstruction(); in.IsNil() || in.IsATerminatorInst().IsNil() { c.builder.CreateBr(resume_block) } } // If there's a block after the "resume" block (i.e. a nested control // statement), then create a branch to it as the last instruction. c.builder.SetInsertPointAtEnd(resume_block) if last := resume_block.Parent().LastBasicBlock(); last != resume_block { c.builder.CreateBr(last) c.builder.SetInsertPointBefore(resume_block.FirstInstruction()) } }
// buildFunction takes a function Value, a list of parameters, and a body, // and generates code for the function. func (c *compiler) buildFunction(f *LLVMValue, params []*ast.Object, body *ast.BlockStmt) { ftyp := f.Type().(*types.Func) llvm_fn := f.LLVMValue() entry := llvm.AddBasicBlock(llvm_fn, "entry") c.builder.SetInsertPointAtEnd(entry) // Bind receiver, arguments and return values to their identifiers/objects. // We'll store each parameter on the stack so they're addressable. for i, obj := range params { if obj.Name != "" { value := llvm_fn.Param(i) typ := obj.Type.(types.Type) stackvalue := c.builder.CreateAlloca(c.types.ToLLVM(typ), obj.Name) c.builder.CreateStore(value, stackvalue) ptrvalue := c.NewLLVMValue(stackvalue, &types.Pointer{Base: typ}) stackvar := ptrvalue.makePointee() stackvar.stack = f obj.Data = stackvar } } // Allocate space on the stack for named results. for _, obj := range ftyp.Results { if obj.Name != "" { typ := obj.Type.(types.Type) llvmtyp := c.types.ToLLVM(typ) stackptr := c.builder.CreateAlloca(llvmtyp, obj.Name) c.builder.CreateStore(llvm.ConstNull(llvmtyp), stackptr) ptrvalue := c.NewLLVMValue(stackptr, &types.Pointer{Base: typ}) stackvar := ptrvalue.makePointee() stackvar.stack = f obj.Data = stackvar } } c.functions = append(c.functions, f) c.VisitBlockStmt(body, false) c.functions = c.functions[0 : len(c.functions)-1] last := llvm_fn.LastBasicBlock() if in := last.LastInstruction(); in.IsNil() || in.IsATerminatorInst().IsNil() { // Assume nil return type, AST should be checked first. c.builder.SetInsertPointAtEnd(last) c.builder.CreateRetVoid() } }
func (c *compiler) defineMemsetFunction(fn llvm.Value) { entry := llvm.AddBasicBlock(fn, "entry") c.builder.SetInsertPointAtEnd(entry) dst, fill, size := fn.Param(0), fn.Param(1), fn.Param(2) sizeType := size.Type() sizeBits := sizeType.IntTypeWidth() memsetName := "llvm.memset.p0i8.i" + strconv.Itoa(sizeBits) memset := c.NamedFunction(memsetName, "func f(dst *int8, fill byte, size uintptr, align int32, volatile bool)") pint8 := memset.Type().ElementType().ParamTypes()[0] dst = c.builder.CreateIntToPtr(dst, pint8, "") args := []llvm.Value{ dst, fill, size, llvm.ConstInt(llvm.Int32Type(), 1, false), // single byte alignment llvm.ConstInt(llvm.Int1Type(), 0, false), // not volatile } c.builder.CreateCall(memset, args, "") c.builder.CreateRetVoid() }
func (tm *TypeMap) interfaceFuncWrapper(f llvm.Value) llvm.Value { ftyp := f.Type().ElementType() paramTypes := ftyp.ParamTypes() recvType := paramTypes[0] paramTypes[0] = llvm.PointerType(llvm.Int8Type(), 0) newf := llvm.AddFunction(f.GlobalParent(), f.Name()+".ifn", llvm.FunctionType( ftyp.ReturnType(), paramTypes, ftyp.IsFunctionVarArg(), )) b := llvm.GlobalContext().NewBuilder() defer b.Dispose() entry := llvm.AddBasicBlock(newf, "entry") b.SetInsertPointAtEnd(entry) args := make([]llvm.Value, len(paramTypes)) for i := range paramTypes { args[i] = newf.Param(i) } recvBits := int(tm.target.TypeSizeInBits(recvType)) if recvBits > 0 { args[0] = b.CreatePtrToInt(args[0], tm.target.IntPtrType(), "") if args[0].Type().IntTypeWidth() > recvBits { args[0] = b.CreateTrunc(args[0], llvm.IntType(recvBits), "") } args[0] = coerce(b, args[0], recvType) } else { args[0] = llvm.ConstNull(recvType) } result := b.CreateCall(f, args, "") if result.Type().TypeKind() == llvm.VoidTypeKind { b.CreateRetVoid() } else { b.CreateRet(result) } return newf }
func (c *compiler) VisitBranchStmt(stmt *ast.BranchStmt) { // TODO handle labeled continue, break. switch stmt.Tok { case token.BREAK: block := c.breakblocks[len(c.breakblocks)-1] c.builder.CreateBr(block) case token.CONTINUE: block := c.continueblocks[len(c.continueblocks)-1] c.builder.CreateBr(block) case token.GOTO: block, _ := stmt.Label.Obj.Data.(llvm.BasicBlock) if block.IsNil() { f := c.builder.GetInsertBlock().Parent() block = llvm.AddBasicBlock(f, stmt.Label.Name) stmt.Label.Obj.Data = block } c.builder.CreateBr(block) default: // TODO implement goto, fallthrough panic("unimplemented: " + stmt.Tok.String()) } }
func (c *compiler) VisitFuncLit(lit *ast.FuncLit) Value { fn_type := c.VisitFuncType(lit.Type) fn := llvm.AddFunction(c.module.Module, "", c.types.ToLLVM(fn_type)) fn.SetFunctionCallConv(llvm.FastCallConv) defer c.builder.SetInsertPointAtEnd(c.builder.GetInsertBlock()) entry := llvm.AddBasicBlock(fn, "entry") c.builder.SetInsertPointAtEnd(entry) fn_value := c.NewLLVMValue(fn, fn_type) c.functions = append(c.functions, fn_value) c.VisitBlockStmt(lit.Body) if fn_type.Results == nil { lasti := entry.LastInstruction() if lasti.IsNil() || lasti.Opcode() != llvm.Ret { // Assume nil return type, AST should be checked first. c.builder.CreateRetVoid() } } c.functions = c.functions[0 : len(c.functions)-1] return fn_value }
// indirectFunction creates an indirect function from a // given function, suitable for use with "defer" and "go". func (c *compiler) indirectFunction(fn *LLVMValue, args []Value, dotdotdot bool) *LLVMValue { nilarytyp := &types.Signature{} if len(args) == 0 { val := fn.LLVMValue() ptr := c.builder.CreateExtractValue(val, 0, "") ctx := c.builder.CreateExtractValue(val, 1, "") fnval := llvm.Undef(c.types.ToLLVM(nilarytyp)) ptr = c.builder.CreateBitCast(ptr, fnval.Type().StructElementTypes()[0], "") ctx = c.builder.CreateBitCast(ctx, fnval.Type().StructElementTypes()[1], "") fnval = c.builder.CreateInsertValue(fnval, ptr, 0, "") fnval = c.builder.CreateInsertValue(fnval, ctx, 1, "") fn = c.NewValue(fnval, nilarytyp) return fn } // TODO check if function pointer is global. I suppose // the same can be done with the context ptr... fnval := fn.LLVMValue() fnptr := c.builder.CreateExtractValue(fnval, 0, "") ctx := c.builder.CreateExtractValue(fnval, 1, "") nctx := 1 // fnptr if !ctx.IsNull() { nctx++ // fnctx } i8ptr := llvm.PointerType(llvm.Int8Type(), 0) llvmargs := make([]llvm.Value, len(args)+nctx) llvmargtypes := make([]llvm.Type, len(args)+nctx) for i, arg := range args { llvmargs[i+nctx] = arg.LLVMValue() llvmargtypes[i+nctx] = llvmargs[i+nctx].Type() } llvmargtypes[0] = fnptr.Type() llvmargs[0] = fnptr if nctx > 1 { llvmargtypes[1] = ctx.Type() llvmargs[1] = ctx } structtyp := llvm.StructType(llvmargtypes, false) argstruct := c.createTypeMalloc(structtyp) for i, llvmarg := range llvmargs { argptr := c.builder.CreateGEP(argstruct, []llvm.Value{ llvm.ConstInt(llvm.Int32Type(), 0, false), llvm.ConstInt(llvm.Int32Type(), uint64(i), false)}, "") c.builder.CreateStore(llvmarg, argptr) } // Create a function that will take a pointer to a structure of the type // defined above, or no parameters if there are none to pass. fntype := llvm.FunctionType(llvm.VoidType(), []llvm.Type{argstruct.Type()}, false) indirectfn := llvm.AddFunction(c.module.Module, "", fntype) i8argstruct := c.builder.CreateBitCast(argstruct, i8ptr, "") currblock := c.builder.GetInsertBlock() c.builder.SetInsertPointAtEnd(llvm.AddBasicBlock(indirectfn, "entry")) argstruct = indirectfn.Param(0) for i := range llvmargs[nctx:] { argptr := c.builder.CreateGEP(argstruct, []llvm.Value{ llvm.ConstInt(llvm.Int32Type(), 0, false), llvm.ConstInt(llvm.Int32Type(), uint64(i+nctx), false)}, "") ptrtyp := types.NewPointer(args[i].Type()) args[i] = c.NewValue(argptr, ptrtyp).makePointee() } // Extract the function pointer. // TODO if function is a global, elide. fnval = llvm.Undef(fnval.Type()) fnptrptr := c.builder.CreateGEP(argstruct, []llvm.Value{ llvm.ConstInt(llvm.Int32Type(), 0, false), llvm.ConstInt(llvm.Int32Type(), 0, false)}, "") fnptr = c.builder.CreateLoad(fnptrptr, "") fnval = c.builder.CreateInsertValue(fnval, fnptr, 0, "") if nctx > 1 { ctxptr := c.builder.CreateGEP(argstruct, []llvm.Value{ llvm.ConstInt(llvm.Int32Type(), 0, false), llvm.ConstInt(llvm.Int32Type(), 1, false)}, "") ctx = c.builder.CreateLoad(ctxptr, "") fnval = c.builder.CreateInsertValue(fnval, ctx, 1, "") fn = c.NewValue(fnval, fn.Type()) } c.createCall(fn, args, dotdotdot, false) // Indirect function calls' return values are always ignored. c.builder.CreateRetVoid() c.builder.SetInsertPointAtEnd(currblock) fnval = llvm.Undef(c.types.ToLLVM(nilarytyp)) indirectfn = c.builder.CreateBitCast(indirectfn, fnval.Type().StructElementTypes()[0], "") fnval = c.builder.CreateInsertValue(fnval, indirectfn, 0, "") fnval = c.builder.CreateInsertValue(fnval, i8argstruct, 1, "") fn = c.NewValue(fnval, nilarytyp) return fn }
func (fr *frame) value(v ssa.Value) (result *LLVMValue) { switch v := v.(type) { case nil: return nil case *ssa.Function: result, ok := fr.funcvals[v] if ok { return result } // fr.globals[v] has the function in raw pointer form; // we must convert it to <f,ctx> form. If the function // does not have a receiver, then create a wrapper // function that has an additional "context" parameter. f := fr.resolveFunction(v) if v.Signature.Recv() == nil && len(v.FreeVars) == 0 { f = contextFunction(fr.compiler, f) } pair := llvm.ConstNull(fr.llvmtypes.ToLLVM(f.Type())) fnptr := llvm.ConstBitCast(f.LLVMValue(), pair.Type().StructElementTypes()[0]) pair = llvm.ConstInsertValue(pair, fnptr, []uint32{0}) result = fr.NewValue(pair, f.Type()) fr.funcvals[v] = result return result case *ssa.Const: return fr.NewConstValue(v.Value, v.Type()) case *ssa.Global: if g, ok := fr.globals[v]; ok { return g } // Create an external global. Globals for this package are defined // on entry to translatePackage, and have initialisers. llelemtyp := fr.llvmtypes.ToLLVM(deref(v.Type())) llglobal := llvm.AddGlobal(fr.module.Module, llelemtyp, v.String()) global := fr.NewValue(llglobal, v.Type()) fr.globals[v] = global return global } if value, ok := fr.env[v]; ok { return value } // Instructions are not necessarily visited before they are used (e.g. Phi // edges) so we must "backpatch": create a value with the resultant type, // and then replace it when we visit the instruction. if b, ok := fr.backpatch[v]; ok { return b } if fr.backpatch == nil { fr.backpatch = make(map[ssa.Value]*LLVMValue) } // Note: we must not create a constant here (e.g. Undef/ConstNull), as // it is not permissible to replace a constant with a non-constant. // We must create the value in its own standalone basic block, so we can // dispose of it after replacing. currBlock := fr.builder.GetInsertBlock() fr.builder.SetInsertPointAtEnd(llvm.AddBasicBlock(currBlock.Parent(), "")) placeholder := fr.compiler.builder.CreatePHI(fr.llvmtypes.ToLLVM(v.Type()), "") fr.builder.SetInsertPointAtEnd(currBlock) value := fr.NewValue(placeholder, v.Type()) fr.backpatch[v] = value return value }
func (u *unit) defineFunction(f *ssa.Function) { // Nothing to do for functions without bodies. if len(f.Blocks) == 0 { return } // Only define functions from this package. if f.Pkg == nil { if r := f.Signature.Recv(); r != nil && r.Pkg() != nil && r.Pkg() != u.pkg.Object { return } } else if f.Pkg != u.pkg { return } fr := frame{ unit: u, blocks: make([]llvm.BasicBlock, len(f.Blocks)), env: make(map[ssa.Value]*LLVMValue), } fr.logf("Define function: %s", f.String()) llvmFunction := fr.resolveFunction(f).LLVMValue() delete(u.undefinedFuncs, f) // Functions that call recover must not be inlined, or we // can't tell whether the recover call is valid at runtime. if f.Recover != nil { llvmFunction.AddFunctionAttr(llvm.NoInlineAttribute) } for i, block := range f.Blocks { fr.blocks[i] = llvm.AddBasicBlock(llvmFunction, fmt.Sprintf(".%d.%s", i, block.Comment)) } fr.builder.SetInsertPointAtEnd(fr.blocks[0]) var paramOffset int if len(f.FreeVars) > 0 { // Extract captures from the first implicit parameter. arg0 := llvmFunction.Param(0) for i, fv := range f.FreeVars { addressPtr := fr.builder.CreateStructGEP(arg0, i, "") address := fr.builder.CreateLoad(addressPtr, "") fr.env[fv] = fr.NewValue(address, fv.Type()) } paramOffset++ } for i, param := range f.Params { fr.env[param] = fr.NewValue(llvmFunction.Param(i+paramOffset), param.Type()) } // Allocate stack space for locals in the prologue block. prologueBlock := llvm.InsertBasicBlock(fr.blocks[0], "prologue") fr.builder.SetInsertPointAtEnd(prologueBlock) for _, local := range f.Locals { typ := fr.llvmtypes.ToLLVM(deref(local.Type())) alloca := fr.builder.CreateAlloca(typ, local.Comment) u.memsetZero(alloca, llvm.SizeOf(typ)) value := fr.NewValue(alloca, local.Type()) fr.env[local] = value } // Move any allocs relating to named results from the entry block // to the prologue block, so they dominate the rundefers and recover // blocks. // // TODO(axw) ask adonovan for a cleaner way of doing this, e.g. // have ssa generate an entry block that defines Allocs and related // stores, and then a separate block for function body instructions. if f.Synthetic == "" { if results := f.Signature.Results(); results != nil { for i := 0; i < results.Len(); i++ { result := results.At(i) if result.Name() == "" { break } for i, instr := range f.Blocks[0].Instrs { if instr, ok := instr.(*ssa.Alloc); ok && instr.Heap && instr.Pos() == result.Pos() { fr.instruction(instr) instrs := f.Blocks[0].Instrs instrs = append(instrs[:i], instrs[i+1:]...) f.Blocks[0].Instrs = instrs break } } } } } // If the function contains any defers, we must first call // setjmp so we can call rundefers in response to a panic. // We can short-circuit the check for defers with // f.Recover != nil. if f.Recover != nil || hasDefer(f) { rdblock := llvm.AddBasicBlock(llvmFunction, "rundefers") defers := fr.builder.CreateAlloca(fr.runtime.defers.llvm, "") fr.builder.CreateCall(fr.runtime.initdefers.LLVMValue(), []llvm.Value{defers}, "") jb := fr.builder.CreateStructGEP(defers, 0, "") jb = fr.builder.CreateBitCast(jb, llvm.PointerType(llvm.Int8Type(), 0), "") result := fr.builder.CreateCall(fr.runtime.setjmp.LLVMValue(), []llvm.Value{jb}, "") result = fr.builder.CreateIsNotNull(result, "") fr.builder.CreateCondBr(result, rdblock, fr.blocks[0]) // We'll only get here via a panic, which must either be // recovered or continue panicking up the stack without // returning from "rundefers". The recover block may be // nil even if we can recover, in which case we just need // to return the zero value for each result (if any). var recoverBlock llvm.BasicBlock if f.Recover != nil { recoverBlock = fr.block(f.Recover) } else { recoverBlock = llvm.AddBasicBlock(llvmFunction, "recover") fr.builder.SetInsertPointAtEnd(recoverBlock) var nresults int results := f.Signature.Results() if results != nil { nresults = results.Len() } switch nresults { case 0: fr.builder.CreateRetVoid() case 1: fr.builder.CreateRet(llvm.ConstNull(fr.llvmtypes.ToLLVM(results.At(0).Type()))) default: values := make([]llvm.Value, nresults) for i := range values { values[i] = llvm.ConstNull(fr.llvmtypes.ToLLVM(results.At(i).Type())) } fr.builder.CreateAggregateRet(values) } } fr.builder.SetInsertPointAtEnd(rdblock) fr.builder.CreateCall(fr.runtime.rundefers.LLVMValue(), nil, "") fr.builder.CreateBr(recoverBlock) } else { fr.builder.CreateBr(fr.blocks[0]) } for i, block := range f.Blocks { fr.translateBlock(block, fr.blocks[i]) } }
func (c *compiler) VisitTypeSwitchStmt(stmt *ast.TypeSwitchStmt) { if stmt.Init != nil { c.VisitStmt(stmt.Init) } var assignIdent *ast.Ident var typeAssertExpr *ast.TypeAssertExpr switch stmt := stmt.Assign.(type) { case *ast.AssignStmt: assignIdent = stmt.Lhs[0].(*ast.Ident) typeAssertExpr = stmt.Rhs[0].(*ast.TypeAssertExpr) case *ast.ExprStmt: typeAssertExpr = stmt.X.(*ast.TypeAssertExpr) } if len(stmt.Body.List) == 0 { // No case clauses, so just evaluate the expression. c.VisitExpr(typeAssertExpr.X) return } currBlock := c.builder.GetInsertBlock() endBlock := llvm.AddBasicBlock(currBlock.Parent(), "") endBlock.MoveAfter(currBlock) defer c.builder.SetInsertPointAtEnd(endBlock) // Add a "break" block to the stack. c.breakblocks = append(c.breakblocks, endBlock) defer func() { c.breakblocks = c.breakblocks[:len(c.breakblocks)-1] }() // TODO: investigate the use of a switch instruction // on the type's hash (when we compute type hashes). // Create blocks for each statement. defaultBlock := endBlock var condBlocks []llvm.BasicBlock var stmtBlocks []llvm.BasicBlock for _, stmt := range stmt.Body.List { caseClause := stmt.(*ast.CaseClause) if caseClause.List == nil { defaultBlock = llvm.InsertBasicBlock(endBlock, "") } else { condBlock := llvm.InsertBasicBlock(endBlock, "") stmtBlock := llvm.InsertBasicBlock(endBlock, "") condBlocks = append(condBlocks, condBlock) stmtBlocks = append(stmtBlocks, stmtBlock) } } stmtBlocks = append(stmtBlocks, defaultBlock) // Evaluate the expression, then jump to the first condition block. iface := c.VisitExpr(typeAssertExpr.X).(*LLVMValue) if len(stmt.Body.List) == 1 && defaultBlock != endBlock { c.builder.CreateBr(defaultBlock) } else { c.builder.CreateBr(condBlocks[0]) } i := 0 for _, stmt := range stmt.Body.List { caseClause := stmt.(*ast.CaseClause) if caseClause.List != nil { c.builder.SetInsertPointAtEnd(condBlocks[i]) stmtBlock := stmtBlocks[i] nextCondBlock := defaultBlock if i+1 < len(condBlocks) { nextCondBlock = condBlocks[i+1] } caseCond := func(j int) Value { if c.isNilIdent(caseClause.List[j]) { iface := iface.LLVMValue() ifacetyp := c.builder.CreateExtractValue(iface, 0, "") isnil := c.builder.CreateIsNull(ifacetyp, "") return c.NewValue(isnil, types.Typ[types.Bool]) } typ := c.typeinfo.Types[caseClause.List[j]] switch typ := typ.Underlying().(type) { case *types.Interface: _, ok := iface.convertI2I(typ) return ok } return iface.interfaceTypeEquals(typ) } cond := caseCond(0) for j := 1; j < len(caseClause.List); j++ { f := func() Value { return caseCond(j) } cond = c.compileLogicalOp(token.LOR, cond, f).(*LLVMValue) } c.builder.CreateCondBr(cond.LLVMValue(), stmtBlock, nextCondBlock) i++ } } i = 0 for _, stmt := range stmt.Body.List { caseClause := stmt.(*ast.CaseClause) var block llvm.BasicBlock var typ types.Type if caseClause.List != nil { block = stmtBlocks[i] if len(caseClause.List) == 1 { typ = c.typeinfo.Types[caseClause.List[0]] } i++ } else { block = defaultBlock } c.builder.SetInsertPointAtEnd(block) if assignIdent != nil { obj := c.typeinfo.Implicits[caseClause] if len(caseClause.List) == 1 && !c.isNilIdent(caseClause.List[0]) { switch utyp := typ.Underlying().(type) { case *types.Interface: // FIXME Use value from convertI2I in the case // clause condition test. c.objectdata[obj].Value, _ = iface.convertI2I(utyp) default: c.objectdata[obj].Value = iface.loadI2V(typ) } } else { c.objectdata[obj].Value = iface } } for _, stmt := range caseClause.Body { c.VisitStmt(stmt) } c.maybeImplicitBranch(endBlock) } }
func (c *compiler) VisitSelectStmt(stmt *ast.SelectStmt) { // TODO optimisations: // 1. No clauses: runtime.block. // 2. Single recv, and default clause: runtime.selectnbrecv // 2. Single send, and default clause: runtime.selectnbsend startBlock := c.builder.GetInsertBlock() function := startBlock.Parent() endBlock := llvm.AddBasicBlock(function, "end") endBlock.MoveAfter(startBlock) defer c.builder.SetInsertPointAtEnd(endBlock) // Cache runtime functions var selectrecv, selectsend llvm.Value getselectsend := func() llvm.Value { if selectsend.IsNil() { selectsend = c.NamedFunction("runtime.selectsend", "func(selectp, blockaddr, ch, elem unsafe.Pointer)") } return selectsend } getselectrecv := func() llvm.Value { if selectrecv.IsNil() { selectrecv = c.NamedFunction("runtime.selectrecv", "func(selectp, blockaddr, ch, elem unsafe.Pointer, received *bool)") } return selectrecv } // We create a pointer-pointer for each newly defined var on the // lhs of receive expressions, which will be assigned to when the // expressions are (conditionally) evaluated. lhsptrs := make([][]llvm.Value, len(stmt.Body.List)) for i, stmt := range stmt.Body.List { clause := stmt.(*ast.CommClause) if stmt, ok := clause.Comm.(*ast.AssignStmt); ok && stmt.Tok == token.DEFINE { lhs := make([]llvm.Value, len(stmt.Lhs)) for i, expr := range stmt.Lhs { ident := expr.(*ast.Ident) if !isBlank(ident.Name) { typ := c.target.IntPtrType() lhs[i] = c.builder.CreateAlloca(typ, "") c.builder.CreateStore(llvm.ConstNull(typ), lhs[i]) } } lhsptrs[i] = lhs } } // Create clause basic blocks. blocks := make([]llvm.BasicBlock, len(stmt.Body.List)) var basesize uint64 for i, stmt := range stmt.Body.List { clause := stmt.(*ast.CommClause) if clause.Comm == nil { basesize++ } currBlock := c.builder.GetInsertBlock() block := llvm.InsertBasicBlock(endBlock, "") c.builder.SetInsertPointAtEnd(block) blocks[i] = block lhs := lhsptrs[i] if stmt, ok := clause.Comm.(*ast.AssignStmt); ok { for i, expr := range stmt.Lhs { ident := expr.(*ast.Ident) if !isBlank(ident.Name) { ptr := c.builder.CreateLoad(lhs[i], "") obj := c.typeinfo.Objects[ident] ptrtyp := types.NewPointer(obj.Type()) ptr = c.builder.CreateIntToPtr(ptr, c.types.ToLLVM(ptrtyp), "") value := c.NewValue(ptr, ptrtyp).makePointee() c.objectdata[obj].Value = value } } } for _, stmt := range clause.Body { c.VisitStmt(stmt) } c.maybeImplicitBranch(endBlock) c.builder.SetInsertPointAtEnd(currBlock) } // We need to make an initial pass through the cases, // discarding those where the channel is nil. size := llvm.ConstInt(llvm.Int32Type(), basesize, false) channels := make([]Value, len(stmt.Body.List)) rhs := make([]*LLVMValue, len(stmt.Body.List)) for i, stmt := range stmt.Body.List { clause := stmt.(*ast.CommClause) switch comm := clause.Comm.(type) { case nil: case *ast.SendStmt: channels[i] = c.VisitExpr(comm.Chan) rhs[i] = c.VisitExpr(comm.Value).(*LLVMValue) case *ast.ExprStmt: channels[i] = c.VisitExpr(comm.X.(*ast.UnaryExpr).X) case *ast.AssignStmt: channels[i] = c.VisitExpr(comm.Rhs[0].(*ast.UnaryExpr).X) default: panic(fmt.Errorf("unhandled: %T", comm)) } if channels[i] != nil { nonnil := c.builder.CreateIsNotNull(channels[i].LLVMValue(), "") zero := llvm.ConstInt(llvm.Int32Type(), 0, false) one := llvm.ConstInt(llvm.Int32Type(), 1, false) addend := c.builder.CreateSelect(nonnil, one, zero, "") size = c.builder.CreateAdd(size, addend, "") } } f := c.NamedFunction("runtime.selectsize", "func(size int32) uintptr") selectsize := c.builder.CreateCall(f, []llvm.Value{size}, "") selectp := c.builder.CreateArrayAlloca(llvm.Int8Type(), selectsize, "selectp") c.memsetZero(selectp, selectsize) selectp = c.builder.CreatePtrToInt(selectp, c.target.IntPtrType(), "") f = c.NamedFunction("runtime.initselect", "func(size int32, ptr unsafe.Pointer)") c.builder.CreateCall(f, []llvm.Value{size, selectp}, "") for i, stmt := range stmt.Body.List { clause := stmt.(*ast.CommClause) blockaddr := llvm.BlockAddress(function, blocks[i]) blockaddr = c.builder.CreatePtrToInt(blockaddr, c.target.IntPtrType(), "") if clause.Comm == nil { // default clause f := c.NamedFunction("runtime.selectdefault", "func(selectp, blockaddr unsafe.Pointer)") c.builder.CreateCall(f, []llvm.Value{selectp, blockaddr}, "") continue } currBlock := c.builder.GetInsertBlock() nextBlock := llvm.InsertBasicBlock(currBlock, "") nextBlock.MoveAfter(currBlock) block := llvm.InsertBasicBlock(endBlock, "") chanval := channels[i].LLVMValue() nonnilchan := c.builder.CreateIsNotNull(chanval, "") c.builder.CreateCondBr(nonnilchan, block, nextBlock) c.builder.SetInsertPointAtEnd(block) switch comm := clause.Comm.(type) { case *ast.SendStmt: // c <- val elem := rhs[i] var elemptr llvm.Value if elem.pointer == nil { value := elem.LLVMValue() elemptr = c.builder.CreateAlloca(value.Type(), "") c.builder.CreateStore(value, elemptr) } else { elemptr = elem.pointer.LLVMValue() } elemptr = c.builder.CreatePtrToInt(elemptr, c.target.IntPtrType(), "") f := getselectsend() c.builder.CreateCall(f, []llvm.Value{selectp, blockaddr, chanval, elemptr}, "") case *ast.ExprStmt: // <-c f := getselectrecv() paramtypes := f.Type().ElementType().ParamTypes() elem := llvm.ConstNull(paramtypes[3]) received := llvm.ConstNull(paramtypes[4]) c.builder.CreateCall(f, []llvm.Value{selectp, blockaddr, chanval, elem, received}, "") case *ast.AssignStmt: // val := <-c // val, ok = <-c f := getselectrecv() lhs := c.assignees(comm) paramtypes := f.Type().ElementType().ParamTypes() var elem llvm.Value if lhs[0] != nil { elem = lhs[0].pointer.LLVMValue() elem = c.builder.CreatePtrToInt(elem, paramtypes[3], "") if !lhsptrs[i][0].IsNil() { c.builder.CreateStore(elem, lhsptrs[i][0]) } } else { elem = llvm.ConstNull(paramtypes[3]) } var received llvm.Value if len(lhs) == 2 && lhs[1] != nil { received = lhs[1].pointer.LLVMValue() received = c.builder.CreatePtrToInt(received, paramtypes[4], "") if !lhsptrs[i][1].IsNil() { c.builder.CreateStore(received, lhsptrs[i][1]) } } else { received = llvm.ConstNull(paramtypes[4]) } c.builder.CreateCall(f, []llvm.Value{selectp, blockaddr, chanval, elem, received}, "") } c.builder.CreateBr(nextBlock) c.builder.SetInsertPointAtEnd(nextBlock) } f = c.NamedFunction("runtime.selectgo", "func(selectp unsafe.Pointer) unsafe.Pointer") blockaddr := c.builder.CreateCall(f, []llvm.Value{selectp}, "") blockaddr = c.builder.CreateIntToPtr(blockaddr, llvm.PointerType(llvm.Int8Type(), 0), "") ibr := c.builder.CreateIndirectBr(blockaddr, len(stmt.Body.List)) for _, block := range blocks { ibr.AddDest(block) } }
func (c *compiler) VisitRangeStmt(stmt *ast.RangeStmt) { currBlock := c.builder.GetInsertBlock() doneBlock := llvm.AddBasicBlock(currBlock.Parent(), "done") doneBlock.MoveAfter(currBlock) postBlock := llvm.InsertBasicBlock(doneBlock, "post") loopBlock := llvm.InsertBasicBlock(postBlock, "loop") condBlock := llvm.InsertBasicBlock(loopBlock, "cond") defer c.builder.SetInsertPointAtEnd(doneBlock) // Evaluate range expression first. x := c.VisitExpr(stmt.X) // If it's a pointer type, we'll first check that it's non-nil. typ := x.Type().Underlying() if _, ok := typ.(*types.Pointer); ok { ifBlock := llvm.InsertBasicBlock(doneBlock, "if") isnotnull := c.builder.CreateIsNotNull(x.LLVMValue(), "") c.builder.CreateCondBr(isnotnull, ifBlock, doneBlock) c.builder.SetInsertPointAtEnd(ifBlock) } // Is it a new var definition? Then allocate some memory on the stack. var keyPtr, valuePtr llvm.Value if stmt.Tok == token.DEFINE { if key := stmt.Key.(*ast.Ident); !isBlank(key.Name) { keyobj := c.typeinfo.Objects[key] keyPtr, _ = c.newStackVar(c.functions.top().LLVMValue, keyobj, llvm.Value{}, key.Name) } if stmt.Value != nil { if value := stmt.Value.(*ast.Ident); !isBlank(value.Name) { valueobj := c.typeinfo.Objects[value] valuePtr, _ = c.newStackVar(c.functions.top().LLVMValue, valueobj, llvm.Value{}, value.Name) } } } else { // Simple assignment, resolve the key/value pointers. if key := stmt.Key.(*ast.Ident); !isBlank(key.Name) { keyPtr = c.Resolve(key).(*LLVMValue).pointer.LLVMValue() } if stmt.Value != nil { if value := stmt.Value.(*ast.Ident); !isBlank(value.Name) { valuePtr = c.Resolve(value).(*LLVMValue).pointer.LLVMValue() } } } if c.lastlabel != nil { labelData := c.labelData(c.lastlabel) labelData.Break = doneBlock labelData.Continue = postBlock c.lastlabel = nil } c.breakblocks = append(c.breakblocks, doneBlock) c.continueblocks = append(c.continueblocks, postBlock) defer func() { c.breakblocks = c.breakblocks[:len(c.breakblocks)-1] c.continueblocks = c.continueblocks[:len(c.continueblocks)-1] }() isarray := false var base, length llvm.Value _, isptr := typ.(*types.Pointer) if isptr { typ = typ.(*types.Pointer).Elem() } switch typ := typ.Underlying().(type) { case *types.Map: goto maprange case *types.Chan: goto chanrange case *types.Basic: stringvalue := x.LLVMValue() length = c.builder.CreateExtractValue(stringvalue, 1, "") goto stringrange case *types.Array: isarray = true x := x if !isptr { if x_, ok := x.(*LLVMValue); ok && x_.pointer != nil { x = x_.pointer } else { ptr := c.builder.CreateAlloca(c.types.ToLLVM(x.Type()), "") c.builder.CreateStore(x.LLVMValue(), ptr) x = c.NewValue(ptr, types.NewPointer(x.Type())) } } base = x.LLVMValue() length = llvm.ConstInt(c.llvmtypes.inttype, uint64(typ.Len()), false) goto arrayrange case *types.Slice: slicevalue := x.LLVMValue() base = c.builder.CreateExtractValue(slicevalue, 0, "") length = c.builder.CreateExtractValue(slicevalue, 1, "") goto arrayrange } panic("unreachable") maprange: { currBlock = c.builder.GetInsertBlock() c.builder.CreateBr(condBlock) c.builder.SetInsertPointAtEnd(condBlock) nextptrphi := c.builder.CreatePHI(c.target.IntPtrType(), "next") nextptr, pk, pv := c.mapNext(x.(*LLVMValue), nextptrphi) notnull := c.builder.CreateIsNotNull(nextptr, "") c.builder.CreateCondBr(notnull, loopBlock, doneBlock) c.builder.SetInsertPointAtEnd(loopBlock) if !keyPtr.IsNil() { keyval := c.builder.CreateLoad(pk, "") c.builder.CreateStore(keyval, keyPtr) } if !valuePtr.IsNil() { valval := c.builder.CreateLoad(pv, "") c.builder.CreateStore(valval, valuePtr) } c.VisitBlockStmt(stmt.Body, false) c.maybeImplicitBranch(postBlock) c.builder.SetInsertPointAtEnd(postBlock) c.builder.CreateBr(condBlock) nextptrphi.AddIncoming([]llvm.Value{llvm.ConstNull(c.target.IntPtrType()), nextptr}, []llvm.BasicBlock{currBlock, postBlock}) return } stringrange: { zero := llvm.ConstNull(c.types.inttype) currBlock = c.builder.GetInsertBlock() c.builder.CreateBr(condBlock) c.builder.SetInsertPointAtEnd(condBlock) index := c.builder.CreatePHI(c.types.inttype, "index") lessthan := c.builder.CreateICmp(llvm.IntULT, index, length, "") c.builder.CreateCondBr(lessthan, loopBlock, doneBlock) c.builder.SetInsertPointAtEnd(loopBlock) consumed, value := c.stringNext(x.LLVMValue(), index) if !keyPtr.IsNil() { c.builder.CreateStore(index, keyPtr) } if !valuePtr.IsNil() { c.builder.CreateStore(value, valuePtr) } c.VisitBlockStmt(stmt.Body, false) c.maybeImplicitBranch(postBlock) c.builder.SetInsertPointAtEnd(postBlock) newindex := c.builder.CreateAdd(index, consumed, "") c.builder.CreateBr(condBlock) index.AddIncoming([]llvm.Value{zero, newindex}, []llvm.BasicBlock{currBlock, postBlock}) return } arrayrange: { zero := llvm.ConstNull(c.types.inttype) currBlock = c.builder.GetInsertBlock() c.builder.CreateBr(condBlock) c.builder.SetInsertPointAtEnd(condBlock) index := c.builder.CreatePHI(c.types.inttype, "index") lessthan := c.builder.CreateICmp(llvm.IntULT, index, length, "") c.builder.CreateCondBr(lessthan, loopBlock, doneBlock) c.builder.SetInsertPointAtEnd(loopBlock) if !keyPtr.IsNil() { c.builder.CreateStore(index, keyPtr) } if !valuePtr.IsNil() { var indices []llvm.Value if isarray { indices = []llvm.Value{zero, index} } else { indices = []llvm.Value{index} } elementptr := c.builder.CreateGEP(base, indices, "") element := c.builder.CreateLoad(elementptr, "") c.builder.CreateStore(element, valuePtr) } c.VisitBlockStmt(stmt.Body, false) c.maybeImplicitBranch(postBlock) c.builder.SetInsertPointAtEnd(postBlock) newindex := c.builder.CreateAdd(index, llvm.ConstInt(c.types.inttype, 1, false), "") c.builder.CreateBr(condBlock) index.AddIncoming([]llvm.Value{zero, newindex}, []llvm.BasicBlock{currBlock, postBlock}) return } chanrange: { c.builder.CreateBr(condBlock) c.builder.SetInsertPointAtEnd(condBlock) value, received := x.(*LLVMValue).chanRecv(true) c.builder.CreateCondBr(received.LLVMValue(), loopBlock, doneBlock) c.builder.SetInsertPointAtEnd(loopBlock) if !keyPtr.IsNil() { c.builder.CreateStore(value.LLVMValue(), keyPtr) } c.VisitBlockStmt(stmt.Body, false) c.maybeImplicitBranch(postBlock) c.builder.SetInsertPointAtEnd(postBlock) c.builder.CreateBr(condBlock) return } }
func (c *compiler) VisitSwitchStmt(stmt *ast.SwitchStmt) { if stmt.Init != nil { c.VisitStmt(stmt.Init) } var tag Value if stmt.Tag != nil { tag = c.VisitExpr(stmt.Tag) } else { tag = c.NewConstValue(exact.MakeBool(true), types.Typ[types.Bool]) } if len(stmt.Body.List) == 0 { return } // Convert untyped constant clauses. for _, clause := range stmt.Body.List { for _, expr := range clause.(*ast.CaseClause).List { if typ := c.typeinfo.Types[expr]; isUntyped(typ) { c.typeinfo.Types[expr] = tag.Type() } } } // makeValueFunc takes an expression, evaluates it, and returns // a Value representing its equality comparison with the tag. makeValueFunc := func(expr ast.Expr) func() Value { return func() Value { return c.VisitExpr(expr).BinaryOp(token.EQL, tag) } } // Create a BasicBlock for each case clause and each associated // statement body. Each case clause will branch to either its // statement body (success) or to the next case (failure), or the // end block if there are no remaining cases. startBlock := c.builder.GetInsertBlock() endBlock := llvm.AddBasicBlock(startBlock.Parent(), "end") endBlock.MoveAfter(startBlock) defer c.builder.SetInsertPointAtEnd(endBlock) if c.lastlabel != nil { labelData := c.labelData(c.lastlabel) labelData.Break = endBlock c.lastlabel = nil } // Add a "break" block to the stack. c.breakblocks = append(c.breakblocks, endBlock) defer func() { c.breakblocks = c.breakblocks[:len(c.breakblocks)-1] }() caseBlocks := make([]llvm.BasicBlock, 0, len(stmt.Body.List)) stmtBlocks := make([]llvm.BasicBlock, 0, len(stmt.Body.List)) for _ = range stmt.Body.List { caseBlocks = append(caseBlocks, llvm.InsertBasicBlock(endBlock, "")) } for _ = range stmt.Body.List { stmtBlocks = append(stmtBlocks, llvm.InsertBasicBlock(endBlock, "")) } // Move the "default" block to the end, if there is one. caseclauses := make([]*ast.CaseClause, 0, len(stmt.Body.List)) var defaultclause *ast.CaseClause for _, stmt := range stmt.Body.List { clause := stmt.(*ast.CaseClause) if clause.List == nil { defaultclause = clause } else { caseclauses = append(caseclauses, clause) } } if defaultclause != nil { caseclauses = append(caseclauses, defaultclause) } c.builder.CreateBr(caseBlocks[0]) for i, clause := range caseclauses { c.builder.SetInsertPointAtEnd(caseBlocks[i]) stmtBlock := stmtBlocks[i] nextBlock := endBlock if i+1 < len(caseBlocks) { nextBlock = caseBlocks[i+1] } if clause.List != nil { value := c.VisitExpr(clause.List[0]) result := value.BinaryOp(token.EQL, tag) for _, expr := range clause.List[1:] { rhsResultFunc := makeValueFunc(expr) result = c.compileLogicalOp(token.LOR, result, rhsResultFunc) } c.builder.CreateCondBr(result.LLVMValue(), stmtBlock, nextBlock) } else { // default case c.builder.CreateBr(stmtBlock) } c.builder.SetInsertPointAtEnd(stmtBlock) branchBlock := endBlock for _, stmt := range clause.Body { if br, isbr := stmt.(*ast.BranchStmt); isbr { if br.Tok == token.FALLTHROUGH { if i+1 < len(stmtBlocks) { branchBlock = stmtBlocks[i+1] } } else { c.VisitStmt(stmt) } // Ignore anything after a branch statement. break } else { c.VisitStmt(stmt) } } c.maybeImplicitBranch(branchBlock) } }
// 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) VisitFuncDecl(f *ast.FuncDecl) Value { var fn Value if f.Name.Obj != nil { fn = c.Resolve(f.Name.Obj) } else { fn = c.VisitFuncProtoDecl(f) } if f.Body == nil { return fn } fn_type := fn.Type().(*types.Func) llvm_fn := fn.LLVMValue() entry := llvm.AddBasicBlock(llvm_fn, "entry") c.builder.SetInsertPointAtEnd(entry) // Bind receiver, arguments and return values to their identifiers/objects. // We'll store each parameter on the stack so they're addressable. paramObjects := fn_type.Params if f.Recv != nil { paramObjects = append([]*ast.Object{fn_type.Recv}, paramObjects...) } for i, obj := range paramObjects { if obj.Name != "" { value := llvm_fn.Param(i) typ := obj.Type.(types.Type) stackvalue := c.builder.CreateAlloca(c.types.ToLLVM(typ), obj.Name) c.builder.CreateStore(value, stackvalue) ptrvalue := c.NewLLVMValue(stackvalue, &types.Pointer{Base: typ}) obj.Data = ptrvalue.makePointee() } } // Allocate space on the stack for named results. for _, obj := range fn_type.Results { if obj.Name != "" { typ := obj.Type.(types.Type) llvmtyp := c.types.ToLLVM(typ) stackptr := c.builder.CreateAlloca(llvmtyp, obj.Name) c.builder.CreateStore(llvm.ConstNull(llvmtyp), stackptr) ptrvalue := c.NewLLVMValue(stackptr, &types.Pointer{Base: typ}) obj.Data = ptrvalue.makePointee() } } c.functions = append(c.functions, fn) if f.Body != nil { c.VisitBlockStmt(f.Body) } c.functions = c.functions[0 : len(c.functions)-1] last := llvm_fn.LastBasicBlock() if in := last.LastInstruction(); in.IsNil() || in.IsATerminatorInst().IsNil() { // Assume nil return type, AST should be checked first. c.builder.SetInsertPointAtEnd(last) c.builder.CreateRetVoid() } // Is it an 'init' function? Then record it. if f.Name.String() == "init" { c.initfuncs = append(c.initfuncs, fn) } else { //if obj != nil { // obj.Data = fn //} } return fn }
// Create a constructor function which initialises a global. // TODO collapse all global inits into one init function? func (c *compiler) createGlobal(e ast.Expr, t types.Type, name string, export bool) (g *LLVMValue) { if e == nil { gv := llvm.AddGlobal(c.module.Module, c.types.ToLLVM(t), name) if !export { gv.SetLinkage(llvm.InternalLinkage) } g = c.NewLLVMValue(gv, &types.Pointer{Base: t}) if !isArray(t) { return g.makePointee() } return g } if block := c.builder.GetInsertBlock(); !block.IsNil() { defer c.builder.SetInsertPointAtEnd(block) } fn_type := new(types.Func) llvm_fn_type := c.types.ToLLVM(fn_type).ElementType() fn := llvm.AddFunction(c.module.Module, "", llvm_fn_type) fn.SetLinkage(llvm.InternalLinkage) entry := llvm.AddBasicBlock(fn, "entry") c.builder.SetInsertPointAtEnd(entry) // Visit the expression. Dereference if necessary, and generalise // the type if one hasn't been specified. init_ := c.VisitExpr(e) _, isconst := init_.(ConstValue) if t == nil { t = init_.Type() } else { init_ = init_.Convert(t) } // If the result is a constant, discard the function before // creating any llvm.Value's. if isconst { fn.EraseFromParentAsFunction() fn = llvm.Value{nil} } // Set the initialiser. If it's a non-const value, then // we'll have to do the assignment in a global constructor // function. gv := llvm.AddGlobal(c.module.Module, c.types.ToLLVM(t), name) if !export { gv.SetLinkage(llvm.InternalLinkage) } g = c.NewLLVMValue(gv, &types.Pointer{Base: t}) if !isArray(t) { g = g.makePointee() } if isconst { // Initialiser is constant; discard function and return global now. gv.SetInitializer(init_.LLVMValue()) } else { gv.SetInitializer(llvm.ConstNull(c.types.ToLLVM(t))) c.builder.CreateStore(init_.LLVMValue(), gv) } if !fn.IsNil() { c.builder.CreateRetVoid() // FIXME order global ctors fn_value := c.NewLLVMValue(fn, fn_type) c.initfuncs = append(c.initfuncs, fn_value) } return g }