func (c *compiler) getBoolString(v llvm.Value) llvm.Value { startBlock := c.builder.GetInsertBlock() resultBlock := llvm.InsertBasicBlock(startBlock, "") resultBlock.MoveAfter(startBlock) falseBlock := llvm.InsertBasicBlock(resultBlock, "") CharPtr := llvm.PointerType(llvm.Int8Type(), 0) falseString := c.builder.CreateGlobalStringPtr("false", "") falseString = c.builder.CreateBitCast(falseString, CharPtr, "") trueString := c.builder.CreateGlobalStringPtr("true", "") trueString = c.builder.CreateBitCast(trueString, CharPtr, "") c.builder.CreateCondBr(v, resultBlock, falseBlock) c.builder.SetInsertPointAtEnd(falseBlock) c.builder.CreateBr(resultBlock) c.builder.SetInsertPointAtEnd(resultBlock) result := c.builder.CreatePHI(CharPtr, "") result.AddIncoming([]llvm.Value{trueString, falseString}, []llvm.BasicBlock{startBlock, falseBlock}) return result }
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 { if r.Pkg() != nil && r.Pkg() != u.pkg.Object { return } else if named, ok := r.Type().(*types.Named); ok && named.Obj().Parent() == types.Universe { // This condition is true iff f is error.Error. if u.pkg.Object.Path() != "runtime" { 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) // Push the function onto the debug context. // TODO(axw) create a fake CU for synthetic functions if u.GenerateDebug && f.Synthetic == "" { u.debug.pushFunctionContext(llvmFunction, f.Signature, f.Pos()) defer u.debug.popFunctionContext() u.debug.setLocation(u.builder, f.Pos()) } // 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++ } // 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 + paramOffset llparam := llvmFunction.Param(i + paramOffset) fr.env[param] = fr.NewValue(llparam, 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 if fr.GenerateDebug { paramIndex, ok := paramPos[local.Pos()] if !ok { paramIndex = -1 } fr.debug.declare(fr.builder, local, alloca, paramIndex) } } // 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]) } }