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 *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 }
// parseBasicBlock converts the provided LLVM IR basic block into a basic block // in which the instructions have been translated to Go AST statement nodes but // the terminator instruction is an unmodified LLVM IR value. func parseBasicBlock(llBB llvm.BasicBlock) (bb *basicBlock, err error) { name, err := getBBName(llBB.AsValue()) if err != nil { return nil, err } bb = &basicBlock{name: name, phis: make(map[string][]*definition)} for inst := llBB.FirstInstruction(); !inst.IsNil(); inst = llvm.NextInstruction(inst) { // Handle terminator instruction. if inst == llBB.LastInstruction() { err = bb.addTerm(inst) if err != nil { return nil, errutil.Err(err) } return bb, nil } // Handle PHI instructions. if inst.InstructionOpcode() == llvm.PHI { ident, def, err := parsePHIInst(inst) if err != nil { return nil, errutil.Err(err) } bb.phis[ident] = def continue } // Handle non-terminator instructions. stmt, err := parseInst(inst) if err != nil { return nil, err } bb.stmts = append(bb.stmts, stmt) } return nil, errutil.Newf("invalid basic block %q; contains no instructions", name) }
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]) fr.transformSwitches(f) prologueBlock := llvm.InsertBasicBlock(fr.blocks[0], "prologue") fr.builder.SetInsertPointAtEnd(prologueBlock) for i, param := range f.Params { 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.function.Param(fti.chainIndex) 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 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(), "") } // Keep track of the block into which we need to insert the call // to __go_register_gc_roots. This needs to be inserted after the // init guard check under the llgo ABI. var registerGcBlock llvm.BasicBlock // If this is the "init" function, emit the init guard check and // enable init-specific optimizations. if !isMethod && f.Name() == "init" { registerGcBlock = fr.emitInitPrologue() fr.isInit = true } fr.builder.CreateBr(fr.blocks[0]) fr.allocaBuilder.SetInsertPointBefore(prologueBlock.FirstInstruction()) for _, block := range f.DomPreorder() { llblock := fr.blocks[block.Index] if llblock.IsNil() { continue } fr.translateBlock(block, llblock) } 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(registerGcBlock.FirstInstruction()) fr.registerGcRoots() } }