Index: debug/debug.go =================================================================== --- debug/debug.go +++ debug/debug.go @@ -17,10 +17,8 @@ "debug/dwarf" "fmt" "go/token" - "os" "strings" - "llvm.org/llgo/third_party/go.tools/go/ssa" "llvm.org/llgo/third_party/go.tools/go/types" "llvm.org/llgo/third_party/go.tools/go/types/typeutil" @@ -49,18 +47,20 @@ sizes types.Sizes fset *token.FileSet prefixMaps []PrefixMap + cwd string types typeutil.Map voidType llvm.Value } // NewDIBuilder creates a new debug information builder. -func NewDIBuilder(sizes types.Sizes, module llvm.Module, fset *token.FileSet, prefixMaps []PrefixMap) *DIBuilder { +func NewDIBuilder(sizes types.Sizes, module llvm.Module, fset *token.FileSet, prefixMaps []PrefixMap, cwd string) *DIBuilder { var d DIBuilder d.module = module d.files = make(map[*token.File]llvm.Value) d.sizes = sizes d.fset = fset d.prefixMaps = prefixMaps + d.cwd = cwd d.builder = llvm.NewDIBuilder(d.module) d.cu = d.createCompileUnit() return &d @@ -94,7 +94,7 @@ if diFile := d.files[file]; !diFile.IsNil() { return diFile } - diFile := d.builder.CreateFile(d.remapFilePath(file.Name()), "") + diFile := d.builder.CreateFile(d.remapFilePath(file.Name()), d.cwd) d.files[file] = diFile return diFile } @@ -108,14 +108,10 @@ file = f return false }) - dir, err := os.Getwd() - if err != nil { - panic("could not get current directory: " + err.Error()) - } return d.builder.CreateCompileUnit(llvm.DICompileUnit{ Language: llvm.DW_LANG_Go, File: d.remapFilePath(file.Name()), - Dir: dir, + Dir: d.cwd, Producer: "llgo", }) } @@ -138,6 +134,7 @@ Type: d.DIType(sig), IsDefinition: true, Function: fnptr, + ScopeLine: line, }) } @@ -148,34 +145,29 @@ d.fnFile = "" } -// 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) { +// Value creates an llvm.dbg.value call, recording the current value for the +// local variable with the specified name and source position. +func (d *DIBuilder) Value(b llvm.Builder, name string, llv llvm.Value, t types.Type, pos token.Pos, 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()) + if file := d.fset.File(pos); file != nil { + line = file.Line(pos) diFile = d.getFile(file) } localVar := d.builder.CreateLocalVariable(d.scope(), llvm.DILocalVariable{ Tag: tag, - Name: llv.Name(), + Name: name, File: diFile, Line: line, ArgNo: paramIndex + 1, - Type: d.DIType(v.Type()), + Type: d.DIType(t), }) expr := d.builder.CreateExpression(nil) - d.builder.InsertDeclareAtEnd(llv, localVar, expr, b.GetInsertBlock()) -} - -// Value creates an llvm.dbg.value call for the specified register value. -func (d *DIBuilder) Value(b llvm.Builder, v ssa.Value, llv llvm.Value, paramIndex int) { - // TODO(axw) + d.builder.InsertValueAtEnd(llv, localVar, expr, 0, b.GetInsertBlock()) } // SetLocation sets the current debug location. @@ -214,7 +206,7 @@ llvm.MDNode([]llvm.Value{ llvm.ConstInt(llvm.Int32Type(), 1, false), // Error on mismatch llvm.MDString("Debug Info Version"), - llvm.ConstInt(llvm.Int32Type(), 1, false), + llvm.ConstInt(llvm.Int32Type(), 2, false), }), ) d.builder.Finalize() Index: irgen/compiler.go =================================================================== --- irgen/compiler.go +++ irgen/compiler.go @@ -18,6 +18,7 @@ "fmt" "go/token" "log" + "os" "sort" "strconv" "strings" @@ -200,6 +201,7 @@ program := ssa.Create(iprog, ssa.BareInits) mainPkginfo := iprog.InitialPackages()[0] mainPkg := program.CreatePackage(mainPkginfo) + mainPkg.SetDebugMode(compiler.GenerateDebug) // Create a Module, which contains the LLVM module. modulename := importpath @@ -229,11 +231,16 @@ ) if compiler.GenerateDebug { + cwd, err := os.Getwd() + if err != nil { + return nil, err + } compiler.debug = debug.NewDIBuilder( types.Sizes(compiler.llvmtypes), compiler.module.Module, impcfg.Fset, compiler.DebugPrefixMaps, + cwd, ) defer compiler.debug.Destroy() defer compiler.debug.Finalize() Index: irgen/ssa.go =================================================================== --- irgen/ssa.go +++ irgen/ssa.go @@ -332,11 +332,9 @@ 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 @@ -356,12 +354,8 @@ prologueBlock := llvm.InsertBasicBlock(fr.blocks[0], "prologue") fr.builder.SetInsertPointAtEnd(prologueBlock) - // 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) + // Decode parameters and generate initial llvm.dbg.value calls for each. for i, param := range f.Params { - paramPos[param.Pos()] = i llparam := fti.argInfos[i].decode(llvm.GlobalContext(), fr.builder, fr.builder) if isMethod && i == 0 { if _, ok := param.Type().Underlying().(*types.Pointer); !ok { @@ -370,6 +364,9 @@ } } fr.env[param] = newValue(llparam, param.Type()) + if fr.GenerateDebug { + fr.debug.Value(fr.builder, param.Name(), llparam, param.Type(), param.Pos(), i) + } } // Load closure, extract free vars. @@ -400,13 +397,6 @@ bcalloca := fr.builder.CreateBitCast(alloca, llvm.PointerType(llvm.Int8Type(), 0), "") value := newValue(bcalloca, 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) - } } // If this is the "init" function, enable init-specific optimizations. @@ -571,6 +561,13 @@ // Runs defers. If a defer panics, check for recovers in later defers. func (fr *frame) runDefers() { + if fr.frameptr.IsNil() { + // rundefers is emitted regardless of the presence of defers + // for SSA in naive form. If frameptr is nil, then there are + // no defers and no recovery block, so nothing to do. + return + } + loopbb := llvm.AddBasicBlock(fr.function, "") fr.builder.CreateBr(loopbb) @@ -821,9 +818,8 @@ case *ssa.Alloc: typ := deref(instr.Type()) llvmtyp := fr.llvmtypes.ToLLVM(typ) - var value llvm.Value if !instr.Heap { - value = fr.env[instr].value + value := fr.env[instr].value fr.memsetZero(value, llvm.SizeOf(llvmtyp)) } else if fr.isInit && fr.shouldStaticallyAllocate(instr) { // If this is the init function and we think it may be beneficial, @@ -836,7 +832,7 @@ ptr := llvm.ConstBitCast(global, llvm.PointerType(llvm.Int8Type(), 0)) fr.env[instr] = newValue(ptr, instr.Type()) } else { - value = fr.createTypeMalloc(typ) + value := fr.createTypeMalloc(typ) value.SetName(instr.Comment) value = fr.builder.CreateBitCast(value, llvm.PointerType(llvm.Int8Type(), 0), "") fr.env[instr] = newValue(value, instr.Type()) @@ -876,6 +872,21 @@ v := fr.value(instr.X) fr.env[instr] = fr.convert(v, instr.Type()) + case *ssa.DebugRef: + id, ok := instr.Expr.(*ast.Ident) + if !ok || id.Obj == nil { + return + } + pos := id.Obj.Pos() + paramIndex := -1 + for i, param := range instr.Parent().Params { + if pos == param.Pos() { + paramIndex = i + break + } + } + fr.debug.Value(fr.builder, id.Name, fr.llvmvalue(instr.X), instr.X.Type(), id.Obj.Pos(), paramIndex) + case *ssa.Defer: fn, arg := fr.createThunk(instr) fr.runtime.Defer.call(fr, fr.frameptr, fn, arg)