// 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 }
// 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) }
// 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()) }
// 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 }