func (n *VarExpr) Gen(cg *CG) llvm.Value { fun := cg.GetInsertBlock().Parent() var oldBindingNames []string var oldBindingValues []llvm.Value for name, init := range n.Names { var initVal llvm.Value if init != nil { init.Gen(cg) if initVal.IsNil() { return llvm.Value{} } } else { initVal = llvm.ConstFloat(cg.FloatType(), 0) } alloca := createEntryBlockAlloca(fun, name) cg.CreateStore(initVal, alloca) oldBindingNames = append(oldBindingNames, name) oldBindingValues = append(oldBindingValues, cg.NamedValues[name]) cg.NamedValues[name] = alloca } bodyVal := n.Body.Gen(cg) if bodyVal.IsNil() { return llvm.Value{} } for i, name := range oldBindingNames { cg.NamedValues[name] = oldBindingValues[i] } return bodyVal }
func (c *Codegen) generateArithmeticBinaryExpr(left, right llvm.Value, op string) llvm.Value { t := c.getUnderlyingType(left.Type()) switch op { case "+": if t == PRIMITIVE_TYPES["float"] { return c.builder.CreateFAdd(left, right, "") } else if t == PRIMITIVE_TYPES["int"] { return c.builder.CreateAdd(left, right, "") } else if t == c.templates["string"].Type { return c.generateStringConcat(left, right) } case "-": if t == PRIMITIVE_TYPES["float"] { return c.builder.CreateFSub(left, right, "") } else if t == PRIMITIVE_TYPES["int"] { return c.builder.CreateSub(left, right, "") } case "*": if t == PRIMITIVE_TYPES["float"] { return c.builder.CreateFMul(left, right, "") } else if t == PRIMITIVE_TYPES["int"] { return c.builder.CreateMul(left, right, "") } case "/": if t == PRIMITIVE_TYPES["float"] { return c.builder.CreateFDiv(left, right, "") } else if t == PRIMITIVE_TYPES["int"] { return c.builder.CreateSDiv(left, right, "") } } return null }
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 (c *Codegen) generateVarDecl(node *parser.VarDeclNode, global bool) { t := c.getLLVMType(node.Type) name := node.Name.Value if c.scope.Declared(name) { // Error name has already been declared } var alloc, val llvm.Value if node.Value == nil { if t.TypeKind() == llvm.PointerTypeKind { val = c.convert(c.scope.GetValue("null"), t) } else { val = llvm.Undef(t) } } else { val = c.convert(c.generateExpression(node.Value), t) } if !global { alloc = c.builder.CreateAlloca(t, name) c.builder.CreateStore(val, alloc) } else { alloc = llvm.AddGlobal(c.module, t, name) alloc.SetInitializer(val) } c.scope.AddVariable(name, alloc) }
func directEncode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, argTypes []llvm.Type, args []llvm.Value, val llvm.Value) { valType := val.Type() switch len(argTypes) { case 0: // do nothing case 1: if argTypes[0].C == valType.C { args[0] = val return } alloca := allocaBuilder.CreateAlloca(valType, "") bitcast := builder.CreateBitCast(alloca, llvm.PointerType(argTypes[0], 0), "") builder.CreateStore(val, alloca) args[0] = builder.CreateLoad(bitcast, "") case 2: encodeType := llvm.StructType(argTypes, false) alloca := allocaBuilder.CreateAlloca(valType, "") bitcast := builder.CreateBitCast(alloca, llvm.PointerType(encodeType, 0), "") builder.CreateStore(val, alloca) args[0] = builder.CreateLoad(builder.CreateStructGEP(bitcast, 0, ""), "") args[1] = builder.CreateLoad(builder.CreateStructGEP(bitcast, 1, ""), "") default: panic("unexpected argTypes size") } }
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 (fr *frame) createZExtOrTrunc(v llvm.Value, t llvm.Type, name string) llvm.Value { switch n := v.Type().IntTypeWidth() - t.IntTypeWidth(); { case n < 0: v = fr.builder.CreateZExt(v, fr.target.IntPtrType(), name) case n > 0: v = fr.builder.CreateTrunc(v, fr.target.IntPtrType(), name) } return v }
func (c *Codegen) unbox(val llvm.Value) llvm.Value { t := c.getUnderlyingType(val.Type()) switch t { case c.templates["string"].Type: val = c.builder.CreateStructGEP(val, 0, "") val = c.builder.CreateLoad(val, "") } return val }
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) setBranchWeightMetadata(br llvm.Value, trueweight, falseweight uint64) { mdprof := llvm.MDKindID("prof") mdnode := llvm.MDNode([]llvm.Value{ llvm.MDString("branch_weights"), llvm.ConstInt(llvm.Int32Type(), trueweight, false), llvm.ConstInt(llvm.Int32Type(), falseweight, false), }) br.SetMetadata(mdprof, mdnode) }
func (v *Codegen) genEnumLiteral(n *parser.EnumLiteral) llvm.Value { enumType := n.Type.ActualType().(parser.EnumType) enumLLVMType := v.typeToLLVMType(n.Type) memberIdx := enumType.MemberIndex(n.Member) member := enumType.Members[memberIdx] if enumType.Simple { return llvm.ConstInt(enumLLVMType, uint64(member.Tag), false) } // TODO: Handle other integer size, maybe dynamic depending on max value? tagValue := llvm.ConstInt(llvm.IntType(32), uint64(member.Tag), false) enumValue := llvm.Undef(enumLLVMType) enumValue = v.builder().CreateInsertValue(enumValue, tagValue, 0, "") memberLLVMType := v.typeToLLVMType(member.Type) var memberValue llvm.Value if n.TupleLiteral != nil { memberValue = v.genTupleLiteral(n.TupleLiteral) } else if n.CompositeLiteral != nil { memberValue = v.genCompositeLiteral(n.CompositeLiteral) } if v.inFunction() { alloc := v.builder().CreateAlloca(enumLLVMType, "") tagGep := v.builder().CreateStructGEP(alloc, 0, "") v.builder().CreateStore(tagValue, tagGep) if !memberValue.IsNil() { dataGep := v.builder().CreateStructGEP(alloc, 1, "") dataGep = v.builder().CreateBitCast(dataGep, llvm.PointerType(memberLLVMType, 0), "") v.builder().CreateStore(memberValue, dataGep) } return v.builder().CreateLoad(alloc, "") } else { panic("unimplemented: global enum literal") } }
// hackDump returns the value dump as a string. func hackDump(v llvm.Value) (string, error) { // Open temp file. // TODO: Use an in-memory file instead of /tmp/x. fd, err := unix.Open("/tmp/x", unix.O_WRONLY|unix.O_TRUNC|unix.O_CREAT, 0644) if err != nil { return "", errutil.Err(err) } // Store original stderr. stderr, err := unix.Dup(2) if err != nil { return "", errutil.Err(err) } // Capture stderr and redirect its output to the temp file. err = unix.Dup2(fd, 2) if err != nil { return "", errutil.Err(err) } err = unix.Close(fd) if err != nil { return "", errutil.Err(err) } // Dump value. v.Dump() C.fflush_stderr() // Restore stderr. err = unix.Dup2(stderr, 2) if err != nil { return "", errutil.Err(err) } err = unix.Close(stderr) if err != nil { return "", errutil.Err(err) } // Return content of temp file. buf, err := ioutil.ReadFile("/tmp/x") if err != nil { return "", errutil.Err(err) } return string(buf), nil }
// parseOperand converts the provided LLVM IR operand into an equivalent Go AST // expression node (a basic literal, a composite literal or an identifier). // // Syntax: // i32 1 // %foo = ... func parseOperand(op llvm.Value) (ast.Expr, error) { // TODO: Support *BasicLit, *CompositeLit. // Parse and validate tokens. tokens, err := getTokens(op) if err != nil { return nil, err } if len(tokens) < 2 { // TODO: Remove debug output. op.Dump() return nil, errutil.Newf("unable to parse operand; expected 2 >= tokens, got %d", len(tokens)) } // TODO: Add support for operand of other types than int. // TODO: Parse type. // Create and return a constant operand. // i32 42 if tokens[0].Kind == lltoken.Type { switch tok := tokens[1]; tok.Kind { case lltoken.Int: return &ast.BasicLit{Kind: token.INT, Value: tok.Val}, nil case lltoken.LocalVar: return getIdent(tok) default: return nil, errutil.Newf("support for LLVM IR token kind %v not yet implemented", tok.Kind) } } // Create and return a variable operand. // %foo = ... if tokens[1].Kind == lltoken.Equal { switch tok := tokens[0]; tok.Kind { case lltoken.LocalVar, lltoken.LocalID: // %foo // %42 return getIdent(tok) default: return nil, errutil.Newf("support for LLVM IR token kind %v not yet implemented", tok.Kind) } } return nil, errutil.New("support for LLVM IR operand not yet implemented") }
// PushFunction creates debug metadata for the specified function, // and pushes it onto the scope stack. func (d *DIBuilder) PushFunction(fnptr llvm.Value, sig *types.Signature, pos token.Pos) { var diFile llvm.Metadata var line int if file := d.fset.File(pos); file != nil { d.fnFile = file.Name() diFile = d.getFile(file) line = file.Line(pos) } d.fn = d.builder.CreateFunction(d.scope(), llvm.DIFunction{ Name: fnptr.Name(), // TODO(axw) unmangled name? LinkageName: fnptr.Name(), File: diFile, Line: line, Type: d.DIType(sig), IsDefinition: true, }) fnptr.SetSubprogram(d.fn) }
// parseBinOp converts the provided LLVM IR binary operation into an equivalent // Go AST node (an assignment statement with a binary expression on the right- // hand side). // // Syntax: // <result> add <type> <op1>, <op2> // // References: // http://llvm.org/docs/LangRef.html#binary-operations func parseBinOp(inst llvm.Value, op token.Token) (ast.Stmt, error) { x, err := parseOperand(inst.Operand(0)) if err != nil { return nil, err } y, err := parseOperand(inst.Operand(1)) if err != nil { return nil, err } result, err := getResult(inst) if err != nil { return nil, errutil.Err(err) } lhs := []ast.Expr{result} rhs := []ast.Expr{&ast.BinaryExpr{X: x, Op: op, Y: y}} // TODO: Use "=" instead of ":=" and let go-post and grind handle the ":=" to // "=" propagation. return &ast.AssignStmt{Lhs: lhs, Tok: token.DEFINE, Rhs: rhs}, nil }
func (c *Codegen) convert(val llvm.Value, t llvm.Type) llvm.Value { if val.Type() == t { return val } if val == c.scope.GetValue("null") { log.Println("Null conversion") return llvm.ConstPointerNull(t) } switch val.Type() { case PRIMITIVE_TYPES["int"]: if t == PRIMITIVE_TYPES["float"] { return c.builder.CreateSIToFP(val, t, "") } } return val }
// addTerm adds the provided terminator instruction to the basic block. If the // terminator instruction doesn't have a target basic block (e.g. ret) it is // parsed and added to the statements list of the basic block instead. func (bb *basicBlock) addTerm(term llvm.Value) error { // TODO: Check why there is no opcode in the llvm library for the resume // terminator instruction. switch opcode := term.InstructionOpcode(); opcode { case llvm.Ret: // The return instruction doesn't have any target basic blocks so treat it // like a regular instruction and append it to the list of statements. ret, err := parseRetInst(term) if err != nil { return err } bb.stmts = append(bb.stmts, ret) case llvm.Br, llvm.Switch, llvm.IndirectBr, llvm.Invoke, llvm.Unreachable: // Parse the terminator instruction during the control flow analysis. bb.term = term default: return errutil.Newf("non-terminator instruction %q at end of basic block", prettyOpcode(opcode)) } return nil }
// getBBName returns the name (or ID if unnamed) of a basic block. func getBBName(v llvm.Value) (string, error) { if !v.IsBasicBlock() { return "", errutil.Newf("invalid value type; expected basic block, got %v", v.Type()) } // Locate the name of a named basic block. if name := v.Name(); len(name) > 0 { return name, nil } // Locate the ID of an unnamed basic block by parsing the value dump in // search for its basic block label. // // Example value dump: // 0: // br i1 true, label %1, label %2 // // Each basic block is expected to have a label, which requires the // "unnamed.patch" to be applied to the llvm.org/llvm/bindings/go/llvm code // base. s, err := hackDump(v) if err != nil { return "", errutil.Err(err) } tokens := lexer.ParseString(s) if len(tokens) < 1 { return "", errutil.Newf("unable to locate basic block label in %q", s) } tok := tokens[0] if tok.Kind != token.Label { return "", errutil.Newf("invalid token; expected %v, got %v", token.Label, tok.Kind) } return tok.Val, nil }
func (a llvmAttribute) Apply(v llvm.Value) { if !v.IsAFunction().IsNil() { v.AddFunctionAttr(llvm.Attribute(a)) } else { v.AddAttribute(llvm.Attribute(a)) } }
func (c *compiler) addCommonFunctionAttrs(fn llvm.Value) { fn.AddTargetDependentFunctionAttr("disable-tail-calls", "true") fn.AddTargetDependentFunctionAttr("split-stack", "") if attr := c.SanitizerAttribute; attr != 0 { fn.AddFunctionAttr(attr) } }
// getBrCond parses the provided branch instruction and returns its condition. // // Syntax: // br i1 <cond>, label <target_true>, label <target_false> func getBrCond(term llvm.Value) (cond ast.Expr, targetTrue, targetFalse string, err error) { // Parse and validate tokens. tokens, err := getTokens(term) if err != nil { return nil, "", "", err } if len(tokens) != 10 { // TODO: Remove debug output. term.Dump() return nil, "", "", errutil.Newf("unable to parse conditional branch instruction; expected 10 tokens, got %d", len(tokens)) } // Create and return the condition. switch tok := tokens[2]; tok.Kind { case lltoken.KwTrue, lltoken.KwFalse, lltoken.LocalVar, lltoken.LocalID: // true // false // %foo // %42 ident, err := getIdent(tok) if err != nil { return nil, "", "", errutil.Err(err) } return ident, tokens[5].Val, tokens[8].Val, nil case lltoken.Int: // 1 // 0 switch tok.Val { case "0": return newIdent("false"), tokens[5].Val, tokens[8].Val, nil case "1": return newIdent("true"), tokens[5].Val, tokens[8].Val, nil default: return nil, "", "", errutil.Newf("invalid integer value; expected boolean, got %q", tok.Val) } default: return nil, "", "", errutil.Newf("support for LLVM IR token kind %v not yet implemented", tok.Kind) } }
// Declare creates an llvm.dbg.declare call for the specified function // parameter or local variable. func (d *DIBuilder) Declare(b llvm.Builder, v ssa.Value, llv llvm.Value, paramIndex int) { tag := tagAutoVariable if paramIndex >= 0 { tag = tagArgVariable } var diFile llvm.Value var line int if file := d.fset.File(v.Pos()); file != nil { line = file.Line(v.Pos()) diFile = d.getFile(file) } localVar := d.builder.CreateLocalVariable(d.scope(), llvm.DILocalVariable{ Tag: tag, Name: llv.Name(), File: diFile, Line: line, ArgNo: paramIndex + 1, Type: d.DIType(v.Type()), }) expr := d.builder.CreateExpression(nil) d.builder.InsertDeclareAtEnd(llv, localVar, expr, b.GetInsertBlock()) }
func (c *Codegen) generateCall(node *parser.CallExprNode, obj llvm.Value) llvm.Value { fn, args := c.getFunction(node.Function) if !obj.IsNil() { args = append([]llvm.Value{obj}, args...) } for i, arg := range node.Arguments { expr := c.generateExpression(arg) if fn.Type().ElementType().ParamTypesCount() > i { expr = c.convert(expr, fn.Type().ElementType().ParamTypes()[i]) } //Unbox arguments for C functions if fn.BasicBlocksCount() == 0 { expr = c.unbox(expr) } args = append(args, expr) } return c.builder.CreateCall(fn, args, "") }
func (a nameAttribute) Apply(v llvm.Value) { if !v.IsAFunction().IsNil() { name := string(a) curr := v.GlobalParent().NamedFunction(name) if !curr.IsNil() && curr != v { if curr.BasicBlocksCount() != 0 { panic(fmt.Errorf("Want to take the name %s from a function that has a body!", name)) } curr.SetName(name + "_llgo_replaced") curr.ReplaceAllUsesWith(llvm.ConstBitCast(v, curr.Type())) } v.SetName(name) } else { v.SetName(string(a)) } }
// parseRetInst converts the provided LLVM IR ret instruction into an equivalent // Go return statement. // // Syntax: // ret void // ret <type> <val> func parseRetInst(inst llvm.Value) (*ast.ReturnStmt, error) { // TODO: Make more robust by using proper parsing instead of relying on // tokens. The current approach is used for a proof of concept and would fail // for composite literals. This TODO applies to the use of tokens in all // functions. // Parse and validate tokens. tokens, err := getTokens(inst) if err != nil { return nil, err } if len(tokens) < 4 { // TODO: Remove debug output. inst.Dump() return nil, errutil.Newf("unable to parse return instruction; expected >= 4 tokens, got %d", len(tokens)) } typ := tokens[1] if typ.Kind != lltoken.Type { return nil, errutil.Newf(`invalid return instruction; expected type token, got %q`, typ) } // Create and return a void return statement. if typ.Val == "void" { return &ast.ReturnStmt{}, nil } // Create and return a return statement. val, err := parseOperand(inst.Operand(0)) if err != nil { return nil, errutil.Err(err) } ret := &ast.ReturnStmt{ Results: []ast.Expr{val}, } return ret, nil }
// parsePHIInst converts the provided LLVM IR phi instruction into an equivalent // variable definition mapping. // // Syntax: // %foo = phi i32 [ 42, %2 ], [ %bar, %3 ] func parsePHIInst(inst llvm.Value) (ident string, defs []*definition, err error) { // Parse result. result, err := getResult(inst) if err != nil { return "", nil, errutil.Err(err) } ident = result.(*ast.Ident).Name // Parse and validate tokens. tokens, err := getTokens(inst) if err != nil { return "", nil, errutil.Err(err) } if len(tokens) < 10 { return "", nil, errutil.Newf("unable to parse PHI instruction; expected >= 10 tokens, got %d", len(tokens)) } // Parse operands. for i := 0; i < inst.OperandsCount(); i++ { // Parse variable definition expression. expr, err := parseOperand(inst.Operand(i)) if err != nil { return "", nil, errutil.Err(err) } // Parse source basic block. bbTok := tokens[7+i*6] if bbTok.Kind != lltoken.LocalID { return "", nil, errutil.Newf("invalid operand token, expected LocalID, got %v", bbTok.Kind) } def := &definition{bb: bbTok.Val, expr: expr} defs = append(defs, def) } return ident, defs, nil }
func (c *Codegen) generateComparisonBinaryExpr(left, right llvm.Value, op string) llvm.Value { t := c.getUnderlyingType(left.Type()) if t == PRIMITIVE_TYPES["float"] { return c.builder.CreateFCmp(floatPredicates[op], left, right, "") } else if t == PRIMITIVE_TYPES["int"] || op == "==" || op == "!=" { log.Println("Left:", left.Type(), "Right:", right.Type()) return c.builder.CreateICmp(intPredicates[op], left, right, "") } return null }
// parseInst converts the provided LLVM IR instruction into an equivalent Go AST // node (a statement). func parseInst(inst llvm.Value) (ast.Stmt, error) { // TODO: Remove debug output. if flagVerbose { fmt.Println("parseInst:") fmt.Println(" nops:", inst.OperandsCount()) inst.Dump() fmt.Println() } // Assignment operation. // %foo = ... opcode := inst.InstructionOpcode() if _, err := getResult(inst); err == nil { // Binary Operations switch opcode { case llvm.Add, llvm.FAdd: return parseBinOp(inst, token.ADD) case llvm.Sub, llvm.FSub: return parseBinOp(inst, token.SUB) case llvm.Mul, llvm.FMul: return parseBinOp(inst, token.MUL) case llvm.UDiv, llvm.SDiv, llvm.FDiv: // TODO: Handle signed and unsigned div separately. return parseBinOp(inst, token.QUO) case llvm.URem, llvm.SRem, llvm.FRem: // TODO: Handle signed and unsigned mod separately. return parseBinOp(inst, token.REM) // Bitwise Binary Operations case llvm.Shl: return parseBinOp(inst, token.SHL) case llvm.LShr, llvm.AShr: // TODO: Handle logical and arithmetic shift right separately. return parseBinOp(inst, token.SHR) case llvm.And: return parseBinOp(inst, token.AND) case llvm.Or: return parseBinOp(inst, token.OR) case llvm.Xor: return parseBinOp(inst, token.XOR) // Other Operators case llvm.ICmp, llvm.FCmp: pred, err := getCmpPred(inst) if err != nil { return nil, errutil.Err(err) } return parseBinOp(inst, pred) } } return nil, errutil.Newf("support for LLVM IR instruction %q not yet implemented", prettyOpcode(opcode)) }
// 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 (ai *indirectArgInfo) encode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, args []llvm.Value, val llvm.Value) { alloca := allocaBuilder.CreateAlloca(val.Type(), "") builder.CreateStore(val, alloca) args[ai.argOffset] = alloca }