diff --git a/cl/_testdata/debug/in.go b/cl/_testdata/debug/in.go index c3877739..b6676580 100644 --- a/cl/_testdata/debug/in.go +++ b/cl/_testdata/debug/in.go @@ -1,4 +1,4 @@ -package foo +package main import "errors" @@ -7,35 +7,36 @@ type Base struct { } type E struct { - Base + // Base i int } type StructWithAllTypeFields struct { - i8 int8 - i16 int16 - i32 int32 - i64 int64 - i int - u8 uint8 - u16 uint16 - u32 uint32 - u64 uint64 - u uint - f32 float32 - f64 float64 - c64 complex64 - c128 complex128 - slice []int - arr [3]int - b bool - s string - e E - pf *StructWithAllTypeFields // resursive - pi *int - intr Interface - m map[string]uint64 - c chan int - err error + i8 int8 + i16 int16 + i32 int32 + i64 int64 + i int + u8 uint8 + u16 uint16 + u32 uint32 + u64 uint64 + u uint + f32 float32 + f64 float64 + b bool + // c64 complex64 + // c128 complex128 + // slice []int + // arr [3]int + // s string + e E + // pf *StructWithAllTypeFields // resursive + // pi *int + // intr Interface + // m map[string]uint64 + // c chan int + // err error + // fn func(string) (int, error) } type Interface interface { @@ -66,24 +67,78 @@ func FuncWithAllTypeParams( u uint, f32 float32, f64 float64, - c64 complex64, - c128 complex128, - slice []int, - arr [3]int, b bool, - s string, + // c64 complex64, + // c128 complex128, + // slice []int, + // arr [3]int, + // s string, e E, f StructWithAllTypeFields, - pf *StructWithAllTypeFields, - pi *int, - intr Interface, - m map[string]uint64, - c chan int, - err error, + // pf *StructWithAllTypeFields, + // pi *int, + // intr Interface, + // m map[string]uint64, + // c chan int, + // err error, + // fn func(string) (int, error), ) (int, error) { println( - i8, i16, i32, i64, i, u8, u16, u32, u64, u, f32, f64, c64, c128, - slice, arr[0:], b, s, &e, &f, pf, pi, intr, m, c, err, + i8, i16, i32, i64, i, u8, u16, u32, u64, u, + f32, f64, b, + // c64, c128, slice, arr[0:], + // s, &e, &f, pf, pi, intr, m, c, err, + // fn, ) return 1, errors.New("Some error") } + +func main() { + i := 100 + s := StructWithAllTypeFields{ + i8: 1, + i16: 2, + i32: 3, + i64: 4, + i: 5, + u8: 6, + u16: 7, + u32: 8, + u64: 9, + u: 10, + f32: 11, + f64: 12, + b: true, + // c64: 13 + 14i, + // c128: 15 + 16i, + // slice: []int{21, 22, 23}, + // arr: [3]int{24, 25, 26}, + // s: "hello", + e: E{i: 30}, + // pf: &StructWithAllTypeFields{}, + // pi: &i, + // intr: &Struct{}, + // m: make(map[string]uint64), + // c: make(chan int), + // err: errors.New("Test error"), + // fn: func(s string) (int, error) { + // println("fn:", s) + // return 1, errors.New("fn error") + // }, + } + println("s:", &s) + FuncWithAllTypeStructParam(s) + println("called function with struct") + i, err := FuncWithAllTypeParams( + s.i8, s.i16, s.i32, s.i64, s.i, s.u8, s.u16, s.u32, s.u64, s.u, + s.f32, s.f64, s.b, + // s.c64, s.c128, s.slice, s.arr, s.s, + s.e, s, + // s.pf, s.pi, + // s.intr, s.m, s.c, s.err, + // s.fn, + ) + println(i, err) + println("called function with types") + println("done") +} diff --git a/cl/compile.go b/cl/compile.go index e7fd95d0..bc87802c 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -304,9 +304,8 @@ func (p *context) debugParams(b llssa.Builder, f *ssa.Function) { v := p.compileValue(b, param) ty := param.Type() argNo := i + 1 - div := b.DIVarParam(p.fn, pos, param.Name(), b.Prog.Type(ty, llssa.InGo), argNo) + div := b.DIVarParam(p.fn, pos, param.Name(), p.prog.Type(ty, llssa.InGo), argNo) b.DIDeclare(v, div, p.fn, pos, p.fn.Block(0)) - b.DIValue(v, div, p.fn, pos, p.fn.Block(0)) } } diff --git a/ssa/decl.go b/ssa/decl.go index 78b5ffab..b5416b37 100644 --- a/ssa/decl.go +++ b/ssa/decl.go @@ -274,7 +274,7 @@ func (p Function) NewBuilder() Builder { b := prog.ctx.NewBuilder() // TODO(xsw): Finalize may cause panic, so comment it. // b.Finalize() - return &aBuilder{b, nil, p, p.Pkg, prog} + return &aBuilder{b, nil, p, p.Pkg, prog, make(map[Expr]Expr)} } // HasBody reports whether the function has a body. diff --git a/ssa/di.go b/ssa/di.go index de620442..16c6b08b 100644 --- a/ssa/di.go +++ b/ssa/di.go @@ -3,6 +3,7 @@ package ssa import ( "debug/dwarf" "fmt" + "go/constant" "go/token" "go/types" "path/filepath" @@ -156,7 +157,8 @@ func (b diBuilder) createType(ty Type, pos token.Position) DIType { case *types.Interface: return b.createBasicType(ty) case *types.Slice: - return b.createBasicType(ty) + ty := b.prog.rawType(b.prog.rtType("Slice").RawType().Underlying()) + return b.createStructType(ty, pos) case *types.Struct: return b.createStructType(ty, pos) case *types.Signature: @@ -348,7 +350,7 @@ func (b diBuilder) createSubroutineType(file DIFile, retTy DIType, paramTys []DI // ---------------------------------------------------------------------------- -func (b diBuilder) dbgDeclare(v Expr, dv DIVar, scope DIScope, pos token.Position, blk BasicBlock) { +func (b diBuilder) dbgDeclare(v Expr, dv DIVar, scope DIScope, pos token.Position, expr DIExpression, blk BasicBlock) { loc := llvm.DebugLoc{ Line: uint(pos.Line), Col: uint(pos.Column), @@ -357,13 +359,13 @@ func (b diBuilder) dbgDeclare(v Expr, dv DIVar, scope DIScope, pos token.Positio b.di.InsertDeclareAtEnd( v.impl, dv.ll, - b.di.CreateExpression(nil), + expr.ll, loc, blk.last, ) } -func (b diBuilder) dbgValue(v Expr, dv DIVar, scope DIScope, pos token.Position, blk BasicBlock) { +func (b diBuilder) dbgValue(v Expr, dv DIVar, scope DIScope, pos token.Position, expr DIExpression, blk BasicBlock) { loc := llvm.DebugLoc{ Line: uint(pos.Line), Col: uint(pos.Column), @@ -372,7 +374,7 @@ func (b diBuilder) dbgValue(v Expr, dv DIVar, scope DIScope, pos token.Position, b.di.InsertValueAtEnd( v.impl, dv.ll, - b.di.CreateExpression(nil), + expr.ll, loc, blk.last, ) @@ -410,14 +412,87 @@ func (b diBuilder) file(filename string) DIFile { return b.createFile(filename) } +// ---------------------------------------------------------------------------- + +type aDIExpression struct { + ll llvm.Metadata +} + +type DIExpression = *aDIExpression + +func (b diBuilder) createExpression(ops []uint64) DIExpression { + return &aDIExpression{b.di.CreateExpression(ops)} +} + // ----------------------------------------------------------------------------- +// Copy struct parameters to alloca'd memory. +func (b Builder) allocatedVar(v Expr) (Expr, bool) { + if v, ok := b.allocVars[v]; ok { + return v, true + } + t := v.Type.RawType().Underlying() + var ty Type + switch t.(type) { + case *types.Struct: + ty = v.Type + case *types.Slice: + ty = b.Prog.Type(b.Prog.rtType("Slice").RawType().Underlying(), InGo) + default: + return v, false + } + size := b.Const(constant.MakeUint64(b.Prog.SizeOf(ty)), b.Prog.Uint64()) + p := b.Alloca(size) + p.Type = b.Prog.Pointer(ty) + b.Store(p, v) + b.allocVars[v] = p + return p, true +} + +const ( + opDeref = 0x06 +) + +func skipType(t types.Type) bool { + switch t := t.(type) { + case *types.Slice: + return true + case *types.Interface: + return true + case *types.Basic: + if t.Info()&types.IsString != 0 { + return true + } else if t.Info()&types.IsComplex != 0 { + return true + } + } + return false +} + func (b Builder) DIDeclare(v Expr, dv DIVar, scope DIScope, pos token.Position, blk BasicBlock) { - b.Pkg.diBuilder().dbgDeclare(v, dv, scope, pos, blk) + t := v.Type.RawType().Underlying() + if skipType(t) { + return + } + v, alloced := b.allocatedVar(v) + expr := b.Pkg.diBuilder().createExpression(nil) + if alloced { + expr = b.Pkg.diBuilder().createExpression([]uint64{opDeref}) + } + b.Pkg.diBuilder().dbgDeclare(v, dv, scope, pos, expr, blk) } func (b Builder) DIValue(v Expr, dv DIVar, scope DIScope, pos token.Position, blk BasicBlock) { - b.Pkg.diBuilder().dbgValue(v, dv, scope, pos, blk) + t := v.Type.RawType().Underlying() + if skipType(t) { + return + } + v, alloced := b.allocatedVar(v) + expr := b.Pkg.diBuilder().createExpression(nil) + if alloced { + expr = b.Pkg.diBuilder().createExpression([]uint64{opDeref}) + } + b.Pkg.diBuilder().dbgValue(v, dv, scope, pos, expr, blk) } func (b Builder) DIVarParam(f Function, pos token.Position, varName string, vt Type, argNo int) DIVar { diff --git a/ssa/stmt_builder.go b/ssa/stmt_builder.go index f837c3fd..2140e986 100644 --- a/ssa/stmt_builder.go +++ b/ssa/stmt_builder.go @@ -63,6 +63,8 @@ type aBuilder struct { Func Function Pkg Package Prog Program + + allocVars map[Expr]Expr } // Builder represents a builder for creating instructions in a function.