diff --git a/cl/compile.go b/cl/compile.go index 97a991fd..91c4d7fd 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -228,6 +228,7 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun sig = types.NewSignatureType(nil, nil, nil, params, results, false) } fn = pkg.NewFuncEx(name, sig, llssa.Background(ftype), hasCtx, f.Origin() != nil) + p.pkg.DIBuilder().DebugFunction(fn, p.goProg.Fset.Position(f.Pos())) } if nblk := len(f.Blocks); nblk > 0 { @@ -249,12 +250,14 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun log.Println("==> FuncBody", name) } b := fn.NewBuilder() + b.SetCurrentDebugLocation(p.fn, p.goProg.Fset.Position(f.Pos())) p.bvals = make(map[ssa.Value]llssa.Expr) off := make([]int, len(f.Blocks)) for i, block := range f.Blocks { off[i] = p.compilePhis(b, block) } p.blkInfos = blocks.Infos(f.Blocks) + p.debugParams(b, f) i := 0 for { block := f.Blocks[i] @@ -277,6 +280,18 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun return fn, nil, goFunc } +func (p *context) debugParams(b llssa.Builder, f *ssa.Function) { + for argNo, param := range f.Params { + blk := p.fn.Block(0) + pos := p.goProg.Fset.Position(param.Pos()) + v := p.compileValue(b, param) + ty := param.Type() + t := b.Pkg.DIBuilder().DIType(p.prog.Type(ty, llssa.InGo), pos) + div := b.Pkg.DIBuilder().DIVarParam(p.fn, p.goProg.Fset.Position(param.Pos()), param.Name(), t, argNo) + b.Pkg.DIBuilder().DebugValue(v, div, p.fn, pos, blk) + } +} + func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, n int, doMainInit, doModInit bool) llssa.BasicBlock { var last int var pyModInit bool @@ -454,6 +469,9 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue } log.Panicln("unreachable:", iv) } + if v, ok := iv.(ssa.Instruction); ok { + b.SetCurrentDebugLocation(p.fn, p.goProg.Fset.Position(v.Pos())) + } switch v := iv.(type) { case *ssa.Call: ret = p.call(b, llssa.Call, &v.Call) @@ -684,11 +702,76 @@ func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) { ch := p.compileValue(b, v.Chan) x := p.compileValue(b, v.X) b.Send(ch, x) + case *ssa.DebugRef: + // object := v.Object() + // variable, ok := object.(*types.Var) + // if !ok { + // // Not a local variable. + // return + // } + // if v.IsAddr { + // // *ssa.Alloc or *ssa.FieldAddr + // return + // } + // fn := v.Parent() + // dbgVar := p.getLocalVariable(b, fn, variable) + // pos := p.goProg.Fset.Position(getPos(v)) + // value := p.compileValue(b, v.X) + // b.Pkg.DIBuilder().Debug(value, dbgVar, p.fn, pos, b.Func.Block(v.Block().Index)) default: panic(fmt.Sprintf("compileInstr: unknown instr - %T\n", instr)) } } +type poser interface { + Pos() token.Pos +} + +func getPos(v poser) token.Pos { + pos := v.Pos() + if pos.IsValid() { + return pos + } + + switch v := v.(type) { + case *ssa.MakeInterface: + return getPos(v.X) + case *ssa.MakeClosure: + return v.Fn.(*ssa.Function).Pos() + case *ssa.Return: + syntax := v.Parent().Syntax() + if syntax != nil { + return syntax.End() + } + return token.NoPos + case *ssa.FieldAddr: + return getPos(v.X) + case *ssa.IndexAddr: + return getPos(v.X) + case *ssa.Slice: + return getPos(v.X) + case *ssa.Store: + return getPos(v.Addr) + case *ssa.Extract: + return getPos(v.Tuple) + default: + fmt.Printf("getPos: unknown instr - %T\n", v) + return token.NoPos + } +} + +func (p *context) getLocalVariable(b llssa.Builder, fn *ssa.Function, v *types.Var) llssa.DIVar { + pos := p.fset.Position(v.Pos()) + t := b.Prog.Type(v.Type(), llssa.InGo) + vt := b.Pkg.DIBuilder().DIType(t, pos) + for i, param := range fn.Params { + if param.Object().(*types.Var) == v { + return b.DIVarParam(p.fn, pos, v.Name(), vt, i) + } + } + return b.DIVarAuto(p.fn, pos, v.Name(), vt) +} + func (p *context) compileFunction(v *ssa.Function) (goFn llssa.Function, pyFn llssa.PyObjRef, kind int) { // TODO(xsw) v.Pkg == nil: means auto generated function? if v.Pkg == p.goPkg || v.Pkg == nil { diff --git a/cl/instr.go b/cl/instr.go index 67d0e2c6..72979a9f 100644 --- a/cl/instr.go +++ b/cl/instr.go @@ -267,6 +267,7 @@ func (p *context) funcOf(fn *ssa.Function) (aFn llssa.Function, pyFn llssa.PyObj } sig := fn.Signature aFn = pkg.NewFuncEx(name, sig, llssa.Background(ftype), false, fn.Origin() != nil) + // p.pkg.DIBuilder().DebugFunction(aFn, p.goProg.Fset.Position(fn.Pos())) } } return diff --git a/internal/build/build.go b/internal/build/build.go index 6bffc12f..a3a26d95 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -236,7 +236,7 @@ func isNeedRuntimeOrPyInit(pkg *packages.Package) (needRuntime, needPyInit bool) } const ( - ssaBuildMode = ssa.SanityCheckFunctions | ssa.InstantiateGenerics + ssaBuildMode = ssa.SanityCheckFunctions | ssa.InstantiateGenerics | ssa.GlobalDebug ) type context struct { @@ -436,6 +436,7 @@ func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, llFiles } } args = append(args, exargs...) + args = append(args, "-gdwarf-5", "-v") // TODO(xsw): show work if verbose { @@ -498,6 +499,7 @@ func buildPkg(ctx *context, aPkg *aPackage, verbose bool) { cl.SetDebug(0) } check(err) + ret.Finalize() if needLLFile(ctx.mode) { pkg.ExportFile += ".ll" os.WriteFile(pkg.ExportFile, []byte(ret.String()), 0644) diff --git a/internal/llgen/llgenf.go b/internal/llgen/llgenf.go index 85a62b25..a55bbfb5 100644 --- a/internal/llgen/llgenf.go +++ b/internal/llgen/llgenf.go @@ -90,7 +90,7 @@ func genFrom(fileOrPkg string, pkgPath string) string { initial, err := packages.LoadEx(dedup, prog.TypeSizes, cfg, fileOrPkg) check(err) - _, pkgs := ssautil.AllPackages(initial, ssa.SanityCheckFunctions|ssa.InstantiateGenerics) + _, pkgs := ssautil.AllPackages(initial, ssa.SanityCheckFunctions|ssa.InstantiateGenerics|ssa.GlobalDebug) pkg := initial[0] ssaPkg := pkgs[0] diff --git a/ssa/decl.go b/ssa/decl.go index 96751a37..23fdc3ac 100644 --- a/ssa/decl.go +++ b/ssa/decl.go @@ -17,6 +17,7 @@ package ssa import ( + "go/token" "go/types" "log" "strconv" @@ -173,6 +174,8 @@ type aFunction struct { freeVars Expr base int // base = 1 if hasFreeVars; base = 0 otherwise hasVArg bool + + diFunc DIFunction } // Function represents a function or method. @@ -274,6 +277,10 @@ func (p Function) NewBuilder() Builder { return &aBuilder{b, nil, p, p.Pkg, prog} } +func (p Function) NewDIBuilder() *llvm.DIBuilder { + return llvm.NewDIBuilder(p.Pkg.mod) +} + // HasBody reports whether the function has a body. func (p Function) HasBody() bool { return len(p.blks) > 0 @@ -324,4 +331,33 @@ func (p Function) SetRecover(blk BasicBlock) { p.recov = blk } +func (p Function) scopeMeta(b diBuilder, pos token.Position) DIScopeMeta { + if p.diFunc == nil { + paramTypes := make([]llvm.Metadata, len(p.params)) + for i, t := range p.params { + paramTypes[i] = b.DIType(t, pos).ll + } + diFuncType := b.di.CreateSubroutineType(llvm.DISubroutineType{ + File: b.DIFile(pos.Filename).ll, + Parameters: paramTypes, + }) + p.diFunc = &aDIFunction{ + b.di.CreateFunction( + p.Pkg.cu.ll, + llvm.DIFunction{ + Type: diFuncType, + Name: p.Name(), + LinkageName: p.Name(), + File: b.DIFile(pos.Filename).ll, + Line: pos.Line, + IsDefinition: true, + Optimized: false, + }, + ), + } + p.impl.SetSubprogram(p.diFunc.ll) + } + return &aDIScopeMeta{p.diFunc.ll} +} + // ----------------------------------------------------------------------------- diff --git a/ssa/di.go b/ssa/di.go new file mode 100644 index 00000000..363672d2 --- /dev/null +++ b/ssa/di.go @@ -0,0 +1,440 @@ +package ssa + +import ( + "debug/dwarf" + "fmt" + "go/token" + "go/types" + "path/filepath" + + "github.com/goplus/llvm" +) + +type aDIBuilder struct { + di *llvm.DIBuilder + prog Program + diTypes map[Type]DIType +} + +type diBuilder = *aDIBuilder + +func newDIBuilder(prog Program, m llvm.Module) diBuilder { + ctx := m.Context() + m.AddNamedMetadataOperand("llvm.module.flags", + ctx.MDNode([]llvm.Metadata{ + llvm.ConstInt(ctx.Int32Type(), 2, false).ConstantAsMetadata(), // Warning on mismatch + ctx.MDString("Debug Info Version"), + llvm.ConstInt(ctx.Int32Type(), 3, false).ConstantAsMetadata(), + }), + ) + m.AddNamedMetadataOperand("llvm.module.flags", + ctx.MDNode([]llvm.Metadata{ + llvm.ConstInt(ctx.Int32Type(), 7, false).ConstantAsMetadata(), // Max on mismatch + ctx.MDString("Dwarf Version"), + llvm.ConstInt(ctx.Int32Type(), 5, false).ConstantAsMetadata(), + }), + ) + return &aDIBuilder{ + di: llvm.NewDIBuilder(m), + prog: prog, + diTypes: make(map[*aType]DIType), + } +} + +func (b diBuilder) Finalize() { + b.di.Finalize() + b.di.Destroy() + b.di = nil +} + +// ---------------------------------------------------------------------------- + +type aCompilationUnit struct { + ll llvm.Metadata +} + +type CompilationUnit = *aCompilationUnit + +func (b diBuilder) CreateCompileUnit(filename, dir string) CompilationUnit { + return &aCompilationUnit{ll: b.di.CreateCompileUnit(llvm.DICompileUnit{ + Language: llvm.DW_LANG_Go, + File: filename, + Dir: dir, + Producer: "LLGo", + Optimized: true, + RuntimeVersion: 1, + })} +} + +// ---------------------------------------------------------------------------- + +type aDIScopeMeta struct { + ll llvm.Metadata +} + +type DIScopeMeta = *aDIScopeMeta + +type DIScope interface { + scopeMeta(b diBuilder, pos token.Position) DIScopeMeta +} + +// ---------------------------------------------------------------------------- + +type aDIFile struct { + ll llvm.Metadata +} + +type DIFile = *aDIFile + +func (b diBuilder) createFile(filename string) DIFile { + dir, file := filepath.Split(filename) + return &aDIFile{ll: b.di.CreateFile(file, dir)} +} + +func (f DIFile) scopeMeta(b diBuilder, cu CompilationUnit, pos token.Position) DIScopeMeta { + return &aDIScopeMeta{b.DIFile(pos.Filename).ll} +} + +// ---------------------------------------------------------------------------- + +type aDILexicalBlock struct { + ll llvm.Metadata +} + +type DILexicalBlock = *aDILexicalBlock + +func (b diBuilder) createLexicalBlock(scope DIScope, pos token.Position) DILexicalBlock { + block := llvm.DILexicalBlock{ + File: b.DIFile(pos.Filename).ll, + Line: pos.Line, + Column: pos.Column, + } + return &aDILexicalBlock{ll: b.di.CreateLexicalBlock(scope.scopeMeta(b, pos).ll, block)} +} + +// ---------------------------------------------------------------------------- + +type aDIType struct { + ll llvm.Metadata +} + +type DIType = *aDIType + +func (b diBuilder) createType(ty Type, pos token.Position) DIType { + fmt.Printf("Create type: %T, %v\n", ty.RawType(), ty.RawType()) + var typ llvm.Metadata + switch t := ty.RawType().(type) { + case *types.Basic: + if t.Kind() == types.UnsafePointer { + typ = b.di.CreatePointerType(llvm.DIPointerType{ + Name: "unsafe.Pointer", + SizeInBits: b.prog.SizeOf(b.prog.rawType(t)) * 8, + AlignInBits: uint32(b.prog.sizes.Alignof(t) * 8), + AddressSpace: 0, + }) + return &aDIType{typ} + } + + var encoding llvm.DwarfTypeEncoding + if t.Info()&types.IsBoolean != 0 { + encoding = llvm.DW_ATE_boolean + } else if t.Info()&types.IsUnsigned != 0 { + encoding = llvm.DW_ATE_unsigned + } else if t.Info()&types.IsInteger != 0 { + encoding = llvm.DW_ATE_signed + } else if t.Info()&types.IsFloat != 0 { + encoding = llvm.DW_ATE_float + } else if t.Info()&types.IsComplex != 0 { + encoding = llvm.DW_ATE_complex_float + } else if t.Info()&types.IsString != 0 { + typ = b.di.CreateBasicType(llvm.DIBasicType{ + Name: "string", + SizeInBits: b.prog.SizeOf(b.prog.rawType(t)) * 8, + Encoding: llvm.DW_ATE_unsigned_char, + }) + return &aDIType{typ} + } else { + encoding = llvm.DW_ATE_unsigned + panic("todo: basic type") + } + + typ = b.di.CreateBasicType(llvm.DIBasicType{ + Name: t.Name(), + SizeInBits: b.prog.SizeOf(b.prog.rawType(t)) * 8, + Encoding: encoding, + }) + case *types.Pointer: + return b.createPointerType(b.prog.rawType(t.Elem()), pos) + case *types.Named: + return b.DIType(b.prog.rawType(t.Underlying()), pos) + case *types.Interface: + return b.createBasicType(ty) + case *types.Slice: + return b.createBasicType(ty) + case *types.Struct: + return b.createStructType(ty, pos) + case *types.Signature: + return b.createFuncPtrType(b.prog.rawType(t), pos) + case *types.Tuple: + return b.createBasicType(ty) + case *types.Array: + return b.createBasicType(ty) + default: + panic(fmt.Errorf("can't create debug info of type: %v, %T", ty.RawType(), ty.RawType())) + } + return &aDIType{typ} +} + +// ---------------------------------------------------------------------------- + +type aDIFunction struct { + ll llvm.Metadata +} + +type DIFunction = *aDIFunction + +func (b diBuilder) CreateFunction(scope DIScope, pos token.Position, name, linkageName string, ty DIType, isLocalToUnit, isDefinition, isOptimized bool) DIFunction { + return &aDIFunction{ll: scope.scopeMeta(b, pos).ll} +} + +// ---------------------------------------------------------------------------- + +type aDIGlobalVariableExpression struct { + ll llvm.Metadata +} + +type DIGlobalVariableExpression = *aDIGlobalVariableExpression + +func (b diBuilder) CreateGlobalVariableExpression(scope DIScope, pos token.Position, name, linkageName string, ty DIType, isLocalToUnit bool) DIGlobalVariableExpression { + return &aDIGlobalVariableExpression{ + ll: b.di.CreateGlobalVariableExpression( + scope.scopeMeta(b, pos).ll, + llvm.DIGlobalVariableExpression{ + Name: name, + LinkageName: linkageName, + File: b.DIFile(pos.Filename).ll, + Line: pos.Line, + Type: ty.ll, + LocalToUnit: isLocalToUnit, + // TODO(lijie): check the following fields + // Expr: llvm.Metadata{}, + // Decl: llvm.Metadata{}, + // AlignInBits: 0, + }, + ), + } +} + +// ---------------------------------------------------------------------------- + +type aDIVar struct { + ll llvm.Metadata +} + +type DIVar = *aDIVar + +func (b diBuilder) CreateParameterVariable(scope DIScope, pos token.Position, name string, argNo int, ty DIType) DIVar { + return &aDIVar{ + ll: b.di.CreateParameterVariable( + scope.scopeMeta(b, pos).ll, + llvm.DIParameterVariable{ + Name: name, + File: b.DIFile(pos.Filename).ll, + Line: pos.Line, + ArgNo: argNo, + Type: ty.ll, + AlwaysPreserve: true, + }, + ), + } +} + +func (b diBuilder) CreateAutoVariable(scope DIScope, pos token.Position, name string, ty DIType) DIVar { + return &aDIVar{ + ll: b.di.CreateAutoVariable( + scope.scopeMeta(b, pos).ll, + llvm.DIAutoVariable{ + Name: name, + File: b.DIFile(pos.Filename).ll, + Line: pos.Line, + Type: ty.ll, + AlwaysPreserve: true, + }, + ), + } +} + +// ---------------------------------------------------------------------------- + +func (b diBuilder) createBasicType(t Type) DIType { + return &aDIType{ll: b.di.CreateBasicType(llvm.DIBasicType{ + Name: t.RawType().String(), + SizeInBits: b.prog.SizeOf(t) * 8, + Encoding: llvm.DW_ATE_unsigned, + })} +} + +func (b diBuilder) createPointerType(ty Type, pos token.Position) DIType { + return &aDIType{ll: b.di.CreatePointerType(llvm.DIPointerType{ + Pointee: b.DIType(ty, pos).ll, + SizeInBits: b.prog.SizeOf(ty) * 8, + AlignInBits: uint32(b.prog.sizes.Alignof(ty.RawType())) * 8, + AddressSpace: 0, + })} +} + +func (b diBuilder) createStructType(ty Type, pos token.Position) (ret DIType) { + scope := b.DIFile(pos.Filename) + ret = &aDIType{b.di.CreateReplaceableCompositeType( + scope.ll, + llvm.DIReplaceableCompositeType{ + Tag: dwarf.TagStructType, + Name: ty.RawType().String(), + }, + )} + b.diTypes[ty] = ret + + // Create struct type + structType := ty.RawType().(*types.Struct) + fields := make([]llvm.Metadata, structType.NumFields()) + + for i := 0; i < structType.NumFields(); i++ { + field := structType.Field(i) + fields[i] = b.di.CreateMemberType( + scope.ll, + llvm.DIMemberType{ + Name: field.Name(), + File: b.DIFile(pos.Filename).ll, + Line: pos.Line, + SizeInBits: b.prog.SizeOf(b.prog.rawType(field.Type())) * 8, + AlignInBits: 8, + OffsetInBits: b.prog.OffsetOf(ty, i) * 8, + Type: b.DIType(b.prog.rawType(field.Type()), pos).ll, + }, + ) + } + st := b.di.CreateStructType( + scope.ll, + llvm.DIStructType{ + Name: ty.RawType().String(), + File: b.DIFile(pos.Filename).ll, + Line: pos.Line, + SizeInBits: b.prog.SizeOf(ty) * 8, + AlignInBits: uint32(b.prog.sizes.Alignof(structType) * 8), + Elements: fields, + }, + ) + ret.ll.ReplaceAllUsesWith(st) + ret.ll = st + return +} + +func (b diBuilder) createFuncPtrType(ty Type, pos token.Position) DIType { + sig := ty.RawType().(*types.Signature) + retTy := b.DIType(b.prog.rawType(sig.Results()), pos) + paramTys := make([]DIType, sig.Params().Len()) + for i := 0; i < sig.Params().Len(); i++ { + paramTys[i] = b.DIType(b.prog.rawType(sig.Params().At(i).Type()), pos) + } + rt := b.createSubroutineType(b.DIFile(pos.Filename), retTy, paramTys) + return &aDIType{ll: b.di.CreatePointerType(llvm.DIPointerType{ + Pointee: rt.ll, + SizeInBits: b.prog.SizeOf(ty) * 8, + AlignInBits: 8, + AddressSpace: 0, + })} +} + +// ---------------------------------------------------------------------------- + +func (b diBuilder) createSubroutineType(file DIFile, retTy DIType, paramTys []DIType) DIType { + params := make([]llvm.Metadata, len(paramTys)+1) + params[0] = retTy.ll + for i, ty := range paramTys { + params[i+1] = ty.ll + } + return &aDIType{ll: b.di.CreateSubroutineType(llvm.DISubroutineType{ + File: file.ll, + Parameters: params, + Flags: 0, + })} +} + +// ---------------------------------------------------------------------------- + +func (b diBuilder) Debug(v Expr, dv DIVar, scope DIScope, pos token.Position, blk BasicBlock) { + loc := llvm.DebugLoc{ + Line: uint(pos.Line), + Col: uint(pos.Column), + Scope: scope.scopeMeta(b, pos).ll, + } + b.di.InsertDeclareAtEnd( + v.impl, + dv.ll, + b.di.CreateExpression(nil), + loc, + blk.last, + ) +} + +func (b diBuilder) DebugValue(v Expr, dv DIVar, scope DIScope, pos token.Position, blk BasicBlock) { + loc := llvm.DebugLoc{ + Line: uint(pos.Line), + Col: uint(pos.Column), + Scope: scope.scopeMeta(b, pos).ll, + } + b.di.InsertValueAtEnd( + v.impl, + dv.ll, + b.di.CreateExpression(nil), + loc, + blk.last, + ) +} + +func (b diBuilder) DIType(t Type, pos token.Position) DIType { + if ty, ok := b.diTypes[t]; ok { + return ty + } + ty := b.createType(t, pos) + b.diTypes[t] = ty + return ty +} + +func (b diBuilder) DIVarParam(f Function, pos token.Position, varName string, vt DIType, argNo int) DIVar { + return b.CreateParameterVariable( + f, + pos, + varName, + argNo, + vt, + ) +} + +func (b diBuilder) DIVarAuto(f Function, pos token.Position, varName string, vt DIType) DIVar { + return b.CreateAutoVariable( + f, + pos, + varName, + vt, + ) +} + +func (b diBuilder) DIFile(filename string) DIFile { + return b.createFile(filename) +} + +// ----------------------------------------------------------------------------- + +func (b Builder) SetCurrentDebugLocation(f Function, pos token.Position) { + b.impl.SetCurrentDebugLocation( + uint(pos.Line), + uint(pos.Column), + f.scopeMeta(b.Pkg.DIBuilder(), pos).ll, + f.impl.InstructionDebugLoc(), + ) +} +func (b diBuilder) DebugFunction(f Function, pos token.Position) { + // attach debug info to function + f.scopeMeta(b, pos) +} diff --git a/ssa/package.go b/ssa/package.go index 4554b56d..a4e6f4c2 100644 --- a/ssa/package.go +++ b/ssa/package.go @@ -338,6 +338,8 @@ func (p Program) tyComplex128() llvm.Type { // NewPackage creates a new package. func (p Program) NewPackage(name, pkgPath string) Package { mod := p.ctx.NewModule(pkgPath) + di := newDIBuilder(p, mod) + cu := di.CreateCompileUnit(name, pkgPath) // TODO(xsw): Finalize may cause panic, so comment it. // mod.Finalize() gbls := make(map[string]Global) @@ -352,7 +354,7 @@ func (p Program) NewPackage(name, pkgPath string) Package { // p.needPyInit = false ret := &aPackage{ mod: mod, vars: gbls, fns: fns, stubs: stubs, - pyobjs: pyobjs, pymods: pymods, strs: strs, named: named, Prog: p} + pyobjs: pyobjs, pymods: pymods, strs: strs, named: named, Prog: p, di: di, cu: cu} ret.abi.Init(pkgPath) return ret } @@ -589,6 +591,8 @@ type aPackage struct { abi abi.Builder Prog Program + di diBuilder + cu CompilationUnit vars map[string]Global fns map[string]Function @@ -706,6 +710,14 @@ func (p Package) AfterInit(b Builder, ret BasicBlock) { } } +func (p Package) Finalize() { + p.di.Finalize() +} + +func (p Package) DIBuilder() diBuilder { + return p.di +} + // ----------------------------------------------------------------------------- /* diff --git a/ssa/stmt_builder.go b/ssa/stmt_builder.go index f837c3fd..bc85f5b7 100644 --- a/ssa/stmt_builder.go +++ b/ssa/stmt_builder.go @@ -287,6 +287,24 @@ func (b Builder) Times(n Expr, loop func(i Expr)) { b.blk.last = blks[2].last } +// ----------------------------------------------------------------------------- + +func (b Builder) Debug(v Expr, dv DIVar, scope DIScope, pos token.Position) { + b.Pkg.DIBuilder().Debug(v, dv, scope, pos, b.blk) +} + +func (b Builder) DebugValue(v Expr, dv DIVar, scope DIScope, pos token.Position) { + b.Pkg.DIBuilder().DebugValue(v, dv, scope, pos, b.blk) +} + +func (b Builder) DIVarParam(f Function, pos token.Position, varName string, vt DIType, argNo int) DIVar { + return b.Pkg.DIBuilder().DIVarParam(f, pos, varName, vt, argNo) +} + +func (b Builder) DIVarAuto(f Function, pos token.Position, varName string, vt DIType) DIVar { + return b.Pkg.DIBuilder().DIVarAuto(f, pos, varName, vt) +} + // ----------------------------------------------------------------------------- /* type caseStmt struct {