go/ssa: add position info to all Load/Store instructions

Was originally https://codereview.appspot.com/92880043/ by Richard Musiol.

Change-Id: If0b22cf962b94ef44edbac28a5e5af4acb950991
Reviewed-on: https://go-review.googlesource.com/2174
Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
Alan Donovan 2014-12-29 16:49:20 -05:00
parent 4f13714aca
commit 538acf1c92
5 changed files with 46 additions and 35 deletions

View File

@ -347,7 +347,7 @@ func (b *builder) addr(fn *Function, e ast.Expr, escaping bool) lvalue {
if v == nil { if v == nil {
v = fn.lookup(obj, escaping) v = fn.lookup(obj, escaping)
} }
return &address{addr: v, expr: e} return &address{addr: v, pos: e.Pos(), expr: e}
case *ast.CompositeLit: case *ast.CompositeLit:
t := deref(fn.Pkg.typeOf(e)) t := deref(fn.Pkg.typeOf(e))
@ -359,7 +359,7 @@ func (b *builder) addr(fn *Function, e ast.Expr, escaping bool) lvalue {
} }
v.Comment = "complit" v.Comment = "complit"
b.compLit(fn, v, e, true) // initialize in place b.compLit(fn, v, e, true) // initialize in place
return &address{addr: v, expr: e} return &address{addr: v, pos: e.Lbrace, expr: e}
case *ast.ParenExpr: case *ast.ParenExpr:
return b.addr(fn, e.X, escaping) return b.addr(fn, e.X, escaping)
@ -378,6 +378,7 @@ func (b *builder) addr(fn *Function, e ast.Expr, escaping bool) lvalue {
last := len(sel.Index()) - 1 last := len(sel.Index()) - 1
return &address{ return &address{
addr: emitFieldSelection(fn, v, sel.Index()[last], true, e.Sel), addr: emitFieldSelection(fn, v, sel.Index()[last], true, e.Sel),
pos: e.Sel.Pos(),
expr: e.Sel, expr: e.Sel,
} }
@ -410,10 +411,10 @@ func (b *builder) addr(fn *Function, e ast.Expr, escaping bool) lvalue {
} }
v.setPos(e.Lbrack) v.setPos(e.Lbrack)
v.setType(et) v.setType(et)
return &address{addr: fn.emit(v), expr: e} return &address{addr: fn.emit(v), pos: e.Lbrack, expr: e}
case *ast.StarExpr: case *ast.StarExpr:
return &address{addr: b.expr(fn, e.X), starPos: e.Star, expr: e} return &address{addr: b.expr(fn, e.X), pos: e.Star, expr: e}
} }
panic(fmt.Sprintf("unexpected address expression: %T", e)) panic(fmt.Sprintf("unexpected address expression: %T", e))
@ -891,7 +892,7 @@ func (b *builder) emitCallArgs(fn *Function, sig *types.Signature, e *ast.CallEx
} }
iaddr.setType(types.NewPointer(vt)) iaddr.setType(types.NewPointer(vt))
fn.emit(iaddr) fn.emit(iaddr)
emitStore(fn, iaddr, arg) emitStore(fn, iaddr, arg, arg.Pos())
} }
s := &Slice{X: a} s := &Slice{X: a}
s.setType(st) s.setType(st)
@ -1044,17 +1045,19 @@ func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit, isZero
switch t := typ.Underlying().(type) { switch t := typ.Underlying().(type) {
case *types.Struct: case *types.Struct:
if !isZero && len(e.Elts) != t.NumFields() { if !isZero && len(e.Elts) != t.NumFields() {
emitMemClear(fn, addr) emitMemClear(fn, addr, e.Lbrace)
isZero = true isZero = true
} }
for i, e := range e.Elts { for i, e := range e.Elts {
fieldIndex := i fieldIndex := i
pos := e.Pos()
if kv, ok := e.(*ast.KeyValueExpr); ok { if kv, ok := e.(*ast.KeyValueExpr); ok {
fname := kv.Key.(*ast.Ident).Name fname := kv.Key.(*ast.Ident).Name
for i, n := 0, t.NumFields(); i < n; i++ { for i, n := 0, t.NumFields(); i < n; i++ {
sf := t.Field(i) sf := t.Field(i)
if sf.Name() == fname { if sf.Name() == fname {
fieldIndex = i fieldIndex = i
pos = kv.Colon
e = kv.Value e = kv.Value
break break
} }
@ -1067,7 +1070,7 @@ func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit, isZero
} }
faddr.setType(types.NewPointer(sf.Type())) faddr.setType(types.NewPointer(sf.Type()))
fn.emit(faddr) fn.emit(faddr)
b.exprInPlace(fn, &address{addr: faddr, expr: e}, e, isZero) b.exprInPlace(fn, &address{addr: faddr, pos: pos, expr: e}, e, isZero)
} }
case *types.Array, *types.Slice: case *types.Array, *types.Slice:
@ -1086,7 +1089,7 @@ func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit, isZero
} }
if !isZero && int64(len(e.Elts)) != at.Len() { if !isZero && int64(len(e.Elts)) != at.Len() {
emitMemClear(fn, array) emitMemClear(fn, array, e.Lbrace)
isZero = true isZero = true
} }
@ -1108,20 +1111,20 @@ func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit, isZero
} }
iaddr.setType(types.NewPointer(at.Elem())) iaddr.setType(types.NewPointer(at.Elem()))
fn.emit(iaddr) fn.emit(iaddr)
b.exprInPlace(fn, &address{addr: iaddr, expr: e}, e, isZero) b.exprInPlace(fn, &address{addr: iaddr, pos: e.Pos(), expr: e}, e, isZero)
} }
if t != at { // slice if t != at { // slice
s := &Slice{X: array} s := &Slice{X: array}
s.setPos(e.Lbrace) s.setPos(e.Lbrace)
s.setType(typ) s.setType(typ)
emitStore(fn, addr, fn.emit(s)) emitStore(fn, addr, fn.emit(s), e.Lbrace)
} }
case *types.Map: case *types.Map:
m := &MakeMap{Reserve: intConst(int64(len(e.Elts)))} m := &MakeMap{Reserve: intConst(int64(len(e.Elts)))}
m.setPos(e.Lbrace) m.setPos(e.Lbrace)
m.setType(typ) m.setType(typ)
emitStore(fn, addr, fn.emit(m)) emitStore(fn, addr, fn.emit(m), e.Lbrace)
for _, e := range e.Elts { for _, e := range e.Elts {
e := e.(*ast.KeyValueExpr) e := e.(*ast.KeyValueExpr)
loc := &element{ loc := &element{
@ -1337,7 +1340,7 @@ func (b *builder) typeCaseBody(fn *Function, cc *ast.CaseClause, x Value, done *
// In a single-type case, y has that type. // In a single-type case, y has that type.
// In multi-type cases, 'case nil' and default, // In multi-type cases, 'case nil' and default,
// y has the same type as the interface operand. // y has the same type as the interface operand.
emitStore(fn, fn.addNamedLocal(obj), x) emitStore(fn, fn.addNamedLocal(obj), x, obj.Pos())
} }
fn.targets = &targets{ fn.targets = &targets{
tail: fn.targets, tail: fn.targets,
@ -1588,8 +1591,9 @@ func (b *builder) forStmt(fn *Function, s *ast.ForStmt, label *lblock) {
// rangeIndexed emits to fn the header for an integer-indexed loop // rangeIndexed emits to fn the header for an integer-indexed loop
// over array, *array or slice value x. // over array, *array or slice value x.
// The v result is defined only if tv is non-nil. // The v result is defined only if tv is non-nil.
// forPos is the position of the "for" token.
// //
func (b *builder) rangeIndexed(fn *Function, x Value, tv types.Type) (k, v Value, loop, done *BasicBlock) { func (b *builder) rangeIndexed(fn *Function, x Value, tv types.Type, pos token.Pos) (k, v Value, loop, done *BasicBlock) {
// //
// length = len(x) // length = len(x)
// index = -1 // index = -1
@ -1623,7 +1627,7 @@ func (b *builder) rangeIndexed(fn *Function, x Value, tv types.Type) (k, v Value
} }
index := fn.addLocal(tInt, token.NoPos) index := fn.addLocal(tInt, token.NoPos)
emitStore(fn, index, intConst(-1)) emitStore(fn, index, intConst(-1), pos)
loop = fn.newBasicBlock("rangeindex.loop") loop = fn.newBasicBlock("rangeindex.loop")
emitJump(fn, loop) emitJump(fn, loop)
@ -1635,7 +1639,7 @@ func (b *builder) rangeIndexed(fn *Function, x Value, tv types.Type) (k, v Value
Y: vOne, Y: vOne,
} }
incr.setType(tInt) incr.setType(tInt)
emitStore(fn, index, fn.emit(incr)) emitStore(fn, index, fn.emit(incr), pos)
body := fn.newBasicBlock("rangeindex.body") body := fn.newBasicBlock("rangeindex.body")
done = fn.newBasicBlock("rangeindex.done") done = fn.newBasicBlock("rangeindex.done")
@ -1814,10 +1818,10 @@ func (b *builder) rangeStmt(fn *Function, s *ast.RangeStmt, label *lblock) {
var loop, done *BasicBlock var loop, done *BasicBlock
switch rt := x.Type().Underlying().(type) { switch rt := x.Type().Underlying().(type) {
case *types.Slice, *types.Array, *types.Pointer: // *array case *types.Slice, *types.Array, *types.Pointer: // *array
k, v, loop, done = b.rangeIndexed(fn, x, tv) k, v, loop, done = b.rangeIndexed(fn, x, tv, s.For)
case *types.Chan: case *types.Chan:
k, loop, done = b.rangeChan(fn, x, tk, s.TokPos) k, loop, done = b.rangeChan(fn, x, tk, s.For)
case *types.Map, *types.Basic: // string case *types.Map, *types.Basic: // string
k, v, loop, done = b.rangeIter(fn, x, tk, tv, s.For) k, v, loop, done = b.rangeIter(fn, x, tk, tv, s.For)
@ -1955,7 +1959,7 @@ start:
// Function has named result parameters (NRPs). // Function has named result parameters (NRPs).
// Perform parallel assignment of return operands to NRPs. // Perform parallel assignment of return operands to NRPs.
for i, r := range results { for i, r := range results {
emitStore(fn, fn.namedResults[i], r) emitStore(fn, fn.namedResults[i], r, s.Return)
} }
} }
// Run function calls deferred in this // Run function calls deferred in this
@ -2206,7 +2210,7 @@ func (p *Package) Build() {
done = init.newBasicBlock("init.done") done = init.newBasicBlock("init.done")
emitIf(init, emitLoad(init, initguard), done, doinit) emitIf(init, emitLoad(init, initguard), done, doinit)
init.currentBlock = doinit init.currentBlock = doinit
emitStore(init, initguard, vTrue) emitStore(init, initguard, vTrue, token.NoPos)
// Call the init() function of each package we import. // Call the init() function of each package we import.
for _, pkg := range p.info.Pkg.Imports() { for _, pkg := range p.info.Pkg.Imports() {
@ -2234,7 +2238,7 @@ func (p *Package) Build() {
// 1:1 initialization: var x, y = a(), b() // 1:1 initialization: var x, y = a(), b()
var lval lvalue var lval lvalue
if v := varinit.Lhs[0]; v.Name() != "_" { if v := varinit.Lhs[0]; v.Name() != "_" {
lval = &address{addr: p.values[v].(*Global)} lval = &address{addr: p.values[v].(*Global), pos: v.Pos()}
} else { } else {
lval = blank{} lval = blank{}
} }
@ -2246,7 +2250,7 @@ func (p *Package) Build() {
if v.Name() == "_" { if v.Name() == "_" {
continue continue
} }
emitStore(init, p.values[v].(*Global), emitExtract(init, tuple, i)) emitStore(init, p.values[v].(*Global), emitExtract(init, tuple, i), v.Pos())
} }
} }
} }

View File

@ -246,10 +246,11 @@ func emitConv(f *Function, val Value, typ types.Type) Value {
// emitStore emits to f an instruction to store value val at location // emitStore emits to f an instruction to store value val at location
// addr, applying implicit conversions as required by assignability rules. // addr, applying implicit conversions as required by assignability rules.
// //
func emitStore(f *Function, addr, val Value) *Store { func emitStore(f *Function, addr, val Value, pos token.Pos) *Store {
s := &Store{ s := &Store{
Addr: addr, Addr: addr,
Val: emitConv(f, val, deref(addr.Type())), Val: emitConv(f, val, deref(addr.Type())),
pos: pos,
} }
f.emit(s) f.emit(s)
return s return s
@ -430,9 +431,9 @@ func zeroValue(f *Function, t types.Type) Value {
} }
// emitMemClear emits to f code to zero the value pointed to by ptr. // emitMemClear emits to f code to zero the value pointed to by ptr.
func emitMemClear(f *Function, ptr Value) { func emitMemClear(f *Function, ptr Value, pos token.Pos) {
// TODO(adonovan): define and use a 'memclr' intrinsic for aggregate types. // TODO(adonovan): define and use a 'memclr' intrinsic for aggregate types.
emitStore(f, ptr, zeroValue(f, deref(ptr.Type()))) emitStore(f, ptr, zeroValue(f, deref(ptr.Type())), pos)
} }
// createRecoverBlock emits to f a block of code to return after a // createRecoverBlock emits to f a block of code to return after a

View File

@ -27,20 +27,19 @@ type lvalue interface {
// An address is an lvalue represented by a true pointer. // An address is an lvalue represented by a true pointer.
type address struct { type address struct {
addr Value addr Value
starPos token.Pos // source position, if from explicit *addr pos token.Pos // source position
expr ast.Expr // source syntax [debug mode] expr ast.Expr // source syntax [debug mode]
} }
func (a *address) load(fn *Function) Value { func (a *address) load(fn *Function) Value {
load := emitLoad(fn, a.addr) load := emitLoad(fn, a.addr)
load.pos = a.starPos load.pos = a.pos
return load return load
} }
func (a *address) store(fn *Function, v Value) { func (a *address) store(fn *Function, v Value) {
store := emitStore(fn, a.addr, v) store := emitStore(fn, a.addr, v, a.pos)
store.pos = a.starPos
if a.expr != nil { if a.expr != nil {
// store.Val is v, converted for assignability. // store.Val is v, converted for assignability.
emitDebugRef(fn, a.expr, store.Val, false) emitDebugRef(fn, a.expr, store.Val, false)

View File

@ -564,8 +564,12 @@ type BinOp struct {
// and a boolean indicating the success of the receive. The // and a boolean indicating the success of the receive. The
// components of the tuple are accessed using Extract. // components of the tuple are accessed using Extract.
// //
// Pos() returns the ast.UnaryExpr.OpPos or ast.RangeStmt.TokPos (for // Pos() returns the ast.UnaryExpr.OpPos, if explicit in the source.
// ranging over a channel), if explicit in the source. // For receive operations (ARROW) implicit in ranging over a channel,
// Pos() returns the ast.RangeStmt.For.
// For implicit memory loads (STAR), Pos() returns the position of the
// most closely associated source-level construct; the details are not
// specified.
// //
// Example printed form: // Example printed form:
// t0 = *x // t0 = *x
@ -1162,7 +1166,10 @@ type Send struct {
// The Store instruction stores Val at address Addr. // The Store instruction stores Val at address Addr.
// Stores can be of arbitrary types. // Stores can be of arbitrary types.
// //
// Pos() returns the ast.StarExpr.Star, if explicit in the source. // Pos() returns the position of the source-level construct most closely
// associated with the memory store operation.
// Since implicit memory stores are numerous and varied and depend upon
// implementation choices, the details are not specified.
// //
// Example printed form: // Example printed form:
// *x = y // *x = y

View File

@ -247,7 +247,7 @@ func testMainSlice(fn *Function, testfuncs []*Function, slice types.Type) Value
pname := fn.emit(fa) pname := fn.emit(fa)
// Emit: *pname = "testfunc" // Emit: *pname = "testfunc"
emitStore(fn, pname, stringConst(testfunc.Name())) emitStore(fn, pname, stringConst(testfunc.Name()), token.NoPos)
// Emit: pfunc = &pitem.F // Emit: pfunc = &pitem.F
fa = &FieldAddr{X: pitem, Field: 1} // .F fa = &FieldAddr{X: pitem, Field: 1} // .F
@ -255,7 +255,7 @@ func testMainSlice(fn *Function, testfuncs []*Function, slice types.Type) Value
pfunc := fn.emit(fa) pfunc := fn.emit(fa)
// Emit: *pfunc = testfunc // Emit: *pfunc = testfunc
emitStore(fn, pfunc, testfunc) emitStore(fn, pfunc, testfunc, token.NoPos)
} }
// Emit: slice array[:] // Emit: slice array[:]