func (c *Codegen) generateLoop(node *parser.LoopStmtNode) (ret bool) { currFunc := c.module.NamedFunction(c.currFunc) if node.Init != nil { c.generateVarDecl(node.Init, false) } entry := llvm.AddBasicBlock(currFunc, "") body := llvm.AddBasicBlock(currFunc, "") exit := llvm.AddBasicBlock(currFunc, "") c.builder.CreateBr(entry) c.builder.SetInsertPoint(entry, entry.LastInstruction()) cond := c.generateExpression(node.Cond) c.builder.CreateCondBr(cond, body, exit) c.builder.SetInsertPoint(body, body.LastInstruction()) if ret = c.generateBlock(node.Body); !ret { if node.Post != nil { switch t := node.Post.(type) { case *parser.AssignStmtNode: c.generateAssign(t) case *parser.CallStmtNode: c.generateCall(t.Call, null) } } c.builder.CreateBr(entry) } c.builder.SetInsertPoint(exit, exit.LastInstruction()) return }
func (v *Codegen) genLoopStat(n *parser.LoopStat) { switch n.LoopType { case parser.LOOP_TYPE_INFINITE: loopBlock := llvm.AddBasicBlock(v.currentFunction, "") v.builder.CreateBr(loopBlock) v.builder.SetInsertPointAtEnd(loopBlock) v.genBlock(n.Body) v.builder.CreateBr(loopBlock) afterBlock := llvm.AddBasicBlock(v.currentFunction, "") v.builder.SetInsertPointAtEnd(afterBlock) case parser.LOOP_TYPE_CONDITIONAL: evalBlock := llvm.AddBasicBlock(v.currentFunction, "") v.builder.CreateBr(evalBlock) loopBlock := llvm.AddBasicBlock(v.currentFunction, "") afterBlock := llvm.AddBasicBlock(v.currentFunction, "") v.builder.SetInsertPointAtEnd(evalBlock) cond := v.genExpr(n.Condition) v.builder.CreateCondBr(cond, loopBlock, afterBlock) v.builder.SetInsertPointAtEnd(loopBlock) v.genBlock(n.Body) v.builder.CreateBr(evalBlock) v.builder.SetInsertPointAtEnd(afterBlock) default: panic("invalid loop type") } }
func (v *Codegen) genLogicalBinop(n *parser.BinaryExpr) llvm.Value { and := n.Op == parser.BINOP_LOG_AND next := llvm.AddBasicBlock(v.currentLLVMFunction(), "and_next") exit := llvm.AddBasicBlock(v.currentLLVMFunction(), "and_exit") b1 := v.genExpr(n.Lhand) first := v.builder().GetInsertBlock() if and { v.builder().CreateCondBr(b1, next, exit) } else { v.builder().CreateCondBr(b1, exit, next) } v.builder().SetInsertPointAtEnd(next) b2 := v.genExpr(n.Rhand) next = v.builder().GetInsertBlock() v.builder().CreateBr(exit) v.builder().SetInsertPointAtEnd(exit) phi := v.builder().CreatePHI(b2.Type(), "and_phi") var testIncVal uint64 if and { testIncVal = 0 } else { testIncVal = 1 } phi.AddIncoming([]llvm.Value{llvm.ConstInt(llvm.IntType(1), testIncVal, false), b2}, []llvm.BasicBlock{first, next}) return phi }
func (fr *frame) condBrRuntimeError(cond llvm.Value, errcode uint64) { if cond.IsNull() { return } errorbb := fr.runtimeErrorBlocks[errcode] newbb := errorbb.C == nil if newbb { errorbb = llvm.AddBasicBlock(fr.function, "") fr.runtimeErrorBlocks[errcode] = errorbb } contbb := llvm.AddBasicBlock(fr.function, "") br := fr.builder.CreateCondBr(cond, errorbb, contbb) fr.setBranchWeightMetadata(br, 1, 1000) if newbb { fr.builder.SetInsertPointAtEnd(errorbb) fr.runtime.runtimeError.call(fr, llvm.ConstInt(llvm.Int32Type(), errcode, false)) fr.builder.CreateUnreachable() } fr.builder.SetInsertPointAtEnd(contbb) }
func (v *Codegen) genBoundsCheck(limit llvm.Value, index llvm.Value, indexType parser.Type) { segvBlock := llvm.AddBasicBlock(v.currentLLVMFunction(), "boundscheck_segv") endBlock := llvm.AddBasicBlock(v.currentLLVMFunction(), "boundscheck_end") upperCheckBlock := llvm.AddBasicBlock(v.currentLLVMFunction(), "boundscheck_upper_block") tooLow := v.builder().CreateICmp(llvm.IntSGT, llvm.ConstInt(index.Type(), 0, false), index, "boundscheck_lower") v.builder().CreateCondBr(tooLow, segvBlock, upperCheckBlock) v.builder().SetInsertPointAtEnd(upperCheckBlock) // make sure limit and index have same width castedLimit := limit castedIndex := index if index.Type().IntTypeWidth() < limit.Type().IntTypeWidth() { if indexType.IsSigned() { castedIndex = v.builder().CreateSExt(index, limit.Type(), "") } else { castedIndex = v.builder().CreateZExt(index, limit.Type(), "") } } else if index.Type().IntTypeWidth() > limit.Type().IntTypeWidth() { castedLimit = v.builder().CreateZExt(limit, index.Type(), "") } tooHigh := v.builder().CreateICmp(llvm.IntSLE, castedLimit, castedIndex, "boundscheck_upper") v.builder().CreateCondBr(tooHigh, segvBlock, endBlock) v.builder().SetInsertPointAtEnd(segvBlock) v.genRaiseSegfault() v.builder().CreateUnreachable() v.builder().SetInsertPointAtEnd(endBlock) }
// emitInitPrologue emits the init-specific function prologue (guard check and // initialization of dependent packages under the llgo native ABI), and returns // the basic block into which the GC registration call should be emitted. func (fr *frame) emitInitPrologue() llvm.BasicBlock { if fr.GccgoABI { return fr.builder.GetInsertBlock() } initGuard := llvm.AddGlobal(fr.module.Module, llvm.Int1Type(), "init$guard") initGuard.SetLinkage(llvm.InternalLinkage) initGuard.SetInitializer(llvm.ConstNull(llvm.Int1Type())) returnBlock := llvm.AddBasicBlock(fr.function, "") initBlock := llvm.AddBasicBlock(fr.function, "") initGuardVal := fr.builder.CreateLoad(initGuard, "") fr.builder.CreateCondBr(initGuardVal, returnBlock, initBlock) fr.builder.SetInsertPointAtEnd(returnBlock) fr.builder.CreateRetVoid() fr.builder.SetInsertPointAtEnd(initBlock) fr.builder.CreateStore(llvm.ConstInt(llvm.Int1Type(), 1, false), initGuard) int8ptr := llvm.PointerType(fr.types.ctx.Int8Type(), 0) ftyp := llvm.FunctionType(llvm.VoidType(), []llvm.Type{int8ptr}, false) for _, pkg := range fr.pkg.Object.Imports() { initname := ManglePackagePath(pkg.Path()) + "..import" initfn := fr.module.Module.NamedFunction(initname) if initfn.IsNil() { initfn = llvm.AddFunction(fr.module.Module, initname, ftyp) } args := []llvm.Value{llvm.Undef(int8ptr)} fr.builder.CreateCall(initfn, args, "") } return initBlock }
func (fr *frame) callRecover(isDeferredRecover bool) *govalue { startbb := fr.builder.GetInsertBlock() recoverbb := llvm.AddBasicBlock(fr.function, "") contbb := llvm.AddBasicBlock(fr.function, "") canRecover := fr.builder.CreateTrunc(fr.canRecover, llvm.Int1Type(), "") fr.builder.CreateCondBr(canRecover, recoverbb, contbb) fr.builder.SetInsertPointAtEnd(recoverbb) var recovered llvm.Value if isDeferredRecover { recovered = fr.runtime.deferredRecover.call(fr)[0] } else { recovered = fr.runtime.recover.call(fr)[0] } recoverbb = fr.builder.GetInsertBlock() fr.builder.CreateBr(contbb) fr.builder.SetInsertPointAtEnd(contbb) eface := types.NewInterface(nil, nil) llv := fr.builder.CreatePHI(fr.types.ToLLVM(eface), "") llv.AddIncoming( []llvm.Value{llvm.ConstNull(llv.Type()), recovered}, []llvm.BasicBlock{startbb, recoverbb}, ) return newValue(llv, eface) }
// Runs defers. If a defer panics, check for recovers in later defers. func (fr *frame) runDefers() { loopbb := llvm.AddBasicBlock(fr.function, "") fr.builder.CreateBr(loopbb) retrylpad := llvm.AddBasicBlock(fr.function, "") fr.builder.SetInsertPointAtEnd(retrylpad) fr.createLandingPad(false) fr.runtime.checkDefer.callOnly(fr, fr.frameptr) fr.builder.CreateBr(loopbb) fr.builder.SetInsertPointAtEnd(loopbb) fr.runtime.undefer.invoke(fr, retrylpad, fr.frameptr) }
func (v *Codegen) genIfStat(n *parser.IfStat) { // Warning to all who tread here: // This function is complicated, but theoretically it should never need to // be changed again. God help the soul who has to edit this. if !v.inFunction() { panic("tried to gen if stat not in function") } statTerm := semantic.IsNodeTerminating(n) var end llvm.BasicBlock if !statTerm { end = llvm.AddBasicBlock(v.currentLLVMFunction(), "end") } for i, expr := range n.Exprs { cond := v.genExpr(expr) ifTrue := llvm.AddBasicBlock(v.currentLLVMFunction(), "if_true") ifFalse := llvm.AddBasicBlock(v.currentLLVMFunction(), "if_false") v.builder().CreateCondBr(cond, ifTrue, ifFalse) v.builder().SetInsertPointAtEnd(ifTrue) v.genBlock(n.Bodies[i]) if !statTerm && !n.Bodies[i].IsTerminating && !isBreakOrNext(n.Bodies[i].LastNode()) { v.builder().CreateBr(end) } v.builder().SetInsertPointAtEnd(ifFalse) if !statTerm { end.MoveAfter(ifFalse) } } if n.Else != nil { v.genBlock(n.Else) } if !statTerm && (n.Else == nil || (!n.Else.IsTerminating && !isBreakOrNext(n.Else.LastNode()))) { v.builder().CreateBr(end) } if !statTerm { v.builder().SetInsertPointAtEnd(end) } }
func (c *compiler) createInitMainFunction(mainPkg *ssa.Package) { int8ptr := llvm.PointerType(c.types.ctx.Int8Type(), 0) ftyp := llvm.FunctionType(llvm.VoidType(), []llvm.Type{int8ptr}, false) initMain := llvm.AddFunction(c.module.Module, "__go_init_main", ftyp) c.addCommonFunctionAttrs(initMain) entry := llvm.AddBasicBlock(initMain, "entry") builder := llvm.GlobalContext().NewBuilder() defer builder.Dispose() builder.SetInsertPointAtEnd(entry) args := []llvm.Value{llvm.Undef(int8ptr)} if !c.GccgoABI { initfn := c.module.Module.NamedFunction("main..import") if !initfn.IsNil() { builder.CreateCall(initfn, args, "") } builder.CreateRetVoid() return } initdata := c.buildPackageInitData(mainPkg) for _, init := range initdata.Inits { initfn := c.module.Module.NamedFunction(init.InitFunc) if initfn.IsNil() { initfn = llvm.AddFunction(c.module.Module, init.InitFunc, ftyp) } builder.CreateCall(initfn, args, "") } builder.CreateRetVoid() }
func (c *Codegen) stdString() { tmpl := &Template{ Type: llvm.GlobalContext().StructCreateNamed("string"), Variables: map[string]int{}, } c.templates["string"] = tmpl vars := []llvm.Type{ llvm.PointerType(PRIMITIVE_TYPES["char"], 0), PRIMITIVE_TYPES["int"], PRIMITIVE_TYPES["int"], } tmpl.Type.StructSetBody(vars, false) lenFuncType := llvm.FunctionType(PRIMITIVE_TYPES["int"], []llvm.Type{llvm.PointerType(tmpl.Type, 0)}, false) lenFunc := llvm.AddFunction(c.module, "-string-len", lenFuncType) lenFunc.Param(0).SetName("this") block := llvm.AddBasicBlock(c.module.NamedFunction("-string-len"), "entry") c.functions["-string-len"] = block c.currFunc = "-string-len" c.builder.SetInsertPoint(block, block.LastInstruction()) ret := c.builder.CreateStructGEP(c.getCurrParam("this"), 1, "") ret = c.builder.CreateLoad(ret, "") ret = c.builder.CreateSub(ret, llvm.ConstInt(PRIMITIVE_TYPES["int"], 1, false), "") c.builder.CreateRet(ret) printFuncType := llvm.FunctionType(PRIMITIVE_TYPES["int"], []llvm.Type{ llvm.PointerType(PRIMITIVE_TYPES["char"], 0), }, true) llvm.AddFunction(c.module, "printf", printFuncType) }
func (v *Codegen) genFunctionDecl(n *parser.FunctionDecl) llvm.Value { var res llvm.Value mangledName := n.Function.MangledName(parser.MANGLE_ARK_UNSTABLE) function := v.curFile.Module.NamedFunction(mangledName) if function.IsNil() { //v.err("genning function `%s` doesn't exist in module", n.Function.Name) // hmmmm seems we just ignore this here } else { if !n.Prototype { block := llvm.AddBasicBlock(function, "entry") v.builder.SetInsertPointAtEnd(block) for i, par := range n.Function.Parameters { alloc := v.builder.CreateAlloca(v.typeToLLVMType(par.Variable.Type), par.Variable.MangledName(parser.MANGLE_ARK_UNSTABLE)) v.variableLookup[par.Variable] = alloc v.builder.CreateStore(function.Params()[i], alloc) } v.inFunction = true v.currentFunction = function v.genBlock(n.Function.Body) v.inFunction = false } } return res }
func (v *Codegen) genFunctionBody(fn *parser.Function, llvmFn llvm.Value) { block := llvm.AddBasicBlock(llvmFn, "entry") v.pushFunction(fn) v.builders[v.currentFunction()] = llvm.NewBuilder() v.builder().SetInsertPointAtEnd(block) pars := fn.Parameters if fn.Type.Receiver != nil { newPars := make([]*parser.VariableDecl, len(pars)+1) newPars[0] = fn.Receiver copy(newPars[1:], pars) pars = newPars } for i, par := range pars { alloc := v.builder().CreateAlloca(v.typeToLLVMType(par.Variable.Type), par.Variable.Name) v.variableLookup[par.Variable] = alloc v.builder().CreateStore(llvmFn.Params()[i], alloc) } v.genBlock(fn.Body) v.builder().Dispose() delete(v.builders, v.currentFunction()) delete(v.curLoopExits, v.currentFunction()) delete(v.curLoopNexts, v.currentFunction()) v.popFunction() }
func (v *Codegen) genLoopStat(n *parser.LoopStat) { curfn := v.currentFunction() afterBlock := llvm.AddBasicBlock(v.currentLLVMFunction(), "loop_exit") v.curLoopExits[curfn] = append(v.curLoopExits[curfn], afterBlock) switch n.LoopType { case parser.LOOP_TYPE_INFINITE: loopBlock := llvm.AddBasicBlock(v.currentLLVMFunction(), "loop_body") v.curLoopNexts[curfn] = append(v.curLoopNexts[curfn], loopBlock) v.builder().CreateBr(loopBlock) v.builder().SetInsertPointAtEnd(loopBlock) v.genBlock(n.Body) if !isBreakOrNext(n.Body.LastNode()) { v.builder().CreateBr(loopBlock) } v.builder().SetInsertPointAtEnd(afterBlock) case parser.LOOP_TYPE_CONDITIONAL: evalBlock := llvm.AddBasicBlock(v.currentLLVMFunction(), "loop_condeval") v.builder().CreateBr(evalBlock) v.curLoopNexts[curfn] = append(v.curLoopNexts[curfn], evalBlock) loopBlock := llvm.AddBasicBlock(v.currentLLVMFunction(), "loop_body") v.builder().SetInsertPointAtEnd(evalBlock) cond := v.genExpr(n.Condition) v.builder().CreateCondBr(cond, loopBlock, afterBlock) v.builder().SetInsertPointAtEnd(loopBlock) v.genBlock(n.Body) if !isBreakOrNext(n.Body.LastNode()) { v.builder().CreateBr(evalBlock) } v.builder().SetInsertPointAtEnd(afterBlock) default: panic("invalid loop type") } v.curLoopExits[curfn] = v.curLoopExits[curfn][:len(v.curLoopExits[curfn])-1] v.curLoopNexts[curfn] = v.curLoopNexts[curfn][:len(v.curLoopNexts[curfn])-1] }
func (v *Codegen) genIfStat(n *parser.IfStat) { if !v.inFunction { panic("tried to gen if stat not in function") } end := llvm.AddBasicBlock(v.currentFunction, "") for i, expr := range n.Exprs { cond := v.genExpr(expr) ifTrue := llvm.AddBasicBlock(v.currentFunction, "") ifFalse := llvm.AddBasicBlock(v.currentFunction, "") v.builder.CreateCondBr(cond, ifTrue, ifFalse) v.builder.SetInsertPointAtEnd(ifTrue) for _, node := range n.Bodies[i].Nodes { v.genNode(node) } if len(n.Bodies[i].Nodes) == 0 { v.builder.CreateBr(end) } else { switch n.Bodies[i].Nodes[len(n.Bodies[i].Nodes)-1].(type) { case *parser.ReturnStat: // do nothing default: v.builder.CreateBr(end) } } v.builder.SetInsertPointAtEnd(ifFalse) end.MoveAfter(ifFalse) } if n.Else != nil { for _, node := range n.Else.Nodes { v.genNode(node) } } v.builder.CreateBr(end) v.builder.SetInsertPointAtEnd(end) }
func (c *Codegen) generateControl(node *parser.IfStmtNode) (ret bool) { currFunc := c.module.NamedFunction(c.currFunc) tru := llvm.AddBasicBlock(currFunc, "") var els llvm.BasicBlock if node.Else != nil { els = llvm.AddBasicBlock(currFunc, "") } exit := llvm.AddBasicBlock(currFunc, "") cond := c.generateExpression(node.Condition) if node.Else != nil { c.builder.CreateCondBr(cond, tru, els) } else { c.builder.CreateCondBr(cond, tru, exit) } c.builder.SetInsertPoint(tru, tru.LastInstruction()) if c.generateBlock(node.Body) { ret = true } else { c.builder.CreateBr(exit) } if node.Else != nil { c.builder.SetInsertPoint(els, els.LastInstruction()) var ok bool switch t := node.Else.(type) { case *parser.BlockNode: ok = c.generateBlock(t) ret = ok && ret case *parser.IfStmtNode: ok = c.generateControl(t) ret = ok && ret } if !ok { c.builder.CreateBr(exit) } } c.builder.SetInsertPoint(exit, exit.LastInstruction()) return }
func (n *ForExpr) Gen(cg *CG) llvm.Value { startVal := n.Start.Gen(cg) if startVal.IsNil() { return errv("Code generation failed for start expression") } fun := cg.GetInsertBlock().Parent() alloca := createEntryBlockAlloca(fun, n.Var) cg.CreateStore(startVal, alloca) loopBB := llvm.AddBasicBlock(fun, "loop") cg.CreateBr(loopBB) cg.SetInsertPointAtEnd(loopBB) oldVal := cg.NamedValues[n.Var] cg.NamedValues[n.Var] = alloca if n.Body.Gen(cg).IsNil() { return llvm.Value{} } var stepVal llvm.Value if n.Step != nil { stepVal = n.Step.Gen(cg) if stepVal.IsNil() { return llvm.ConstNull(llvm.DoubleType()) } } else { stepVal = llvm.ConstFloat(llvm.DoubleType(), 1) } endVal := n.End.Gen(cg) if endVal.IsNil() { return llvm.Value{} } curVar := cg.CreateLoad(alloca, n.Var) nextVar := cg.CreateFAdd(curVar, stepVal, "nextvar") cg.CreateStore(nextVar, alloca) endVal = cg.CreateFCmp(llvm.FloatONE, endVal, llvm.ConstFloat(llvm.DoubleType(), 0), "loopcond") afterBB := cg.AddBasicBlock(fun, "afterloop") cg.CreateCondBr(endVal, loopBB, afterBB) cg.SetInsertPointAtEnd(afterBB) if !oldVal.IsNil() { cg.NamedValues[n.Var] = oldVal } else { delete(cg.NamedValues, n.Var) } return llvm.ConstFloat(llvm.DoubleType(), 0) }
func (fr *frame) loadOrNull(cond, ptr llvm.Value, ty types.Type) *govalue { startbb := fr.builder.GetInsertBlock() loadbb := llvm.AddBasicBlock(fr.function, "") contbb := llvm.AddBasicBlock(fr.function, "") fr.builder.CreateCondBr(cond, loadbb, contbb) fr.builder.SetInsertPointAtEnd(loadbb) llty := fr.types.ToLLVM(ty) typedptr := fr.builder.CreateBitCast(ptr, llvm.PointerType(llty, 0), "") loadedval := fr.builder.CreateLoad(typedptr, "") fr.builder.CreateBr(contbb) fr.builder.SetInsertPointAtEnd(contbb) llv := fr.builder.CreatePHI(llty, "") llv.AddIncoming( []llvm.Value{llvm.ConstNull(llty), loadedval}, []llvm.BasicBlock{startbb, loadbb}, ) return newValue(llv, ty) }
func (c *Codegen) declareFunc(n *parser.FuncNode, obj llvm.Type) { sig := n.Signature name := c.mangle(sig.Name.Value) f := c.getLLVMFuncType(sig.Return, sig.Parameters, obj) llvmf := llvm.AddFunction(c.module, name, f) if obj != llvm.VoidType() { llvmf.Param(0).SetName("this") } block := llvm.AddBasicBlock(c.module.NamedFunction(name), "entry") c.functions[name] = block }
func (fr *frame) setupUnwindBlock(rec *ssa.BasicBlock, results *types.Tuple) { recoverbb := llvm.AddBasicBlock(fr.function, "") if rec != nil { fr.translateBlock(rec, recoverbb) } else if results.Len() == 0 || results.At(0).Anonymous() { // TODO(pcc): Remove this code after https://codereview.appspot.com/87210044/ lands fr.builder.SetInsertPointAtEnd(recoverbb) values := make([]llvm.Value, results.Len()) for i := range values { values[i] = llvm.ConstNull(fr.llvmtypes.ToLLVM(results.At(i).Type())) } fr.retInf.encode(llvm.GlobalContext(), fr.allocaBuilder, fr.builder, values) } else { fr.builder.SetInsertPointAtEnd(recoverbb) fr.builder.CreateUnreachable() } checkunwindbb := llvm.AddBasicBlock(fr.function, "") fr.builder.SetInsertPointAtEnd(checkunwindbb) exc := fr.createLandingPad(true) fr.runDefers() frame := fr.builder.CreateLoad(fr.frameptr, "") shouldresume := fr.builder.CreateIsNull(frame, "") resumebb := llvm.AddBasicBlock(fr.function, "") fr.builder.CreateCondBr(shouldresume, resumebb, recoverbb) fr.builder.SetInsertPointAtEnd(resumebb) fr.builder.CreateResume(exc) fr.builder.SetInsertPointAtEnd(fr.unwindBlock) fr.createLandingPad(false) fr.runtime.checkDefer.invoke(fr, checkunwindbb, fr.frameptr) fr.runDefers() fr.builder.CreateBr(recoverbb) }
func (v *Codegen) genFunctionDecl(n *parser.FunctionDecl) llvm.Value { var res llvm.Value mangledName := n.Function.MangledName(parser.MANGLE_ARK_UNSTABLE) function := v.curFile.Module.NamedFunction(mangledName) if function.IsNil() { //v.err("genning function `%s` doesn't exist in module", n.Function.Name) // hmmmm seems we just ignore this here } else { if !n.Prototype { block := llvm.AddBasicBlock(function, "entry") v.builder.SetInsertPointAtEnd(block) for i, par := range n.Function.Parameters { alloc := v.builder.CreateAlloca(v.typeToLLVMType(par.Variable.Type), par.Variable.MangledName(parser.MANGLE_ARK_UNSTABLE)) v.variableLookup[par.Variable] = alloc v.builder.CreateStore(function.Params()[i], alloc) } v.inFunction = true v.currentFunction = function for _, stat := range n.Function.Body.Nodes { v.genNode(stat) } v.inFunction = false retType := llvm.VoidType() if n.Function.ReturnType != nil { retType = v.typeToLLVMType(n.Function.ReturnType) } // function returns void, lets return void // unless its a prototype obviously... if retType == llvm.VoidType() && !n.Prototype { v.builder.CreateRetVoid() } } } return res }
// createCall emits the code for a function call, // taking into account receivers, and panic/defer. func (fr *frame) createCall(fn *govalue, argValues []*govalue) []*govalue { fntyp := fn.Type().Underlying().(*types.Signature) typinfo := fr.types.getSignatureInfo(fntyp) args := make([]llvm.Value, len(argValues)) for i, arg := range argValues { args[i] = arg.value } var results []llvm.Value if fr.unwindBlock.IsNil() { results = typinfo.call(fr.types.ctx, fr.allocaBuilder, fr.builder, fn.value, args) } else { contbb := llvm.AddBasicBlock(fr.function, "") results = typinfo.invoke(fr.types.ctx, fr.allocaBuilder, fr.builder, fn.value, args, contbb, fr.unwindBlock) } resultValues := make([]*govalue, len(results)) for i, res := range results { resultValues[i] = newValue(res, fntyp.Results().At(i).Type()) } return resultValues }
// bridgeRecoverFunc creates a function that may call recover(), and creates // a call to it from the current frame. The created function will be called // with a boolean parameter that indicates whether it may call recover(). // // The created function will have the same name as the current frame's function // with "$recover" appended, having the same return types and parameters with // an additional boolean parameter appended. // // A new frame will be returned for the newly created function. func (fr *frame) bridgeRecoverFunc(llfn llvm.Value, fti functionTypeInfo) *frame { // The bridging function must not be inlined, or the return address // may not correspond to the source function. llfn.AddFunctionAttr(llvm.NoInlineAttribute) // Call __go_can_recover, passing in the function's return address. entry := llvm.AddBasicBlock(llfn, "entry") fr.builder.SetInsertPointAtEnd(entry) canRecover := fr.runtime.canRecover.call(fr, fr.returnAddress(0))[0] returnType := fti.functionType.ReturnType() argTypes := fti.functionType.ParamTypes() argTypes = append(argTypes, canRecover.Type()) // Create and call the $recover function. ftiRecover := fti ftiRecover.functionType = llvm.FunctionType(returnType, argTypes, false) llfnRecover := ftiRecover.declare(fr.module.Module, llfn.Name()+"$recover") fr.addCommonFunctionAttrs(llfnRecover) llfnRecover.SetLinkage(llvm.InternalLinkage) args := make([]llvm.Value, len(argTypes)-1, len(argTypes)) for i := range args { args[i] = llfn.Param(i) } args = append(args, canRecover) result := fr.builder.CreateCall(llfnRecover, args, "") if returnType.TypeKind() == llvm.VoidTypeKind { fr.builder.CreateRetVoid() } else { fr.builder.CreateRet(result) } // The $recover function must condition calls to __go_recover on // the result of __go_can_recover passed in as an argument. fr = newFrame(fr.unit, llfnRecover) fr.retInf = ftiRecover.retInf fr.canRecover = fr.function.Param(len(argTypes) - 1) return fr }
func (n *FuncDecl) Gen(p *Parser, cg *CG) llvm.Value { cg.Protos[n.Proto.Name] = n.Proto fun := cg.GetFunction(n.Proto.Name) if fun.IsNil() { return errv("Prototype is missing") } if n.Proto.IsBinaryOp() { p.Prec[n.Proto.OperatorName()] = p.precedence() } bb := llvm.AddBasicBlock(fun, "entry") cg.SetInsertPointAtEnd(bb) cg.NamedValues = make(map[string]llvm.Value) args := fun.Params() for i := range args { alloca := createEntryBlockAlloca(fun, n.Proto.Args[i]) cg.CreateStore(args[i], alloca) cg.NamedValues[n.Proto.Args[i]] = alloca } retVal := n.Body.Gen(cg) if !retVal.IsNil() { cg.CreateRet(retVal) llvm.VerifyFunction(fun, llvm.PrintMessageAction) cg.Fpm.RunFunc(fun) return fun } fun.EraseFromParentAsFunction() if n.Proto.IsBinaryOp() { delete(p.Prec, n.Proto.OperatorName()) } return llvm.Value{} }
func (c *compiler) createInitMainFunction(mainPkg *ssa.Package, initmap map[*types.Package]gccgoimporter.InitData) error { initdata := c.buildPackageInitData(mainPkg, initmap) ftyp := llvm.FunctionType(llvm.VoidType(), nil, false) initMain := llvm.AddFunction(c.module.Module, "__go_init_main", ftyp) c.addCommonFunctionAttrs(initMain) entry := llvm.AddBasicBlock(initMain, "entry") builder := llvm.GlobalContext().NewBuilder() defer builder.Dispose() builder.SetInsertPointAtEnd(entry) for _, init := range initdata.Inits { initfn := c.module.Module.NamedFunction(init.InitFunc) if initfn.IsNil() { initfn = llvm.AddFunction(c.module.Module, init.InitFunc, ftyp) } builder.CreateCall(initfn, nil, "") } builder.CreateRetVoid() return nil }
func (u *unit) defineFunction(f *ssa.Function) { // Only define functions from this package, or synthetic // wrappers (which do not have a package). if f.Pkg != nil && f.Pkg != u.pkg { return } llfn := u.resolveFunctionGlobal(f) linkage := u.getFunctionLinkage(f) isMethod := f.Signature.Recv() != nil // Methods cannot be referred to via a descriptor. if !isMethod { llfd := u.resolveFunctionDescriptorGlobal(f) llfd.SetInitializer(llvm.ConstBitCast(llfn, llvm.PointerType(llvm.Int8Type(), 0))) llfd.SetLinkage(linkage) } // We only need to emit a descriptor for functions without bodies. if len(f.Blocks) == 0 { return } ssaopt.LowerAllocsToStack(f) if u.DumpSSA { f.WriteTo(os.Stderr) } fr := newFrame(u, llfn) defer fr.dispose() fr.addCommonFunctionAttrs(fr.function) fr.function.SetLinkage(linkage) fr.logf("Define function: %s", f.String()) fti := u.llvmtypes.getSignatureInfo(f.Signature) delete(u.undefinedFuncs, f) fr.retInf = fti.retInf // Push the compile unit and function onto the debug context. if u.GenerateDebug { u.debug.PushFunction(fr.function, f.Signature, f.Pos()) defer u.debug.PopFunction() u.debug.SetLocation(fr.builder, f.Pos()) } // If a function calls recover, we create a separate function to // hold the real function, and this function calls __go_can_recover // and bridges to it. if callsRecover(f) { fr = fr.bridgeRecoverFunc(fr.function, fti) } fr.blocks = make([]llvm.BasicBlock, len(f.Blocks)) fr.lastBlocks = make([]llvm.BasicBlock, len(f.Blocks)) for i, block := range f.Blocks { fr.blocks[i] = llvm.AddBasicBlock(fr.function, fmt.Sprintf(".%d.%s", i, block.Comment)) } fr.builder.SetInsertPointAtEnd(fr.blocks[0]) prologueBlock := llvm.InsertBasicBlock(fr.blocks[0], "prologue") fr.builder.SetInsertPointAtEnd(prologueBlock) // Map parameter positions to indices. We use this // when processing locals to map back to parameters // when generating debug metadata. paramPos := make(map[token.Pos]int) for i, param := range f.Params { paramPos[param.Pos()] = i llparam := fti.argInfos[i].decode(llvm.GlobalContext(), fr.builder, fr.builder) if isMethod && i == 0 { if _, ok := param.Type().Underlying().(*types.Pointer); !ok { llparam = fr.builder.CreateBitCast(llparam, llvm.PointerType(fr.types.ToLLVM(param.Type()), 0), "") llparam = fr.builder.CreateLoad(llparam, "") } } fr.env[param] = newValue(llparam, param.Type()) } // Load closure, extract free vars. if len(f.FreeVars) > 0 { for _, fv := range f.FreeVars { fr.env[fv] = newValue(llvm.ConstNull(u.llvmtypes.ToLLVM(fv.Type())), fv.Type()) } elemTypes := make([]llvm.Type, len(f.FreeVars)+1) elemTypes[0] = llvm.PointerType(llvm.Int8Type(), 0) // function pointer for i, fv := range f.FreeVars { elemTypes[i+1] = u.llvmtypes.ToLLVM(fv.Type()) } structType := llvm.StructType(elemTypes, false) closure := fr.runtime.getClosure.call(fr)[0] closure = fr.builder.CreateBitCast(closure, llvm.PointerType(structType, 0), "") for i, fv := range f.FreeVars { ptr := fr.builder.CreateStructGEP(closure, i+1, "") ptr = fr.builder.CreateLoad(ptr, "") fr.env[fv] = newValue(ptr, fv.Type()) } } // Allocate stack space for locals in the prologue block. for _, local := range f.Locals { typ := fr.llvmtypes.ToLLVM(deref(local.Type())) alloca := fr.builder.CreateAlloca(typ, local.Comment) fr.memsetZero(alloca, llvm.SizeOf(typ)) bcalloca := fr.builder.CreateBitCast(alloca, llvm.PointerType(llvm.Int8Type(), 0), "") value := newValue(bcalloca, local.Type()) fr.env[local] = value if fr.GenerateDebug { paramIndex, ok := paramPos[local.Pos()] if !ok { paramIndex = -1 } fr.debug.Declare(fr.builder, local, alloca, paramIndex) } } // If this is the "init" function, enable init-specific optimizations. if !isMethod && f.Name() == "init" { fr.isInit = true } // If the function contains any defers, we must first create // an unwind block. We can short-circuit the check for defers with // f.Recover != nil. if f.Recover != nil || hasDefer(f) { fr.unwindBlock = llvm.AddBasicBlock(fr.function, "") fr.frameptr = fr.builder.CreateAlloca(llvm.Int8Type(), "") } term := fr.builder.CreateBr(fr.blocks[0]) fr.allocaBuilder.SetInsertPointBefore(term) for _, block := range f.DomPreorder() { fr.translateBlock(block, fr.blocks[block.Index]) } fr.fixupPhis() if !fr.unwindBlock.IsNil() { fr.setupUnwindBlock(f.Recover, f.Signature.Results()) } // The init function needs to register the GC roots first. We do this // after generating code for it because allocations may have caused // additional GC roots to be created. if fr.isInit { fr.builder.SetInsertPointBefore(prologueBlock.FirstInstruction()) fr.registerGcRoots() } }
// createThunk creates a thunk from a // given function and arguments, suitable for use with // "defer" and "go". func (fr *frame) createThunk(call ssa.CallInstruction) (thunk llvm.Value, arg llvm.Value) { seenarg := make(map[ssa.Value]bool) var args []ssa.Value var argtypes []*types.Var packArg := func(arg ssa.Value) { switch arg.(type) { case *ssa.Builtin, *ssa.Function, *ssa.Const, *ssa.Global: // Do nothing: we can generate these in the thunk default: if !seenarg[arg] { seenarg[arg] = true args = append(args, arg) field := types.NewField(0, nil, "_", arg.Type(), true) argtypes = append(argtypes, field) } } } packArg(call.Common().Value) for _, arg := range call.Common().Args { packArg(arg) } var isRecoverCall bool i8ptr := llvm.PointerType(llvm.Int8Type(), 0) var structllptr llvm.Type if len(args) == 0 { if builtin, ok := call.Common().Value.(*ssa.Builtin); ok { isRecoverCall = builtin.Name() == "recover" } if isRecoverCall { // When creating a thunk for recover(), we must pass fr.canRecover. arg = fr.builder.CreateZExt(fr.canRecover, fr.target.IntPtrType(), "") arg = fr.builder.CreateIntToPtr(arg, i8ptr, "") } else { arg = llvm.ConstPointerNull(i8ptr) } } else { structtype := types.NewStruct(argtypes, nil) arg = fr.createTypeMalloc(structtype) structllptr = arg.Type() for i, ssaarg := range args { argptr := fr.builder.CreateStructGEP(arg, i, "") fr.builder.CreateStore(fr.llvmvalue(ssaarg), argptr) } arg = fr.builder.CreateBitCast(arg, i8ptr, "") } thunkfntype := llvm.FunctionType(llvm.VoidType(), []llvm.Type{i8ptr}, false) thunkfn := llvm.AddFunction(fr.module.Module, "", thunkfntype) thunkfn.SetLinkage(llvm.InternalLinkage) fr.addCommonFunctionAttrs(thunkfn) thunkfr := newFrame(fr.unit, thunkfn) defer thunkfr.dispose() prologuebb := llvm.AddBasicBlock(thunkfn, "prologue") thunkfr.builder.SetInsertPointAtEnd(prologuebb) if isRecoverCall { thunkarg := thunkfn.Param(0) thunkarg = thunkfr.builder.CreatePtrToInt(thunkarg, fr.target.IntPtrType(), "") thunkfr.canRecover = thunkfr.builder.CreateTrunc(thunkarg, llvm.Int1Type(), "") } else if len(args) > 0 { thunkarg := thunkfn.Param(0) thunkarg = thunkfr.builder.CreateBitCast(thunkarg, structllptr, "") for i, ssaarg := range args { thunkargptr := thunkfr.builder.CreateStructGEP(thunkarg, i, "") thunkarg := thunkfr.builder.CreateLoad(thunkargptr, "") thunkfr.env[ssaarg] = newValue(thunkarg, ssaarg.Type()) } } _, isDefer := call.(*ssa.Defer) entrybb := llvm.AddBasicBlock(thunkfn, "entry") br := thunkfr.builder.CreateBr(entrybb) thunkfr.allocaBuilder.SetInsertPointBefore(br) thunkfr.builder.SetInsertPointAtEnd(entrybb) var exitbb llvm.BasicBlock if isDefer { exitbb = llvm.AddBasicBlock(thunkfn, "exit") thunkfr.runtime.setDeferRetaddr.call(thunkfr, llvm.BlockAddress(thunkfn, exitbb)) } if isDefer && isRecoverCall { thunkfr.callRecover(true) } else { thunkfr.callInstruction(call) } if isDefer { thunkfr.builder.CreateBr(exitbb) thunkfr.builder.SetInsertPointAtEnd(exitbb) } thunkfr.builder.CreateRetVoid() thunk = fr.builder.CreateBitCast(thunkfn, i8ptr, "") return }
func (rfi *runtimeFnInfo) invoke(f *frame, lpad llvm.BasicBlock, args ...llvm.Value) []llvm.Value { contbb := llvm.AddBasicBlock(f.function, "") return rfi.fi.invoke(f.llvmtypes.ctx, f.allocaBuilder, f.builder, rfi.fn, llvm.Value{nil}, args, contbb, lpad) }
// mapIterNext advances the iterator, and returns the tuple (ok, k, v). func (fr *frame) mapIterNext(iter []*govalue) []*govalue { maptyp := iter[0].Type().Underlying().(*types.Map) ktyp := maptyp.Key() klltyp := fr.types.ToLLVM(ktyp) vtyp := maptyp.Elem() vlltyp := fr.types.ToLLVM(vtyp) m, isinitptr := iter[0], iter[1] i8ptr := llvm.PointerType(llvm.Int8Type(), 0) mapiterbufty := llvm.ArrayType(i8ptr, 4) mapiterbuf := fr.allocaBuilder.CreateAlloca(mapiterbufty, "") mapiterbufelem0ptr := fr.builder.CreateStructGEP(mapiterbuf, 0, "") keybuf := fr.allocaBuilder.CreateAlloca(klltyp, "") keyptr := fr.builder.CreateBitCast(keybuf, i8ptr, "") valbuf := fr.allocaBuilder.CreateAlloca(vlltyp, "") valptr := fr.builder.CreateBitCast(valbuf, i8ptr, "") isinit := fr.builder.CreateLoad(isinitptr.value, "") initbb := llvm.AddBasicBlock(fr.function, "") nextbb := llvm.AddBasicBlock(fr.function, "") contbb := llvm.AddBasicBlock(fr.function, "") fr.builder.CreateCondBr(isinit, nextbb, initbb) fr.builder.SetInsertPointAtEnd(initbb) fr.builder.CreateStore(llvm.ConstAllOnes(llvm.Int1Type()), isinitptr.value) fr.runtime.mapiterinit.call(fr, m.value, mapiterbufelem0ptr) fr.builder.CreateBr(contbb) fr.builder.SetInsertPointAtEnd(nextbb) fr.runtime.mapiternext.call(fr, mapiterbufelem0ptr) fr.builder.CreateBr(contbb) fr.builder.SetInsertPointAtEnd(contbb) mapiterbufelem0 := fr.builder.CreateLoad(mapiterbufelem0ptr, "") okbit := fr.builder.CreateIsNotNull(mapiterbufelem0, "") ok := fr.builder.CreateZExt(okbit, llvm.Int8Type(), "") loadbb := llvm.AddBasicBlock(fr.function, "") cont2bb := llvm.AddBasicBlock(fr.function, "") fr.builder.CreateCondBr(okbit, loadbb, cont2bb) fr.builder.SetInsertPointAtEnd(loadbb) fr.runtime.mapiter2.call(fr, mapiterbufelem0ptr, keyptr, valptr) loadbb = fr.builder.GetInsertBlock() loadedkey := fr.builder.CreateLoad(keybuf, "") loadedval := fr.builder.CreateLoad(valbuf, "") fr.builder.CreateBr(cont2bb) fr.builder.SetInsertPointAtEnd(cont2bb) k := fr.builder.CreatePHI(klltyp, "") k.AddIncoming( []llvm.Value{llvm.ConstNull(klltyp), loadedkey}, []llvm.BasicBlock{contbb, loadbb}, ) v := fr.builder.CreatePHI(vlltyp, "") v.AddIncoming( []llvm.Value{llvm.ConstNull(vlltyp), loadedval}, []llvm.BasicBlock{contbb, loadbb}, ) return []*govalue{newValue(ok, types.Typ[types.Bool]), newValue(k, ktyp), newValue(v, vtyp)} }