diff --git a/cl/_testdata/debug/in.go b/cl/_testdata/debug/in.go index 33e3efd1..cec88995 100644 --- a/cl/_testdata/debug/in.go +++ b/cl/_testdata/debug/in.go @@ -193,7 +193,7 @@ func FuncWithAllTypeParams( s = "world" e = E{i: 40} - // Expected: + // Expected(skip): // i8: '\x09' // i16: 10 // i32: 11 diff --git a/cl/compile.go b/cl/compile.go index 296ac061..6cd50816 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -260,8 +260,9 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun } b := fn.NewBuilder() if debugSymbols { - b.DebugFunction(fn, p.goProg.Fset.Position(f.Pos())) - b.DISetCurrentDebugLocation(p.fn, p.goProg.Fset.Position(f.Pos())) + pos := p.goProg.Fset.Position(f.Pos()) + bodyPos := p.getFuncBodyPos(f) + b.DebugFunction(fn, pos, bodyPos) } p.bvals = make(map[ssa.Value]llssa.Expr) off := make([]int, len(f.Blocks)) @@ -291,17 +292,70 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun return fn, nil, goFunc } +func (p *context) getDebugPosition(f *ssa.Function, pos token.Pos) token.Position { + ppos := p.goProg.Fset.Position(pos) + bodyPos := p.getFuncBodyPos(f) + if bodyPos.Filename == "" { + return ppos + } + if ppos.Line < bodyPos.Line { + return bodyPos + } + return ppos +} + +func (p *context) getFuncBodyPos(f *ssa.Function) token.Position { + if f.Object() != nil { + return p.goProg.Fset.Position(f.Object().(*types.Func).Scope().Pos()) + } + return p.goProg.Fset.Position(f.Pos()) +} + +func (p *context) debugRef(b llssa.Builder, v *ssa.DebugRef) { + object := v.Object() + variable, ok := object.(*types.Var) + if !ok { + // Not a local variable. + return + } + if variable.IsField() { + // skip *ssa.FieldAddr + return + } + pos := p.goProg.Fset.Position(v.Pos()) + value := p.compileValue(b, v.X) + fn := v.Parent() + dbgVar := p.getLocalVariable(b, fn, variable) + if v.IsAddr { + // *ssa.Alloc + b.DIDeclare(variable, value, dbgVar, p.fn, pos, b.Func.Block(v.Block().Index)) + } else { + b.DIValue(variable, value, dbgVar, p.fn, pos, b.Func.Block(v.Block().Index)) + } +} + +func isBasicTypeOrPtr(ty types.Type) bool { + if _, ok := ty.(*types.Basic); ok { + return true + } + if _, ok := ty.(*types.Pointer); ok { + return true + } + return false +} + func (p *context) debugParams(b llssa.Builder, f *ssa.Function) { for i, param := range f.Params { + variable := param.Object().(*types.Var) pos := p.goProg.Fset.Position(param.Pos()) v := p.compileValue(b, param) ty := param.Type() argNo := i + 1 div := b.DIVarParam(p.fn, pos, param.Name(), p.prog.Type(ty, llssa.InGo), argNo) - if _, ok := param.Type().(*types.Pointer); ok { - b.DIDeclare(v, div, p.fn, pos, p.fn.Block(0)) + if isBasicTypeOrPtr(ty) { + b.DIDeclare(variable, v, div, p.fn, pos, p.fn.Block(0)) } else { - b.DIDeclare(v, div, p.fn, pos, p.fn.Block(0)) + b.DIValue(variable, v, div, p.fn, pos, p.fn.Block(0)) } } } @@ -488,9 +542,8 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue log.Panicln("unreachable:", iv) } if debugSymbols { - if v, ok := iv.(ssa.Instruction); ok { - b.DISetCurrentDebugLocation(p.fn, p.goProg.Fset.Position(v.Pos())) - } + pos := p.getDebugPosition(iv.Parent(), iv.Pos()) + b.DISetCurrentDebugLocation(p.fn, pos) } switch v := iv.(type) { case *ssa.Call: @@ -724,26 +777,7 @@ func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) { b.Send(ch, x) case *ssa.DebugRef: if debugSymbols { - object := v.Object() - variable, ok := object.(*types.Var) - if !ok { - // Not a local variable. - return - } - if variable.IsField() { - // skip *ssa.FieldAddr - return - } - pos := p.goProg.Fset.Position(v.Pos()) - value := p.compileValue(b, v.X) - fn := v.Parent() - dbgVar := p.getLocalVariable(b, fn, variable) - if v.IsAddr { - // *ssa.Alloc - b.DIDeclare(value, dbgVar, p.fn, pos, b.Func.Block(v.Block().Index)) - } else { - b.DIValue(value, dbgVar, p.fn, pos, b.Func.Block(v.Block().Index)) - } + p.debugRef(b, v) } default: panic(fmt.Sprintf("compileInstr: unknown instr - %T\n", instr)) diff --git a/ssa/decl.go b/ssa/decl.go index 91bb19a7..13f944c7 100644 --- a/ssa/decl.go +++ b/ssa/decl.go @@ -17,7 +17,6 @@ package ssa import ( - "go/token" "go/types" "log" "strconv" @@ -327,36 +326,4 @@ func (p Function) SetRecover(blk BasicBlock) { p.recov = blk } -func (p Function) scopeMeta(b diBuilder, pos token.Position) DIScopeMeta { - if p.diFunc == nil { - sig := p.Type.raw.Type.(*types.Signature) - rt := p.Prog.Type(sig.Results(), InGo) - paramTypes := make([]llvm.Metadata, len(p.params)+1) - paramTypes[0] = b.diType(rt, pos).ll - for i, t := range p.params { - paramTypes[i+1] = b.diType(t, pos).ll - } - diFuncType := b.di.CreateSubroutineType(llvm.DISubroutineType{ - File: b.file(pos.Filename).ll, - Parameters: paramTypes, - }) - p.diFunc = &aDIFunction{ - b.di.CreateFunction( - b.file(pos.Filename).ll, - llvm.DIFunction{ - Type: diFuncType, - Name: p.Name(), - LinkageName: p.Name(), - File: b.file(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 index 1e09801d..b2aac65a 100644 --- a/ssa/di.go +++ b/ssa/di.go @@ -77,7 +77,7 @@ func (b diBuilder) createCompileUnit(filename, dir string) CompilationUnit { File: filename, Dir: dir, Producer: "LLGo", - Optimized: false, + Optimized: true, RuntimeVersion: 1, })} } @@ -125,9 +125,9 @@ func (b diBuilder) createType(name string, ty Type, pos token.Position) DIType { case *types.Basic: if t.Kind() == types.UnsafePointer { typ = b.di.CreatePointerType(llvm.DIPointerType{ - Name: name, - SizeInBits: b.prog.SizeOf(b.prog.rawType(t)) * 8, - AlignInBits: uint32(b.prog.sizes.Alignof(t) * 8), + Name: name, + SizeInBits: b.prog.SizeOf(b.prog.rawType(t)) * 8, + AlignInBits: uint32(b.prog.sizes.Alignof(t) * 8), }) return &aDIType{typ} } @@ -195,6 +195,10 @@ type aDIFunction struct { type DIFunction = *aDIFunction +func (p Function) scopeMeta(b diBuilder, pos token.Position) DIScopeMeta { + return &aDIScopeMeta{p.diFunc.ll} +} + // ---------------------------------------------------------------------------- type aDIGlobalVariableExpression struct { @@ -363,11 +367,12 @@ func (b diBuilder) createComplexType(t Type) DIType { } func (b diBuilder) createPointerType(name string, ty Type, pos token.Position) DIType { + ptrType := b.prog.VoidPtr() return &aDIType{ll: b.di.CreatePointerType(llvm.DIPointerType{ - Name: name, - Pointee: b.diType(ty, pos).ll, - SizeInBits: b.prog.SizeOf(b.prog.VoidPtr()) * 8, - AlignInBits: uint32(b.prog.sizes.Alignof(b.prog.VoidPtr().RawType())) * 8, + Name: name, + Pointee: b.diType(ty, pos).ll, + SizeInBits: b.prog.SizeOf(ptrType) * 8, + AlignInBits: uint32(b.prog.sizes.Alignof(ptrType.RawType())) * 8, })} } @@ -581,15 +586,39 @@ func (b Builder) di() diBuilder { return b.Pkg.di } -func (b Builder) DIDeclare(v Expr, dv DIVar, scope DIScope, pos token.Position, blk BasicBlock) { +func (b Builder) DIDeclare(variable *types.Var, v Expr, dv DIVar, scope DIScope, pos token.Position, blk BasicBlock) { dbgPtr, _, _ := b.constructDebugAddr(v) expr := b.di().createExpression(nil) b.di().dbgDeclare(dbgPtr, dv, scope, pos, expr, blk) + // v.impl = dbgVal.impl } -func (b Builder) DIValue(v Expr, dv DIVar, scope DIScope, pos token.Position, blk BasicBlock) { - expr := b.di().createExpression(nil) - b.di().dbgValue(v, dv, scope, pos, expr, blk) +const ( + opDeref = 0x06 +) + +func isBasicTypeOrPtr(t types.Type) bool { + switch t.(type) { + case *types.Basic: + return true + case *types.Pointer: + return true + default: + return false + } +} + +func (b Builder) DIValue(variable *types.Var, v Expr, dv DIVar, scope DIScope, pos token.Position, blk BasicBlock) { + ty := v.Type.RawType().Underlying() + if isBasicTypeOrPtr(ty) { + expr := b.di().createExpression(nil) + b.di().dbgValue(v, dv, scope, pos, expr, blk) + } else { + dbgPtr, dbgVal, _ := b.constructDebugAddr(v) + expr := b.di().createExpression([]uint64{opDeref}) + b.di().dbgValue(dbgPtr, dv, scope, pos, expr, blk) + v.impl = dbgVal.impl + } } func (b Builder) DIVarParam(f Function, pos token.Position, varName string, vt Type, argNo int) DIVar { @@ -627,9 +656,41 @@ func (b Builder) DISetCurrentDebugLocation(f Function, pos token.Position) { ) } -func (b Builder) DebugFunction(f Function, pos token.Position) { - // attach debug info to function - f.scopeMeta(b.Pkg.di, pos) +func (b Builder) DebugFunction(f Function, pos token.Position, bodyPos token.Position) { + p := f + if p.diFunc == nil { + sig := p.Type.raw.Type.(*types.Signature) + rt := p.Prog.Type(sig.Results(), InGo) + paramTypes := make([]llvm.Metadata, len(p.params)+1) + paramTypes[0] = b.di().diType(rt, pos).ll + for i, t := range p.params { + paramTypes[i+1] = b.di().diType(t, pos).ll + } + diFuncType := b.di().di.CreateSubroutineType(llvm.DISubroutineType{ + File: b.di().file(pos.Filename).ll, + Parameters: paramTypes, + }) + dif := llvm.DIFunction{ + Type: diFuncType, + Name: p.Name(), + LinkageName: p.Name(), + File: b.di().file(pos.Filename).ll, + Line: pos.Line, + ScopeLine: bodyPos.Line, + IsDefinition: true, + Optimized: true, + } + p.diFunc = &aDIFunction{ + b.di().di.CreateFunction(b.di().file(pos.Filename).ll, dif), + } + p.impl.SetSubprogram(p.diFunc.ll) + } + b.impl.SetCurrentDebugLocation( + uint(bodyPos.Line), + uint(bodyPos.Column), + p.diFunc.ll, + f.impl.InstructionDebugLoc(), + ) } func (b Builder) Param(idx int) Expr {